/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include "inc.h"
#include "conv.h"
/*
* Forward declarations
*/
static void setup(int, char **, Cmd_info *);
static void setcom(Cmd_info *, Cmd_func);
static void usage(void);
static void sigexit(int sig);
static int notfound(Cmd_info *);
static void check_swap();
const char *
_ar_msg(Msg mid)
{
return (gettext(MSG_ORIG(mid)));
}
void
establish_sighandler(void (*handler)())
{
static const int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
int i;
if (handler == SIG_IGN) {
/* Ignore all the specified signals */
for (i = 0; signum[i]; i++)
(void) signal(signum[i], SIG_IGN);
} else {
/*
* Set any signal that doesn't default to being ignored
* to our signal handler.
*/
for (i = 0; signum[i]; i++)
if (signal(signum[i], SIG_IGN) != SIG_IGN)
(void) signal(signum[i], handler);
}
}
int
main(int argc, char **argv, char *envp[])
{
int fd;
Cmd_info *cmd_info;
int ret;
char *new = NULL;
#ifndef XPG4
/*
* Check for a binary that better fits this architecture.
*/
(void) conv_check_native(argv, envp);
#endif
/*
* Establish locale.
*/
(void) setlocale(LC_ALL, MSG_ORIG(MSG_STR_EMPTY));
(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
/* Allow a graceful exit up until we start to write an archive */
establish_sighandler(sigexit);
/*
* Initialize cmd_info
*/
cmd_info = (Cmd_info *)calloc(1, sizeof (Cmd_info));
if (cmd_info == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
exit(1);
}
if (argc < 2)
usage();
/*
* Option handling.
*/
if (argv[1][0] != '-') {
new = (char *)malloc(strlen(argv[1]) + 2);
if (new == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
strerror(err));
exit(1);
}
(void) strcpy(new, MSG_ORIG(MSG_STR_HYPHEN));
(void) strcat(new, argv[1]);
argv[1] = new;
}
setup(argc, argv, cmd_info);
/*
* Check SWAP
*/
if (cmd_info->opt_flgs & z_FLAG)
check_swap();
if (cmd_info->comfun == NULL) {
if ((cmd_info->opt_flgs & (d_FLAG | r_FLAG | q_FLAG |
t_FLAG | p_FLAG | m_FLAG | x_FLAG)) == 0) {
(void) fprintf(stderr, MSG_INTL(MSG_USAGE_01));
exit(1);
}
}
cmd_info->modified = (cmd_info->opt_flgs & s_FLAG);
fd = getaf(cmd_info);
if ((fd == -1) &&
(cmd_info->opt_flgs &
(d_FLAG | m_FLAG | p_FLAG | t_FLAG | x_FLAG)) ||
((cmd_info->opt_flgs & r_FLAG) &&
(cmd_info->opt_flgs & (a_FLAG | b_FLAG)))) {
(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_AR),
cmd_info->arnam);
exit(1);
}
(*cmd_info->comfun)(cmd_info);
if (cmd_info->modified) {
writefile(cmd_info);
} else
(void) close(fd);
ret = notfound(cmd_info);
/*
* Check SWAP
*/
if (cmd_info->opt_flgs & z_FLAG)
check_swap();
free(new);
free(cmd_info);
return (ret);
}
/*
* Option handing function.
* Using getopt(), following xcu4 convention.
*/
static void
setup(int argc, char *argv[], Cmd_info *cmd_info)
{
int Vflag = 0;
int c;
int usage_err = 0;
while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
switch (c) {
case 'a': /* position after named archive member file */
cmd_info->opt_flgs |= a_FLAG;
cmd_info->ponam = trim(optarg);
break;
case 'b': /* position before named archive member file */
case 'i': /* position before named archive member: same as b */
cmd_info->opt_flgs |= b_FLAG;
cmd_info->ponam = trim(optarg);
break;
case 'c': /* supress messages */
cmd_info->opt_flgs |= c_FLAG;
break;
case 'd':
/*
* key operation:
* delete files from the archive
*/
setcom(cmd_info, dcmd);
cmd_info->opt_flgs |= d_FLAG;
break;
case 'l': /* ignored */
break;
case 'm':
/*
* key operation:
* move files to end of the archive
* or as indicated by position flag
*/
setcom(cmd_info, mcmd);
cmd_info->opt_flgs |= m_FLAG;
break;
case 'p':
/*
* key operation:
* print files in the archive
*/
setcom(cmd_info, pcmd);
cmd_info->opt_flgs |= p_FLAG;
break;
case 'q':
/*
* key operation:
* quickly append files to end of the archive
*/
setcom(cmd_info, qcmd);
cmd_info->opt_flgs |= q_FLAG;
break;
case 'r':
/*
* key operation:
* replace or add files to the archive
*/
setcom(cmd_info, rcmd);
cmd_info->opt_flgs |= r_FLAG;
break;
case 's': /* force symbol table regeneration */
cmd_info->opt_flgs |= s_FLAG;
break;
case 'S': /* Build SYM64 symbol table */
cmd_info->opt_flgs |= S_FLAG;
break;
case 't':
/*
* key operation:
* print table of contents
*/
setcom(cmd_info, tcmd);
cmd_info->opt_flgs |= t_FLAG;
break;
case 'u': /* update: change archive dependent on file dates */
cmd_info->opt_flgs |= u_FLAG;
break;
case 'v': /* verbose */
cmd_info->opt_flgs |= v_FLAG;
break;
case 'x':
/*
* key operation:
* extract files from the archive
*/
setcom(cmd_info, xcmd);
cmd_info->opt_flgs |= x_FLAG;
break;
case 'z':
cmd_info->opt_flgs |= z_FLAG;
break;
case 'V':
/*
* print version information.
* adjust command line access accounting
*/
if (Vflag == 0) {
(void) fprintf(stderr,
MSG_ORIG(MSG_FMT_VERSION),
(const char *)SGU_PKG,
(const char *)SGU_REL);
Vflag++;
}
break;
case 'C':
cmd_info->opt_flgs |= C_FLAG;
break;
case 'M':
/*
* -M was an original undocumented AT&T feature that
* would force the use of mmap() instead of read()
* for pulling file data into the process before
* writing it to the archive. Ignored.
*/
break;
case 'T':
cmd_info->opt_flgs |= T_FLAG;
break;
case ':':
(void) fprintf(stderr, MSG_INTL(MSG_USAGE_02), optopt);
usage_err++;
break;
case '?':
(void) fprintf(stderr, MSG_INTL(MSG_USAGE_03), optopt);
usage_err++;
break;
}
}
if (usage_err || argc - optind < 1)
usage();
cmd_info->arnam = argv[optind];
cmd_info->namv = &argv[optind+1];
cmd_info->namc = argc - optind - 1;
}
/*
* Set the function to be called to do the key operation.
* Check that only one key is indicated.
*/
static void
setcom(Cmd_info *cmd_info, Cmd_func *fun)
{
if (cmd_info->comfun != 0) {
(void) fprintf(stderr, MSG_INTL(MSG_USAGE_04));
exit(1);
}
cmd_info->comfun = fun;
}
static void
usage(void)
{
(void) fprintf(stderr, MSG_INTL(MSG_USAGE));
exit(1);
}
/*ARGSUSED0*/
static void
sigexit(int sig)
{
exit(100);
}
/* tells the user which of the listed files were not found in the archive */
static int
notfound(Cmd_info *cmd_info)
{
int i, n;
n = 0;
for (i = 0; i < cmd_info->namc; i++)
if (cmd_info->namv[i]) {
(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_FILE),
cmd_info->namv[i]);
n++;
}
return (n);
}
/*
* Debugging info
*/
static void
check_swap(void)
{
(void) system(MSG_ORIG(MSG_CMD_SWAP));
}