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 }