xref: /illumos-gate/usr/src/cmd/sgs/ar/common/main.c (revision 8a2b682e57a046b828f37bcde1776f131ef4629f)
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  */
31 
32 #include "inc.h"
33 #include "conv.h"
34 
35 /*
36  * Forward declarations
37  */
38 static void setup(int, char **, Cmd_info *);
39 static void setcom(Cmd_info *, Cmd_func);
40 static void usage(void);
41 static void sigexit(int sig);
42 static int notfound(Cmd_info *);
43 static void check_swap();
44 
45 const char *
46 _ar_msg(Msg mid)
47 {
48 	return (gettext(MSG_ORIG(mid)));
49 }
50 
51 
52 void
53 establish_sighandler(void (*handler)())
54 {
55 	static const int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
56 	int i;
57 
58 	if (handler == SIG_IGN) {
59 		/* Ignore all the specified signals */
60 		for (i = 0; signum[i]; i++)
61 			(void) signal(signum[i], SIG_IGN);
62 
63 	} else {
64 		/*
65 		 * Set any signal that doesn't default to being ignored
66 		 * to our signal handler.
67 		 */
68 		for (i = 0; signum[i]; i++)
69 			if (signal(signum[i], SIG_IGN) != SIG_IGN)
70 				(void) signal(signum[i], handler);
71 	}
72 }
73 
74 int
75 main(int argc, char **argv, char *envp[])
76 {
77 	int fd;
78 	Cmd_info *cmd_info;
79 	int ret;
80 	char *new = NULL;
81 
82 #ifndef	XPG4
83 	/*
84 	 * Check for a binary that better fits this architecture.
85 	 */
86 	(void) conv_check_native(argv, envp);
87 #endif
88 
89 	/*
90 	 * Establish locale.
91 	 */
92 	(void) setlocale(LC_ALL, MSG_ORIG(MSG_STR_EMPTY));
93 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
94 
95 	/* Allow a graceful exit up until we start to write an archive */
96 	establish_sighandler(sigexit);
97 
98 	/*
99 	 * Initialize cmd_info
100 	 */
101 	cmd_info = (Cmd_info *)calloc(1, sizeof (Cmd_info));
102 	if (cmd_info == NULL) {
103 		int err = errno;
104 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
105 		exit(1);
106 	}
107 
108 	if (argc < 2)
109 		usage();
110 
111 	/*
112 	 * Option handling.
113 	 */
114 	if (argv[1][0] != '-') {
115 		new = (char *)malloc(strlen(argv[1]) + 2);
116 		if (new == NULL) {
117 			int err = errno;
118 			(void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
119 			    strerror(err));
120 			exit(1);
121 		}
122 		(void) strcpy(new, MSG_ORIG(MSG_STR_HYPHEN));
123 		(void) strcat(new, argv[1]);
124 		argv[1] = new;
125 	}
126 	setup(argc, argv, cmd_info);
127 
128 	/*
129 	 * Check SWAP
130 	 */
131 	if (cmd_info->opt_flgs & z_FLAG)
132 		check_swap();
133 
134 	if (cmd_info->comfun == NULL) {
135 		if ((cmd_info->opt_flgs & (d_FLAG | r_FLAG | q_FLAG |
136 		    t_FLAG | p_FLAG | m_FLAG | x_FLAG)) == 0) {
137 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_01));
138 			exit(1);
139 		}
140 	}
141 
142 	cmd_info->modified = (cmd_info->opt_flgs & s_FLAG);
143 	fd = getaf(cmd_info);
144 
145 	if ((fd == -1) &&
146 	    (cmd_info->opt_flgs &
147 	    (d_FLAG | m_FLAG | p_FLAG | t_FLAG | x_FLAG)) ||
148 	    ((cmd_info->opt_flgs & r_FLAG) &&
149 	    (cmd_info->opt_flgs & (a_FLAG | b_FLAG)))) {
150 		(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_AR),
151 		    cmd_info->arnam);
152 		exit(1);
153 	}
154 
155 	(*cmd_info->comfun)(cmd_info);
156 	if (cmd_info->modified) {
157 		writefile(cmd_info);
158 	} else
159 		(void) close(fd);
160 
161 	ret = notfound(cmd_info);
162 
163 	/*
164 	 * Check SWAP
165 	 */
166 	if (cmd_info->opt_flgs & z_FLAG)
167 		check_swap();
168 
169 	free(new);
170 	free(cmd_info);
171 	return (ret);
172 
173 }
174 
175 /*
176  * Option handing function.
177  *	Using getopt(), following xcu4 convention.
178  */
179 static void
180 setup(int argc, char *argv[], Cmd_info *cmd_info)
181 {
182 	int Vflag = 0;
183 	int c;
184 	int usage_err = 0;
185 
186 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
187 		switch (c) {
188 		case 'a': /* position after named archive member file */
189 			cmd_info->opt_flgs |= a_FLAG;
190 			cmd_info->ponam = trim(optarg);
191 			break;
192 		case 'b': /* position before named archive member file */
193 		case 'i': /* position before named archive member: same as b */
194 			cmd_info->opt_flgs |= b_FLAG;
195 			cmd_info->ponam = trim(optarg);
196 			break;
197 		case 'c': /* supress messages */
198 			cmd_info->opt_flgs |= c_FLAG;
199 			break;
200 		case 'd':
201 			/*
202 			 * key operation:
203 			 * delete files from the archive
204 			 */
205 			setcom(cmd_info, dcmd);
206 			cmd_info->opt_flgs |= d_FLAG;
207 			break;
208 		case 'l': /* ignored */
209 			break;
210 		case 'm':
211 			/*
212 			 * key operation:
213 			 * move files to end of the archive
214 			 * or as indicated by position flag
215 			 */
216 			setcom(cmd_info, mcmd);
217 			cmd_info->opt_flgs |= m_FLAG;
218 			break;
219 		case 'p':
220 			/*
221 			 * key operation:
222 			 * print files in the archive
223 			 */
224 			setcom(cmd_info, pcmd);
225 			cmd_info->opt_flgs |= p_FLAG;
226 			break;
227 		case 'q':
228 			/*
229 			 * key operation:
230 			 * quickly append files to end of the archive
231 			 */
232 			setcom(cmd_info, qcmd);
233 			cmd_info->opt_flgs |= q_FLAG;
234 			break;
235 		case 'r':
236 			/*
237 			 * key operation:
238 			 * replace or add files to the archive
239 			 */
240 			setcom(cmd_info, rcmd);
241 			cmd_info->opt_flgs |= r_FLAG;
242 			break;
243 		case 's': /* force symbol table regeneration */
244 			cmd_info->opt_flgs |= s_FLAG;
245 			break;
246 		case 'S': /* Build SYM64 symbol table */
247 			cmd_info->opt_flgs |= S_FLAG;
248 			break;
249 		case 't':
250 			/*
251 			 * key operation:
252 			 * print table of contents
253 			 */
254 			setcom(cmd_info, tcmd);
255 			cmd_info->opt_flgs |= t_FLAG;
256 			break;
257 		case 'u': /* update: change archive dependent on file dates */
258 			cmd_info->opt_flgs |= u_FLAG;
259 			break;
260 		case 'v': /* verbose */
261 			cmd_info->opt_flgs |= v_FLAG;
262 			break;
263 		case 'x':
264 			/*
265 			 * key operation:
266 			 * extract files from the archive
267 			 */
268 			setcom(cmd_info, xcmd);
269 			cmd_info->opt_flgs |= x_FLAG;
270 			break;
271 		case 'z':
272 			cmd_info->opt_flgs |= z_FLAG;
273 			break;
274 		case 'V':
275 			/*
276 			 * print version information.
277 			 * adjust command line access accounting
278 			 */
279 			if (Vflag == 0) {
280 				(void) fprintf(stderr,
281 				    MSG_ORIG(MSG_FMT_VERSION),
282 				    (const char *)SGU_PKG,
283 				    (const char *)SGU_REL);
284 				Vflag++;
285 			}
286 			break;
287 		case 'C':
288 			cmd_info->opt_flgs |= C_FLAG;
289 			break;
290 		case 'M':
291 			/*
292 			 * -M was an original undocumented AT&T feature that
293 			 * would force the use of mmap() instead of read()
294 			 * for pulling file data into the process before
295 			 * writing it to the archive. Ignored.
296 			 */
297 			break;
298 		case 'T':
299 			cmd_info->opt_flgs |= T_FLAG;
300 			break;
301 		case ':':
302 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_02), optopt);
303 			usage_err++;
304 			break;
305 		case '?':
306 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_03), optopt);
307 			usage_err++;
308 			break;
309 		}
310 	}
311 
312 	if (usage_err || argc - optind < 1)
313 		usage();
314 
315 	cmd_info->arnam = argv[optind];
316 	cmd_info->namv = &argv[optind+1];
317 	cmd_info->namc = argc - optind - 1;
318 }
319 
320 
321 /*
322  * Set the function to be called to do the key operation.
323  * Check that only one key is indicated.
324  */
325 static void
326 setcom(Cmd_info *cmd_info, Cmd_func *fun)
327 {
328 	if (cmd_info->comfun != 0) {
329 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_04));
330 		exit(1);
331 	}
332 	cmd_info->comfun = fun;
333 }
334 
335 static void
336 usage(void)
337 {
338 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE));
339 	exit(1);
340 }
341 
342 /*ARGSUSED0*/
343 static void
344 sigexit(int sig)
345 {
346 	exit(100);
347 }
348 
349 /* tells the user which of the listed files were not found in the archive */
350 
351 static int
352 notfound(Cmd_info *cmd_info)
353 {
354 	int i, n;
355 
356 	n = 0;
357 	for (i = 0; i < cmd_info->namc; i++)
358 		if (cmd_info->namv[i]) {
359 			(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_FILE),
360 			    cmd_info->namv[i]);
361 			n++;
362 		}
363 	return (n);
364 }
365 
366 /*
367  * Debugging info
368  */
369 static void
370 check_swap(void)
371 {
372 	(void) system(MSG_ORIG(MSG_CMD_SWAP));
373 }
374