1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*	$OpenBSD: ar.c,v 1.3 1997/01/15 23:42:11 millert Exp $	*/
24/*	$NetBSD: ar.c,v 1.5 1995/03/26 03:27:44 glass Exp $	*/
25
26/*-
27 * Copyright (c) 1990, 1993, 1994
28 *	The Regents of the University of California.  All rights reserved.
29 *
30 * This code is derived from software contributed to Berkeley by
31 * Hugh Smith at The University of Guelph.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 *    must display the following acknowledgement:
43 *	This product includes software developed by the University of
44 *	California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62#ifndef lint
63#if 0
64static char copyright[] =
65"@(#) Copyright (c) 1990, 1993, 1994\n\
66	The Regents of the University of California.  All rights reserved.\n";
67static char sccsid[] = "@(#)ar.c	8.3 (Berkeley) 4/2/94";
68static char rcsid[] = "$OpenBSD: ar.c,v 1.3 1997/01/15 23:42:11 millert Exp $";
69#endif
70#endif /* not lint */
71
72#include <sys/param.h>
73
74#include <ar.h>
75#include <dirent.h>
76#include <err.h>
77#include <paths.h>
78#include <stdio.h>
79#include <stdlib.h>
80#include <string.h>
81#include <unistd.h>
82
83#include "archive.h"
84#include "extern.h"
85#include "stuff/execute.h"
86#include "stuff/unix_standard_mode.h"
87
88CHDR chdr;
89u_int options;
90char *archive, *envtmp, *posarg, *posname;
91static void badoptions __P((char *));
92static void usage __P((void));
93char *progname;
94
95/*
96 * main --
97 *	main basically uses getopt to parse options and calls the appropriate
98 *	functions.  Some hacks that let us be backward compatible with 4.3 ar
99 *	option parsing and sanity checking.
100 */
101int
102main(argc, argv)
103	int argc;
104	char **argv;
105{
106	int c, retval, verbose, run_ranlib;
107	char *p;
108	int (*fcall) __P((char **));
109
110	fcall = 0;
111	verbose = 0;
112	progname = argv[0];
113	run_ranlib = 1;
114
115	if (argc < 3)
116		usage();
117
118	/*
119	 * Historic versions didn't require a '-' in front of the options.
120	 * Fix it, if necessary.
121	*/
122	if (*argv[1] != '-') {
123		if (!(p = malloc((u_int)(strlen(argv[1]) + 2))))
124			err(1, NULL);
125		*p = '-';
126		(void)strcpy(p + 1, argv[1]);
127		argv[1] = p;
128	}
129
130	/*
131	 * For Rhapsody Premier the option to use long member names, -L, is the
132	 * default.  The compiler tools for Rhapsody Premier do understand
133	 * extended format #1.  The new option -L allows ar to use the extended
134	 * format and the old -T option causes the truncation of names.
135	 */
136	while ((c = getopt(argc, argv, "abcdilLmopqrSsTtuVvx")) != -1) {
137		switch(c) {
138		case 'a':
139			options |= AR_A;
140			break;
141		case 'b':
142		case 'i':
143			options |= AR_B;
144			break;
145		case 'c':
146			options |= AR_C;
147			break;
148		case 'd':
149			options |= AR_D;
150			fcall = delete;
151			break;
152		case 'l':		/* not documented, compatibility only */
153			envtmp = ".";
154			break;
155		case 'L':
156			options &= ~AR_TR;
157			break;
158		case 'm':
159			options |= AR_M;
160			fcall = move;
161			break;
162		case 'o':
163			options |= AR_O;
164			break;
165		case 'p':
166			options |= AR_P;
167			fcall = print;
168			break;
169		case 'q':
170			options |= AR_Q;
171			fcall = append;
172			break;
173		case 'r':
174			options |= AR_R;
175			fcall = replace;
176			break;
177		case 's':
178			options |= AR_S;
179			break;
180		case 'S':
181			options &= ~AR_S;
182			run_ranlib = 0;
183			break;
184		case 'T':
185			options |= AR_TR;
186			break;
187		case 't':
188			options |= AR_T;
189			fcall = contents;
190			break;
191		case 'u':
192			options |= AR_U;
193			break;
194		case 'V':
195			verbose = 1;
196			break;
197		case 'v':
198			options |= AR_V;
199			break;
200		case 'x':
201			options |= AR_X;
202			fcall = extract;
203			break;
204		default:
205			usage();
206		}
207	}
208
209	argv += optind;
210	argc -= optind;
211
212	/* One of -dmpqrtsx required. */
213	if (!(options & (AR_D|AR_M|AR_P|AR_Q|AR_R|AR_S|AR_T|AR_X))) {
214		warnx("one of options -dmpqrtsx is required");
215		usage();
216	}
217	/* Only one of -a and -bi allowed. */
218	if (options & AR_A && options & AR_B) {
219		warnx("only one of -a and -[bi] options allowed");
220		usage();
221	}
222	/* -ab require a position argument. */
223	if (options & (AR_A|AR_B)) {
224		if (!(posarg = *argv++)) {
225			warnx("no position operand specified");
226			usage();
227		}
228		posname = rname(posarg);
229	}
230	/* -d only valid with -Tsv. */
231	if (options & AR_D && options & ~(AR_D|AR_TR|AR_S|AR_V))
232		badoptions("-d");
233	/* -m only valid with -abiTsv. */
234	if (options & AR_M && options & ~(AR_A|AR_B|AR_M|AR_TR|AR_S|AR_V))
235		badoptions("-m");
236	/* -p only valid with -Tsv. */
237	if (options & AR_P && options & ~(AR_P|AR_TR|AR_S|AR_V))
238		badoptions("-p");
239	/* -q only valid with -cTsv. */
240	if (options & AR_Q && options & ~(AR_C|AR_Q|AR_TR|AR_S|AR_V))
241		badoptions("-q");
242	/* -r only valid with -abcuTsv. */
243	if (options & AR_R && options & ~(AR_A|AR_B|AR_C|AR_R|AR_U|AR_TR|AR_S|AR_V))
244		badoptions("-r");
245	/* -t only valid with -Tsv. */
246	if (options & AR_T && options & ~(AR_T|AR_TR|AR_S|AR_V))
247		badoptions("-t");
248	/* -x only valid with -ouTsv. */
249	if (options & AR_X && options & ~(AR_O|AR_U|AR_TR|AR_S|AR_V|AR_X))
250		badoptions("-x");
251
252	if (!(archive = *argv++)) {
253		warnx("no archive specified");
254		usage();
255	}
256
257	/* -dmqr require a list of archive elements. */
258	if (options & (AR_D|AR_M|AR_Q|AR_R) && !*argv) {
259		warnx("no archive members specified");
260		usage();
261	}
262
263	if(fcall != 0){
264	    retval = (*fcall)(argv);
265	    if(retval != EXIT_SUCCESS ||
266	       ((options & AR_S) != AR_S &&
267	        (get_unix_standard_mode() == FALSE ||
268		 archive_opened_for_writing == 0)))
269		exit(retval);
270	}
271
272	/*
273	 * The default is to run ranlib(1) for UNIX conformance.  But if the -S
274	 * option is specified by the user we don't run it.
275	 */
276	if(run_ranlib){
277	    /* run ranlib -f or -q on the archive */
278	    reset_execute_list();
279	    add_execute_list_with_prefix("ranlib");
280	    if(options & AR_S)
281		add_execute_list("-f");
282	    else
283		add_execute_list("-q");
284	    add_execute_list(archive);
285	    if(execute_list(verbose) == 0){
286		(void)fprintf(stderr, "%s: internal ranlib command failed\n",
287			      progname);
288		exit(EXIT_FAILURE);
289	    }
290	}
291	exit(EXIT_SUCCESS);
292}
293
294static void
295badoptions(arg)
296	char *arg;
297{
298
299	warnx("illegal option combination for %s", arg);
300	usage();
301}
302
303static void
304usage()
305{
306
307	(void)fprintf(stderr, "usage:  ar -d [-TLsv] archive file ...\n");
308	(void)fprintf(stderr, "\tar -m [-TLsv] archive file ...\n");
309	(void)fprintf(stderr, "\tar -m [-abiTLsv] position archive file ...\n");
310	(void)fprintf(stderr, "\tar -p [-TLsv] archive [file ...]\n");
311	(void)fprintf(stderr, "\tar -q [-cTLsv] archive file ...\n");
312	(void)fprintf(stderr, "\tar -r [-cuTLsv] archive file ...\n");
313	(void)fprintf(stderr, "\tar -r [-abciuTLsv] position archive file ...\n");
314	(void)fprintf(stderr, "\tar -t [-TLsv] archive [file ...]\n");
315	(void)fprintf(stderr, "\tar -x [-ouTLsv] archive [file ...]\n");
316	exit(1);
317}
318