xref: /illumos-gate/usr/src/cmd/sgs/ar/common/main.c (revision 488060a6285c53d78d4e5360e7db00d6d544d960)
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