ar.c revision 183218
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 183218 2008-09-20 22:10:10Z 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
111176527Skaiw	if (strcmp(bsdar->progname, "ranlib") == 0 ||
112176527Skaiw	    strcmp(bsdar->progname, "bsdranlib") == 0) {
113176434Skaiw		while ((opt = getopt_long(argc, argv, "tV", longopts,
114176434Skaiw		    NULL)) != -1) {
115176434Skaiw			switch(opt) {
116176434Skaiw			case 't':
117176434Skaiw				/* Ignored. */
118176434Skaiw				break;
119176434Skaiw			case 'V':
120176434Skaiw				ranlib_version();
121176434Skaiw				break;
122176434Skaiw			case OPTION_HELP:
123176434Skaiw				ranlib_usage();
124176434Skaiw			default:
125176434Skaiw				ranlib_usage();
126176434Skaiw			}
127176434Skaiw		}
128176434Skaiw		argv += optind;
129176434Skaiw		argc -= optind;
130176434Skaiw
131176434Skaiw		if (*argv == NULL)
132176434Skaiw			ranlib_usage();
133176434Skaiw
134176434Skaiw		bsdar->options |= AR_S;
135176434Skaiw		for (;(bsdar->filename = *argv++) != NULL;)
136176434Skaiw			ar_mode_s(bsdar);
137176434Skaiw
138176434Skaiw		exit(EX_OK);
139176434Skaiw	} else {
140176434Skaiw		if (argc < 2)
141176434Skaiw			bsdar_usage();
142176434Skaiw
143176434Skaiw		if (*argv[1] != '-') {
144176434Skaiw			len = strlen(argv[1]) + 2;
145176434Skaiw			if ((p = malloc(len)) == NULL)
146176434Skaiw				bsdar_errc(bsdar, EX_SOFTWARE, errno,
147176434Skaiw				    "malloc failed");
148176434Skaiw			*p = '-';
149176434Skaiw			(void)strlcpy(p + 1, argv[1], len - 1);
150176434Skaiw			argv[1] = p;
151176434Skaiw		}
152176434Skaiw	}
153176434Skaiw
154183218Skaiw	while ((opt = getopt_long(argc, argv, "abCcdfijlMmopqrSsTtuVvxz",
155176434Skaiw	    longopts, NULL)) != -1) {
156176434Skaiw		switch(opt) {
157176434Skaiw		case 'a':
158176434Skaiw			bsdar->options |= AR_A;
159176434Skaiw			break;
160176434Skaiw		case 'b':
161176434Skaiw		case 'i':
162176434Skaiw			bsdar->options |= AR_B;
163176434Skaiw			break;
164176434Skaiw		case 'C':
165176434Skaiw			bsdar->options |= AR_CC;
166176434Skaiw			break;
167176434Skaiw		case 'c':
168176434Skaiw			bsdar->options |= AR_C;
169176434Skaiw			break;
170176434Skaiw		case 'd':
171176434Skaiw			set_mode(bsdar, opt);
172176434Skaiw			break;
173176434Skaiw		case 'f':
174176434Skaiw		case 'T':
175176434Skaiw			bsdar->options |= AR_TR;
176176434Skaiw			break;
177176434Skaiw		case 'j':
178176434Skaiw			bsdar->options |= AR_J;
179176434Skaiw			break;
180176434Skaiw		case 'l':
181176434Skaiw			/* ignored, for GNU ar comptibility */
182176434Skaiw			break;
183183218Skaiw		case 'M':
184183218Skaiw			set_mode(bsdar, opt);
185183218Skaiw			break;
186176434Skaiw		case 'm':
187176434Skaiw			set_mode(bsdar, opt);
188176434Skaiw			break;
189176434Skaiw		case 'o':
190176434Skaiw			bsdar->options |= AR_O;
191176434Skaiw			break;
192176434Skaiw		case 'p':
193176434Skaiw			set_mode(bsdar, opt);
194176434Skaiw			break;
195176434Skaiw		case 'q':
196176434Skaiw			set_mode(bsdar, opt);
197176434Skaiw			break;
198176434Skaiw		case 'r':
199176434Skaiw			set_mode(bsdar, opt);
200176434Skaiw			break;
201176434Skaiw		case 'S':
202176434Skaiw			bsdar->options |= AR_SS;
203176434Skaiw			break;
204176434Skaiw		case 's':
205176434Skaiw			bsdar->options |= AR_S;
206176434Skaiw			break;
207176434Skaiw		case 't':
208176434Skaiw			set_mode(bsdar, opt);
209176434Skaiw			break;
210176434Skaiw		case 'u':
211176434Skaiw			bsdar->options |= AR_U;
212176434Skaiw			break;
213176434Skaiw		case 'V':
214176434Skaiw			bsdar_version();
215176434Skaiw			break;
216176434Skaiw		case 'v':
217176434Skaiw			bsdar->options |= AR_V;
218176434Skaiw			break;
219176434Skaiw		case 'x':
220176434Skaiw			set_mode(bsdar, opt);
221176434Skaiw			break;
222176434Skaiw		case 'z':
223176434Skaiw			bsdar->options |= AR_Z;
224176434Skaiw			break;
225176434Skaiw		case OPTION_HELP:
226176434Skaiw			bsdar_usage();
227176434Skaiw		default:
228176434Skaiw			bsdar_usage();
229176434Skaiw		}
230176434Skaiw	}
231176434Skaiw
232176434Skaiw	argv += optind;
233176434Skaiw	argc -= optind;
234176434Skaiw
235183218Skaiw	if (*argv == NULL && bsdar->mode != 'M')
236176434Skaiw		bsdar_usage();
237176434Skaiw
238176434Skaiw	if (bsdar->options & AR_A && bsdar->options & AR_B)
239176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
240176434Skaiw		    "only one of -a and -[bi] options allowed");
241176434Skaiw
242176434Skaiw	if (bsdar->options & AR_J && bsdar->options & AR_Z)
243176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
244176434Skaiw		    "only one of -j and -z options allowed");
245176434Skaiw
246176434Skaiw	if (bsdar->options & AR_S && bsdar->options & AR_SS)
247176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
248176434Skaiw		    "only one of -s and -S options allowed");
249176434Skaiw
250176434Skaiw	if (bsdar->options & (AR_A | AR_B)) {
251176434Skaiw		if ((bsdar->posarg = *argv) == NULL)
252176434Skaiw			bsdar_errc(bsdar, EX_USAGE, 0,
253176434Skaiw			    "no position operand specified");
254176434Skaiw		if ((bsdar->posarg = basename(bsdar->posarg)) == NULL)
255176434Skaiw			bsdar_errc(bsdar, EX_SOFTWARE, errno,
256176434Skaiw			    "basename failed");
257176434Skaiw		argc--;
258176434Skaiw		argv++;
259176434Skaiw	}
260176434Skaiw
261176434Skaiw	if (bsdar->options & AR_A)
262176434Skaiw		only_mode(bsdar, "-a", "mqr");
263176434Skaiw	if (bsdar->options & AR_B)
264176434Skaiw		only_mode(bsdar, "-b", "mqr");
265176434Skaiw	if (bsdar->options & AR_C)
266176434Skaiw		only_mode(bsdar, "-c", "qr");
267176434Skaiw	if (bsdar->options & AR_CC)
268176434Skaiw		only_mode(bsdar, "-C", "x");
269176434Skaiw	if (bsdar->options & AR_O)
270176434Skaiw		only_mode(bsdar, "-o", "x");
271176434Skaiw	if (bsdar->options & AR_SS)
272176434Skaiw		only_mode(bsdar, "-S", "mqr");
273176434Skaiw	if (bsdar->options & AR_U)
274176434Skaiw		only_mode(bsdar, "-u", "qrx");
275176434Skaiw
276183218Skaiw	if (bsdar->mode == 'M') {
277183218Skaiw		ar_mode_script(bsdar);
278183218Skaiw		exit(EX_OK);
279183218Skaiw	}
280183218Skaiw
281176434Skaiw	if ((bsdar->filename = *argv) == NULL)
282176434Skaiw		bsdar_usage();
283176434Skaiw
284176434Skaiw	bsdar->argc = --argc;
285176434Skaiw	bsdar->argv = ++argv;
286176434Skaiw
287176434Skaiw	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
288176434Skaiw	    bsdar->options & AR_S) {
289176434Skaiw		ar_mode_s(bsdar);
290176434Skaiw		if (!bsdar->mode)
291176434Skaiw			exit(EX_OK);
292176434Skaiw	}
293176434Skaiw
294176434Skaiw	switch(bsdar->mode) {
295176434Skaiw	case 'd':
296176434Skaiw		ar_mode_d(bsdar);
297176434Skaiw		break;
298176434Skaiw	case 'm':
299176434Skaiw		ar_mode_m(bsdar);
300176434Skaiw		break;
301176434Skaiw	case 'p':
302176434Skaiw		ar_mode_p(bsdar);
303176434Skaiw		break;
304176434Skaiw	case 'q':
305177064Skaiw		ar_mode_q(bsdar);
306176434Skaiw		break;
307176434Skaiw	case 'r':
308176434Skaiw		ar_mode_r(bsdar);
309176434Skaiw		break;
310176434Skaiw	case 't':
311176434Skaiw		ar_mode_t(bsdar);
312176434Skaiw		break;
313176434Skaiw	case 'x':
314176434Skaiw		ar_mode_x(bsdar);
315176434Skaiw		break;
316176434Skaiw	default:
317176434Skaiw		bsdar_usage();
318176434Skaiw		/* NOTREACHED */
319176434Skaiw	}
320176434Skaiw
321176434Skaiw	for (i = 0; i < bsdar->argc; i++)
322176434Skaiw		if (bsdar->argv[i] != NULL)
323176434Skaiw			bsdar_warnc(bsdar, 0, "%s: not found in archive",
324176434Skaiw			    bsdar->argv[i]);
325176434Skaiw
326176434Skaiw	exit(EX_OK);
327176434Skaiw}
328176434Skaiw
329176434Skaiwstatic void
330176434Skaiwset_mode(struct bsdar *bsdar, char opt)
331176434Skaiw{
332176434Skaiw
333176434Skaiw	if (bsdar->mode != '\0' && bsdar->mode != opt)
334176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
335176434Skaiw		    "Can't specify both -%c and -%c", opt, bsdar->mode);
336176434Skaiw	bsdar->mode = opt;
337176434Skaiw}
338176434Skaiw
339176434Skaiwstatic void
340176434Skaiwonly_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
341176434Skaiw{
342176434Skaiw
343176434Skaiw	if (strchr(valid_modes, bsdar->mode) == NULL)
344176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
345176434Skaiw		    "Option %s is not permitted in mode -%c", opt, bsdar->mode);
346176434Skaiw}
347176434Skaiw
348176434Skaiwstatic void
349176434Skaiwbsdar_usage()
350176434Skaiw{
351176434Skaiw
352176434Skaiw	(void)fprintf(stderr, "usage:  ar -d [-Tjsvz] archive file ...\n");
353176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n");
354176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n");
355176434Skaiw	(void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
356177064Skaiw	(void)fprintf(stderr, "\tar -q [-Tcjsvz] archive file ...\n");
357176434Skaiw	(void)fprintf(stderr, "\tar -r [-Tcjsuvz] archive file ...\n");
358176434Skaiw	(void)fprintf(stderr, "\tar -r [-Tabcijsuvz] position archive file ...\n");
359176434Skaiw	(void)fprintf(stderr, "\tar -s [-jz] archive\n");
360176434Skaiw	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
361176434Skaiw	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
362176434Skaiw	(void)fprintf(stderr, "\tar -V\n");
363176434Skaiw	exit(EX_USAGE);
364176434Skaiw}
365176434Skaiw
366176434Skaiwstatic void
367176434Skaiwranlib_usage()
368176434Skaiw{
369176434Skaiw
370176434Skaiw	(void)fprintf(stderr, "usage:	ranlib [-t] archive ...\n");
371176434Skaiw	(void)fprintf(stderr, "\tranlib -V\n");
372176434Skaiw	exit(EX_USAGE);
373176434Skaiw}
374176434Skaiw
375176434Skaiwstatic void
376176434Skaiwbsdar_version()
377176434Skaiw{
378176434Skaiw	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version());
379176434Skaiw	exit(EX_OK);
380176434Skaiw}
381176434Skaiw
382176434Skaiwstatic void
383176434Skaiwranlib_version()
384176434Skaiw{
385176434Skaiw	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version());
386176434Skaiw	exit(EX_OK);
387176434Skaiw}
388