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 }