sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

xinstall.c (4859B)


      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 	DIR *dp;
     47 	int f1, f2;
     48 	struct dirent *d;
     49 	struct stat st;
     50 	ssize_t r;
     51 	char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
     52 
     53 	if (stat(s1, &st) < 0)
     54 		eprintf("stat %s:", s1);
     55 
     56 	if (S_ISLNK(st.st_mode)) {
     57 		if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
     58 			target[r] = '\0';
     59 			if (unlink(s2) < 0 && errno != ENOENT)
     60 				eprintf("unlink %s:", s2);
     61 			else if (symlink(target, s2) < 0)
     62 				eprintf("symlink %s -> %s:", s2, target);
     63 		}
     64 	} else if (S_ISDIR(st.st_mode)) {
     65 		if (!(dp = opendir(s1)))
     66 			eprintf("opendir %s:", s1);
     67 		if (mkdir(s2, mode | 0111) < 0 && errno != EEXIST)
     68 			eprintf("mkdir %s:", s2);
     69 
     70 		while ((d = readdir(dp))) {
     71 			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
     72 				continue;
     73 
     74 			estrlcpy(ns1, s1, sizeof(ns1));
     75 			if (s1[strlen(s1) - 1] != '/')
     76 				estrlcat(ns1, "/", sizeof(ns1));
     77 			estrlcat(ns1, d->d_name, sizeof(ns1));
     78 
     79 			estrlcpy(ns2, s2, sizeof(ns2));
     80 			if (s2[strlen(s2) - 1] != '/')
     81 				estrlcat(ns2, "/", sizeof(ns2));
     82 			estrlcat(ns2, d->d_name, sizeof(ns2));
     83 
     84 			fnck(ns1, ns2, install, depth + 1);
     85 		}
     86 
     87 		closedir(dp);
     88 	} else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
     89 	           S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode)) {
     90 		if (unlink(s2) < 0 && errno != ENOENT)
     91 			eprintf("unlink %s:", s2);
     92 		else if (mknod(s2, (st.st_mode & ~07777) | mode, st.st_rdev) < 0)
     93 			eprintf("mknod %s:", s2);
     94 	} else {
     95 		if ((f1 = open(s1, O_RDONLY)) < 0)
     96 			eprintf("open %s:", s1);
     97 		if ((f2 = creat(s2, 0600)) < 0) {
     98 			if (unlink(s2) < 0 && errno != ENOENT)
     99 				eprintf("unlink %s:", s2);
    100 			if ((f2 = creat(s2, 0600)) < 0)
    101 				eprintf("creat %s:", s2);
    102 		}
    103 		if (concat(f1, s1, f2, s2) < 0)
    104 			exit(1);
    105 
    106 		if (fchmod(f2, mode) < 0)
    107 			eprintf("fchmod %s:", s2);
    108 
    109 		close(f1);
    110 		close(f2);
    111 	}
    112 
    113 	if (lchown(s2, owner, group) < 0)
    114 		eprintf("lchown %s:", s2);
    115 
    116 	return 0;
    117 }
    118 
    119 static void
    120 usage(void)
    121 {
    122 	eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... | [-D] (-t dest source ... | source ... dest))\n", argv0);
    123 }
    124 
    125 int
    126 main(int argc, char *argv[])
    127 {
    128 	int dflag = 0;
    129 	char *gflag = 0;
    130 	char *oflag = 0;
    131 	char *mflag = 0;
    132 	char *tflag = 0;
    133 	struct group *gr;
    134 	struct passwd *pw;
    135 	struct stat st;
    136 	char *p;
    137 
    138 	ARGBEGIN {
    139 	case 'c':
    140 		/* no-op for compatibility */
    141 		break;
    142 	case 'd':
    143 		dflag = 1;
    144 		break;
    145 	case 'D':
    146 		Dflag = 1;
    147 		break;
    148 	case 's':
    149 		/* no-op for compatibility */
    150 		break;
    151 	case 'g':
    152 		gflag = EARGF(usage());
    153 		break;
    154 	case 'o':
    155 		oflag = EARGF(usage());
    156 		break;
    157 	case 'm':
    158 		mflag = EARGF(usage());
    159 		break;
    160 	case 't':
    161 		tflag = EARGF(usage());
    162 		break;
    163 	default:
    164 		usage();
    165 	} ARGEND
    166 
    167 	if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | !!tflag))
    168 		usage();
    169 
    170 	if (gflag) {
    171 		errno = 0;
    172 		gr = getgrnam(gflag);
    173 		if (gr) {
    174 			group = gr->gr_gid;
    175 		} else {
    176 			if (errno)
    177 				eprintf("getgrnam %s:", gflag);
    178 			group = estrtonum(gflag, 0, UINT_MAX);
    179 		}
    180 	} else {
    181 		group = getgid();
    182 	}
    183 
    184 	if (oflag) {
    185 		errno = 0;
    186 		pw = getpwnam(oflag);
    187 		if (pw) {
    188 			owner = pw->pw_uid;
    189 		} else {
    190 			if (errno)
    191 				eprintf("getpwnam %s:", oflag);
    192 			owner = estrtonum(oflag, 0, UINT_MAX);
    193 		}
    194 	} else {
    195 		owner = getuid();
    196 	}
    197 
    198 	if (mflag)
    199 		mode = parsemode(mflag, mode, 0);
    200 
    201 	if (tflag) {
    202 		argv = memmove(argv - 1, argv, argc * sizeof(*argv));
    203 		argv[argc++] = tflag;
    204 	}
    205 	if (tflag || argc > 2) {
    206 		if (stat(argv[argc - 1], &st) < 0) {
    207 			if ((errno == ENOENT) && Dflag) {
    208 				make_dirs(argv[argc - 1], 1);
    209 			} else {
    210 				eprintf("stat %s:", argv[argc - 1]);
    211 			}
    212 		} else if (!S_ISDIR(st.st_mode)) {
    213 			eprintf("%s: not a directory\n", argv[argc - 1]);
    214 		}
    215 	}
    216 
    217 	if (dflag) {
    218 		for (; *argv; argc--, argv++)
    219 			make_dirs(*argv, 0);
    220 	} else {
    221 		if (stat(argv[argc - 1], &st) < 0) {
    222 			if (errno != ENOENT)
    223 				eprintf("stat %s:", argv[argc - 1]);
    224 			if (tflag || Dflag || argc > 2) {
    225 				if ((p = strrchr(argv[argc - 1], '/')) != NULL) {
    226 					*p = '\0';
    227 					make_dirs(argv[argc - 1], 1);
    228 					*p = '/';
    229 				}
    230 			}
    231 		}
    232 		enmasse(argc, argv, install);
    233 	}
    234 
    235 	return 0;
    236 }