1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*      Copyright (c) 1988 AT&T     */
  22 /*        All Rights Reserved   */
  23 
  24 /*
  25  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  26  */
  27 
  28 #include "inc.h"
  29 #include "conv.h"
  30 
  31 /*
  32  * Forward declarations
  33  */
  34 static void setup(int, char **, Cmd_info *);
  35 static void setcom(Cmd_info *, Cmd_func);
  36 static void usage(void);
  37 static void sigexit(int sig);
  38 static int notfound(Cmd_info *);
  39 static void check_swap();
  40 
  41 const char *
  42 _ar_msg(Msg mid)
  43 {
  44         return (gettext(MSG_ORIG(mid)));
  45 }
  46 
  47 
  48 void
  49 establish_sighandler(void (*handler)())
  50 {
  51         static const int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
  52         int i;
  53 
  54         if (handler == SIG_IGN) {
  55                 /* Ignore all the specified signals */
  56                 for (i = 0; signum[i]; i++)
  57                         (void) signal(signum[i], SIG_IGN);
  58 
  59         } else {
  60                 /*
  61                  * Set any signal that doesn't default to being ignored
  62                  * to our signal handler.
  63                  */
  64                 for (i = 0; signum[i]; i++)
  65                         if (signal(signum[i], SIG_IGN) != SIG_IGN)
  66                                 (void) signal(signum[i], handler);
  67         }
  68 }
  69 
  70 int
  71 main(int argc, char **argv, char *envp[])
  72 {
  73         int fd;
  74         Cmd_info *cmd_info;
  75         int ret;
  76         char *new = NULL;
  77 
  78 #ifndef XPG4
  79         /*
  80          * Check for a binary that better fits this architecture.
  81          */
  82         (void) conv_check_native(argv, envp);
  83 #endif
  84 
  85         /*
  86          * Establish locale.
  87          */
  88         (void) setlocale(LC_ALL, MSG_ORIG(MSG_STR_EMPTY));
  89         (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
  90 
  91         /* Allow a graceful exit up until we start to write an archive */
  92         establish_sighandler(sigexit);
  93 
  94         /*
  95          * Initialize cmd_info
  96          */
  97         cmd_info = (Cmd_info *)calloc(1, sizeof (Cmd_info));
  98         if (cmd_info == NULL) {
  99                 int err = errno;
 100                 (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
 101                 exit(1);
 102         }
 103 
 104         if (argc < 2)
 105                 usage();
 106 
 107         /*
 108          * Option handling.
 109          */
 110         if (argv[1][0] != '-') {
 111                 new = (char *)malloc(strlen(argv[1]) + 2);
 112                 if (new == NULL) {
 113                         int err = errno;
 114                         (void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
 115                             strerror(err));
 116                         exit(1);
 117                 }
 118                 (void) strcpy(new, MSG_ORIG(MSG_STR_HYPHEN));
 119                 (void) strcat(new, argv[1]);
 120                 argv[1] = new;
 121         }
 122         setup(argc, argv, cmd_info);
 123 
 124         /*
 125          * Check SWAP
 126          */
 127         if (cmd_info->opt_flgs & z_FLAG)
 128                 check_swap();
 129 
 130         if (cmd_info->comfun == NULL) {
 131                 if ((cmd_info->opt_flgs & (d_FLAG | r_FLAG | q_FLAG |
 132                     t_FLAG | p_FLAG | m_FLAG | x_FLAG)) == 0) {
 133                         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_01));
 134                         exit(1);
 135                 }
 136         }
 137 
 138         cmd_info->modified = (cmd_info->opt_flgs & s_FLAG);
 139         fd = getaf(cmd_info);
 140 
 141         if ((fd == -1) &&
 142             (cmd_info->opt_flgs &
 143             (d_FLAG | m_FLAG | p_FLAG | t_FLAG | x_FLAG)) ||
 144             ((cmd_info->opt_flgs & r_FLAG) &&
 145             (cmd_info->opt_flgs & (a_FLAG | b_FLAG)))) {
 146                 (void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_AR),
 147                     cmd_info->arnam);
 148                 exit(1);
 149         }
 150 
 151         (*cmd_info->comfun)(cmd_info);
 152         if (cmd_info->modified) {
 153                 writefile(cmd_info);
 154         } else
 155                 (void) close(fd);
 156 
 157         ret = notfound(cmd_info);
 158 
 159         /*
 160          * Check SWAP
 161          */
 162         if (cmd_info->opt_flgs & z_FLAG)
 163                 check_swap();
 164 
 165         free(new);
 166         free(cmd_info);
 167         return (ret);
 168 
 169 }
 170 
 171 /*
 172  * Option handing function.
 173  *      Using getopt(), following xcu4 convention.
 174  */
 175 static void
 176 setup(int argc, char *argv[], Cmd_info *cmd_info)
 177 {
 178         int Vflag = 0;
 179         int c;
 180         int usage_err = 0;
 181 
 182         while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
 183                 switch (c) {
 184                 case 'a': /* position after named archive member file */
 185                         cmd_info->opt_flgs |= a_FLAG;
 186                         cmd_info->ponam = trim(optarg);
 187                         break;
 188                 case 'b': /* position before named archive member file */
 189                 case 'i': /* position before named archive member: same as b */
 190                         cmd_info->opt_flgs |= b_FLAG;
 191                         cmd_info->ponam = trim(optarg);
 192                         break;
 193                 case 'c': /* supress messages */
 194                         cmd_info->opt_flgs |= c_FLAG;
 195                         break;
 196                 case 'd':
 197                         /*
 198                          * key operation:
 199                          * delete files from the archive
 200                          */
 201                         setcom(cmd_info, dcmd);
 202                         cmd_info->opt_flgs |= d_FLAG;
 203                         break;
 204                 case 'l': /* ignored */
 205                         break;
 206                 case 'm':
 207                         /*
 208                          * key operation:
 209                          * move files to end of the archive
 210                          * or as indicated by position flag
 211                          */
 212                         setcom(cmd_info, mcmd);
 213                         cmd_info->opt_flgs |= m_FLAG;
 214                         break;
 215                 case 'p':
 216                         /*
 217                          * key operation:
 218                          * print files in the archive
 219                          */
 220                         setcom(cmd_info, pcmd);
 221                         cmd_info->opt_flgs |= p_FLAG;
 222                         break;
 223                 case 'q':
 224                         /*
 225                          * key operation:
 226                          * quickly append files to end of the archive
 227                          */
 228                         setcom(cmd_info, qcmd);
 229                         cmd_info->opt_flgs |= q_FLAG;
 230                         break;
 231                 case 'r':
 232                         /*
 233                          * key operation:
 234                          * replace or add files to the archive
 235                          */
 236                         setcom(cmd_info, rcmd);
 237                         cmd_info->opt_flgs |= r_FLAG;
 238                         break;
 239                 case 's': /* force symbol table regeneration */
 240                         cmd_info->opt_flgs |= s_FLAG;
 241                         break;
 242                 case 'S': /* Build SYM64 symbol table */
 243                         cmd_info->opt_flgs |= S_FLAG;
 244                         break;
 245                 case 't':
 246                         /*
 247                          * key operation:
 248                          * print table of contents
 249                          */
 250                         setcom(cmd_info, tcmd);
 251                         cmd_info->opt_flgs |= t_FLAG;
 252                         break;
 253                 case 'u': /* update: change archive dependent on file dates */
 254                         cmd_info->opt_flgs |= u_FLAG;
 255                         break;
 256                 case 'v': /* verbose */
 257                         cmd_info->opt_flgs |= v_FLAG;
 258                         break;
 259                 case 'x':
 260                         /*
 261                          * key operation:
 262                          * extract files from the archive
 263                          */
 264                         setcom(cmd_info, xcmd);
 265                         cmd_info->opt_flgs |= x_FLAG;
 266                         break;
 267                 case 'z':
 268                         cmd_info->opt_flgs |= z_FLAG;
 269                         break;
 270                 case 'V':
 271                         /*
 272                          * print version information.
 273                          * adjust command line access accounting
 274                          */
 275                         if (Vflag == 0) {
 276                                 (void) fprintf(stderr,
 277                                     MSG_ORIG(MSG_FMT_VERSION),
 278                                     (const char *)SGU_PKG,
 279                                     (const char *)SGU_REL);
 280                                         Vflag++;
 281                         }
 282                         break;
 283                 case 'C':
 284                         cmd_info->opt_flgs |= C_FLAG;
 285                         break;
 286                 case 'M':
 287                         /*
 288                          * -M was an original undocumented AT&T feature that
 289                          * would force the use of mmap() instead of read()
 290                          * for pulling file data into the process before
 291                          * writing it to the archive. Ignored.
 292                          */
 293                         break;
 294                 case 'T':
 295                         cmd_info->opt_flgs |= T_FLAG;
 296                         break;
 297                 case ':':
 298                         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_02), optopt);
 299                         usage_err++;
 300                         break;
 301                 case '?':
 302                         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_03), optopt);
 303                         usage_err++;
 304                         break;
 305                 }
 306         }
 307 
 308         if (usage_err || argc - optind < 1)
 309                 usage();
 310 
 311         cmd_info->arnam = argv[optind];
 312         cmd_info->namv = &argv[optind+1];
 313         cmd_info->namc = argc - optind - 1;
 314 }
 315 
 316 
 317 /*
 318  * Set the function to be called to do the key operation.
 319  * Check that only one key is indicated.
 320  */
 321 static void
 322 setcom(Cmd_info *cmd_info, Cmd_func *fun)
 323 {
 324         if (cmd_info->comfun != 0) {
 325                 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_04));
 326                 exit(1);
 327         }
 328         cmd_info->comfun = fun;
 329 }
 330 
 331 static void
 332 usage(void)
 333 {
 334         (void) fprintf(stderr, MSG_INTL(MSG_USAGE));
 335         exit(1);
 336 }
 337 
 338 /*ARGSUSED0*/
 339 static void
 340 sigexit(int sig)
 341 {
 342         exit(100);
 343 }
 344 
 345 /* tells the user which of the listed files were not found in the archive */
 346 
 347 static int
 348 notfound(Cmd_info *cmd_info)
 349 {
 350         int i, n;
 351 
 352         n = 0;
 353         for (i = 0; i < cmd_info->namc; i++)
 354                 if (cmd_info->namv[i]) {
 355                         (void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_FILE),
 356                             cmd_info->namv[i]);
 357                         n++;
 358                 }
 359         return (n);
 360 }
 361 
 362 /*
 363  * Debugging info
 364  */
 365 static void
 366 check_swap(void)
 367 {
 368         (void) system(MSG_ORIG(MSG_CMD_SWAP));
 369 }