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-06-02 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             468 :     for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
     532             459 :         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