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