home *** CD-ROM | disk | FTP | other *** search
- /*
- * @(#) binst.c 1.1 91/01/26
- *
- * Copyright (C) 1991 by Christian Schlichtherle
- * (chris@attron.ruhr.sub.org)
- *
- * Permission is hereby granted to use, copy, modify or distribute
- * this file at will unless this copyright notice is removed.
- * The author disclaims any kind of warranty.
- *
- * binst.c - C module for binst(C).
- */
-
- #if !defined(lint) && !defined(library)
- static char sccsid[] = "@(#) binst.c 1.1 91/01/26 ";
- #endif /* not lint and not library */
-
- #include <string.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <errno.h>
- #include "config.h"
-
- #define MAXPATHLEN 80
- #define ERRBUFSIZ 255
-
- extern char *sys_errlist[];
- extern int sys_nerr;
-
- extern int setjmp();
- extern void longjmp();
- extern void exit();
-
- char *prg_nam = NULL;
- char pubbin[] = PUBBIN;
- jmp_buf env;
- char errbuf[ERRBUFSIZ + 1];
-
- /*
- * Certain messages.
- */
- char *message[] = {
- "Usage: %s <filename> ...\n",
- "Not owner of %s"
- };
-
- /*
- * Index of message in upper message vector.
- */
- #define USAGE 0
- #define NOT_OWNER 1
-
- /*
- * sig_list - List of signals that have to be caught.
- */
- int sig_list[] = {
- SIGHUP,
- SIGINT,
- SIGQUIT,
- SIGTERM,
- 0
- };
-
- /*
- * sig_action - List of actions for all signals.
- */
- int sigcatch();
- int (*sig_action[NSIG])() = {
- (int (*)()) 0, /* invalid */
- sigcatch, /* SIGHUP */
- sigcatch, /* SIGINT */
- sigcatch, /* SIGQUIT */
- sigcatch, /* SIGILL */
- sigcatch, /* SIGTRAP */
- sigcatch, /* SIGIOT */
- sigcatch, /* SIGEMT */
- sigcatch, /* SIGFPE */
- sigcatch, /* SIGKILL */
- sigcatch, /* SIGBUS */
- sigcatch, /* SIGSEGV */
- sigcatch, /* SIGSYS */
- sigcatch, /* SIGPIPE */
- sigcatch, /* SIGALRM */
- sigcatch, /* SIGTERM */
- sigcatch, /* SIGUSR1 */
- sigcatch /* SIGUSR2 */
- /* If there are more signals they are ignored! */
- };
-
- /*
- * print_error - Outputs error messages.
- * print_error uses "s" for perror(s) and "t" for error output.
- */
- void print_error(s, t)
- char *s;
- char *t;
- {
- if ((s == NULL || !*s) && (t == NULL || !*t))
- return;
-
- if (prg_nam != NULL && *prg_nam)
- (void) fprintf(stderr, "%s: ", prg_nam);
- if (errno > 0 && errno <= sys_nerr && s != NULL && *s)
- (void) fprintf(stderr, "%s: %s\n", s, sys_errlist[errno]);
- if (t != NULL && *t)
- (void) fprintf(stderr, "%s\n", t);
-
- return;
- }
-
- /*
- * build_dstname - Builds a pathname.
- * 'build_dstname' builds a new pathname and copies it to the string
- * "dst".
- * The pathname is build from the directory name "dir" and the
- * filename from pathname "src" appended.
- */
- void build_path(src, dir, dst)
- char *src;
- char *dir;
- char *dst;
- {
- char *ptr;
-
- if ((ptr = strrchr(src, '/')) != NULL)
- ptr++;
- else
- ptr = src;
- (void) sprintf(dst, "%s/%s", dir, ptr);
-
- return;
- }
-
- int sigcatch(num)
- int num;
- {
- (void) signal(num, SIG_IGN);
-
- longjmp(env, num);
-
- return (-1);
- }
-
- /*
- * set_act_sig - Sets only an active signal.
- * This function sets only a signal which is "active" (i.e. not ignored).
- * It returns the old action associated with the signal.
- * Note: When you set an active signal inactive with this function, you
- * can not redefine it. Use signal(S) instead.
- */
- #if defined(INT_SIG)
- int (*set_act_sig(sig_type, sig_func))()
- int sig_type;
- int (*sig_func)();
- #else /* VOID_SIG */
- void (*set_act_sig(sig_type, sig_func))()
- int sig_type;
- void (*sig_func)();
- #endif /* VOID_SIG */
- {
- #if defined(INT_SIG)
- int (*old_func)();
- #else /* VOID_SIG */
- void (*old_func)();
- #endif /* VOID_SIG */
-
- /*
- * Use an algorithm to leave no gap where the program
- * can be terminated at the cost of two "signal" calls
- * when all was right.
- */
- if ((old_func = signal(sig_type, SIG_IGN)) != SIG_IGN)
- (void) signal(sig_type, sig_func);
-
- return (old_func);
- }
-
- /*
- * set_sig_grp - Sets a group of signals.
- * "sig_lst" is a zero terminated list of signals to be set.
- * The function to set the signals is pointed to by "set_fnc".
- * The new action (i.e. the new pointer to a function) for a
- * signal can be found in the vector "new_act" with the signal
- * (i.e. it's number) as it's offset.
- * If "old_act" is nonnull the old action of a signal is stored
- * here with the signal (i.e. it's number) as it's offset again.
- * If it is null the old action is stored in "new_act" instead.
- */
- void set_sig_grp(sig_lst, set_fnc, new_act, old_act)
- int sig_lst[]; /* Zero terminated list of functions */
- int (*(*set_fnc)())(); /* Signal set function (see signal(S)) */
- int (*new_act[NSIG])(); /* Vector of new signal actions */
- int (*old_act[NSIG])(); /* Vector of old signal actions */
- {
- while (*sig_lst != 0) {
- if (old_act != (int (**)()) 0)
- old_act[*sig_lst] = (*set_fnc)(*sig_lst,
- new_act[*sig_lst]);
- else
- new_act[*sig_lst] = (*set_fnc)(*sig_lst,
- new_act[*sig_lst]);
- sig_lst++;
- }
-
- return;
- }
-
- /*
- * copy - copies a file from "src" to "dst".
- * If the file cannot be copied an error message is output and
- * -1 is returned.
- * No destination file is left except that this file already exists
- * and is not writable.
- * Owner, group and mode of the destination file are not reset.
- * Instead the mode is 0666 according to umask (see creat(S)).
- */
- int copy(src, dst)
- char *src;
- char *dst;
- {
- char buf[BUFSIZ];
- int src_fd;
- int dst_fd;
- int nread;
-
- if ((src_fd = open(src, O_RDONLY)) == -1)
- return (-1);
-
- if ((dst_fd = creat(dst, 0666)) == -1) {
- (void) close(src_fd);
- print_error(src, "");
-
- return (-1);
- }
-
- while ((nread = read(src_fd, buf, sizeof(buf) / sizeof(buf[0]))) > 0)
- if (write(dst_fd, buf, nread) != nread) {
- (void) close(src_fd);
- (void) close(dst_fd);
- (void) unlink(dst);
- print_error(dst, "");
-
- return (-1);
- }
-
- if (nread == -1) {
- (void) close(src_fd);
- (void) close(dst_fd);
- (void) unlink(dst);
- print_error(src, "");
-
- return (-1);
- }
-
- (void) close(src_fd);
- (void) close(dst_fd);
-
- return (0);
- }
-
- /*
- * chall - Changes mode, owner and group of the specified file.
- */
- int chall(file, mode, owner, group)
- char *file;
- int mode;
- int owner;
- int group;
- {
- if (chmod(file, mode) == -1)
- return (-1);
- if (chown(file, owner, group) == -1)
- return (-1);
-
- return (0);
- }
-
- /*
- * check_files - Checks files.
- */
- int check_files(src, dst, dst_mode, dst_owner, dst_group)
- char *src;
- char *dst;
- int *dst_mode;
- int *dst_owner;
- int *dst_group;
- {
- struct stat src_stat, dst_stat;
-
- /* Get info about source file */
- if (stat(src, &src_stat) == -1) {
- print_error(src, "");
- return -1;
- }
-
- #if defined(INSTALL_OTHER)
- if (access(src, 04) == -1)
- print_error(src, "");
- return -1;
- }
- #else /* not INSTALL_OTHER */
- if (src_stat.st_uid != getuid()) {
- (void) sprintf(errbuf, message[NOT_OWNER], src);
- print_error("", errbuf);
- return -1;
- }
- #endif /* not INSTALL_OTHER */
-
- #if defined(SRC_OWNER)
- *dst_owner = src_stat.st_uid;
- *dst_group = src_stat.st_gid;
- #else /* not SRC_OWNER */
- *dst_owner = getuid();
- *dst_group = getgid();
- #endif /* not SRC_OWNER */
-
- #if defined(SETUID)
- if (((*dst_mode = src_stat.st_mode) & 07000) == 0)
- *dst_mode |= 0755;
- #else /* not SETUID */
- *dst_mode = src_stat.st_mode & ~07000 | 0755;
- #endif /* not SETUID */
-
- #if !defined(OVERWRITE)
- if (stat(dst, &dst_stat) == 0) {
- if (*dst_owner != dst_stat.st_uid) {
- (void) sprintf(errbuf, message[NOT_OWNER], dst);
- print_error("", errbuf);
- return -1;
- }
-
- #if defined(INSTALL_OTHER) && defined(SRC_OWNER) && defined(OWNER_UPDATE)
- if (*dst_owner != getuid()) {
- (void) sprintf(errbuf, message[NOT_OWNER], dst);
- print_error("", errbuf);
- return -1;
- }
- #endif /* INSTALL_OTHER and SRC_OWNER and OWNER_UPDATE */
- }
- #endif /* not OVERWRITE */
-
- return 0;
- }
-
- /*
- * binst - Installs a file in the public binary directory.
- * Returns 0 if successfull, -1 otherwise.
- */
- int binst(src_path)
- char *src_path;
- {
- char dst_path[MAXPATHLEN + 1];
- int dst_mode, dst_owner, dst_group;
- int sig_num;
-
- /* Build destination pathname */
- build_path(src_path, pubbin, dst_path);
-
- if (check_files(src_path, dst_path, &dst_mode, &dst_owner,
- &dst_group) == -1)
- return -1;
-
- /*
- * Set a long jump mark.
- * If we return from a jump triggered by a signal remove the
- * destination file (it is assumed to be an incomplete copy!),
- * print an error message, restore all signal actions and
- * execute the signal's previously stored action.
- * If it returns from this action (in fact it does not return!),
- * return with an error status.
- */
- if ((sig_num = setjmp(env)) != 0) {
- (void) unlink(dst_path);
-
- (void) sprintf(errbuf, "%s removed", dst_path);
- (void) print_error("", errbuf);
-
- set_sig_grp(sig_list, signal, sig_action, (int (**)()) 0);
-
- (*sig_action[sig_num])(sig_num);
-
- return -1;
- }
-
- /*
- * Catch all important signals which are not ignored.
- * If one is catched a long jump to the previously set mark is
- * performed.
- */
- set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
-
- /*
- * Copy the files and set the permissions according to
- * the source file.
- */
- if (copy(src_path, dst_path) == -1)
- return -1;
- (void) chall(dst_path, dst_mode, dst_owner, dst_group);
-
- /*
- * Restore all previously catched signals.
- */
- set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
-
- return 0;
- }
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int status;
-
- prg_nam = argv[0];
-
- if (argc == 1) {
- (void) fprintf(stderr, message[USAGE], argv[0]);
- exit (1);
- }
-
- while (--argc)
- status = binst(*++argv);
-
- exit(-status);
- /* For your 'lint' only... */
- return -1;
- }
-