1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2007 Kai Wang
5 * Copyright (c) 2007 Tim Kientzle
6 * Copyright (c) 2007 Joseph Koshy
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*-
32 * Copyright (c) 1990, 1993, 1994
33 *	The Regents of the University of California.  All rights reserved.
34 *
35 * This code is derived from software contributed to Berkeley by
36 * Hugh Smith at The University of Guelph.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 */
62
63#include <sys/cdefs.h>
64#include <sys/queue.h>
65#include <sys/types.h>
66#include <archive.h>
67#include <err.h>
68#include <errno.h>
69#include <getopt.h>
70#include <libgen.h>
71#include <stdio.h>
72#include <stdlib.h>
73#include <string.h>
74
75#include "ar.h"
76
77enum options
78{
79	OPTION_HELP
80};
81
82static struct option longopts[] =
83{
84	{"help", no_argument, NULL, OPTION_HELP},
85	{"version", no_argument, NULL, 'V'},
86	{NULL, 0, NULL, 0}
87};
88
89static void	bsdar_usage(void);
90static void	ranlib_usage(void);
91static void	set_mode(struct bsdar *bsdar, char opt);
92static void	only_mode(struct bsdar *bsdar, const char *opt,
93		    const char *valid_modes);
94static void	bsdar_version(void);
95static void	ranlib_version(void);
96
97int
98main(int argc, char **argv)
99{
100	struct bsdar	*bsdar, bsdar_storage;
101	char		*p;
102	size_t		 len;
103	int		 exitcode, i, opt, Dflag, Uflag;
104
105	bsdar = &bsdar_storage;
106	memset(bsdar, 0, sizeof(*bsdar));
107	exitcode = EXIT_SUCCESS;
108	Dflag = 0;
109	Uflag = 0;
110
111	if ((bsdar->progname = getprogname()) == NULL)
112		bsdar->progname = "ar";
113
114	/* Act like ranlib if our name ends in "ranlib"; this
115	 * accommodates arm-freebsd7.1-ranlib, bsdranlib, etc. */
116	len = strlen(bsdar->progname);
117	if (len >= strlen("ranlib") &&
118	    strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) {
119		while ((opt = getopt_long(argc, argv, "tDUV", longopts,
120		    NULL)) != -1) {
121			switch(opt) {
122			case 't':
123				/* Ignored. */
124				break;
125			case 'D':
126				Dflag = 1;
127				Uflag = 0;
128				break;
129			case 'U':
130				Uflag = 1;
131				Dflag = 0;
132				break;
133			case 'V':
134				ranlib_version();
135				break;
136			case OPTION_HELP:
137				ranlib_usage();
138			default:
139				ranlib_usage();
140			}
141		}
142		argv += optind;
143		argc -= optind;
144
145		if (*argv == NULL)
146			ranlib_usage();
147
148		/* Enable determinstic mode unless -U is set. */
149		if (Uflag == 0)
150			bsdar->options |= AR_D;
151		bsdar->options |= AR_S;
152		while ((bsdar->filename = *argv++) != NULL)
153			if (ar_write_archive(bsdar, 's'))
154				exitcode = EXIT_FAILURE;
155
156		exit(exitcode);
157	} else {
158		if (argc < 2)
159			bsdar_usage();
160
161		if (*argv[1] != '-') {
162			len = strlen(argv[1]) + 2;
163			if ((p = malloc(len)) == NULL)
164				bsdar_errc(bsdar, errno, "malloc failed");
165			*p = '-';
166			(void)strlcpy(p + 1, argv[1], len - 1);
167			argv[1] = p;
168		}
169	}
170
171	while ((opt = getopt_long(argc, argv, "abCcdDfijlMmopqrSsTtUuVvxz",
172	    longopts, NULL)) != -1) {
173		switch(opt) {
174		case 'a':
175			bsdar->options |= AR_A;
176			break;
177		case 'b':
178		case 'i':
179			bsdar->options |= AR_B;
180			break;
181		case 'C':
182			bsdar->options |= AR_CC;
183			break;
184		case 'c':
185			bsdar->options |= AR_C;
186			break;
187		case 'd':
188			set_mode(bsdar, opt);
189			break;
190		case 'D':
191			Dflag = 1;
192			Uflag = 0;
193			break;
194		case 'f':
195			bsdar->options |= AR_TR;
196			break;
197		case 'j':
198			/* ignored */
199			break;
200		case 'l':
201			/* ignored, for GNU ar comptibility */
202			break;
203		case 'M':
204			set_mode(bsdar, opt);
205			break;
206		case 'm':
207			set_mode(bsdar, opt);
208			break;
209		case 'o':
210			bsdar->options |= AR_O;
211			break;
212		case 'p':
213			set_mode(bsdar, opt);
214			break;
215		case 'q':
216			set_mode(bsdar, opt);
217			break;
218		case 'r':
219			set_mode(bsdar, opt);
220			break;
221		case 'S':
222			bsdar->options |= AR_SS;
223			break;
224		case 's':
225			bsdar->options |= AR_S;
226			break;
227		case 'T':
228			/* ignored */
229			break;
230		case 't':
231			set_mode(bsdar, opt);
232			break;
233		case 'U':
234			Uflag = 1;
235			Dflag = 0;
236			break;
237		case 'u':
238			bsdar->options |= AR_U;
239			break;
240		case 'V':
241			bsdar_version();
242			break;
243		case 'v':
244			bsdar->options |= AR_V;
245			break;
246		case 'x':
247			set_mode(bsdar, opt);
248			break;
249		case 'z':
250			/* ignored */
251			break;
252		case OPTION_HELP:
253			bsdar_usage();
254		default:
255			bsdar_usage();
256		}
257	}
258
259	argv += optind;
260	argc -= optind;
261
262	if (*argv == NULL && bsdar->mode != 'M')
263		bsdar_usage();
264
265	if (bsdar->options & AR_A && bsdar->options & AR_B)
266		bsdar_errc(bsdar, 0,
267		    "only one of -a and -[bi] options allowed");
268
269	if (bsdar->options & AR_J && bsdar->options & AR_Z)
270		bsdar_errc(bsdar, 0, "only one of -j and -z options allowed");
271
272	if (bsdar->options & AR_S && bsdar->options & AR_SS)
273		bsdar_errc(bsdar, 0, "only one of -s and -S options allowed");
274
275	if (bsdar->options & (AR_A | AR_B)) {
276		if (*argv == NULL)
277			bsdar_errc(bsdar, 0, "no position operand specified");
278		if ((bsdar->posarg = basename(*argv)) == NULL)
279			bsdar_errc(bsdar, errno, "basename failed");
280		argc--;
281		argv++;
282	}
283
284	/* Set determinstic mode for -D, and by default without -U. */
285	if (Dflag || (Uflag == 0 && (bsdar->mode == 'q' || bsdar->mode == 'r' ||
286	    (bsdar->mode == '\0' && bsdar->options & AR_S))))
287		bsdar->options |= AR_D;
288
289	if (bsdar->options & AR_A)
290		only_mode(bsdar, "-a", "mqr");
291	if (bsdar->options & AR_B)
292		only_mode(bsdar, "-b", "mqr");
293	if (bsdar->options & AR_C)
294		only_mode(bsdar, "-c", "qr");
295	if (bsdar->options & AR_CC)
296		only_mode(bsdar, "-C", "x");
297	if (Dflag)
298		only_mode(bsdar, "-D", "qr");
299	if (Uflag)
300		only_mode(bsdar, "-U", "qr");
301	if (bsdar->options & AR_O)
302		only_mode(bsdar, "-o", "x");
303	if (bsdar->options & AR_SS)
304		only_mode(bsdar, "-S", "mqr");
305	if (bsdar->options & AR_U)
306		only_mode(bsdar, "-u", "qrx");
307
308	if (bsdar->mode == 'M') {
309		ar_mode_script(bsdar);
310		exit(EXIT_SUCCESS);
311	}
312
313	if ((bsdar->filename = *argv) == NULL)
314		bsdar_usage();
315
316	bsdar->argc = --argc;
317	bsdar->argv = ++argv;
318
319	if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
320	    bsdar->options & AR_S) {
321		exitcode = ar_write_archive(bsdar, 's');
322		if (!bsdar->mode)
323			exit(exitcode);
324	}
325
326	switch(bsdar->mode) {
327	case 'd': case 'm': case 'q': case 'r':
328		exitcode = ar_write_archive(bsdar, bsdar->mode);
329		break;
330	case 'p': case 't': case 'x':
331		exitcode = ar_read_archive(bsdar, bsdar->mode, stdout);
332		break;
333	default:
334		bsdar_usage();
335		/* NOTREACHED */
336	}
337
338	for (i = 0; i < bsdar->argc; i++) {
339		if (bsdar->argv[i] != NULL) {
340			bsdar_warnc(bsdar, 0, "%s: not found in archive",
341			    bsdar->argv[i]);
342			exitcode = EXIT_FAILURE;
343		}
344	}
345
346	exit(exitcode);
347}
348
349static void
350set_mode(struct bsdar *bsdar, char opt)
351{
352
353	if (bsdar->mode != '\0' && bsdar->mode != opt)
354		bsdar_errc(bsdar, 0, "Can't specify both -%c and -%c", opt,
355		    bsdar->mode);
356	bsdar->mode = opt;
357}
358
359static void
360only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
361{
362
363	if (strchr(valid_modes, bsdar->mode) == NULL)
364		bsdar_errc(bsdar, 0, "Option %s is not permitted in mode -%c",
365		    opt, bsdar->mode);
366}
367
368static void
369bsdar_usage(void)
370{
371
372	(void)fprintf(stderr, "usage:  ar -d [-Tjsvz] archive file ...\n");
373	(void)fprintf(stderr, "\tar -m [-Tjsvz] archive file ...\n");
374	(void)fprintf(stderr, "\tar -m [-Tabijsvz] position archive file ...\n");
375	(void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n");
376	(void)fprintf(stderr, "\tar -q [-TcDjsUvz] archive file ...\n");
377	(void)fprintf(stderr, "\tar -r [-TcDjsUuvz] archive file ...\n");
378	(void)fprintf(stderr, "\tar -r [-TabcDijsUuvz] position archive file ...\n");
379	(void)fprintf(stderr, "\tar -s [-jz] archive\n");
380	(void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n");
381	(void)fprintf(stderr, "\tar -x [-CTouv] archive [file ...]\n");
382	(void)fprintf(stderr, "\tar -V\n");
383	exit(EXIT_FAILURE);
384}
385
386static void
387ranlib_usage(void)
388{
389
390	(void)fprintf(stderr, "usage:	ranlib [-DtU] archive ...\n");
391	(void)fprintf(stderr, "\tranlib -V\n");
392	exit(EXIT_FAILURE);
393}
394
395static void
396bsdar_version(void)
397{
398	(void)printf("BSD ar %s - %s\n", BSDAR_VERSION, archive_version_string());
399	exit(EXIT_SUCCESS);
400}
401
402static void
403ranlib_version(void)
404{
405	(void)printf("ranlib %s - %s\n", BSDAR_VERSION, archive_version_string());
406	exit(EXIT_SUCCESS);
407}
408