xref: /illumos-gate/usr/src/cmd/sgs/ar/common/main.c (revision a0fbb7fb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*	Copyright (c) 1988 AT&T	*/
22 /*	  All Rights Reserved   */
23 
24 /*
25  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 /*
29  * Copyright (c) 2018, Joyent, Inc.
30  * Copyright 2021 Oxide Computer Company
31  */
32 
33 #include "inc.h"
34 #include "conv.h"
35 
36 /*
37  * Forward declarations
38  */
39 static void setup(int, char **, Cmd_info *);
40 static void setcom(Cmd_info *, Cmd_func);
41 static void usage(void);
42 static void sigexit(int sig);
43 static int notfound(Cmd_info *);
44 static void check_swap();
45 
46 const char *
47 _ar_msg(Msg mid)
48 {
49 	return (gettext(MSG_ORIG(mid)));
50 }
51 
52 
53 void
54 establish_sighandler(void (*handler)())
55 {
56 	static const int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
57 	int i;
58 
59 	if (handler == SIG_IGN) {
60 		/* Ignore all the specified signals */
61 		for (i = 0; signum[i]; i++)
62 			(void) signal(signum[i], SIG_IGN);
63 
64 	} else {
65 		/*
66 		 * Set any signal that doesn't default to being ignored
67 		 * to our signal handler.
68 		 */
69 		for (i = 0; signum[i]; i++)
70 			if (signal(signum[i], SIG_IGN) != SIG_IGN)
71 				(void) signal(signum[i], handler);
72 	}
73 }
74 
75 int
76 main(int argc, char **argv, char *envp[])
77 {
78 	int fd;
79 	Cmd_info *cmd_info;
80 	int ret;
81 	char *new = NULL;
82 
83 #ifndef	XPG4
84 	/*
85 	 * Check for a binary that better fits this architecture.
86 	 */
87 	(void) conv_check_native(argv, envp);
88 #endif
89 
90 	/*
91 	 * Establish locale.
92 	 */
93 	(void) setlocale(LC_ALL, MSG_ORIG(MSG_STR_EMPTY));
94 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
95 
96 	/* Allow a graceful exit up until we start to write an archive */
97 	establish_sighandler(sigexit);
98 
99 	/*
100 	 * Initialize cmd_info
101 	 */
102 	cmd_info = (Cmd_info *)calloc(1, sizeof (Cmd_info));
103 	if (cmd_info == NULL) {
104 		int err = errno;
105 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
106 		exit(1);
107 	}
108 
109 	if (argc < 2)
110 		usage();
111 
112 	/*
113 	 * Option handling.
114 	 */
115 	if (argv[1][0] != '-') {
116 		new = (char *)malloc(strlen(argv[1]) + 2);
117 		if (new == NULL) {
118 			int err = errno;
119 			(void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
120 			    strerror(err));
121 			exit(1);
122 		}
123 		(void) strcpy(new, MSG_ORIG(MSG_STR_HYPHEN));
124 		(void) strcat(new, argv[1]);
125 		argv[1] = new;
126 	}
127 	setup(argc, argv, cmd_info);
128 
129 	/*
130 	 * Check SWAP
131 	 */
132 	if (cmd_info->opt_flgs & z_FLAG)
133 		check_swap();
134 
135 	cmd_info->modified = (cmd_info->opt_flgs & s_FLAG);
136 	fd = getaf(cmd_info);
137 
138 	if ((fd == -1) &&
139 	    (cmd_info->opt_flgs &
140 	    (d_FLAG | m_FLAG | p_FLAG | s_FLAG | t_FLAG | x_FLAG)) ||
141 	    ((cmd_info->opt_flgs & r_FLAG) &&
142 	    (cmd_info->opt_flgs & (a_FLAG | b_FLAG)))) {
143 		(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_AR),
144 		    cmd_info->arnam);
145 		exit(1);
146 	}
147 
148 	(*cmd_info->comfun)(cmd_info);
149 	if (cmd_info->modified) {
150 		writefile(cmd_info);
151 	} else
152 		(void) close(fd);
153 
154 	ret = notfound(cmd_info);
155 
156 	/*
157 	 * Check SWAP
158 	 */
159 	if (cmd_info->opt_flgs & z_FLAG)
160 		check_swap();
161 
162 	free(new);
163 	free(cmd_info);
164 	return (ret);
165 
166 }
167 
168 /*
169  * Option handing function.
170  *	Using getopt(), following xcu4 convention.
171  */
172 static void
173 setup(int argc, char *argv[], Cmd_info *cmd_info)
174 {
175 	int Vflag = 0;
176 	int c;
177 	int usage_err = 0;
178 
179 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
180 		switch (c) {
181 		case 'a': /* position after named archive member file */
182 			cmd_info->opt_flgs |= a_FLAG;
183 			cmd_info->ponam = trim(optarg);
184 			break;
185 		case 'b': /* position before named archive member file */
186 		case 'i': /* position before named archive member: same as b */
187 			cmd_info->opt_flgs |= b_FLAG;
188 			cmd_info->ponam = trim(optarg);
189 			break;
190 		case 'c': /* supress messages */
191 			cmd_info->opt_flgs |= c_FLAG;
192 			break;
193 		case 'd':
194 			/*
195 			 * key operation:
196 			 * delete files from the archive
197 			 */
198 			setcom(cmd_info, dcmd);
199 			cmd_info->opt_flgs |= d_FLAG;
200 			break;
201 		case 'l': /* ignored */
202 			break;
203 		case 'm':
204 			/*
205 			 * key operation:
206 			 * move files to end of the archive
207 			 * or as indicated by position flag
208 			 */
209 			setcom(cmd_info, mcmd);
210 			cmd_info->opt_flgs |= m_FLAG;
211 			break;
212 		case 'p':
213 			/*
214 			 * key operation:
215 			 * print files in the archive
216 			 */
217 			setcom(cmd_info, pcmd);
218 			cmd_info->opt_flgs |= p_FLAG;
219 			break;
220 		case 'q':
221 			/*
222 			 * key operation:
223 			 * quickly append files to end of the archive
224 			 */
225 			setcom(cmd_info, qcmd);
226 			cmd_info->opt_flgs |= q_FLAG;
227 			break;
228 		case 'r':
229 			/*
230 			 * key operation:
231 			 * replace or add files to the archive
232 			 */
233 			setcom(cmd_info, rcmd);
234 			cmd_info->opt_flgs |= r_FLAG;
235 			break;
236 		case 's': /* force symbol table regeneration */
237 			cmd_info->opt_flgs |= s_FLAG;
238 			break;
239 		case 'S': /* Build SYM64 symbol table */
240 			cmd_info->opt_flgs |= S_FLAG;
241 			break;
242 		case 't':
243 			/*
244 			 * key operation:
245 			 * print table of contents
246 			 */
247 			setcom(cmd_info, tcmd);
248 			cmd_info->opt_flgs |= t_FLAG;
249 			break;
250 		case 'u': /* update: change archive dependent on file dates */
251 			cmd_info->opt_flgs |= u_FLAG;
252 			break;
253 		case 'v': /* verbose */
254 			cmd_info->opt_flgs |= v_FLAG;
255 			break;
256 		case 'x':
257 			/*
258 			 * key operation:
259 			 * extract files from the archive
260 			 */
261 			setcom(cmd_info, xcmd);
262 			cmd_info->opt_flgs |= x_FLAG;
263 			break;
264 		case 'z':
265 			cmd_info->opt_flgs |= z_FLAG;
266 			break;
267 		case 'V':
268 			/*
269 			 * print version information.
270 			 * adjust command line access accounting
271 			 */
272 			if (Vflag == 0) {
273 				(void) fprintf(stderr,
274 				    MSG_ORIG(MSG_FMT_VERSION),
275 				    (const char *)SGU_PKG,
276 				    (const char *)SGU_REL);
277 				Vflag++;
278 			}
279 			break;
280 		case 'C':
281 			cmd_info->opt_flgs |= C_FLAG;
282 			break;
283 		case 'M':
284 			/*
285 			 * -M was an original undocumented AT&T feature that
286 			 * would force the use of mmap() instead of read()
287 			 * for pulling file data into the process before
288 			 * writing it to the archive. Ignored.
289 			 */
290 			break;
291 		case 'T':
292 			cmd_info->opt_flgs |= T_FLAG;
293 			break;
294 		case ':':
295 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_02), optopt);
296 			usage_err++;
297 			break;
298 		case '?':
299 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_03), optopt);
300 			usage_err++;
301 			break;
302 		}
303 	}
304 
305 	if (usage_err || argc - optind < 1)
306 		usage();
307 
308 	cmd_info->arnam = argv[optind];
309 	cmd_info->namv = &argv[optind+1];
310 	cmd_info->namc = argc - optind - 1;
311 
312 	/*
313 	 * GNU ar popularized the use of -s on its own which previously used to
314 	 * require another command function. As such, we don't set a command
315 	 * function when we encounter the -s flag because that might otherwise
316 	 * clobber an existing one being set and would interrupt the detection
317 	 * of multiple flags being used that way.
318 	 *
319 	 * If after processing everything, we find there's no command function
320 	 * set and the -s flag has been set, then we can finally set a command
321 	 * function. The command function for -t 'tcmd' is used in this case. It
322 	 * knows to only print out data if -t has been specified.
323 	 *
324 	 * While ar has not traditionally been very stringent about using flags
325 	 * in circumstances they aren't called for, we go ahead and check for
326 	 * that now for this newer option.
327 	 */
328 	if (cmd_info->comfun == NULL) {
329 		if ((cmd_info->opt_flgs & s_FLAG) != 0) {
330 			if ((cmd_info->opt_flgs & ~(s_FLAG | v_FLAG)) != 0) {
331 				(void) fprintf(stderr,
332 				    MSG_INTL(MSG_USAGE_S_BAD_ARG));
333 				exit(1);
334 			}
335 
336 			if (cmd_info->namc > 1) {
337 				(void) fprintf(stderr,
338 				    MSG_INTL(MSG_USAGE_S_EXTRA_AR));
339 				exit(1);
340 			}
341 
342 			setcom(cmd_info, tcmd);
343 		} else if ((cmd_info->opt_flgs & (d_FLAG | r_FLAG | q_FLAG |
344 		    s_FLAG | t_FLAG | p_FLAG | m_FLAG | x_FLAG)) == 0) {
345 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_01));
346 			exit(1);
347 		}
348 	}
349 }
350 
351 
352 /*
353  * Set the function to be called to do the key operation.
354  * Check that only one key is indicated.
355  */
356 static void
357 setcom(Cmd_info *cmd_info, Cmd_func *fun)
358 {
359 	if (cmd_info->comfun != 0) {
360 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_04));
361 		exit(1);
362 	}
363 	cmd_info->comfun = fun;
364 }
365 
366 static void
367 usage(void)
368 {
369 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE));
370 	exit(1);
371 }
372 
373 /*ARGSUSED0*/
374 static void
375 sigexit(int sig)
376 {
377 	exit(100);
378 }
379 
380 /* tells the user which of the listed files were not found in the archive */
381 
382 static int
383 notfound(Cmd_info *cmd_info)
384 {
385 	int i, n;
386 
387 	n = 0;
388 	for (i = 0; i < cmd_info->namc; i++)
389 		if (cmd_info->namv[i]) {
390 			(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_FILE),
391 			    cmd_info->namv[i]);
392 			n++;
393 		}
394 	return (n);
395 }
396 
397 /*
398  * Debugging info
399  */
400 static void
401 check_swap(void)
402 {
403 	(void) system(MSG_ORIG(MSG_CMD_SWAP));
404 }
405