LCOV - app.info - nsprpub/config/nsinstall.c

LCOV - code coverage report
| Current view: | directory - nsprpub/config - nsinstall.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 255 | 130 | 51.0 %
| Date: | 2012-07-07 | Functions: | 14 | 7 | 50.0 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : /*
          39                 : ** Netscape portable install command.
          40                 : **
          41                 : ** Brendan Eich, 7/20/95
          42                 : */
          43                 : #include <stdio.h>  /* OSF/1 requires this before grp.h, so put it first */
          44                 : #include <assert.h>
          45                 : #include <fcntl.h>
          46                 : #include <grp.h>
          47                 : #include <pwd.h>
          48                 : #include <stdlib.h>
          49                 : #include <string.h>
          50                 : #include <unistd.h>
          51                 : #include <utime.h>
          52                 : #include <sys/types.h>
          53                 : #include <sys/stat.h>
          54                 : #include <dirent.h>
          55                 : #include <errno.h>
          56                 : #include <stdarg.h>
          57                 : #ifdef USE_REENTRANT_LIBC
          58                 : #include "libc_r.h"
          59                 : #endif /* USE_REENTRANT_LIBC */
          60                 :
          61                 : #include "pathsub.h"
          62                 :
          63                 : #define HAVE_FCHMOD
          64                 :
          65                 : #if defined(BEOS)
          66                 : #undef HAVE_FCHMOD
          67                 : #endif
          68                 :
          69                 : /*
          70                 :  * Does getcwd() take NULL as the first argument and malloc
          71                 :  * the result buffer?
          72                 :  */
          73                 : #if !defined(DARWIN) && !defined(NEXTSTEP)
          74                 : #define GETCWD_CAN_MALLOC
          75                 : #endif
          76                 :
          77                 : #ifdef NEXTSTEP
          78                 : #include <bsd/libc.h>
          79                 :
          80                 : /*
          81                 : ** balazs.pataki@sztaki.hu: The getcwd is broken in NEXTSTEP (returns 0),
          82                 : ** when called on a mounted fs. Did anyone notice this? Here's an ugly
          83                 : ** workaround ...
          84                 : */
          85                 : #define getcwd(b,s)   my_getcwd(b,s)
          86                 :
          87                 : static char *
          88                 : my_getcwd (char *buf, size_t size)
          89                 : {
          90                 :     FILE *pwd = popen("pwd", "r");
          91                 :     char *result = fgets(buf, size, pwd);
          92                 :
          93                 :     if (result) {
          94                 :         buf[strlen(buf)-1] = '\0';
          95                 :     }
          96                 :     pclose (pwd);
          97                 :     return buf;
          98                 : }
          99                 : #endif /* NEXTSTEP */
         100                 :
         101                 : #if defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)
         102                 : #include <getopt.h>
         103                 : #endif
         104                 :
         105                 : #if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC) || defined(NEXTSTEP)
         106                 : #if !defined(S_ISLNK) && defined(S_IFLNK)
         107                 : #define S_ISLNK(a)      (((a) & S_IFMT) == S_IFLNK)
         108                 : #endif
         109                 : #endif
         110                 :
         111                 : #if defined(SNI)
         112                 : extern int fchmod(int fildes, mode_t mode);
         113                 : #endif
         114                 :
         115                 : #ifdef QNX
         116                 : #define d_ino d_stat.st_ino
         117                 : #endif
         118                 :
         119                 : static void
         120               0 : usage(void)
         121                 : {
         122               0 :     fprintf(stderr,
         123                 :         "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
         124                 :         "       %*s [-DdltR] file [file ...] directory\n",
         125               0 :         program, (int)strlen(program), "");
         126               0 :     exit(2);
         127                 : }
         128                 :
         129                 : static int
         130               9 : mkdirs(char *path, mode_t mode)
         131                 : {
         132                 :     char *cp;
         133                 :     struct stat sb;
         134                 :     int res;
         135                 :
         136              18 :     while (*path == '/' && path[1] == '/')
         137               0 :         path++;
         138               9 :     for (cp = strrchr(path, '/'); cp && cp != path && cp[-1] == '/'; cp--)
         139                 :         ;
         140               9 :     if (cp && cp != path) {
         141               9 :         *cp = '\0';
         142              10 :         if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
         143               1 :             mkdirs(path, mode) < 0) {
         144               0 :             return -1;
         145                 :         }
         146               9 :         *cp = '/';
         147                 :     }
         148               9 :     res = mkdir(path, mode);
         149               9 :     if ((res != 0) && (errno == EEXIST))
         150               0 :         return 0;
         151                 :      else
         152               9 :         return res;
         153                 : }
         154                 :
         155                 : static uid_t
         156               0 : touid(char *owner)
         157                 : {
         158                 :     struct passwd *pw;
         159                 :     uid_t uid;
         160                 :     char *cp;
         161                 :
         162               0 :     pw = getpwnam(owner);
         163               0 :     if (pw)
         164               0 :         return pw->pw_uid;
         165               0 :     uid = strtol(owner, &cp, 0);
         166               0 :     if (uid == 0 && cp == owner)
         167               0 :         fail("cannot find uid for %s", owner);
         168               0 :     return uid;
         169                 : }
         170                 :
         171                 : static gid_t
         172               0 : togid(char *group)
         173                 : {
         174                 :     struct group *gr;
         175                 :     gid_t gid;
         176                 :     char *cp;
         177                 :
         178               0 :     gr = getgrnam(group);
         179               0 :     if (gr)
         180               0 :         return gr->gr_gid;
         181               0 :     gid = strtol(group, &cp, 0);
         182               0 :     if (gid == 0 && cp == group)
         183               0 :         fail("cannot find gid for %s", group);
         184               0 :     return gid;
         185                 : }
         186                 :
         187                 : int
         188              28 : main(int argc, char **argv)
         189                 : {
         190                 :     int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
         191              28 :     mode_t mode = 0755;
         192                 :     char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
         193                 :     uid_t uid;
         194                 :     gid_t gid;
         195                 :     struct stat sb, tosb;
         196                 :     struct utimbuf utb;
         197                 :
         198              28 :     program = argv[0];
         199              28 :     cwd = linkname = linkprefix = owner = group = 0;
         200              28 :     onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0;
         201                 :
         202             110 :     while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
         203              54 :         switch (opt) {
         204                 :           case 'C':
         205               0 :             cwd = optarg;
         206               0 :             break;
         207                 :           case 'D':
         208               2 :             onlydir = 1;
         209               2 :             break;
         210                 :           case 'd':
         211               0 :             dodir = 1;
         212               0 :             break;
         213                 :           case 'l':
         214               0 :             dolink = 1;
         215               0 :             break;
         216                 :           case 'L':
         217               0 :             linkprefix = optarg;
         218               0 :             lplen = strlen(linkprefix);
         219               0 :             dolink = 1;
         220               0 :             break;
         221                 :           case 'R':
         222              13 :             dolink = dorelsymlink = 1;
         223              13 :             break;
         224                 :           case 'm':
         225              26 :             mode = strtoul(optarg, &cp, 8);
         226              26 :             if (mode == 0 && cp == optarg)
         227               0 :                 usage();
         228              26 :             break;
         229                 :           case 'o':
         230               0 :             owner = optarg;
         231               0 :             break;
         232                 :           case 'g':
         233               0 :             group = optarg;
         234               0 :             break;
         235                 :           case 't':
         236              13 :             dotimes = 1;
         237              13 :             break;
         238                 :           default:
         239               0 :             usage();
         240                 :         }
         241                 :     }
         242                 :
         243              28 :     argc -= optind;
         244              28 :     argv += optind;
         245              28 :     if (argc < 2 - onlydir)
         246               0 :         usage();
         247                 :
         248              28 :     todir = argv[argc-1];
         249              36 :     if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
         250               8 :         mkdirs(todir, 0777) < 0) {
         251               0 :         fail("cannot make directory %s", todir);
         252                 :     }
         253              28 :     if (onlydir)
         254               2 :         return 0;
         255                 :
         256              26 :     if (!cwd) {
         257                 : #ifdef GETCWD_CAN_MALLOC
         258              26 :         cwd = getcwd(0, PATH_MAX);
         259                 : #else
         260                 :         cwd = malloc(PATH_MAX + 1);
         261                 :         cwd = getcwd(cwd, PATH_MAX);
         262                 : #endif
         263                 :     }
         264              26 :     xchdir(todir);
         265                 : #ifdef GETCWD_CAN_MALLOC
         266              26 :     todir = getcwd(0, PATH_MAX);
         267                 : #else
         268                 :     todir = malloc(PATH_MAX + 1);
         269                 :     todir = getcwd(todir, PATH_MAX);
         270                 : #endif
         271              26 :     tdlen = strlen(todir);
         272              26 :     xchdir(cwd);
         273              26 :     tdlen = strlen(todir);
         274                 :
         275              26 :     uid = owner ? touid(owner) : -1;
         276              26 :     gid = group ? togid(group) : -1;
         277                 :
         278             245 :     while (--argc > 0) {
         279             193 :         name = *argv++;
         280             193 :         len = strlen(name);
         281             193 :         base = xbasename(name);
         282             193 :         bnlen = strlen(base);
         283             193 :         toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
         284             193 :         sprintf(toname, "%s/%s", todir, base);
         285             193 :         exists = (lstat(toname, &tosb) == 0);
         286                 :
         287             193 :         if (dodir) {
         288                 :             /* -d means create a directory, always */
         289               0 :             if (exists && !S_ISDIR(tosb.st_mode)) {
         290               0 :                 (void) unlink(toname);
         291               0 :                 exists = 0;
         292                 :             }
         293               0 :             if (!exists && mkdir(toname, mode) < 0)
         294               0 :                 fail("cannot make directory %s", toname);
         295               0 :             if ((owner || group) && chown(toname, uid, gid) < 0)
         296               0 :                 fail("cannot change owner of %s", toname);
         297             193 :         } else if (dolink) {
         298              96 :             if (*name == '/') {
         299                 :                 /* source is absolute pathname, link to it directly */
         300              87 :                 linkname = 0;
         301                 :             } else {
         302               9 :                 if (linkprefix) {
         303                 :                     /* -L implies -l and prefixes names with a $cwd arg. */
         304               0 :                     len += lplen + 1;
         305               0 :                     linkname = (char*)xmalloc(len + 1);
         306               0 :                     sprintf(linkname, "%s/%s", linkprefix, name);
         307               9 :                 } else if (dorelsymlink) {
         308                 :                     /* Symlink the relative path from todir to source name. */
         309               9 :                     linkname = (char*)xmalloc(PATH_MAX);
         310                 :
         311               9 :                     if (*todir == '/') {
         312                 :                         /* todir is absolute: skip over common prefix. */
         313               9 :                         lplen = relatepaths(todir, cwd, linkname);
         314               9 :                         strcpy(linkname + lplen, name);
         315                 :                     } else {
         316                 :                         /* todir is named by a relative path: reverse it. */
         317               0 :                         reversepath(todir, name, len, linkname);
         318               0 :                         xchdir(cwd);
         319                 :                     }
         320                 :
         321               9 :                     len = strlen(linkname);
         322                 :                 }
         323               9 :                 name = linkname;
         324                 :             }
         325                 :
         326                 :             /* Check for a pre-existing symlink with identical content. */
         327              96 :             if (exists &&
         328               0 :                 (!S_ISLNK(tosb.st_mode) ||
         329               0 :                  readlink(toname, buf, sizeof buf) != len ||
         330               0 :                  strncmp(buf, name, len) != 0)) {
         331               0 :                 (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
         332               0 :                 exists = 0;
         333                 :             }
         334              96 :             if (!exists && symlink(name, toname) < 0)
         335               0 :                 fail("cannot make symbolic link %s", toname);
         336                 : #ifdef HAVE_LCHOWN
         337              96 :             if ((owner || group) && lchown(toname, uid, gid) < 0)
         338               0 :                 fail("cannot change owner of %s", toname);
         339                 : #endif
         340                 :
         341              96 :             if (linkname) {
         342               9 :                 free(linkname);
         343               9 :                 linkname = 0;
         344                 :             }
         345                 :         } else {
         346                 :             /* Copy from name to toname, which might be the same file. */
         347              97 :             fromfd = open(name, O_RDONLY);
         348              97 :             if (fromfd < 0 || fstat(fromfd, &sb) < 0)
         349               0 :                 fail("cannot access %s", name);
         350              97 :             if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
         351               0 :                 (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
         352              97 :             tofd = open(toname, O_CREAT | O_WRONLY, 0666);
         353              97 :             if (tofd < 0)
         354               0 :                 fail("cannot create %s", toname);
         355                 :
         356              97 :             bp = buf;
         357             714 :             while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
         358            1040 :                 while ((wc = write(tofd, bp, cc)) > 0) {
         359             520 :                     if ((cc -= wc) == 0)
         360             520 :                         break;
         361               0 :                     bp += wc;
         362                 :                 }
         363             520 :                 if (wc < 0)
         364               0 :                     fail("cannot write to %s", toname);
         365                 :             }
         366              97 :             if (cc < 0)
         367               0 :                 fail("cannot read from %s", name);
         368                 :
         369              97 :             if (ftruncate(tofd, sb.st_size) < 0)
         370               0 :                 fail("cannot truncate %s", toname);
         371              97 :             if (dotimes) {
         372              97 :                 utb.actime = sb.st_atime;
         373              97 :                 utb.modtime = sb.st_mtime;
         374              97 :                 if (utime(toname, &utb) < 0)
         375               0 :                     fail("cannot set times of %s", toname);
         376                 :             }
         377                 : #ifdef HAVE_FCHMOD
         378              97 :             if (fchmod(tofd, mode) < 0)
         379                 : #else
         380                 :             if (chmod(toname, mode) < 0)
         381                 : #endif
         382               0 :                 fail("cannot change mode of %s", toname);
         383              97 :             if ((owner || group) && fchown(tofd, uid, gid) < 0)
         384               0 :                 fail("cannot change owner of %s", toname);
         385                 :
         386                 :             /* Must check for delayed (NFS) write errors on close. */
         387              97 :             if (close(tofd) < 0)
         388               0 :                 fail("cannot write to %s", toname);
         389              97 :             close(fromfd);
         390                 :         }
         391                 :
         392             193 :         free(toname);
         393                 :     }
         394                 :
         395              26 :     free(cwd);
         396              26 :     free(todir);
         397              26 :     return 0;
         398                 : }
         399                 :
         400                 : /*
         401                 : ** Pathname subroutines.
         402                 : **
         403                 : ** Brendan Eich, 8/29/95
         404                 : */
         405                 :
         406                 : char *program;
         407                 :
         408                 : void
         409               0 : fail(char *format, ...)
         410                 : {
         411                 :     int error;
         412                 :     va_list ap;
         413                 :
         414                 : #ifdef USE_REENTRANT_LIBC
         415                 :     R_STRERROR_INIT_R();
         416                 : #endif
         417                 :
         418               0 :     error = errno;
         419               0 :     fprintf(stderr, "%s: ", program);
         420               0 :     va_start(ap, format);
         421               0 :     vfprintf(stderr, format, ap);
         422               0 :     va_end(ap);
         423               0 :     if (error)
         424                 :
         425                 : #ifdef USE_REENTRANT_LIBC
         426                 :     R_STRERROR_R(errno);
         427                 :         fprintf(stderr, ": %s", r_strerror_r);
         428                 : #else
         429               0 :         fprintf(stderr, ": %s", strerror(errno));
         430                 : #endif
         431                 :
         432               0 :     putc('\n', stderr);
         433               0 :     exit(1);
         434                 : }
         435                 :
         436                 : char *
         437              66 : getcomponent(char *path, char *name)
         438                 : {
         439              66 :     if (*path == '\0')
         440              18 :         return 0;
         441              48 :     if (*path == '/') {
         442               0 :         *name++ = '/';
         443                 :     } else {
         444                 :         do {
         445             186 :             *name++ = *path++;
         446             186 :         } while (*path != '/' && *path != '\0');
         447                 :     }
         448              48 :     *name = '\0';
         449             126 :     while (*path == '/')
         450              30 :         path++;
         451              48 :     return path;
         452                 : }
         453                 :
         454                 : #ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL
         455                 : /* Sigh.  The static buffer in Unixware's readdir is too small. */
         456                 : struct dirent * readdir(DIR *d)
         457                 : {
         458                 :         static struct dirent *buf = NULL;
         459                 : #define MAX_PATH_LEN 1024
         460                 :
         461                 :
         462                 :         if(buf == NULL)
         463                 :                 buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
         464                 : ;
         465                 :         return(readdir_r(d, buf));
         466                 : }
         467                 : #endif
         468                 :
         469                 : char *
         470               0 : ino2name(ino_t ino, char *dir)
         471                 : {
         472                 :     DIR *dp;
         473                 :     struct dirent *ep;
         474                 :     char *name;
         475                 :
         476               0 :     dp = opendir("..");
         477               0 :     if (!dp)
         478               0 :         fail("cannot read parent directory");
         479                 :     for (;;) {
         480               0 :         if (!(ep = readdir(dp)))
         481               0 :             fail("cannot find current directory");
         482               0 :         if (ep->d_ino == ino)
         483                 :             break;
         484               0 :     }
         485               0 :     name = xstrdup(ep->d_name);
         486               0 :     closedir(dp);
         487               0 :     return name;
         488                 : }
         489                 :
         490                 : void *
         491             202 : xmalloc(size_t size)
         492                 : {
         493             202 :     void *p = malloc(size);
         494             202 :     if (!p)
         495               0 :         fail("cannot allocate %u bytes", size);
         496             202 :     return p;
         497                 : }
         498                 :
         499                 : char *
         500               0 : xstrdup(char *s)
         501                 : {
         502               0 :     return strcpy((char*)xmalloc(strlen(s) + 1), s);
         503                 : }
         504                 :
         505                 : char *
         506             193 : xbasename(char *path)
         507                 : {
         508                 :     char *cp;
         509                 :
         510             386 :     while ((cp = strrchr(path, '/')) && cp[1] == '\0')
         511               0 :         *cp = '\0';
         512             193 :     if (!cp) return path;
         513             192 :     return cp + 1;
         514                 : }
         515                 :
         516                 : void
         517              52 : xchdir(char *dir)
         518                 : {
         519              52 :     if (chdir(dir) < 0)
         520               0 :         fail("cannot change directory to %s", dir);
         521              52 : }
         522                 :
         523                 : int
         524               9 : relatepaths(char *from, char *to, char *outpath)
         525                 : {
         526                 :     char *cp, *cp2;
         527                 :     int len;
         528                 :     char buf[NAME_MAX];
         529                 :
         530               9 :     assert(*from == '/' && *to == '/');
         531             459 :     for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
         532             450 :         if (*cp == '\0')
         533               0 :             break;
         534              18 :     while (cp[-1] != '/')
         535               0 :         cp--, cp2--;
         536               9 :     if (cp - 1 == to) {
         537                 :         /* closest common ancestor is /, so use full pathname */
         538               0 :         len = strlen(strcpy(outpath, to));
         539               0 :         if (outpath[len] != '/') {
         540               0 :             outpath[len++] = '/';
         541               0 :             outpath[len] = '\0';
         542                 :         }
         543                 :     } else {
         544               9 :         len = 0;
         545              36 :         while ((cp2 = getcomponent(cp2, buf)) != 0) {
         546              18 :             strcpy(outpath + len, "../");
         547              18 :             len += 3;
         548                 :         }
         549              48 :         while ((cp = getcomponent(cp, buf)) != 0) {
         550              30 :             sprintf(outpath + len, "%s/", buf);
         551              30 :             len += strlen(outpath + len);
         552                 :         }
         553                 :     }
         554               9 :     return len;
         555                 : }
         556                 :
         557                 : void
         558               0 : reversepath(char *inpath, char *name, int len, char *outpath)
         559                 : {
         560                 :     char *cp, *cp2;
         561                 :     char buf[NAME_MAX];
         562                 :     struct stat sb;
         563                 :
         564               0 :     cp = strcpy(outpath + PATH_MAX - (len + 1), name);
         565               0 :     cp2 = inpath;
         566               0 :     while ((cp2 = getcomponent(cp2, buf)) != 0) {
         567               0 :         if (strcmp(buf, ".") == 0)
         568               0 :             continue;
         569               0 :         if (strcmp(buf, "..") == 0) {
         570               0 :             if (stat(".", &sb) < 0)
         571               0 :                 fail("cannot stat current directory");
         572               0 :             name = ino2name(sb.st_ino, "..");
         573               0 :             len = strlen(name);
         574               0 :             cp -= len + 1;
         575               0 :             strcpy(cp, name);
         576               0 :             cp[len] = '/';
         577               0 :             free(name);
         578               0 :             xchdir("..");
         579                 :         } else {
         580               0 :             cp -= 3;
         581               0 :             strncpy(cp, "../", 3);
         582               0 :             xchdir(buf);
         583                 :         }
         584                 :     }
         585               0 :     strcpy(outpath, cp);
         586               0 : }

Generated by: LCOV version 1.7