xinstall.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       xinstall.c (3531B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <grp.h>
            3 #include <pwd.h>
            4 #include <errno.h>
            5 #include <fcntl.h>
            6 #include <unistd.h>
            7 #include <stdlib.h>
            8 #include <string.h>
            9 #include <dirent.h>
           10 #include <sys/stat.h>
           11 #include <sys/wait.h>
           12 
           13 #include "util.h"
           14 
           15 static int Dflag = 0;
           16 static gid_t group;
           17 static uid_t owner;
           18 static mode_t mode = 0755;
           19 
           20 static void
           21 make_dir(char *dir, int was_missing)
           22 {
           23         if (!mkdir(dir, was_missing ? 0755 : mode)) {
           24                 if (!was_missing && (lchown(dir, owner, group) < 0))
           25                         eprintf("lchmod %s:", dir);
           26         } else if (errno != EEXIST) {
           27                 eprintf("mkdir %s:", dir);
           28         }
           29 }
           30 
           31 static void
           32 make_dirs(char *dir, int was_missing)
           33 {
           34         char *p;
           35         for (p = strchr(dir + (dir[0] == '/'), '/'); p; p = strchr(p + 1, '/')) {
           36                 *p = '\0';
           37                 make_dir(dir, was_missing);
           38                 *p = '/';
           39         }
           40         make_dir(dir, was_missing);
           41 }
           42 
           43 static int
           44 install(const char *s1, const char *s2, int depth)
           45 {
           46         int f1, f2;
           47 
           48         if ((f1 = open(s1, O_RDONLY)) < 0)
           49                 eprintf("open %s:", s1);
           50         if ((f2 = creat(s2, 0600)) < 0) {
           51                 if (unlink(s2) < 0 && errno != ENOENT)
           52                         eprintf("unlink %s:", s2);
           53                 if ((f2 = creat(s2, 0600)) < 0)
           54                         eprintf("creat %s:", s2);
           55         }
           56         if (concat(f1, s1, f2, s2) < 0)
           57                 goto fail;
           58         if (fchmod(f2, mode) < 0) {
           59                 weprintf("fchmod %s:", s2);
           60                 goto fail;
           61         }
           62         if (fchown(f2, owner, group) < 0) {
           63                 weprintf("fchown %s:", s2);
           64                 goto fail;
           65         }
           66 
           67         close(f1);
           68         close(f2);
           69 
           70         return 0;
           71 
           72 fail:
           73         unlink(s2);
           74         exit(1);
           75 }
           76 
           77 static void
           78 usage(void)
           79 {
           80         eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... | [-D] (-t dest source ... | source ... dest))\n", argv0);
           81 }
           82 
           83 int
           84 main(int argc, char *argv[])
           85 {
           86         int dflag = 0;
           87         char *gflag = 0;
           88         char *oflag = 0;
           89         char *mflag = 0;
           90         char *tflag = 0;
           91         struct group *gr;
           92         struct passwd *pw;
           93         struct stat st;
           94         char *p;
           95 
           96         ARGBEGIN {
           97         case 'c':
           98                 /* no-op for compatibility */
           99                 break;
          100         case 'd':
          101                 dflag = 1;
          102                 break;
          103         case 'D':
          104                 Dflag = 1;
          105                 break;
          106         case 's':
          107                 /* no-op for compatibility */
          108                 break;
          109         case 'g':
          110                 gflag = EARGF(usage());
          111                 break;
          112         case 'o':
          113                 oflag = EARGF(usage());
          114                 break;
          115         case 'm':
          116                 mflag = EARGF(usage());
          117                 break;
          118         case 't':
          119                 tflag = EARGF(usage());
          120                 break;
          121         default:
          122                 usage();
          123         } ARGEND
          124 
          125         if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | !!tflag))
          126                 usage();
          127 
          128         if (gflag) {
          129                 errno = 0;
          130                 gr = getgrnam(gflag);
          131                 if (gr) {
          132                         group = gr->gr_gid;
          133                 } else {
          134                         if (errno)
          135                                 eprintf("getgrnam %s:", gflag);
          136                         group = estrtonum(gflag, 0, UINT_MAX);
          137                 }
          138         } else {
          139                 group = getgid();
          140         }
          141 
          142         if (oflag) {
          143                 errno = 0;
          144                 pw = getpwnam(oflag);
          145                 if (pw) {
          146                         owner = pw->pw_uid;
          147                 } else {
          148                         if (errno)
          149                                 eprintf("getpwnam %s:", oflag);
          150                         owner = estrtonum(oflag, 0, UINT_MAX);
          151                 }
          152         } else {
          153                 owner = getuid();
          154         }
          155 
          156         if (mflag)
          157                 mode = parsemode(mflag, mode, 0);
          158 
          159         if (dflag) {
          160                 for (; *argv; argc--, argv++)
          161                         make_dirs(*argv, 0);
          162                 return 0;
          163         }
          164 
          165         if (tflag) {
          166                 argv = memmove(argv - 1, argv, argc * sizeof(*argv));
          167                 argv[argc++] = tflag;
          168         }
          169         if (tflag || argc > 2) {
          170                 if (stat(argv[argc - 1], &st) < 0) {
          171                         if ((errno == ENOENT) && Dflag) {
          172                                 make_dirs(argv[argc - 1], 1);
          173                         } else {
          174                                 eprintf("stat %s:", argv[argc - 1]);
          175                         }
          176                 } else if (!S_ISDIR(st.st_mode)) {
          177                         eprintf("%s: not a directory\n", argv[argc - 1]);
          178                 }
          179         }
          180         if (stat(argv[argc - 1], &st) < 0) {
          181                 if (errno != ENOENT)
          182                         eprintf("stat %s:", argv[argc - 1]);
          183                 if (tflag || Dflag || argc > 2) {
          184                         if ((p = strrchr(argv[argc - 1], '/')) != NULL) {
          185                                 *p = '\0';
          186                                 make_dirs(argv[argc - 1], 1);
          187                                 *p = '/';
          188                         }
          189                 }
          190         }
          191         enmasse(argc, argv, install);
          192 
          193         return 0;
          194 }