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