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 }