1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/config/nsinstall.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,525 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** Netscape portable install command. 1.11 +** 1.12 +** Brendan Eich, 7/20/95 1.13 +*/ 1.14 +#include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */ 1.15 +#include <assert.h> 1.16 +#include <fcntl.h> 1.17 +#include <grp.h> 1.18 +#include <pwd.h> 1.19 +#include <stdlib.h> 1.20 +#include <string.h> 1.21 +#include <unistd.h> 1.22 +#include <utime.h> 1.23 +#include <sys/types.h> 1.24 +#include <sys/stat.h> 1.25 +#include <dirent.h> 1.26 +#include <errno.h> 1.27 +#include <stdarg.h> 1.28 +#ifdef USE_REENTRANT_LIBC 1.29 +#include "libc_r.h" 1.30 +#endif /* USE_REENTRANT_LIBC */ 1.31 + 1.32 +#include "pathsub.h" 1.33 + 1.34 +#define HAVE_FCHMOD 1.35 + 1.36 +#if defined(BEOS) 1.37 +#undef HAVE_FCHMOD 1.38 +#endif 1.39 + 1.40 +/* 1.41 + * Does getcwd() take NULL as the first argument and malloc 1.42 + * the result buffer? 1.43 + */ 1.44 +#if !defined(DARWIN) 1.45 +#define GETCWD_CAN_MALLOC 1.46 +#endif 1.47 + 1.48 +#if defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) 1.49 +#include <getopt.h> 1.50 +#endif 1.51 + 1.52 +#if defined(SCO) || defined(UNIXWARE) 1.53 +#if !defined(S_ISLNK) && defined(S_IFLNK) 1.54 +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) 1.55 +#endif 1.56 +#endif 1.57 + 1.58 +#ifdef QNX 1.59 +#define d_ino d_stat.st_ino 1.60 +#endif 1.61 + 1.62 +static void 1.63 +usage(void) 1.64 +{ 1.65 + fprintf(stderr, 1.66 + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" 1.67 + " %*s [-DdltR] file [file ...] directory\n", 1.68 + program, (int)strlen(program), ""); 1.69 + exit(2); 1.70 +} 1.71 + 1.72 +static int 1.73 +mkdirs(char *path, mode_t mode) 1.74 +{ 1.75 + char *cp; 1.76 + struct stat sb; 1.77 + int res; 1.78 + 1.79 + while (*path == '/' && path[1] == '/') 1.80 + path++; 1.81 + for (cp = strrchr(path, '/'); cp && cp != path && cp[-1] == '/'; cp--) 1.82 + ; 1.83 + if (cp && cp != path) { 1.84 + *cp = '\0'; 1.85 + if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && 1.86 + mkdirs(path, mode) < 0) { 1.87 + return -1; 1.88 + } 1.89 + *cp = '/'; 1.90 + } 1.91 + res = mkdir(path, mode); 1.92 + if ((res != 0) && (errno == EEXIST)) 1.93 + return 0; 1.94 + else 1.95 + return res; 1.96 +} 1.97 + 1.98 +static uid_t 1.99 +touid(char *owner) 1.100 +{ 1.101 + struct passwd *pw; 1.102 + uid_t uid; 1.103 + char *cp; 1.104 + 1.105 + pw = getpwnam(owner); 1.106 + if (pw) 1.107 + return pw->pw_uid; 1.108 + uid = strtol(owner, &cp, 0); 1.109 + if (uid == 0 && cp == owner) 1.110 + fail("cannot find uid for %s", owner); 1.111 + return uid; 1.112 +} 1.113 + 1.114 +static gid_t 1.115 +togid(char *group) 1.116 +{ 1.117 + struct group *gr; 1.118 + gid_t gid; 1.119 + char *cp; 1.120 + 1.121 + gr = getgrnam(group); 1.122 + if (gr) 1.123 + return gr->gr_gid; 1.124 + gid = strtol(group, &cp, 0); 1.125 + if (gid == 0 && cp == group) 1.126 + fail("cannot find gid for %s", group); 1.127 + return gid; 1.128 +} 1.129 + 1.130 +int 1.131 +main(int argc, char **argv) 1.132 +{ 1.133 + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; 1.134 + mode_t mode = 0755; 1.135 + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; 1.136 + uid_t uid; 1.137 + gid_t gid; 1.138 + struct stat sb, tosb; 1.139 + struct utimbuf utb; 1.140 + 1.141 + program = argv[0]; 1.142 + cwd = linkname = linkprefix = owner = group = 0; 1.143 + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; 1.144 + 1.145 + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { 1.146 + switch (opt) { 1.147 + case 'C': 1.148 + cwd = optarg; 1.149 + break; 1.150 + case 'D': 1.151 + onlydir = 1; 1.152 + break; 1.153 + case 'd': 1.154 + dodir = 1; 1.155 + break; 1.156 + case 'l': 1.157 + dolink = 1; 1.158 + break; 1.159 + case 'L': 1.160 + linkprefix = optarg; 1.161 + lplen = strlen(linkprefix); 1.162 + dolink = 1; 1.163 + break; 1.164 + case 'R': 1.165 + dolink = dorelsymlink = 1; 1.166 + break; 1.167 + case 'm': 1.168 + mode = strtoul(optarg, &cp, 8); 1.169 + if (mode == 0 && cp == optarg) 1.170 + usage(); 1.171 + break; 1.172 + case 'o': 1.173 + owner = optarg; 1.174 + break; 1.175 + case 'g': 1.176 + group = optarg; 1.177 + break; 1.178 + case 't': 1.179 + dotimes = 1; 1.180 + break; 1.181 + default: 1.182 + usage(); 1.183 + } 1.184 + } 1.185 + 1.186 + argc -= optind; 1.187 + argv += optind; 1.188 + if (argc < 2 - onlydir) 1.189 + usage(); 1.190 + 1.191 + todir = argv[argc-1]; 1.192 + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && 1.193 + mkdirs(todir, 0777) < 0) { 1.194 + fail("cannot make directory %s", todir); 1.195 + } 1.196 + if (onlydir) 1.197 + return 0; 1.198 + 1.199 + if (!cwd) { 1.200 +#ifdef GETCWD_CAN_MALLOC 1.201 + cwd = getcwd(0, PATH_MAX); 1.202 +#else 1.203 + cwd = malloc(PATH_MAX + 1); 1.204 + cwd = getcwd(cwd, PATH_MAX); 1.205 +#endif 1.206 + } 1.207 + xchdir(todir); 1.208 +#ifdef GETCWD_CAN_MALLOC 1.209 + todir = getcwd(0, PATH_MAX); 1.210 +#else 1.211 + todir = malloc(PATH_MAX + 1); 1.212 + todir = getcwd(todir, PATH_MAX); 1.213 +#endif 1.214 + xchdir(cwd); 1.215 + tdlen = strlen(todir); 1.216 + 1.217 + uid = owner ? touid(owner) : -1; 1.218 + gid = group ? togid(group) : -1; 1.219 + 1.220 + while (--argc > 0) { 1.221 + name = *argv++; 1.222 + len = strlen(name); 1.223 + base = xbasename(name); 1.224 + bnlen = strlen(base); 1.225 + toname = (char*)xmalloc(tdlen + 1 + bnlen + 1); 1.226 + sprintf(toname, "%s/%s", todir, base); 1.227 + exists = (lstat(toname, &tosb) == 0); 1.228 + 1.229 + if (dodir) { 1.230 + /* -d means create a directory, always */ 1.231 + if (exists && !S_ISDIR(tosb.st_mode)) { 1.232 + (void) unlink(toname); 1.233 + exists = 0; 1.234 + } 1.235 + if (!exists && mkdir(toname, mode) < 0) 1.236 + fail("cannot make directory %s", toname); 1.237 + if ((owner || group) && chown(toname, uid, gid) < 0) 1.238 + fail("cannot change owner of %s", toname); 1.239 + } else if (dolink) { 1.240 + if (*name == '/') { 1.241 + /* source is absolute pathname, link to it directly */ 1.242 + linkname = 0; 1.243 + } else { 1.244 + if (linkprefix) { 1.245 + /* -L implies -l and prefixes names with a $cwd arg. */ 1.246 + len += lplen + 1; 1.247 + linkname = (char*)xmalloc(len + 1); 1.248 + sprintf(linkname, "%s/%s", linkprefix, name); 1.249 + } else if (dorelsymlink) { 1.250 + /* Symlink the relative path from todir to source name. */ 1.251 + linkname = (char*)xmalloc(PATH_MAX); 1.252 + 1.253 + if (*todir == '/') { 1.254 + /* todir is absolute: skip over common prefix. */ 1.255 + lplen = relatepaths(todir, cwd, linkname); 1.256 + strcpy(linkname + lplen, name); 1.257 + } else { 1.258 + /* todir is named by a relative path: reverse it. */ 1.259 + reversepath(todir, name, len, linkname); 1.260 + xchdir(cwd); 1.261 + } 1.262 + 1.263 + len = strlen(linkname); 1.264 + } 1.265 + name = linkname; 1.266 + } 1.267 + 1.268 + /* Check for a pre-existing symlink with identical content. */ 1.269 + if (exists && 1.270 + (!S_ISLNK(tosb.st_mode) || 1.271 + readlink(toname, buf, sizeof buf) != len || 1.272 + strncmp(buf, name, len) != 0)) { 1.273 + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); 1.274 + exists = 0; 1.275 + } 1.276 + if (!exists && symlink(name, toname) < 0) 1.277 + fail("cannot make symbolic link %s", toname); 1.278 +#ifdef HAVE_LCHOWN 1.279 + if ((owner || group) && lchown(toname, uid, gid) < 0) 1.280 + fail("cannot change owner of %s", toname); 1.281 +#endif 1.282 + 1.283 + if (linkname) { 1.284 + free(linkname); 1.285 + linkname = 0; 1.286 + } 1.287 + } else { 1.288 + /* Copy from name to toname, which might be the same file. */ 1.289 + fromfd = open(name, O_RDONLY); 1.290 + if (fromfd < 0 || fstat(fromfd, &sb) < 0) 1.291 + fail("cannot access %s", name); 1.292 + if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) 1.293 + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); 1.294 + tofd = open(toname, O_CREAT | O_WRONLY, 0666); 1.295 + if (tofd < 0) 1.296 + fail("cannot create %s", toname); 1.297 + 1.298 + bp = buf; 1.299 + while ((cc = read(fromfd, bp, sizeof buf)) > 0) { 1.300 + while ((wc = write(tofd, bp, cc)) > 0) { 1.301 + if ((cc -= wc) == 0) 1.302 + break; 1.303 + bp += wc; 1.304 + } 1.305 + if (wc < 0) 1.306 + fail("cannot write to %s", toname); 1.307 + } 1.308 + if (cc < 0) 1.309 + fail("cannot read from %s", name); 1.310 + 1.311 + if (ftruncate(tofd, sb.st_size) < 0) 1.312 + fail("cannot truncate %s", toname); 1.313 + if (dotimes) { 1.314 + utb.actime = sb.st_atime; 1.315 + utb.modtime = sb.st_mtime; 1.316 + if (utime(toname, &utb) < 0) 1.317 + fail("cannot set times of %s", toname); 1.318 + } 1.319 +#ifdef HAVE_FCHMOD 1.320 + if (fchmod(tofd, mode) < 0) 1.321 +#else 1.322 + if (chmod(toname, mode) < 0) 1.323 +#endif 1.324 + fail("cannot change mode of %s", toname); 1.325 + if ((owner || group) && fchown(tofd, uid, gid) < 0) 1.326 + fail("cannot change owner of %s", toname); 1.327 + 1.328 + /* Must check for delayed (NFS) write errors on close. */ 1.329 + if (close(tofd) < 0) 1.330 + fail("cannot write to %s", toname); 1.331 + close(fromfd); 1.332 + } 1.333 + 1.334 + free(toname); 1.335 + } 1.336 + 1.337 + free(cwd); 1.338 + free(todir); 1.339 + return 0; 1.340 +} 1.341 + 1.342 +/* 1.343 +** Pathname subroutines. 1.344 +** 1.345 +** Brendan Eich, 8/29/95 1.346 +*/ 1.347 + 1.348 +char *program; 1.349 + 1.350 +void 1.351 +fail(char *format, ...) 1.352 +{ 1.353 + int error; 1.354 + va_list ap; 1.355 + 1.356 +#ifdef USE_REENTRANT_LIBC 1.357 + R_STRERROR_INIT_R(); 1.358 +#endif 1.359 + 1.360 + error = errno; 1.361 + fprintf(stderr, "%s: ", program); 1.362 + va_start(ap, format); 1.363 + vfprintf(stderr, format, ap); 1.364 + va_end(ap); 1.365 + if (error) 1.366 + 1.367 +#ifdef USE_REENTRANT_LIBC 1.368 + R_STRERROR_R(errno); 1.369 + fprintf(stderr, ": %s", r_strerror_r); 1.370 +#else 1.371 + fprintf(stderr, ": %s", strerror(errno)); 1.372 +#endif 1.373 + 1.374 + putc('\n', stderr); 1.375 + exit(1); 1.376 +} 1.377 + 1.378 +char * 1.379 +getcomponent(char *path, char *name) 1.380 +{ 1.381 + if (*path == '\0') 1.382 + return 0; 1.383 + if (*path == '/') { 1.384 + *name++ = '/'; 1.385 + } else { 1.386 + do { 1.387 + *name++ = *path++; 1.388 + } while (*path != '/' && *path != '\0'); 1.389 + } 1.390 + *name = '\0'; 1.391 + while (*path == '/') 1.392 + path++; 1.393 + return path; 1.394 +} 1.395 + 1.396 +#ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL 1.397 +/* Sigh. The static buffer in Unixware's readdir is too small. */ 1.398 +struct dirent * readdir(DIR *d) 1.399 +{ 1.400 + static struct dirent *buf = NULL; 1.401 +#define MAX_PATH_LEN 1024 1.402 + 1.403 + 1.404 + if(buf == NULL) 1.405 + buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN) 1.406 +; 1.407 + return(readdir_r(d, buf)); 1.408 +} 1.409 +#endif 1.410 + 1.411 +char * 1.412 +ino2name(ino_t ino, char *dir) 1.413 +{ 1.414 + DIR *dp; 1.415 + struct dirent *ep; 1.416 + char *name; 1.417 + 1.418 + dp = opendir(".."); 1.419 + if (!dp) 1.420 + fail("cannot read parent directory"); 1.421 + for (;;) { 1.422 + if (!(ep = readdir(dp))) 1.423 + fail("cannot find current directory"); 1.424 + if (ep->d_ino == ino) 1.425 + break; 1.426 + } 1.427 + name = xstrdup(ep->d_name); 1.428 + closedir(dp); 1.429 + return name; 1.430 +} 1.431 + 1.432 +void * 1.433 +xmalloc(size_t size) 1.434 +{ 1.435 + void *p = malloc(size); 1.436 + if (!p) 1.437 + fail("cannot allocate %u bytes", size); 1.438 + return p; 1.439 +} 1.440 + 1.441 +char * 1.442 +xstrdup(char *s) 1.443 +{ 1.444 + return strcpy((char*)xmalloc(strlen(s) + 1), s); 1.445 +} 1.446 + 1.447 +char * 1.448 +xbasename(char *path) 1.449 +{ 1.450 + char *cp; 1.451 + 1.452 + while ((cp = strrchr(path, '/')) && cp[1] == '\0') 1.453 + *cp = '\0'; 1.454 + if (!cp) return path; 1.455 + return cp + 1; 1.456 +} 1.457 + 1.458 +void 1.459 +xchdir(char *dir) 1.460 +{ 1.461 + if (chdir(dir) < 0) 1.462 + fail("cannot change directory to %s", dir); 1.463 +} 1.464 + 1.465 +int 1.466 +relatepaths(char *from, char *to, char *outpath) 1.467 +{ 1.468 + char *cp, *cp2; 1.469 + int len; 1.470 + char buf[NAME_MAX]; 1.471 + 1.472 + assert(*from == '/' && *to == '/'); 1.473 + for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) 1.474 + if (*cp == '\0') 1.475 + break; 1.476 + while (cp[-1] != '/') 1.477 + cp--, cp2--; 1.478 + if (cp - 1 == to) { 1.479 + /* closest common ancestor is /, so use full pathname */ 1.480 + len = strlen(strcpy(outpath, to)); 1.481 + if (outpath[len] != '/') { 1.482 + outpath[len++] = '/'; 1.483 + outpath[len] = '\0'; 1.484 + } 1.485 + } else { 1.486 + len = 0; 1.487 + while ((cp2 = getcomponent(cp2, buf)) != 0) { 1.488 + strcpy(outpath + len, "../"); 1.489 + len += 3; 1.490 + } 1.491 + while ((cp = getcomponent(cp, buf)) != 0) { 1.492 + sprintf(outpath + len, "%s/", buf); 1.493 + len += strlen(outpath + len); 1.494 + } 1.495 + } 1.496 + return len; 1.497 +} 1.498 + 1.499 +void 1.500 +reversepath(char *inpath, char *name, int len, char *outpath) 1.501 +{ 1.502 + char *cp, *cp2; 1.503 + char buf[NAME_MAX]; 1.504 + struct stat sb; 1.505 + 1.506 + cp = strcpy(outpath + PATH_MAX - (len + 1), name); 1.507 + cp2 = inpath; 1.508 + while ((cp2 = getcomponent(cp2, buf)) != 0) { 1.509 + if (strcmp(buf, ".") == 0) 1.510 + continue; 1.511 + if (strcmp(buf, "..") == 0) { 1.512 + if (stat(".", &sb) < 0) 1.513 + fail("cannot stat current directory"); 1.514 + name = ino2name(sb.st_ino, ".."); 1.515 + len = strlen(name); 1.516 + cp -= len + 1; 1.517 + strcpy(cp, name); 1.518 + cp[len] = '/'; 1.519 + free(name); 1.520 + xchdir(".."); 1.521 + } else { 1.522 + cp -= 3; 1.523 + strncpy(cp, "../", 3); 1.524 + xchdir(buf); 1.525 + } 1.526 + } 1.527 + strcpy(outpath, cp); 1.528 +}