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