home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
2
/
2619
/
binst.c
next >
Wrap
C/C++ Source or Header
|
1991-01-28
|
9KB
|
432 lines
/*
* @(#) 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;
}