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 *
_ar_msg(Msg mid)42 _ar_msg(Msg mid)
43 {
44 return (gettext(MSG_ORIG(mid)));
45 }
46
47
48 void
establish_sighandler(void (* handler)())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
main(int argc,char ** argv,char * envp[])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
setup(int argc,char * argv[],Cmd_info * cmd_info)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
setcom(Cmd_info * cmd_info,Cmd_func * fun)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
usage(void)332 usage(void)
333 {
334 (void) fprintf(stderr, MSG_INTL(MSG_USAGE));
335 exit(1);
336 }
337
338 /*ARGSUSED0*/
339 static void
sigexit(int sig)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
notfound(Cmd_info * cmd_info)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
check_swap(void)366 check_swap(void)
367 {
368 (void) system(MSG_ORIG(MSG_CMD_SWAP));
369 }
370