ar.c revision 208189
1176434Skaiw/*-
2176434Skaiw * Copyright (c) 2007 Kai Wang
3176434Skaiw * Copyright (c) 2007 Tim Kientzle
4176434Skaiw * Copyright (c) 2007 Joseph Koshy
5176434Skaiw * All rights reserved.
6176434Skaiw *
7176434Skaiw * Redistribution and use in source and binary forms, with or without
8176434Skaiw * modification, are permitted provided that the following conditions
9176434Skaiw * are met:
10176434Skaiw * 1. Redistributions of source code must retain the above copyright
11176434Skaiw *    notice, this list of conditions and the following disclaimer
12176434Skaiw *    in this position and unchanged.
13176434Skaiw * 2. Redistributions in binary form must reproduce the above copyright
14176434Skaiw *    notice, this list of conditions and the following disclaimer in the
15176434Skaiw *    documentation and/or other materials provided with the distribution.
16176434Skaiw *
17176434Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18176434Skaiw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19176434Skaiw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20176434Skaiw * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21176434Skaiw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22176434Skaiw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23176434Skaiw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24176434Skaiw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25176434Skaiw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26176434Skaiw * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27176434Skaiw */
28176434Skaiw
29176434Skaiw/*-
30176434Skaiw * Copyright (c) 1990, 1993, 1994
31176434Skaiw *	The Regents of the University of California.  All rights reserved.
32176434Skaiw *
33176434Skaiw * This code is derived from software contributed to Berkeley by
34176434Skaiw * Hugh Smith at The University of Guelph.
35176434Skaiw *
36176434Skaiw * Redistribution and use in source and binary forms, with or without
37176434Skaiw * modification, are permitted provided that the following conditions
38176434Skaiw * are met:
39176434Skaiw * 1. Redistributions of source code must retain the above copyright
40176434Skaiw *    notice, this list of conditions and the following disclaimer.
41176434Skaiw * 2. Redistributions in binary form must reproduce the above copyright
42176434Skaiw *    notice, this list of conditions and the following disclaimer in the
43176434Skaiw *    documentation and/or other materials provided with the distribution.
44176434Skaiw * 3. Neither the name of the University nor the names of its contributors
45176434Skaiw *    may be used to endorse or promote products derived from this software
46176434Skaiw *    without specific prior written permission.
47176434Skaiw *
48176434Skaiw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49176434Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50176434Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51176434Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52176434Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53176434Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54176434Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55176434Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56176434Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57176434Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58176434Skaiw * SUCH DAMAGE.
59176434Skaiw */
60176434Skaiw
61176434Skaiw#include <sys/cdefs.h>
62176434Skaiw__FBSDID("$FreeBSD: head/usr.bin/ar/ar.c 208189 2010-05-17 09:37:59Z kaiw $");
63176434Skaiw
64176434Skaiw#include <sys/queue.h>
65176434Skaiw#include <sys/types.h>
66176434Skaiw#include <archive.h>
67176434Skaiw#include <errno.h>
68176434Skaiw#include <getopt.h>
69176434Skaiw#include <libgen.h>
70176434Skaiw#include <stdio.h>
71176434Skaiw#include <stdlib.h>
72176434Skaiw#include <string.h>
73176434Skaiw#include <sysexits.h>
74176434Skaiw
75176434Skaiw#include "ar.h"
76176434Skaiw
77176434Skaiwenum options
78176434Skaiw{
79176434Skaiw	OPTION_HELP
80176434Skaiw};
81176434Skaiw
82176434Skaiwstatic struct option longopts[] =
83176434Skaiw{
84176434Skaiw	{"help", no_argument, NULL, OPTION_HELP},
85176434Skaiw	{"version", no_argument, NULL, 'V'},
86176434Skaiw	{NULL, 0, NULL, 0}
87176434Skaiw};
88176434Skaiw
89176434Skaiwstatic void	bsdar_usage(void);
90176434Skaiwstatic void	ranlib_usage(void);
91176434Skaiwstatic void	set_mode(struct bsdar *bsdar, char opt);
92176434Skaiwstatic void	only_mode(struct bsdar *bsdar, const char *opt,
93176434Skaiw		    const char *valid_modes);
94176434Skaiwstatic void	bsdar_version(void);
95176434Skaiwstatic void	ranlib_version(void);
96176434Skaiw
97176434Skaiwint
98176434Skaiwmain(int argc, char **argv)
99176434Skaiw{
100176434Skaiw	struct bsdar	*bsdar, bsdar_storage;
101176434Skaiw	char		*p;
102176434Skaiw	size_t		 len;
103176434Skaiw	int		 i, opt;
104176434Skaiw
105176434Skaiw	bsdar = &bsdar_storage;
106176434Skaiw	memset(bsdar, 0, sizeof(*bsdar));
107176434Skaiw
108176434Skaiw	if ((bsdar->progname = getprogname()) == NULL)
109176434Skaiw		bsdar->progname = "ar";
110176434Skaiw
111190162Skientzle	/* Act like ranlib if our name ends in "ranlib"; this
112190162Skientzle	 * accomodates arm-freebsd7.1-ranlib, bsdranlib, etc. */
113190162Skientzle	len = strlen(bsdar->progname);
114190162Skientzle	if (len >= strlen("ranlib") &&
115190162Skientzle	    strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) {
116176434Skaiw		while ((opt = getopt_long(argc, argv, "tV", longopts,
117176434Skaiw		    NULL)) != -1) {
118176434Skaiw			switch(opt) {
119176434Skaiw			case 't':
120176434Skaiw				/* Ignored. */
121176434Skaiw				break;
122176434Skaiw			case 'V':
123176434Skaiw				ranlib_version();
124176434Skaiw				break;
125176434Skaiw			case OPTION_HELP:
126176434Skaiw				ranlib_usage();
127176434Skaiw			default:
128176434Skaiw				ranlib_usage();
129176434Skaiw			}
130176434Skaiw		}
131176434Skaiw		argv += optind;
132176434Skaiw		argc -= optind;
133176434Skaiw
134176434Skaiw		if (*argv == NULL)
135176434Skaiw			ranlib_usage();
136176434Skaiw
137176434Skaiw		bsdar->options |= AR_S;
138176434Skaiw		for (;(bsdar->filename = *argv++) != NULL;)
139176434Skaiw			ar_mode_s(bsdar);
140176434Skaiw
141176434Skaiw		exit(EX_OK);
142176434Skaiw	} else {
143176434Skaiw		if (argc < 2)
144176434Skaiw			bsdar_usage();
145176434Skaiw
146176434Skaiw		if (*argv[1] != '-') {
147176434Skaiw			len = strlen(argv[1]) + 2;
148176434Skaiw			if ((p = malloc(len)) == NULL)
149176434Skaiw				bsdar_errc(bsdar, EX_SOFTWARE, errno,
150176434Skaiw				    "malloc failed");
151176434Skaiw			*p = '-';
152176434Skaiw			(void)strlcpy(p + 1, argv[1], len - 1);
153176434Skaiw			argv[1] = p;
154176434Skaiw		}
155176434Skaiw	}
156176434Skaiw
157183218Skaiw	while ((opt = getopt_long(argc, argv, "abCcdfijlMmopqrSsTtuVvxz",
158176434Skaiw	    longopts, NULL)) != -1) {
159176434Skaiw		switch(opt) {
160176434Skaiw		case 'a':
161176434Skaiw			bsdar->options |= AR_A;
162176434Skaiw			break;
163176434Skaiw		case 'b':
164176434Skaiw		case 'i':
165176434Skaiw			bsdar->options |= AR_B;
166176434Skaiw			break;
167176434Skaiw		case 'C':
168176434Skaiw			bsdar->options |= AR_CC;
169176434Skaiw			break;
170176434Skaiw		case 'c':
171176434Skaiw			bsdar->options |= AR_C;
172176434Skaiw			break;
173176434Skaiw		case 'd':
174176434Skaiw			set_mode(bsdar, opt);
175176434Skaiw			break;
176176434Skaiw		case 'f':
177176434Skaiw		case 'T':
178176434Skaiw			bsdar->options |= AR_TR;
179176434Skaiw			break;
180176434Skaiw		case 'j':
181208189Skaiw			/* ignored */
182176434Skaiw			break;
183176434Skaiw		case 'l':
184176434Skaiw			/* ignored, for GNU ar comptibility */
185176434Skaiw			break;
186183218Skaiw		case 'M':
187183218Skaiw			set_mode(bsdar, opt);
188183218Skaiw			break;
189176434Skaiw		case 'm':
190176434Skaiw			set_mode(bsdar, opt);
191176434Skaiw			break;
192176434Skaiw		case 'o':
193176434Skaiw			bsdar->options |= AR_O;
194176434Skaiw			break;
195176434Skaiw		case 'p':
196176434Skaiw			set_mode(bsdar, opt);
197176434Skaiw			break;
198176434Skaiw		case 'q':
199176434Skaiw			set_mode(bsdar, opt);
200176434Skaiw			break;
201176434Skaiw		case 'r':
202176434Skaiw			set_mode(bsdar, opt);
203176434Skaiw			break;
204176434Skaiw		case 'S':
205176434Skaiw			bsdar->options |= AR_SS;
206176434Skaiw			break;
207176434Skaiw		case 's':
208176434Skaiw			bsdar->options |= AR_S;
209176434Skaiw			break;
210176434Skaiw		case 't':
211176434Skaiw			set_mode(bsdar, opt);
212176434Skaiw			break;
213176434Skaiw		case 'u':
214176434Skaiw			bsdar->options |= AR_U;
215176434Skaiw			break;
216176434Skaiw		case 'V':
217176434Skaiw			bsdar_version();
218176434Skaiw			break;
219176434Skaiw		case 'v':
220176434Skaiw			bsdar->options |= AR_V;
221176434Skaiw			break;
222176434Skaiw		case 'x':
223176434Skaiw			set_mode(bsdar, opt);
224176434Skaiw			break;
225176434Skaiw		case 'z':
226208189Skaiw			/* ignored */
227176434Skaiw			break;
228176434Skaiw		case OPTION_HELP:
229176434Skaiw			bsdar_usage();
230176434Skaiw		default:
231176434Skaiw			bsdar_usage();
232176434Skaiw		}
233176434Skaiw	}
234176434Skaiw
235176434Skaiw	argv += optind;
236176434Skaiw	argc -= optind;
237176434Skaiw
238183218Skaiw	if (*argv == NULL && bsdar->mode != 'M')
239176434Skaiw		bsdar_usage();
240176434Skaiw
241176434Skaiw	if (bsdar->options & AR_A && bsdar->options & AR_B)
242176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
243176434Skaiw		    "only one of -a and -[bi] options allowed");
244176434Skaiw
245176434Skaiw	if (bsdar->options & AR_J && bsdar->options & AR_Z)
246176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
247176434Skaiw		    "only one of -j and -z options allowed");
248176434Skaiw
249176434Skaiw	if (bsdar->options & AR_S && bsdar->options & AR_SS)
250176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
251176434Skaiw		    "only one of -s and -S options allowed");
252176434Skaiw
253176434Skaiw	if (bsdar->options & (AR_A | AR_B)) {
254176434Skaiw		if ((bsdar->posarg = *argv) == NULL)
255176434Skaiw			bsdar_errc(bsdar, EX_USAGE, 0,
256176434Skaiw			    "no position operand specified");
257176434Skaiw		if ((bsdar->posarg = basename(bsdar->posarg)) == NULL)
258176434Skaiw			bsdar_errc(bsdar, EX_SOFTWARE, errno,
259176434Skaiw			    "basename failed");
260176434Skaiw		argc--;
261176434Skaiw		argv++;
262176434Skaiw	}
263176434Skaiw
264176434Skaiw	if (bsdar->options & AR_A)
265176434Skaiw		only_mode(bsdar, "-a", "mqr");
266176434Skaiw	if (bsdar->options & AR_B)
267176434Skaiw		only_mode(bsdar, "-b", "mqr");
268176434Skaiw	if (bsdar->options & AR_C)
269176434Skaiw		only_mode(bsdar, "-c", "qr");
270176434Skaiw	if (bsdar->options & AR_CC)
271176434Skaiw		only_mode(bsdar, "-C", "x");
272176434Skaiw	if (bsdar->options & AR_O)
273176434Skaiw		only_mode(bsdar, "-o", "x");
274176434Skaiw	if (bsdar->options & AR_SS)
275176434Skaiw		only_mode(bsdar, "-S", "mqr");
276176434Skaiw	if (bsdar->options & AR_U)
277176434Skaiw		only_mode(bsdar, "-u", "qrx");
278176434Skaiw
279183218Skaiw	if (bsdar->mode == 'M') {
280183218Skaiw		ar_mode_script(bsdar);
281183218Skaiw		exit(EX_OK);
282183218Skaiw	}
283183218Skaiw
284176434Skaiw	if ((bsdar->filename = *argv) == NULL)
285176434Skaiw		bsdar_usage();
286176434Skaiw
287176434Skaiw	bsdar->argc = --argc;
288176434Skaiw	bsdar->argv = ++argv;
289176434Skaiw
290176434Skaiw	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
291176434Skaiw	    bsdar->options & AR_S) {
292176434Skaiw		ar_mode_s(bsdar);
293176434Skaiw		if (!bsdar->mode)
294176434Skaiw			exit(EX_OK);
295176434Skaiw	}
296176434Skaiw
297176434Skaiw	switch(bsdar->mode) {
298176434Skaiw	case 'd':
299176434Skaiw		ar_mode_d(bsdar);
300176434Skaiw		break;
301176434Skaiw	case 'm':
302176434Skaiw		ar_mode_m(bsdar);
303176434Skaiw		break;
304176434Skaiw	case 'p':
305176434Skaiw		ar_mode_p(bsdar);
306176434Skaiw		break;
307176434Skaiw	case 'q':
308177064Skaiw		ar_mode_q(bsdar);
309176434Skaiw		break;
310176434Skaiw	case 'r':
311176434Skaiw		ar_mode_r(bsdar);
312176434Skaiw		break;
313176434Skaiw	case 't':
314176434Skaiw		ar_mode_t(bsdar);
315176434Skaiw		break;
316176434Skaiw	case 'x':
317176434Skaiw		ar_mode_x(bsdar);
318176434Skaiw		break;
319176434Skaiw	default:
320176434Skaiw		bsdar_usage();
321176434Skaiw		/* NOTREACHED */
322176434Skaiw	}
323176434Skaiw
324176434Skaiw	for (i = 0; i < bsdar->argc; i++)
325176434Skaiw		if (bsdar->argv[i] != NULL)
326176434Skaiw			bsdar_warnc(bsdar, 0, "%s: not found in archive",
327176434Skaiw			    bsdar->argv[i]);
328176434Skaiw
329176434Skaiw	exit(EX_OK);
330176434Skaiw}
331176434Skaiw
332176434Skaiwstatic void
333176434Skaiwset_mode(struct bsdar *bsdar, char opt)
334176434Skaiw{
335176434Skaiw
336176434Skaiw	if (bsdar->mode != '\0' && bsdar->mode != opt)
337176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
338176434Skaiw		    "Can't specify both -%c and -%c", opt, bsdar->mode);
339176434Skaiw	bsdar->mode = opt;
340176434Skaiw}
341176434Skaiw
342176434Skaiwstatic void
343176434Skaiwonly_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
344176434Skaiw{
345176434Skaiw
346176434Skaiw	if (strchr(valid_modes, bsdar->mode) == NULL)
347176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
348176434Skaiw		    "Option %s is not permitted in mode -%c", opt, bsdar->mode);
349176434Skaiw}
350176434Skaiw
351176434Skaiwstatic void
352201382Sedbsdar_usage(void)
353176434Skaiw{
354176434Skaiw
355176434Skaiw	(void)fprintf(stderr, "usage:  ar -d [-Tjsvz] archive file ...\n");
356176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n");
357176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n");
358176434Skaiw	(void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
359177064Skaiw	(void)fprintf(stderr, "\tar -q [-Tcjsvz] archive file ...\n");
360176434Skaiw	(void)fprintf(stderr, "\tar -r [-Tcjsuvz] archive file ...\n");
361176434Skaiw	(void)fprintf(stderr, "\tar -r [-Tabcijsuvz] position archive file ...\n");
362176434Skaiw	(void)fprintf(stderr, "\tar -s [-jz] archive\n");
363176434Skaiw	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
364176434Skaiw	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
365176434Skaiw	(void)fprintf(stderr, "\tar -V\n");
366176434Skaiw	exit(EX_USAGE);
367176434Skaiw}
368176434Skaiw
369176434Skaiwstatic void
370201382Sedranlib_usage(void)
371176434Skaiw{
372176434Skaiw
373176434Skaiw	(void)fprintf(stderr, "usage:	ranlib [-t] archive ...\n");
374176434Skaiw	(void)fprintf(stderr, "\tranlib -V\n");
375176434Skaiw	exit(EX_USAGE);
376176434Skaiw}
377176434Skaiw
378176434Skaiwstatic void
379201382Sedbsdar_version(void)
380176434Skaiw{
381176434Skaiw	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version());
382176434Skaiw	exit(EX_OK);
383176434Skaiw}
384176434Skaiw
385176434Skaiwstatic void
386201382Sedranlib_version(void)
387176434Skaiw{
388176434Skaiw	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version());
389176434Skaiw	exit(EX_OK);
390176434Skaiw}
391