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 >
C/C++ Source or Header  |  1991-01-28  |  9KB  |  432 lines

  1. /*
  2.  *    @(#) binst.c    1.1 91/01/26 
  3.  *
  4.  *    Copyright (C) 1991 by Christian Schlichtherle
  5.  *                  (chris@attron.ruhr.sub.org)
  6.  *    
  7.  *    Permission is hereby granted to use, copy, modify or distribute
  8.  *    this file at will unless this copyright notice is removed.
  9.  *    The author disclaims any kind of warranty.
  10.  *
  11.  *    binst.c - C module for binst(C).
  12.  */
  13.  
  14. #if    !defined(lint) && !defined(library)
  15. static char    sccsid[] = "@(#) binst.c 1.1 91/01/26 ";
  16. #endif /* not lint and not library */
  17.  
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <fcntl.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <signal.h>
  24. #include <setjmp.h>
  25. #include <errno.h>
  26. #include "config.h"
  27.  
  28. #define MAXPATHLEN    80
  29. #define ERRBUFSIZ    255
  30.  
  31. extern char    *sys_errlist[];
  32. extern int    sys_nerr;
  33.  
  34. extern int    setjmp();
  35. extern void    longjmp();
  36. extern void    exit();
  37.  
  38. char    *prg_nam = NULL;
  39. char    pubbin[] = PUBBIN;
  40. jmp_buf    env;
  41. char    errbuf[ERRBUFSIZ + 1];
  42.  
  43. /*
  44.  * Certain messages.
  45.  */
  46. char    *message[] = {
  47.     "Usage: %s <filename> ...\n",
  48.     "Not owner of %s"
  49. };
  50.  
  51. /*
  52.  * Index of message in upper message vector.
  53.  */
  54. #define USAGE        0
  55. #define NOT_OWNER    1
  56.  
  57. /*
  58.  * sig_list - List of signals that have to be caught.
  59.  */
  60. int    sig_list[] = {
  61.     SIGHUP,
  62.     SIGINT,
  63.     SIGQUIT,
  64.     SIGTERM,
  65.     0
  66. };
  67.  
  68. /*
  69.  * sig_action - List of actions for all signals.
  70.  */
  71. int    sigcatch();
  72. int    (*sig_action[NSIG])() = {
  73.     (int (*)()) 0,    /* invalid */
  74.     sigcatch,    /* SIGHUP  */
  75.     sigcatch,    /* SIGINT  */
  76.     sigcatch,    /* SIGQUIT */
  77.     sigcatch,    /* SIGILL  */
  78.     sigcatch,    /* SIGTRAP */
  79.     sigcatch,    /* SIGIOT  */
  80.     sigcatch,    /* SIGEMT  */
  81.     sigcatch,    /* SIGFPE  */
  82.     sigcatch,    /* SIGKILL */
  83.     sigcatch,    /* SIGBUS  */
  84.     sigcatch,    /* SIGSEGV */
  85.     sigcatch,    /* SIGSYS  */
  86.     sigcatch,    /* SIGPIPE */
  87.     sigcatch,    /* SIGALRM */
  88.     sigcatch,    /* SIGTERM */
  89.     sigcatch,    /* SIGUSR1 */
  90.     sigcatch    /* SIGUSR2 */
  91.             /* If there are more signals they are ignored! */
  92. };
  93.  
  94. /*
  95.  * print_error - Outputs error messages.
  96.  * print_error uses "s" for perror(s) and "t" for error output.
  97.  */
  98. void    print_error(s, t)
  99. char    *s;
  100. char    *t;
  101. {
  102.     if ((s == NULL || !*s) && (t == NULL || !*t))
  103.         return;
  104.  
  105.     if (prg_nam != NULL && *prg_nam)
  106.         (void) fprintf(stderr, "%s: ", prg_nam);
  107.     if (errno > 0 && errno <= sys_nerr && s != NULL && *s)
  108.         (void) fprintf(stderr, "%s: %s\n", s, sys_errlist[errno]);
  109.     if (t != NULL && *t)
  110.         (void) fprintf(stderr, "%s\n", t);
  111.         
  112.     return;
  113. }
  114.  
  115. /*
  116.  * build_dstname - Builds a pathname.
  117.  * 'build_dstname' builds a new pathname and copies it to the string
  118.  * "dst".
  119.  * The pathname is build from the directory name "dir" and the
  120.  * filename from pathname "src" appended.
  121.  */
  122. void    build_path(src, dir, dst)
  123. char    *src;
  124. char    *dir;
  125. char    *dst;
  126. {
  127.     char    *ptr;
  128.  
  129.     if ((ptr = strrchr(src, '/')) != NULL) 
  130.         ptr++;
  131.     else
  132.         ptr = src;
  133.     (void) sprintf(dst, "%s/%s", dir, ptr);
  134.  
  135.     return;
  136. }
  137.  
  138. int    sigcatch(num)
  139. int    num;
  140. {
  141.     (void) signal(num, SIG_IGN);
  142.  
  143.     longjmp(env, num);
  144.  
  145.     return (-1);
  146. }
  147.  
  148. /*
  149.  * set_act_sig - Sets only an active signal.
  150.  * This function sets only a signal which is "active" (i.e. not ignored).
  151.  * It returns the old action associated with the signal.
  152.  * Note: When you set an active signal inactive with this function, you
  153.  * can not redefine it. Use signal(S) instead.
  154.  */
  155. #if    defined(INT_SIG)
  156. int    (*set_act_sig(sig_type, sig_func))()
  157. int    sig_type;
  158. int    (*sig_func)();
  159. #else    /* VOID_SIG */
  160. void    (*set_act_sig(sig_type, sig_func))()
  161. int    sig_type;
  162. void    (*sig_func)();
  163. #endif    /* VOID_SIG */
  164. {
  165. #if    defined(INT_SIG)
  166.     int    (*old_func)();
  167. #else    /* VOID_SIG */
  168.     void    (*old_func)();
  169. #endif    /* VOID_SIG */
  170.  
  171.     /*
  172.      * Use an algorithm to leave no gap where the program
  173.      * can be terminated at the cost of two "signal" calls
  174.      * when all was right.
  175.      */
  176.     if ((old_func = signal(sig_type, SIG_IGN)) != SIG_IGN)
  177.         (void) signal(sig_type, sig_func);
  178.  
  179.     return (old_func);
  180. }
  181.  
  182. /*
  183.  * set_sig_grp - Sets a group of signals.
  184.  * "sig_lst" is a zero terminated list of signals to be set.
  185.  * The function to set the signals is pointed to by "set_fnc".
  186.  * The new action (i.e. the new pointer to a function) for a
  187.  * signal can be found in the vector "new_act" with the signal
  188.  * (i.e. it's number) as it's offset.
  189.  * If "old_act" is nonnull the old action of a signal is stored
  190.  * here with the signal (i.e. it's number) as it's offset again.
  191.  * If it is null the old action is stored in "new_act" instead.
  192.  */
  193. void    set_sig_grp(sig_lst, set_fnc, new_act, old_act)
  194. int    sig_lst[];        /* Zero terminated list of functions   */
  195. int    (*(*set_fnc)())();    /* Signal set function (see signal(S)) */
  196. int    (*new_act[NSIG])();    /* Vector of new signal actions        */
  197. int    (*old_act[NSIG])();    /* Vector of old signal actions        */
  198. {
  199.     while (*sig_lst != 0) {
  200.         if (old_act != (int (**)()) 0)
  201.             old_act[*sig_lst] = (*set_fnc)(*sig_lst,
  202.                                new_act[*sig_lst]);
  203.         else
  204.             new_act[*sig_lst] = (*set_fnc)(*sig_lst,
  205.                                new_act[*sig_lst]);
  206.         sig_lst++;
  207.     }
  208.  
  209.     return;
  210. }
  211.  
  212. /*
  213.  * copy - copies a file from "src" to "dst".
  214.  * If the file cannot be copied an error message is output and
  215.  * -1 is returned.
  216.  * No destination file is left except that this file already exists
  217.  * and is not writable.
  218.  * Owner, group and mode of the destination file are not reset.
  219.  * Instead the mode is 0666 according to umask (see creat(S)).
  220.  */
  221. int    copy(src, dst)
  222. char    *src;
  223. char    *dst;
  224. {
  225.     char    buf[BUFSIZ];
  226.     int    src_fd;
  227.     int    dst_fd;
  228.     int    nread;
  229.  
  230.     if ((src_fd = open(src, O_RDONLY)) == -1)
  231.         return (-1);
  232.  
  233.     if ((dst_fd = creat(dst, 0666)) == -1) {
  234.         (void) close(src_fd);
  235.         print_error(src, "");
  236.  
  237.         return (-1);
  238.     }
  239.  
  240.     while ((nread = read(src_fd, buf, sizeof(buf) / sizeof(buf[0]))) > 0)
  241.         if (write(dst_fd, buf, nread) != nread) {
  242.             (void) close(src_fd);
  243.             (void) close(dst_fd);
  244.             (void) unlink(dst);
  245.             print_error(dst, "");
  246.  
  247.             return (-1);
  248.         }
  249.  
  250.     if (nread == -1) {
  251.         (void) close(src_fd);
  252.         (void) close(dst_fd);
  253.         (void) unlink(dst);
  254.         print_error(src, "");
  255.  
  256.         return (-1);
  257.     }
  258.  
  259.     (void) close(src_fd);
  260.     (void) close(dst_fd);
  261.  
  262.     return (0);
  263. }
  264.  
  265. /*
  266.  * chall - Changes mode, owner and group of the specified file.
  267.  */
  268. int    chall(file, mode, owner, group)
  269. char    *file;
  270. int    mode;
  271. int    owner;
  272. int    group;
  273. {
  274.     if (chmod(file, mode) == -1)
  275.         return (-1);
  276.     if (chown(file, owner, group) == -1)
  277.         return (-1);
  278.  
  279.     return (0);
  280. }
  281.  
  282. /*
  283.  * check_files - Checks files.
  284.  */
  285. int    check_files(src, dst, dst_mode, dst_owner, dst_group)
  286. char    *src;
  287. char    *dst;
  288. int    *dst_mode;
  289. int    *dst_owner;
  290. int    *dst_group;
  291. {
  292.     struct stat    src_stat, dst_stat;
  293.  
  294.         /* Get info about source file */
  295.     if (stat(src, &src_stat) == -1) {
  296.         print_error(src, "");
  297.         return -1;
  298.     }
  299.  
  300. #if    defined(INSTALL_OTHER)
  301.     if (access(src, 04) == -1)
  302.         print_error(src, "");
  303.         return -1;
  304.     }
  305. #else    /* not INSTALL_OTHER */
  306.     if (src_stat.st_uid != getuid()) {
  307.         (void) sprintf(errbuf, message[NOT_OWNER], src);
  308.         print_error("", errbuf);
  309.         return -1;
  310.     }
  311. #endif    /* not INSTALL_OTHER */
  312.  
  313. #if    defined(SRC_OWNER)
  314.     *dst_owner = src_stat.st_uid;
  315.     *dst_group = src_stat.st_gid;
  316. #else    /* not SRC_OWNER */
  317.     *dst_owner = getuid();
  318.     *dst_group = getgid();
  319. #endif    /* not SRC_OWNER */
  320.  
  321. #if    defined(SETUID)
  322.     if (((*dst_mode = src_stat.st_mode) & 07000) == 0)
  323.         *dst_mode |= 0755;
  324. #else    /* not SETUID */
  325.     *dst_mode = src_stat.st_mode & ~07000 | 0755;
  326. #endif    /* not SETUID */
  327.  
  328. #if    !defined(OVERWRITE)
  329.     if (stat(dst, &dst_stat) == 0) {
  330.         if (*dst_owner != dst_stat.st_uid) {
  331.             (void) sprintf(errbuf, message[NOT_OWNER], dst);
  332.             print_error("", errbuf);
  333.             return -1;
  334.         }
  335.  
  336. #if    defined(INSTALL_OTHER) && defined(SRC_OWNER) && defined(OWNER_UPDATE)
  337.         if (*dst_owner != getuid()) {
  338.             (void) sprintf(errbuf, message[NOT_OWNER], dst);
  339.             print_error("", errbuf);
  340.             return -1;
  341.         }
  342. #endif    /* INSTALL_OTHER and SRC_OWNER and OWNER_UPDATE */
  343.     }
  344. #endif    /* not OVERWRITE */
  345.  
  346.     return 0;
  347. }
  348.  
  349. /*
  350.  * binst - Installs a file in the public binary directory.
  351.  * Returns 0 if successfull, -1 otherwise.
  352.  */
  353. int    binst(src_path)
  354. char    *src_path;
  355. {
  356.     char    dst_path[MAXPATHLEN + 1];
  357.     int    dst_mode, dst_owner, dst_group;
  358.     int    sig_num;
  359.  
  360.         /* Build destination pathname */
  361.     build_path(src_path, pubbin, dst_path);
  362.  
  363.     if (check_files(src_path, dst_path, &dst_mode, &dst_owner,
  364.             &dst_group) == -1)
  365.         return -1;
  366.  
  367.     /*
  368.      * Set a long jump mark.
  369.      * If we return from a jump triggered by a signal remove the
  370.      * destination file (it is assumed to be an incomplete copy!),
  371.      * print an error message, restore all signal actions and
  372.      * execute the signal's previously stored action.
  373.      * If it returns from this action (in fact it does not return!),
  374.      * return with an error status.
  375.      */
  376.     if ((sig_num = setjmp(env)) != 0) {
  377.         (void) unlink(dst_path);
  378.  
  379.         (void) sprintf(errbuf, "%s removed", dst_path);
  380.         (void) print_error("", errbuf);
  381.  
  382.         set_sig_grp(sig_list, signal, sig_action, (int (**)()) 0);
  383.  
  384.         (*sig_action[sig_num])(sig_num);
  385.         
  386.         return -1;
  387.     }
  388.  
  389.     /*
  390.      * Catch all important signals which are not ignored.
  391.      * If one is catched a long jump to the previously set mark is
  392.      * performed.
  393.      */
  394.     set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
  395.  
  396.     /*
  397.      * Copy the files and set the permissions according to
  398.      * the source file.
  399.      */
  400.     if (copy(src_path, dst_path) == -1)
  401.         return -1;
  402.     (void) chall(dst_path, dst_mode, dst_owner, dst_group);
  403.  
  404.     /*
  405.      * Restore all previously catched signals.
  406.      */
  407.     set_sig_grp(sig_list, set_act_sig, sig_action, (int (**)()) 0);
  408.     
  409.     return 0;
  410. }
  411.  
  412. main(argc, argv)
  413. int    argc;
  414. char    **argv;
  415. {
  416.     int    status;
  417.  
  418.     prg_nam = argv[0];
  419.  
  420.     if (argc == 1) {
  421.         (void) fprintf(stderr, message[USAGE], argv[0]);
  422.         exit (1);
  423.     }
  424.  
  425.     while (--argc)
  426.         status = binst(*++argv);
  427.  
  428.     exit(-status);
  429.         /* For your 'lint' only... */
  430.     return -1;
  431. }
  432.