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$");
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;
103288202Semaste	int		 i, opt, Dflag, Uflag;
104176434Skaiw
105176434Skaiw	bsdar = &bsdar_storage;
106176434Skaiw	memset(bsdar, 0, sizeof(*bsdar));
107288202Semaste	Dflag = 0;
108288202Semaste	Uflag = 0;
109176434Skaiw
110176434Skaiw	if ((bsdar->progname = getprogname()) == NULL)
111176434Skaiw		bsdar->progname = "ar";
112176434Skaiw
113190162Skientzle	/* Act like ranlib if our name ends in "ranlib"; this
114222122Sbcr	 * accommodates arm-freebsd7.1-ranlib, bsdranlib, etc. */
115190162Skientzle	len = strlen(bsdar->progname);
116190162Skientzle	if (len >= strlen("ranlib") &&
117190162Skientzle	    strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) {
118287326Semaste		while ((opt = getopt_long(argc, argv, "tDUV", longopts,
119176434Skaiw		    NULL)) != -1) {
120176434Skaiw			switch(opt) {
121176434Skaiw			case 't':
122176434Skaiw				/* Ignored. */
123176434Skaiw				break;
124216014Skaiw			case 'D':
125288202Semaste				Dflag = 1;
126288202Semaste				Uflag = 0;
127216014Skaiw				break;
128287326Semaste			case 'U':
129288202Semaste				Uflag = 1;
130288202Semaste				Dflag = 0;
131287326Semaste				break;
132176434Skaiw			case 'V':
133176434Skaiw				ranlib_version();
134176434Skaiw				break;
135176434Skaiw			case OPTION_HELP:
136176434Skaiw				ranlib_usage();
137176434Skaiw			default:
138176434Skaiw				ranlib_usage();
139176434Skaiw			}
140176434Skaiw		}
141176434Skaiw		argv += optind;
142176434Skaiw		argc -= optind;
143176434Skaiw
144176434Skaiw		if (*argv == NULL)
145176434Skaiw			ranlib_usage();
146176434Skaiw
147288202Semaste		/* Enable determinstic mode unless -U is set. */
148288202Semaste		if (Uflag == 0)
149288202Semaste			bsdar->options |= AR_D;
150176434Skaiw		bsdar->options |= AR_S;
151288172Semaste		while ((bsdar->filename = *argv++) != NULL)
152176434Skaiw			ar_mode_s(bsdar);
153176434Skaiw
154176434Skaiw		exit(EX_OK);
155176434Skaiw	} else {
156176434Skaiw		if (argc < 2)
157176434Skaiw			bsdar_usage();
158176434Skaiw
159176434Skaiw		if (*argv[1] != '-') {
160176434Skaiw			len = strlen(argv[1]) + 2;
161176434Skaiw			if ((p = malloc(len)) == NULL)
162176434Skaiw				bsdar_errc(bsdar, EX_SOFTWARE, errno,
163176434Skaiw				    "malloc failed");
164176434Skaiw			*p = '-';
165176434Skaiw			(void)strlcpy(p + 1, argv[1], len - 1);
166176434Skaiw			argv[1] = p;
167176434Skaiw		}
168176434Skaiw	}
169176434Skaiw
170287326Semaste	while ((opt = getopt_long(argc, argv, "abCcdDfijlMmopqrSsTtUuVvxz",
171176434Skaiw	    longopts, NULL)) != -1) {
172176434Skaiw		switch(opt) {
173176434Skaiw		case 'a':
174176434Skaiw			bsdar->options |= AR_A;
175176434Skaiw			break;
176176434Skaiw		case 'b':
177176434Skaiw		case 'i':
178176434Skaiw			bsdar->options |= AR_B;
179176434Skaiw			break;
180176434Skaiw		case 'C':
181176434Skaiw			bsdar->options |= AR_CC;
182176434Skaiw			break;
183176434Skaiw		case 'c':
184176434Skaiw			bsdar->options |= AR_C;
185176434Skaiw			break;
186176434Skaiw		case 'd':
187176434Skaiw			set_mode(bsdar, opt);
188176434Skaiw			break;
189213643Skientzle		case 'D':
190288202Semaste			Dflag = 1;
191288202Semaste			Uflag = 0;
192213643Skientzle			break;
193176434Skaiw		case 'f':
194176434Skaiw		case 'T':
195176434Skaiw			bsdar->options |= AR_TR;
196176434Skaiw			break;
197176434Skaiw		case 'j':
198208189Skaiw			/* ignored */
199176434Skaiw			break;
200176434Skaiw		case 'l':
201176434Skaiw			/* ignored, for GNU ar comptibility */
202176434Skaiw			break;
203183218Skaiw		case 'M':
204183218Skaiw			set_mode(bsdar, opt);
205183218Skaiw			break;
206176434Skaiw		case 'm':
207176434Skaiw			set_mode(bsdar, opt);
208176434Skaiw			break;
209176434Skaiw		case 'o':
210176434Skaiw			bsdar->options |= AR_O;
211176434Skaiw			break;
212176434Skaiw		case 'p':
213176434Skaiw			set_mode(bsdar, opt);
214176434Skaiw			break;
215176434Skaiw		case 'q':
216176434Skaiw			set_mode(bsdar, opt);
217176434Skaiw			break;
218176434Skaiw		case 'r':
219176434Skaiw			set_mode(bsdar, opt);
220176434Skaiw			break;
221176434Skaiw		case 'S':
222176434Skaiw			bsdar->options |= AR_SS;
223176434Skaiw			break;
224176434Skaiw		case 's':
225176434Skaiw			bsdar->options |= AR_S;
226176434Skaiw			break;
227176434Skaiw		case 't':
228176434Skaiw			set_mode(bsdar, opt);
229176434Skaiw			break;
230287326Semaste		case 'U':
231288202Semaste			Uflag = 1;
232288202Semaste			Dflag = 0;
233287326Semaste			break;
234176434Skaiw		case 'u':
235176434Skaiw			bsdar->options |= AR_U;
236176434Skaiw			break;
237176434Skaiw		case 'V':
238176434Skaiw			bsdar_version();
239176434Skaiw			break;
240176434Skaiw		case 'v':
241176434Skaiw			bsdar->options |= AR_V;
242176434Skaiw			break;
243176434Skaiw		case 'x':
244176434Skaiw			set_mode(bsdar, opt);
245176434Skaiw			break;
246176434Skaiw		case 'z':
247208189Skaiw			/* ignored */
248176434Skaiw			break;
249176434Skaiw		case OPTION_HELP:
250176434Skaiw			bsdar_usage();
251176434Skaiw		default:
252176434Skaiw			bsdar_usage();
253176434Skaiw		}
254176434Skaiw	}
255176434Skaiw
256176434Skaiw	argv += optind;
257176434Skaiw	argc -= optind;
258176434Skaiw
259183218Skaiw	if (*argv == NULL && bsdar->mode != 'M')
260176434Skaiw		bsdar_usage();
261176434Skaiw
262176434Skaiw	if (bsdar->options & AR_A && bsdar->options & AR_B)
263176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
264176434Skaiw		    "only one of -a and -[bi] options allowed");
265176434Skaiw
266176434Skaiw	if (bsdar->options & AR_J && bsdar->options & AR_Z)
267176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
268176434Skaiw		    "only one of -j and -z options allowed");
269176434Skaiw
270176434Skaiw	if (bsdar->options & AR_S && bsdar->options & AR_SS)
271176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
272176434Skaiw		    "only one of -s and -S options allowed");
273176434Skaiw
274176434Skaiw	if (bsdar->options & (AR_A | AR_B)) {
275176434Skaiw		if ((bsdar->posarg = *argv) == NULL)
276176434Skaiw			bsdar_errc(bsdar, EX_USAGE, 0,
277176434Skaiw			    "no position operand specified");
278176434Skaiw		if ((bsdar->posarg = basename(bsdar->posarg)) == NULL)
279176434Skaiw			bsdar_errc(bsdar, EX_SOFTWARE, errno,
280176434Skaiw			    "basename failed");
281176434Skaiw		argc--;
282176434Skaiw		argv++;
283176434Skaiw	}
284176434Skaiw
285288202Semaste	/* Set determinstic mode for -D, and by default without -U. */
286303295Semaste	if (Dflag || (Uflag == 0 && (bsdar->mode == 'q' || bsdar->mode == 'r' ||
287303295Semaste	    (bsdar->mode == '\0' && bsdar->options & AR_S))))
288288202Semaste		bsdar->options |= AR_D;
289288202Semaste
290176434Skaiw	if (bsdar->options & AR_A)
291176434Skaiw		only_mode(bsdar, "-a", "mqr");
292176434Skaiw	if (bsdar->options & AR_B)
293176434Skaiw		only_mode(bsdar, "-b", "mqr");
294176434Skaiw	if (bsdar->options & AR_C)
295176434Skaiw		only_mode(bsdar, "-c", "qr");
296176434Skaiw	if (bsdar->options & AR_CC)
297176434Skaiw		only_mode(bsdar, "-C", "x");
298288202Semaste	if (Dflag)
299213643Skientzle		only_mode(bsdar, "-D", "qr");
300288202Semaste	if (Uflag)
301288202Semaste		only_mode(bsdar, "-U", "qr");
302176434Skaiw	if (bsdar->options & AR_O)
303176434Skaiw		only_mode(bsdar, "-o", "x");
304176434Skaiw	if (bsdar->options & AR_SS)
305176434Skaiw		only_mode(bsdar, "-S", "mqr");
306176434Skaiw	if (bsdar->options & AR_U)
307176434Skaiw		only_mode(bsdar, "-u", "qrx");
308176434Skaiw
309183218Skaiw	if (bsdar->mode == 'M') {
310183218Skaiw		ar_mode_script(bsdar);
311183218Skaiw		exit(EX_OK);
312183218Skaiw	}
313183218Skaiw
314176434Skaiw	if ((bsdar->filename = *argv) == NULL)
315176434Skaiw		bsdar_usage();
316176434Skaiw
317176434Skaiw	bsdar->argc = --argc;
318176434Skaiw	bsdar->argv = ++argv;
319176434Skaiw
320176434Skaiw	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
321176434Skaiw	    bsdar->options & AR_S) {
322176434Skaiw		ar_mode_s(bsdar);
323176434Skaiw		if (!bsdar->mode)
324176434Skaiw			exit(EX_OK);
325176434Skaiw	}
326176434Skaiw
327176434Skaiw	switch(bsdar->mode) {
328176434Skaiw	case 'd':
329176434Skaiw		ar_mode_d(bsdar);
330176434Skaiw		break;
331176434Skaiw	case 'm':
332176434Skaiw		ar_mode_m(bsdar);
333176434Skaiw		break;
334176434Skaiw	case 'p':
335176434Skaiw		ar_mode_p(bsdar);
336176434Skaiw		break;
337176434Skaiw	case 'q':
338177064Skaiw		ar_mode_q(bsdar);
339176434Skaiw		break;
340176434Skaiw	case 'r':
341176434Skaiw		ar_mode_r(bsdar);
342176434Skaiw		break;
343176434Skaiw	case 't':
344176434Skaiw		ar_mode_t(bsdar);
345176434Skaiw		break;
346176434Skaiw	case 'x':
347176434Skaiw		ar_mode_x(bsdar);
348176434Skaiw		break;
349176434Skaiw	default:
350176434Skaiw		bsdar_usage();
351176434Skaiw		/* NOTREACHED */
352176434Skaiw	}
353176434Skaiw
354176434Skaiw	for (i = 0; i < bsdar->argc; i++)
355176434Skaiw		if (bsdar->argv[i] != NULL)
356176434Skaiw			bsdar_warnc(bsdar, 0, "%s: not found in archive",
357176434Skaiw			    bsdar->argv[i]);
358176434Skaiw
359176434Skaiw	exit(EX_OK);
360176434Skaiw}
361176434Skaiw
362176434Skaiwstatic void
363176434Skaiwset_mode(struct bsdar *bsdar, char opt)
364176434Skaiw{
365176434Skaiw
366176434Skaiw	if (bsdar->mode != '\0' && bsdar->mode != opt)
367176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
368176434Skaiw		    "Can't specify both -%c and -%c", opt, bsdar->mode);
369176434Skaiw	bsdar->mode = opt;
370176434Skaiw}
371176434Skaiw
372176434Skaiwstatic void
373176434Skaiwonly_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
374176434Skaiw{
375176434Skaiw
376176434Skaiw	if (strchr(valid_modes, bsdar->mode) == NULL)
377176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
378176434Skaiw		    "Option %s is not permitted in mode -%c", opt, bsdar->mode);
379176434Skaiw}
380176434Skaiw
381176434Skaiwstatic void
382201382Sedbsdar_usage(void)
383176434Skaiw{
384176434Skaiw
385176434Skaiw	(void)fprintf(stderr, "usage:  ar -d [-Tjsvz] archive file ...\n");
386176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n");
387176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n");
388176434Skaiw	(void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
389287326Semaste	(void)fprintf(stderr, "\tar -q [-TcDjsUvz] archive file ...\n");
390287326Semaste	(void)fprintf(stderr, "\tar -r [-TcDjsUuvz] archive file ...\n");
391287326Semaste	(void)fprintf(stderr, "\tar -r [-TabcDijsUuvz] position archive file ...\n");
392176434Skaiw	(void)fprintf(stderr, "\tar -s [-jz] archive\n");
393176434Skaiw	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
394176434Skaiw	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
395176434Skaiw	(void)fprintf(stderr, "\tar -V\n");
396176434Skaiw	exit(EX_USAGE);
397176434Skaiw}
398176434Skaiw
399176434Skaiwstatic void
400201382Sedranlib_usage(void)
401176434Skaiw{
402176434Skaiw
403287326Semaste	(void)fprintf(stderr, "usage:	ranlib [-DtU] archive ...\n");
404176434Skaiw	(void)fprintf(stderr, "\tranlib -V\n");
405176434Skaiw	exit(EX_USAGE);
406176434Skaiw}
407176434Skaiw
408176434Skaiwstatic void
409201382Sedbsdar_version(void)
410176434Skaiw{
411232153Smm	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version_string());
412176434Skaiw	exit(EX_OK);
413176434Skaiw}
414176434Skaiw
415176434Skaiwstatic void
416201382Sedranlib_version(void)
417176434Skaiw{
418232153Smm	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version_string());
419176434Skaiw	exit(EX_OK);
420176434Skaiw}
421