sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | 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 }