1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/config/nsinstall.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,452 @@ 1.4 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 +** Netscape portable install command. 1.10 +** 1.11 +** Brendan Eich, 7/20/95 1.12 +*/ 1.13 +#include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */ 1.14 +#include <assert.h> 1.15 +#include <fcntl.h> 1.16 +#include <errno.h> 1.17 +#include <dirent.h> 1.18 +#include <limits.h> 1.19 +#include <grp.h> 1.20 +#include <pwd.h> 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <string.h> 1.24 +#include <unistd.h> 1.25 +#include <utime.h> 1.26 +#include <sys/types.h> 1.27 +#include <sys/stat.h> 1.28 +#include "pathsub.h" 1.29 + 1.30 +#ifdef HAVE_GETOPT_H 1.31 +#include <getopt.h> 1.32 +#endif 1.33 + 1.34 +#ifdef SUNOS4 1.35 +#include "sunos4.h" 1.36 +#endif 1.37 + 1.38 +#ifdef NEXTSTEP 1.39 +#include <bsd/libc.h> 1.40 +#endif 1.41 + 1.42 +#ifdef __QNX__ 1.43 +#include <unix.h> 1.44 +#endif 1.45 + 1.46 +#ifdef NEED_S_ISLNK 1.47 +#if !defined(S_ISLNK) && defined(S_IFLNK) 1.48 +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) 1.49 +#endif 1.50 +#endif 1.51 + 1.52 +#ifndef _DIRECTORY_SEPARATOR 1.53 +#define _DIRECTORY_SEPARATOR "/" 1.54 +#endif /* _DIRECTORY_SEPARATOR */ 1.55 + 1.56 +#ifdef NEED_FCHMOD_PROTO 1.57 +extern int fchmod(int fildes, mode_t mode); 1.58 +#endif 1.59 + 1.60 +static void 1.61 +usage(void) 1.62 +{ 1.63 + fprintf(stderr, 1.64 + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" 1.65 + " %*s [-DdltR] file [file ...] directory\n", 1.66 + program, (int) strlen(program), ""); 1.67 + exit(2); 1.68 +} 1.69 + 1.70 +static int 1.71 +mkdirs(char *path, mode_t mode) 1.72 +{ 1.73 + char *cp; 1.74 + struct stat sb; 1.75 + int res; 1.76 + int l; 1.77 + 1.78 + /* strip trailing "/." */ 1.79 + l = strlen(path); 1.80 + if(l > 1 && path[l - 1] == '.' && path[l - 2] == '/') 1.81 + path[l - 2] = 0; 1.82 + 1.83 + while (*path == '/' && path[1] == '/') 1.84 + path++; 1.85 + for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--); 1.86 + if (cp && cp != path) { 1.87 + *cp = '\0'; 1.88 + if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && 1.89 + mkdirs(path, mode) < 0) { 1.90 + return -1; 1.91 + } 1.92 + *cp = '/'; 1.93 + } 1.94 + 1.95 + res = mkdir(path, mode); 1.96 + if ((res != 0) && (errno == EEXIST)) 1.97 + return 0; 1.98 + else 1.99 + return res; 1.100 +} 1.101 + 1.102 +static uid_t 1.103 +touid(char *owner) 1.104 +{ 1.105 + struct passwd *pw; 1.106 + uid_t uid; 1.107 + char *cp; 1.108 + 1.109 + pw = getpwnam(owner); 1.110 + if (pw) 1.111 + return pw->pw_uid; 1.112 + uid = strtol(owner, &cp, 0); 1.113 + if (uid == 0 && cp == owner) 1.114 + fail("cannot find uid for %s", owner); 1.115 + return uid; 1.116 +} 1.117 + 1.118 +static gid_t 1.119 +togid(char *group) 1.120 +{ 1.121 + struct group *gr; 1.122 + gid_t gid; 1.123 + char *cp; 1.124 + 1.125 + gr = getgrnam(group); 1.126 + if (gr) 1.127 + return gr->gr_gid; 1.128 + gid = strtol(group, &cp, 0); 1.129 + if (gid == 0 && cp == group) 1.130 + fail("cannot find gid for %s", group); 1.131 + return gid; 1.132 +} 1.133 + 1.134 +static void 1.135 +copyfile( char *name, char *toname, mode_t mode, char *group, char *owner, 1.136 + int dotimes, uid_t uid, gid_t gid ) 1.137 +{ 1.138 + int fromfd, tofd = -1, cc, wc, exists; 1.139 + char buf[BUFSIZ], *bp; 1.140 + struct stat sb, tosb; 1.141 + struct utimbuf utb; 1.142 + 1.143 + exists = (lstat(toname, &tosb) == 0); 1.144 + 1.145 + fromfd = open(name, O_RDONLY); 1.146 + if (fromfd < 0 || fstat(fromfd, &sb) < 0) 1.147 + fail("cannot access %s", name); 1.148 + if (exists) { 1.149 + if (S_ISREG(tosb.st_mode)) { 1.150 + /* See if we can open it. This is more reliable than 'access'. */ 1.151 + tofd = open(toname, O_CREAT | O_WRONLY, 0666); 1.152 + } 1.153 + if (tofd < 0) { 1.154 + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); 1.155 + } 1.156 + } 1.157 + if (tofd < 0) { 1.158 + tofd = open(toname, O_CREAT | O_WRONLY, 0666); 1.159 + if (tofd < 0) 1.160 + fail("cannot create %s", toname); 1.161 + } 1.162 + 1.163 + bp = buf; 1.164 + while ((cc = read(fromfd, bp, sizeof buf)) > 0) 1.165 + { 1.166 + while ((wc = write(tofd, bp, (unsigned int)cc)) > 0) 1.167 + { 1.168 + if ((cc -= wc) == 0) 1.169 + break; 1.170 + bp += wc; 1.171 + } 1.172 + if (wc < 0) 1.173 + fail("cannot write to %s", toname); 1.174 + } 1.175 + if (cc < 0) 1.176 + fail("cannot read from %s", name); 1.177 + 1.178 + if (ftruncate(tofd, sb.st_size) < 0) 1.179 + fail("cannot truncate %s", toname); 1.180 +#if !defined(VMS) 1.181 + if (dotimes) 1.182 + { 1.183 + utb.actime = sb.st_atime; 1.184 + utb.modtime = sb.st_mtime; 1.185 + if (utime(toname, &utb) < 0) 1.186 + fail("cannot set times of %s", toname); 1.187 + } 1.188 +#ifdef HAVE_FCHMOD 1.189 + if (fchmod(tofd, mode) < 0) 1.190 +#else 1.191 + if (chmod(toname, mode) < 0) 1.192 +#endif 1.193 + fail("cannot change mode of %s", toname); 1.194 +#endif 1.195 + if ((owner || group) && fchown(tofd, uid, gid) < 0) 1.196 + fail("cannot change owner of %s", toname); 1.197 + 1.198 + /* Must check for delayed (NFS) write errors on close. */ 1.199 + if (close(tofd) < 0) 1.200 + fail("cannot write to %s", toname); 1.201 + close(fromfd); 1.202 +#if defined(VMS) 1.203 + if (chmod(toname, (mode & (S_IREAD | S_IWRITE))) < 0) 1.204 + fail("cannot change mode of %s", toname); 1.205 + if (dotimes) 1.206 + { 1.207 + utb.actime = sb.st_atime; 1.208 + utb.modtime = sb.st_mtime; 1.209 + if (utime(toname, &utb) < 0) 1.210 + fail("cannot set times of %s", toname); 1.211 + } 1.212 +#endif 1.213 +} 1.214 + 1.215 +static void 1.216 +copydir( char *from, char *to, mode_t mode, char *group, char *owner, 1.217 + int dotimes, uid_t uid, gid_t gid) 1.218 +{ 1.219 + int i; 1.220 + DIR *dir; 1.221 + struct dirent *ep; 1.222 + struct stat sb; 1.223 + char *base, *destdir, *direntry, *destentry; 1.224 + 1.225 + base = xbasename(from); 1.226 + 1.227 + /* create destination directory */ 1.228 + destdir = xmalloc((unsigned int)(strlen(to) + 1 + strlen(base) + 1)); 1.229 + sprintf(destdir, "%s%s%s", to, _DIRECTORY_SEPARATOR, base); 1.230 + if (mkdirs(destdir, mode) != 0) { 1.231 + fail("cannot make directory %s\n", destdir); 1.232 + free(destdir); 1.233 + return; 1.234 + } 1.235 + 1.236 + if (!(dir = opendir(from))) { 1.237 + fail("cannot open directory %s\n", from); 1.238 + free(destdir); 1.239 + return; 1.240 + } 1.241 + 1.242 + direntry = xmalloc((unsigned int)PATH_MAX); 1.243 + destentry = xmalloc((unsigned int)PATH_MAX); 1.244 + 1.245 + while ((ep = readdir(dir))) 1.246 + { 1.247 + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) 1.248 + continue; 1.249 + 1.250 + sprintf(direntry, "%s/%s", from, ep->d_name); 1.251 + sprintf(destentry, "%s%s%s", destdir, _DIRECTORY_SEPARATOR, ep->d_name); 1.252 + 1.253 + if (stat(direntry, &sb) == 0 && S_ISDIR(sb.st_mode)) 1.254 + copydir( direntry, destdir, mode, group, owner, dotimes, uid, gid ); 1.255 + else 1.256 + copyfile( direntry, destentry, mode, group, owner, dotimes, uid, gid ); 1.257 + } 1.258 + 1.259 + free(destdir); 1.260 + free(direntry); 1.261 + free(destentry); 1.262 + closedir(dir); 1.263 +} 1.264 + 1.265 +int 1.266 +main(int argc, char **argv) 1.267 +{ 1.268 + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; 1.269 + mode_t mode = 0755; 1.270 + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; 1.271 + uid_t uid; 1.272 + gid_t gid; 1.273 + struct stat sb, tosb, fromsb; 1.274 + struct utimbuf utb; 1.275 + 1.276 + program = argv[0]; 1.277 + cwd = linkname = linkprefix = owner = group = 0; 1.278 + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; 1.279 + 1.280 + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { 1.281 + switch (opt) { 1.282 + case 'C': 1.283 + cwd = optarg; 1.284 + break; 1.285 + case 'D': 1.286 + onlydir = 1; 1.287 + break; 1.288 + case 'd': 1.289 + dodir = 1; 1.290 + break; 1.291 + case 'L': 1.292 + linkprefix = optarg; 1.293 + lplen = strlen(linkprefix); 1.294 + dolink = 1; 1.295 + break; 1.296 + case 'R': 1.297 + dolink = dorelsymlink = 1; 1.298 + break; 1.299 + case 'm': 1.300 + mode = strtoul(optarg, &cp, 8); 1.301 + if (mode == 0 && cp == optarg) 1.302 + usage(); 1.303 + break; 1.304 + case 'o': 1.305 + owner = optarg; 1.306 + break; 1.307 + case 'g': 1.308 + group = optarg; 1.309 + break; 1.310 + case 't': 1.311 + dotimes = 1; 1.312 + break; 1.313 + default: 1.314 + usage(); 1.315 + } 1.316 + } 1.317 + 1.318 + argc -= optind; 1.319 + argv += optind; 1.320 + if (argc < 2 - onlydir) 1.321 + usage(); 1.322 + 1.323 + todir = argv[argc-1]; 1.324 + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && 1.325 + mkdirs(todir, 0777) < 0) { 1.326 + fail("cannot make directory %s", todir); 1.327 + } 1.328 + if (onlydir) 1.329 + return 0; 1.330 + 1.331 + if (!cwd) { 1.332 +#ifndef NEEDS_GETCWD 1.333 +#ifndef GETCWD_CANT_MALLOC 1.334 + cwd = getcwd(0, PATH_MAX); 1.335 +#else 1.336 + cwd = malloc(PATH_MAX + 1); 1.337 + cwd = getcwd(cwd, PATH_MAX); 1.338 +#endif 1.339 +#else 1.340 + cwd = malloc(PATH_MAX + 1); 1.341 + cwd = getwd(cwd); 1.342 +#endif 1.343 + } 1.344 + 1.345 + xchdir(todir); 1.346 +#ifndef NEEDS_GETCWD 1.347 +#ifndef GETCWD_CANT_MALLOC 1.348 + todir = getcwd(0, PATH_MAX); 1.349 +#else 1.350 + todir = malloc(PATH_MAX + 1); 1.351 + todir = getcwd(todir, PATH_MAX); 1.352 +#endif 1.353 +#else 1.354 + todir = malloc(PATH_MAX + 1); 1.355 + todir = getwd(todir); 1.356 +#endif 1.357 + tdlen = strlen(todir); 1.358 + xchdir(cwd); 1.359 + tdlen = strlen(todir); 1.360 + 1.361 + uid = owner ? touid(owner) : (uid_t)(-1); 1.362 + gid = group ? togid(group) : (gid_t)(-1); 1.363 + 1.364 + while (--argc > 0) { 1.365 + name = *argv++; 1.366 + len = strlen(name); 1.367 + base = xbasename(name); 1.368 + bnlen = strlen(base); 1.369 + toname = xmalloc((unsigned int)(tdlen + 1 + bnlen + 1)); 1.370 + sprintf(toname, "%s%s%s", todir, _DIRECTORY_SEPARATOR, base); 1.371 + exists = (lstat(toname, &tosb) == 0); 1.372 + 1.373 + if (dodir) { 1.374 + /* -d means create a directory, always */ 1.375 + if (exists && !S_ISDIR(tosb.st_mode)) { 1.376 + (void) unlink(toname); 1.377 + exists = 0; 1.378 + } 1.379 + if (!exists && mkdir(toname, mode) < 0) 1.380 + fail("cannot make directory %s", toname); 1.381 + if ((owner || group) && chown(toname, uid, gid) < 0) 1.382 + fail("cannot change owner of %s", toname); 1.383 + } else if (dolink) { 1.384 + if (access(name, R_OK) != 0) { 1.385 + fail("cannot access %s", name); 1.386 + } 1.387 + if (*name == '/') { 1.388 + /* source is absolute pathname, link to it directly */ 1.389 + linkname = 0; 1.390 + } else { 1.391 + if (linkprefix) { 1.392 + /* -L prefixes names with a $cwd arg. */ 1.393 + len += lplen + 1; 1.394 + linkname = xmalloc((unsigned int)(len + 1)); 1.395 + sprintf(linkname, "%s/%s", linkprefix, name); 1.396 + } else if (dorelsymlink) { 1.397 + /* Symlink the relative path from todir to source name. */ 1.398 + linkname = xmalloc(PATH_MAX); 1.399 + 1.400 + if (*todir == '/') { 1.401 + /* todir is absolute: skip over common prefix. */ 1.402 + lplen = relatepaths(todir, cwd, linkname); 1.403 + strcpy(linkname + lplen, name); 1.404 + } else { 1.405 + /* todir is named by a relative path: reverse it. */ 1.406 + reversepath(todir, name, len, linkname); 1.407 + xchdir(cwd); 1.408 + } 1.409 + 1.410 + len = strlen(linkname); 1.411 + } 1.412 + name = linkname; 1.413 + } 1.414 + 1.415 + /* Check for a pre-existing symlink with identical content. */ 1.416 + if ((exists && (!S_ISLNK(tosb.st_mode) || 1.417 + readlink(toname, buf, sizeof buf) != len || 1.418 + strncmp(buf, name, (unsigned int)len) != 0)) || 1.419 + ((stat(name, &fromsb) == 0) && 1.420 + (fromsb.st_mtime > tosb.st_mtime))) { 1.421 + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); 1.422 + exists = 0; 1.423 + } 1.424 + if (!exists && symlink(name, toname) < 0) 1.425 + fail("cannot make symbolic link %s", toname); 1.426 +#ifdef HAVE_LCHOWN 1.427 + if ((owner || group) && lchown(toname, uid, gid) < 0) 1.428 + fail("cannot change owner of %s", toname); 1.429 +#endif 1.430 + 1.431 + if (linkname) { 1.432 + free(linkname); 1.433 + linkname = 0; 1.434 + } 1.435 + } else { 1.436 + /* Copy from name to toname, which might be the same file. */ 1.437 + if( stat(name, &sb) == 0 && S_IFDIR & sb.st_mode ) 1.438 + { 1.439 + /* then is directory: must explicitly create destination dir */ 1.440 + /* and manually copy files over */ 1.441 + copydir( name, todir, mode, group, owner, dotimes, uid, gid ); 1.442 + } 1.443 + else 1.444 + { 1.445 + copyfile(name, toname, mode, group, owner, dotimes, uid, gid); 1.446 + } 1.447 + } 1.448 + 1.449 + free(toname); 1.450 + } 1.451 + 1.452 + free(cwd); 1.453 + free(todir); 1.454 + return 0; 1.455 +}