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;
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
112222122Sbcr	 * accommodates 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) {
116216014Skaiw		while ((opt = getopt_long(argc, argv, "tDV", longopts,
117176434Skaiw		    NULL)) != -1) {
118176434Skaiw			switch(opt) {
119176434Skaiw			case 't':
120176434Skaiw				/* Ignored. */
121176434Skaiw				break;
122216014Skaiw			case 'D':
123216014Skaiw				bsdar->options |= AR_D;
124216014Skaiw				break;
125176434Skaiw			case 'V':
126176434Skaiw				ranlib_version();
127176434Skaiw				break;
128176434Skaiw			case OPTION_HELP:
129176434Skaiw				ranlib_usage();
130176434Skaiw			default:
131176434Skaiw				ranlib_usage();
132176434Skaiw			}
133176434Skaiw		}
134176434Skaiw		argv += optind;
135176434Skaiw		argc -= optind;
136176434Skaiw
137176434Skaiw		if (*argv == NULL)
138176434Skaiw			ranlib_usage();
139176434Skaiw
140176434Skaiw		bsdar->options |= AR_S;
141176434Skaiw		for (;(bsdar->filename = *argv++) != NULL;)
142176434Skaiw			ar_mode_s(bsdar);
143176434Skaiw
144176434Skaiw		exit(EX_OK);
145176434Skaiw	} else {
146176434Skaiw		if (argc < 2)
147176434Skaiw			bsdar_usage();
148176434Skaiw
149176434Skaiw		if (*argv[1] != '-') {
150176434Skaiw			len = strlen(argv[1]) + 2;
151176434Skaiw			if ((p = malloc(len)) == NULL)
152176434Skaiw				bsdar_errc(bsdar, EX_SOFTWARE, errno,
153176434Skaiw				    "malloc failed");
154176434Skaiw			*p = '-';
155176434Skaiw			(void)strlcpy(p + 1, argv[1], len - 1);
156176434Skaiw			argv[1] = p;
157176434Skaiw		}
158176434Skaiw	}
159176434Skaiw
160213643Skientzle	while ((opt = getopt_long(argc, argv, "abCcdDfijlMmopqrSsTtuVvxz",
161176434Skaiw	    longopts, NULL)) != -1) {
162176434Skaiw		switch(opt) {
163176434Skaiw		case 'a':
164176434Skaiw			bsdar->options |= AR_A;
165176434Skaiw			break;
166176434Skaiw		case 'b':
167176434Skaiw		case 'i':
168176434Skaiw			bsdar->options |= AR_B;
169176434Skaiw			break;
170176434Skaiw		case 'C':
171176434Skaiw			bsdar->options |= AR_CC;
172176434Skaiw			break;
173176434Skaiw		case 'c':
174176434Skaiw			bsdar->options |= AR_C;
175176434Skaiw			break;
176176434Skaiw		case 'd':
177176434Skaiw			set_mode(bsdar, opt);
178176434Skaiw			break;
179213643Skientzle		case 'D':
180213643Skientzle			bsdar->options |= AR_D;
181213643Skientzle			break;
182176434Skaiw		case 'f':
183176434Skaiw		case 'T':
184176434Skaiw			bsdar->options |= AR_TR;
185176434Skaiw			break;
186176434Skaiw		case 'j':
187208189Skaiw			/* ignored */
188176434Skaiw			break;
189176434Skaiw		case 'l':
190176434Skaiw			/* ignored, for GNU ar comptibility */
191176434Skaiw			break;
192183218Skaiw		case 'M':
193183218Skaiw			set_mode(bsdar, opt);
194183218Skaiw			break;
195176434Skaiw		case 'm':
196176434Skaiw			set_mode(bsdar, opt);
197176434Skaiw			break;
198176434Skaiw		case 'o':
199176434Skaiw			bsdar->options |= AR_O;
200176434Skaiw			break;
201176434Skaiw		case 'p':
202176434Skaiw			set_mode(bsdar, opt);
203176434Skaiw			break;
204176434Skaiw		case 'q':
205176434Skaiw			set_mode(bsdar, opt);
206176434Skaiw			break;
207176434Skaiw		case 'r':
208176434Skaiw			set_mode(bsdar, opt);
209176434Skaiw			break;
210176434Skaiw		case 'S':
211176434Skaiw			bsdar->options |= AR_SS;
212176434Skaiw			break;
213176434Skaiw		case 's':
214176434Skaiw			bsdar->options |= AR_S;
215176434Skaiw			break;
216176434Skaiw		case 't':
217176434Skaiw			set_mode(bsdar, opt);
218176434Skaiw			break;
219176434Skaiw		case 'u':
220176434Skaiw			bsdar->options |= AR_U;
221176434Skaiw			break;
222176434Skaiw		case 'V':
223176434Skaiw			bsdar_version();
224176434Skaiw			break;
225176434Skaiw		case 'v':
226176434Skaiw			bsdar->options |= AR_V;
227176434Skaiw			break;
228176434Skaiw		case 'x':
229176434Skaiw			set_mode(bsdar, opt);
230176434Skaiw			break;
231176434Skaiw		case 'z':
232208189Skaiw			/* ignored */
233176434Skaiw			break;
234176434Skaiw		case OPTION_HELP:
235176434Skaiw			bsdar_usage();
236176434Skaiw		default:
237176434Skaiw			bsdar_usage();
238176434Skaiw		}
239176434Skaiw	}
240176434Skaiw
241176434Skaiw	argv += optind;
242176434Skaiw	argc -= optind;
243176434Skaiw
244183218Skaiw	if (*argv == NULL && bsdar->mode != 'M')
245176434Skaiw		bsdar_usage();
246176434Skaiw
247176434Skaiw	if (bsdar->options & AR_A && bsdar->options & AR_B)
248176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
249176434Skaiw		    "only one of -a and -[bi] options allowed");
250176434Skaiw
251176434Skaiw	if (bsdar->options & AR_J && bsdar->options & AR_Z)
252176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
253176434Skaiw		    "only one of -j and -z options allowed");
254176434Skaiw
255176434Skaiw	if (bsdar->options & AR_S && bsdar->options & AR_SS)
256176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
257176434Skaiw		    "only one of -s and -S options allowed");
258176434Skaiw
259176434Skaiw	if (bsdar->options & (AR_A | AR_B)) {
260176434Skaiw		if ((bsdar->posarg = *argv) == NULL)
261176434Skaiw			bsdar_errc(bsdar, EX_USAGE, 0,
262176434Skaiw			    "no position operand specified");
263176434Skaiw		if ((bsdar->posarg = basename(bsdar->posarg)) == NULL)
264176434Skaiw			bsdar_errc(bsdar, EX_SOFTWARE, errno,
265176434Skaiw			    "basename failed");
266176434Skaiw		argc--;
267176434Skaiw		argv++;
268176434Skaiw	}
269176434Skaiw
270176434Skaiw	if (bsdar->options & AR_A)
271176434Skaiw		only_mode(bsdar, "-a", "mqr");
272176434Skaiw	if (bsdar->options & AR_B)
273176434Skaiw		only_mode(bsdar, "-b", "mqr");
274176434Skaiw	if (bsdar->options & AR_C)
275176434Skaiw		only_mode(bsdar, "-c", "qr");
276176434Skaiw	if (bsdar->options & AR_CC)
277176434Skaiw		only_mode(bsdar, "-C", "x");
278213643Skientzle	if (bsdar->options & AR_D)
279213643Skientzle		only_mode(bsdar, "-D", "qr");
280176434Skaiw	if (bsdar->options & AR_O)
281176434Skaiw		only_mode(bsdar, "-o", "x");
282176434Skaiw	if (bsdar->options & AR_SS)
283176434Skaiw		only_mode(bsdar, "-S", "mqr");
284176434Skaiw	if (bsdar->options & AR_U)
285176434Skaiw		only_mode(bsdar, "-u", "qrx");
286176434Skaiw
287183218Skaiw	if (bsdar->mode == 'M') {
288183218Skaiw		ar_mode_script(bsdar);
289183218Skaiw		exit(EX_OK);
290183218Skaiw	}
291183218Skaiw
292176434Skaiw	if ((bsdar->filename = *argv) == NULL)
293176434Skaiw		bsdar_usage();
294176434Skaiw
295176434Skaiw	bsdar->argc = --argc;
296176434Skaiw	bsdar->argv = ++argv;
297176434Skaiw
298176434Skaiw	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
299176434Skaiw	    bsdar->options & AR_S) {
300176434Skaiw		ar_mode_s(bsdar);
301176434Skaiw		if (!bsdar->mode)
302176434Skaiw			exit(EX_OK);
303176434Skaiw	}
304176434Skaiw
305176434Skaiw	switch(bsdar->mode) {
306176434Skaiw	case 'd':
307176434Skaiw		ar_mode_d(bsdar);
308176434Skaiw		break;
309176434Skaiw	case 'm':
310176434Skaiw		ar_mode_m(bsdar);
311176434Skaiw		break;
312176434Skaiw	case 'p':
313176434Skaiw		ar_mode_p(bsdar);
314176434Skaiw		break;
315176434Skaiw	case 'q':
316177064Skaiw		ar_mode_q(bsdar);
317176434Skaiw		break;
318176434Skaiw	case 'r':
319176434Skaiw		ar_mode_r(bsdar);
320176434Skaiw		break;
321176434Skaiw	case 't':
322176434Skaiw		ar_mode_t(bsdar);
323176434Skaiw		break;
324176434Skaiw	case 'x':
325176434Skaiw		ar_mode_x(bsdar);
326176434Skaiw		break;
327176434Skaiw	default:
328176434Skaiw		bsdar_usage();
329176434Skaiw		/* NOTREACHED */
330176434Skaiw	}
331176434Skaiw
332176434Skaiw	for (i = 0; i < bsdar->argc; i++)
333176434Skaiw		if (bsdar->argv[i] != NULL)
334176434Skaiw			bsdar_warnc(bsdar, 0, "%s: not found in archive",
335176434Skaiw			    bsdar->argv[i]);
336176434Skaiw
337176434Skaiw	exit(EX_OK);
338176434Skaiw}
339176434Skaiw
340176434Skaiwstatic void
341176434Skaiwset_mode(struct bsdar *bsdar, char opt)
342176434Skaiw{
343176434Skaiw
344176434Skaiw	if (bsdar->mode != '\0' && bsdar->mode != opt)
345176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
346176434Skaiw		    "Can't specify both -%c and -%c", opt, bsdar->mode);
347176434Skaiw	bsdar->mode = opt;
348176434Skaiw}
349176434Skaiw
350176434Skaiwstatic void
351176434Skaiwonly_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
352176434Skaiw{
353176434Skaiw
354176434Skaiw	if (strchr(valid_modes, bsdar->mode) == NULL)
355176434Skaiw		bsdar_errc(bsdar, EX_USAGE, 0,
356176434Skaiw		    "Option %s is not permitted in mode -%c", opt, bsdar->mode);
357176434Skaiw}
358176434Skaiw
359176434Skaiwstatic void
360201382Sedbsdar_usage(void)
361176434Skaiw{
362176434Skaiw
363176434Skaiw	(void)fprintf(stderr, "usage:  ar -d [-Tjsvz] archive file ...\n");
364176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n");
365176434Skaiw	(void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n");
366176434Skaiw	(void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
367213643Skientzle	(void)fprintf(stderr, "\tar -q [-TcDjsvz] archive file ...\n");
368213643Skientzle	(void)fprintf(stderr, "\tar -r [-TcDjsuvz] archive file ...\n");
369213643Skientzle	(void)fprintf(stderr, "\tar -r [-TabcDijsuvz] position archive file ...\n");
370176434Skaiw	(void)fprintf(stderr, "\tar -s [-jz] archive\n");
371176434Skaiw	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
372176434Skaiw	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
373176434Skaiw	(void)fprintf(stderr, "\tar -V\n");
374176434Skaiw	exit(EX_USAGE);
375176434Skaiw}
376176434Skaiw
377176434Skaiwstatic void
378201382Sedranlib_usage(void)
379176434Skaiw{
380176434Skaiw
381176434Skaiw	(void)fprintf(stderr, "usage:	ranlib [-t] archive ...\n");
382176434Skaiw	(void)fprintf(stderr, "\tranlib -V\n");
383176434Skaiw	exit(EX_USAGE);
384176434Skaiw}
385176434Skaiw
386176434Skaiwstatic void
387201382Sedbsdar_version(void)
388176434Skaiw{
389232153Smm	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version_string());
390176434Skaiw	exit(EX_OK);
391176434Skaiw}
392176434Skaiw
393176434Skaiwstatic void
394201382Sedranlib_version(void)
395176434Skaiw{
396232153Smm	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version_string());
397176434Skaiw	exit(EX_OK);
398176434Skaiw}
399