1 /*- 2 * Copyright (c) 2007 Kai Wang 3 * Copyright (c) 2007 Tim Kientzle 4 * Copyright (c) 2007 Joseph Koshy 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /*- 30 * Copyright (c) 1990, 1993, 1994 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * Hugh Smith at The University of Guelph. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 __FBSDID("$FreeBSD$"); 63 64 #include <sys/queue.h> 65 #include <sys/types.h> 66 #include <archive.h> 67 #include <errno.h> 68 #include <getopt.h> 69 #include <libgen.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <sysexits.h> 74 75 #include "ar.h" 76 77 enum options 78 { 79 OPTION_HELP 80 }; 81 82 static struct option longopts[] = 83 { 84 {"help", no_argument, NULL, OPTION_HELP}, 85 {"version", no_argument, NULL, 'V'}, 86 {NULL, 0, NULL, 0} 87 }; 88 89 static void bsdar_usage(void); 90 static void ranlib_usage(void); 91 static void set_mode(struct bsdar *bsdar, char opt); 92 static void only_mode(struct bsdar *bsdar, const char *opt, 93 const char *valid_modes); 94 static void bsdar_version(void); 95 static void ranlib_version(void); 96 97 int 98 main(int argc, char **argv) 99 { 100 struct bsdar *bsdar, bsdar_storage; 101 char *p; 102 size_t len; 103 int i, opt, Dflag, Uflag; 104 105 bsdar = &bsdar_storage; 106 memset(bsdar, 0, sizeof(*bsdar)); 107 Dflag = 0; 108 Uflag = 0; 109 110 if ((bsdar->progname = getprogname()) == NULL) 111 bsdar->progname = "ar"; 112 113 /* Act like ranlib if our name ends in "ranlib"; this 114 * accommodates arm-freebsd7.1-ranlib, bsdranlib, etc. */ 115 len = strlen(bsdar->progname); 116 if (len >= strlen("ranlib") && 117 strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) { 118 while ((opt = getopt_long(argc, argv, "tDUV", longopts, 119 NULL)) != -1) { 120 switch(opt) { 121 case 't': 122 /* Ignored. */ 123 break; 124 case 'D': 125 Dflag = 1; 126 Uflag = 0; 127 break; 128 case 'U': 129 Uflag = 1; 130 Dflag = 0; 131 break; 132 case 'V': 133 ranlib_version(); 134 break; 135 case OPTION_HELP: 136 ranlib_usage(); 137 default: 138 ranlib_usage(); 139 } 140 } 141 argv += optind; 142 argc -= optind; 143 144 if (*argv == NULL) 145 ranlib_usage(); 146 147 /* Enable determinstic mode unless -U is set. */ 148 if (Uflag == 0) 149 bsdar->options |= AR_D; 150 bsdar->options |= AR_S; 151 while ((bsdar->filename = *argv++) != NULL) 152 ar_mode_s(bsdar); 153 154 exit(EX_OK); 155 } else { 156 if (argc < 2) 157 bsdar_usage(); 158 159 if (*argv[1] != '-') { 160 len = strlen(argv[1]) + 2; 161 if ((p = malloc(len)) == NULL) 162 bsdar_errc(bsdar, EX_SOFTWARE, errno, 163 "malloc failed"); 164 *p = '-'; 165 (void)strlcpy(p + 1, argv[1], len - 1); 166 argv[1] = p; 167 } 168 } 169 170 while ((opt = getopt_long(argc, argv, "abCcdDfijlMmopqrSsTtUuVvxz", 171 longopts, NULL)) != -1) { 172 switch(opt) { 173 case 'a': 174 bsdar->options |= AR_A; 175 break; 176 case 'b': 177 case 'i': 178 bsdar->options |= AR_B; 179 break; 180 case 'C': 181 bsdar->options |= AR_CC; 182 break; 183 case 'c': 184 bsdar->options |= AR_C; 185 break; 186 case 'd': 187 set_mode(bsdar, opt); 188 break; 189 case 'D': 190 Dflag = 1; 191 Uflag = 0; 192 break; 193 case 'f': 194 case 'T': 195 bsdar->options |= AR_TR; 196 break; 197 case 'j': 198 /* ignored */ 199 break; 200 case 'l': 201 /* ignored, for GNU ar comptibility */ 202 break; 203 case 'M': 204 set_mode(bsdar, opt); 205 break; 206 case 'm': 207 set_mode(bsdar, opt); 208 break; 209 case 'o': 210 bsdar->options |= AR_O; 211 break; 212 case 'p': 213 set_mode(bsdar, opt); 214 break; 215 case 'q': 216 set_mode(bsdar, opt); 217 break; 218 case 'r': 219 set_mode(bsdar, opt); 220 break; 221 case 'S': 222 bsdar->options |= AR_SS; 223 break; 224 case 's': 225 bsdar->options |= AR_S; 226 break; 227 case 't': 228 set_mode(bsdar, opt); 229 break; 230 case 'U': 231 Uflag = 1; 232 Dflag = 0; 233 break; 234 case 'u': 235 bsdar->options |= AR_U; 236 break; 237 case 'V': 238 bsdar_version(); 239 break; 240 case 'v': 241 bsdar->options |= AR_V; 242 break; 243 case 'x': 244 set_mode(bsdar, opt); 245 break; 246 case 'z': 247 /* ignored */ 248 break; 249 case OPTION_HELP: 250 bsdar_usage(); 251 default: 252 bsdar_usage(); 253 } 254 } 255 256 argv += optind; 257 argc -= optind; 258 259 if (*argv == NULL && bsdar->mode != 'M') 260 bsdar_usage(); 261 262 if (bsdar->options & AR_A && bsdar->options & AR_B) 263 bsdar_errc(bsdar, EX_USAGE, 0, 264 "only one of -a and -[bi] options allowed"); 265 266 if (bsdar->options & AR_J && bsdar->options & AR_Z) 267 bsdar_errc(bsdar, EX_USAGE, 0, 268 "only one of -j and -z options allowed"); 269 270 if (bsdar->options & AR_S && bsdar->options & AR_SS) 271 bsdar_errc(bsdar, EX_USAGE, 0, 272 "only one of -s and -S options allowed"); 273 274 if (bsdar->options & (AR_A | AR_B)) { 275 if ((bsdar->posarg = *argv) == NULL) 276 bsdar_errc(bsdar, EX_USAGE, 0, 277 "no position operand specified"); 278 if ((bsdar->posarg = basename(bsdar->posarg)) == NULL) 279 bsdar_errc(bsdar, EX_SOFTWARE, errno, 280 "basename failed"); 281 argc--; 282 argv++; 283 } 284 285 /* Set determinstic mode for -D, and by default without -U. */ 286 if (Dflag || (Uflag == 0 && (bsdar->mode == 'q' || bsdar->mode == 'r'))) 287 bsdar->options |= AR_D; 288 289 if (bsdar->options & AR_A) 290 only_mode(bsdar, "-a", "mqr"); 291 if (bsdar->options & AR_B) 292 only_mode(bsdar, "-b", "mqr"); 293 if (bsdar->options & AR_C) 294 only_mode(bsdar, "-c", "qr"); 295 if (bsdar->options & AR_CC) 296 only_mode(bsdar, "-C", "x"); 297 if (Dflag) 298 only_mode(bsdar, "-D", "qr"); 299 if (Uflag) 300 only_mode(bsdar, "-U", "qr"); 301 if (bsdar->options & AR_O) 302 only_mode(bsdar, "-o", "x"); 303 if (bsdar->options & AR_SS) 304 only_mode(bsdar, "-S", "mqr"); 305 if (bsdar->options & AR_U) 306 only_mode(bsdar, "-u", "qrx"); 307 308 if (bsdar->mode == 'M') { 309 ar_mode_script(bsdar); 310 exit(EX_OK); 311 } 312 313 if ((bsdar->filename = *argv) == NULL) 314 bsdar_usage(); 315 316 bsdar->argc = --argc; 317 bsdar->argv = ++argv; 318 319 if ((!bsdar->mode || strchr("ptx", bsdar->mode)) && 320 bsdar->options & AR_S) { 321 ar_mode_s(bsdar); 322 if (!bsdar->mode) 323 exit(EX_OK); 324 } 325 326 switch(bsdar->mode) { 327 case 'd': 328 ar_mode_d(bsdar); 329 break; 330 case 'm': 331 ar_mode_m(bsdar); 332 break; 333 case 'p': 334 ar_mode_p(bsdar); 335 break; 336 case 'q': 337 ar_mode_q(bsdar); 338 break; 339 case 'r': 340 ar_mode_r(bsdar); 341 break; 342 case 't': 343 ar_mode_t(bsdar); 344 break; 345 case 'x': 346 ar_mode_x(bsdar); 347 break; 348 default: 349 bsdar_usage(); 350 /* NOTREACHED */ 351 } 352 353 for (i = 0; i < bsdar->argc; i++) 354 if (bsdar->argv[i] != NULL) 355 bsdar_warnc(bsdar, 0, "%s: not found in archive", 356 bsdar->argv[i]); 357 358 exit(EX_OK); 359 } 360 361 static void 362 set_mode(struct bsdar *bsdar, char opt) 363 { 364 365 if (bsdar->mode != '\0' && bsdar->mode != opt) 366 bsdar_errc(bsdar, EX_USAGE, 0, 367 "Can't specify both -%c and -%c", opt, bsdar->mode); 368 bsdar->mode = opt; 369 } 370 371 static void 372 only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes) 373 { 374 375 if (strchr(valid_modes, bsdar->mode) == NULL) 376 bsdar_errc(bsdar, EX_USAGE, 0, 377 "Option %s is not permitted in mode -%c", opt, bsdar->mode); 378 } 379 380 static void 381 bsdar_usage(void) 382 { 383 384 (void)fprintf(stderr, "usage: ar -d [-Tjsvz] archive file ...\n"); 385 (void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n"); 386 (void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n"); 387 (void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n"); 388 (void)fprintf(stderr, "\tar -q [-TcDjsUvz] archive file ...\n"); 389 (void)fprintf(stderr, "\tar -r [-TcDjsUuvz] archive file ...\n"); 390 (void)fprintf(stderr, "\tar -r [-TabcDijsUuvz] position archive file ...\n"); 391 (void)fprintf(stderr, "\tar -s [-jz] archive\n"); 392 (void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n"); 393 (void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n"); 394 (void)fprintf(stderr, "\tar -V\n"); 395 exit(EX_USAGE); 396 } 397 398 static void 399 ranlib_usage(void) 400 { 401 402 (void)fprintf(stderr, "usage: ranlib [-DtU] archive ...\n"); 403 (void)fprintf(stderr, "\tranlib -V\n"); 404 exit(EX_USAGE); 405 } 406 407 static void 408 bsdar_version(void) 409 { 410 (void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version_string()); 411 exit(EX_OK); 412 } 413 414 static void 415 ranlib_version(void) 416 { 417 (void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version_string()); 418 exit(EX_OK); 419 } 420