nsinstall.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:10k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* 
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34. ** Netscape portable install command.
  35. */
  36. #include <stdio.h>  /* OSF/1 requires this before grp.h, so put it first */
  37. #include <assert.h>
  38. #include <fcntl.h>
  39. #include <string.h>
  40. #if defined(_WINDOWS)
  41. #include <windows.h>
  42. typedef unsigned int mode_t;
  43. #else
  44. #include <grp.h>
  45. #include <pwd.h>
  46. #include <errno.h>
  47. #include <stdlib.h>
  48. #include <unistd.h>
  49. #include <utime.h>
  50. #endif
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include "pathsub.h"
  54. #define HAVE_LCHOWN
  55. #if defined(AIX) || defined(BSDI) || defined(HPUX) || defined(LINUX) || defined(SUNOS4) || defined(SCO) || defined(UNIXWARE)
  56. #undef HAVE_LCHOWN
  57. #endif
  58. #ifdef LINUX
  59. #include <getopt.h>
  60. #endif
  61. #if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC)
  62. #if !defined(S_ISLNK) && defined(S_IFLNK)
  63. #define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK)
  64. #endif
  65. #endif
  66. #if defined(SNI)
  67. extern int fchmod(int fildes, mode_t mode);
  68. #endif
  69. static void
  70. usage(void)
  71. {
  72.     fprintf(stderr,
  73. "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]n"
  74. "       %*s [-DdltR] file [file ...] directoryn",
  75. program, strlen(program), "");
  76.     exit(2);
  77. }
  78. /* this is more-or-less equivalent to mkdir -p */
  79. static int
  80. mkdirs(char *path, mode_t mode)
  81. {
  82.     char *      cp;
  83.     int         rv;
  84.     struct stat sb;
  85.     
  86.     if (!path || !path[0]) 
  87. fail("Null pointer or empty string passed to mkdirs()");
  88.     while (*path == '/' && path[1] == '/')
  89. path++;
  90.     while ((cp = strrchr(path, '/')) && cp[1] == '')
  91. *cp = '';
  92.     if (cp && cp != path) {
  93. *cp = '';
  94. if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
  95.     mkdirs(path, mode) < 0) {
  96.     return -1;
  97. }
  98. *cp = '/';
  99.     }
  100.     rv = mkdir(path, mode);
  101.     if (rv) {
  102. if (errno != EEXIST)
  103.     fail("mkdirs cannot make %s", path);
  104. fprintf(stderr, "directory creation race: %sn", path);
  105. if (!stat(path, &sb) && S_ISDIR(sb.st_mode)) 
  106.     rv = 0;
  107.     }
  108.     return rv;
  109. }
  110. static uid_t
  111. touid(char *owner)
  112. {
  113.     struct passwd *pw;
  114.     uid_t uid;
  115.     char *cp;
  116.     if (!owner || !owner[0]) 
  117. fail("Null pointer or empty string passed to touid()");
  118.     pw = getpwnam(owner);
  119.     if (pw)
  120. return pw->pw_uid;
  121.     uid = strtol(owner, &cp, 0);
  122.     if (uid == 0 && cp == owner)
  123. fail("cannot find uid for %s", owner);
  124.     return uid;
  125. }
  126. static gid_t
  127. togid(char *group)
  128. {
  129.     struct group *gr;
  130.     gid_t gid;
  131.     char *cp;
  132.     if (!group || !group[0]) 
  133. fail("Null pointer or empty string passed to togid()");
  134.     gr = getgrnam(group);
  135.     if (gr)
  136. return gr->gr_gid;
  137.     gid = strtol(group, &cp, 0);
  138.     if (gid == 0 && cp == group)
  139. fail("cannot find gid for %s", group);
  140.     return gid;
  141. }
  142. void * const uninit = (void *)0xdeadbeef;
  143. int
  144. main(int argc, char **argv)
  145. {
  146.     char * base = uninit;
  147.     char * bp = uninit;
  148.     char * cp = uninit;
  149.     char * cwd = 0;
  150.     char * group = 0;
  151.     char * linkname = 0;
  152.     char * linkprefix = 0;
  153.     char * name = uninit;
  154.     char * owner = 0;
  155.     char * todir = uninit;
  156.     char * toname = uninit;
  157.     int  bnlen = -1;
  158.     int  cc = 0;
  159.     int  dodir = 0;
  160.     int  dolink = 0;
  161.     int  dorelsymlink = 0;
  162.     int  dotimes = 0;
  163.     int  exists = 0;
  164.     int  fromfd = -1;
  165.     int  len = -1;
  166.     int  lplen = 0;
  167.     int onlydir = 0;
  168.     int  opt = -1;
  169.     int  tdlen = -1;
  170.     int  tofd = -1;
  171.     int  wc = -1;
  172.     mode_t  mode = 0755;
  173.     uid_t  uid = -1;
  174.     gid_t  gid = -1;
  175.     struct stat sb;
  176.     struct stat tosb;
  177.     struct utimbuf utb;
  178.     char  buf[BUFSIZ];
  179.     program = strrchr(argv[0], '/');
  180.     if (!program)
  181. program = strrchr(argv[0], '\');
  182.     program = program ? program+1 : argv[0];
  183.     while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
  184. switch (opt) {
  185.   case 'C': cwd = optarg; break;
  186.   case 'D': onlydir = 1;  break;
  187.   case 'd': dodir = 1;  break;
  188.   case 'l': dolink = 1; break;
  189.   case 'L':
  190.     linkprefix = optarg;
  191.     lplen = strlen(linkprefix);
  192.     dolink = 1;
  193.     break;
  194.   case 'R': dolink = dorelsymlink = 1; break;
  195.   case 'm':
  196.     mode = strtoul(optarg, &cp, 8);
  197.     if (mode == 0 && cp == optarg)
  198. usage();
  199.     break;
  200.   case 'o': owner = optarg;  break;
  201.   case 'g': group = optarg;  break;
  202.   case 't': dotimes = 1;  break;
  203.   default:  usage();
  204. }
  205.     }
  206.     argc -= optind;
  207.     argv += optind;
  208.     if (argc < 2 - onlydir)
  209. usage();
  210.     todir = argv[argc-1];
  211.     if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
  212. mkdirs(todir, 0777) < 0) {
  213. fail("cannot mkdir -p %s", todir);
  214.     }
  215.     if (onlydir)
  216. return 0;
  217.     if (!cwd) {
  218. cwd = getcwd(0, PATH_MAX);
  219. if (!cwd)
  220.     fail("could not get CWD");
  221.     }
  222.     /* make sure we can get into todir. */
  223.     xchdir(todir);
  224.     todir = getcwd(0, PATH_MAX);
  225.     if (!todir)
  226. fail("could not get CWD in todir");
  227.     tdlen = strlen(todir);
  228.     /* back to original directory. */
  229.     xchdir(cwd);
  230.     uid = owner ? touid(owner) : -1;
  231.     gid = group ? togid(group) : -1;
  232.     while (--argc > 0) {
  233. name   = *argv++;
  234. len    = strlen(name);
  235. base   = xbasename(name);
  236. bnlen  = strlen(base);
  237. toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
  238. sprintf(toname, "%s/%s", todir, base);
  239. retry:
  240. exists = (lstat(toname, &tosb) == 0);
  241. if (dodir) {
  242.     /* -d means create a directory, always */
  243.     if (exists && !S_ISDIR(tosb.st_mode)) {
  244. int rv = unlink(toname);
  245. if (rv)
  246.     fail("cannot unlink %s", toname);
  247. exists = 0;
  248.     }
  249.     if (!exists && mkdir(toname, mode) < 0) {
  250.      /* we probably have two nsinstall programs in a race here. */
  251. if (errno == EEXIST && !stat(toname, &sb) && 
  252.     S_ISDIR(sb.st_mode)) {
  253.     fprintf(stderr, "directory creation race: %sn", toname);
  254.     goto retry;
  255.      }
  256. fail("cannot make directory %s", toname);
  257.     }
  258.     if ((owner || group) && chown(toname, uid, gid) < 0)
  259. fail("cannot change owner of %s", toname);
  260. } else if (dolink) {
  261.     if (*name == '/') {
  262. /* source is absolute pathname, link to it directly */
  263. linkname = 0;
  264.     } else {
  265. if (linkprefix) {
  266.     /* -L implies -l and prefixes names with a $cwd arg. */
  267.     len += lplen + 1;
  268.     linkname = (char*)xmalloc(len + 1);
  269.     sprintf(linkname, "%s/%s", linkprefix, name);
  270. } else if (dorelsymlink) {
  271.     /* Symlink the relative path from todir to source name. */
  272.     linkname = (char*)xmalloc(PATH_MAX);
  273.     if (*todir == '/') {
  274. /* todir is absolute: skip over common prefix. */
  275. lplen = relatepaths(todir, cwd, linkname);
  276. strcpy(linkname + lplen, name);
  277.     } else {
  278. /* todir is named by a relative path: reverse it. */
  279. reversepath(todir, name, len, linkname);
  280. xchdir(cwd);
  281.     }
  282.     len = strlen(linkname);
  283. }
  284. name = linkname;
  285.     }
  286.     /* Check for a pre-existing symlink with identical content. */
  287.     if (exists &&
  288. (!S_ISLNK(tosb.st_mode) ||
  289.  readlink(toname, buf, sizeof buf) != len ||
  290.  strncmp(buf, name, len) != 0)) {
  291. int rmrv;
  292. rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
  293. if (rmrv < 0) {
  294.     fail("destination exists, cannot remove %s", toname);
  295. }
  296. exists = 0;
  297.     }
  298.     if (!exists && symlink(name, toname) < 0) {
  299. if (errno == EEXIST) {
  300.     fprintf(stderr, "symlink creation race: %sn", toname);
  301.     goto retry;
  302. }
  303. diagnosePath(toname);
  304. fail("cannot make symbolic link %s", toname);
  305.     }
  306. #ifdef HAVE_LCHOWN
  307.     if ((owner || group) && lchown(toname, uid, gid) < 0)
  308. fail("cannot change owner of %s", toname);
  309. #endif
  310.     if (linkname) {
  311. free(linkname);
  312. linkname = 0;
  313.     }
  314. } else {
  315.     /* Copy from name to toname, which might be the same file. */
  316.     fromfd = open(name, O_RDONLY);
  317.     if (fromfd < 0 || fstat(fromfd, &sb) < 0)
  318. fail("cannot access %s", name);
  319.     if (exists && 
  320.         (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) {
  321. int rmrv;
  322. rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
  323. if (rmrv < 0) {
  324.     fail("destination exists, cannot remove %s", toname);
  325. }
  326.     }
  327.     tofd = open(toname, O_CREAT | O_WRONLY, 0666);
  328.     if (tofd < 0)
  329. fail("cannot create %s", toname);
  330.     bp = buf;
  331.     while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
  332. while ((wc = write(tofd, bp, cc)) > 0) {
  333.     if ((cc -= wc) == 0)
  334. break;
  335.     bp += wc;
  336. }
  337. if (wc < 0)
  338.     fail("cannot write to %s", toname);
  339.     }
  340.     if (cc < 0)
  341. fail("cannot read from %s", name);
  342.     if (ftruncate(tofd, sb.st_size) < 0)
  343. fail("cannot truncate %s", toname);
  344.     if (dotimes) {
  345. utb.actime = sb.st_atime;
  346. utb.modtime = sb.st_mtime;
  347. if (utime(toname, &utb) < 0)
  348.     fail("cannot set times of %s", toname);
  349.     }
  350.     if (fchmod(tofd, mode) < 0)
  351. fail("cannot change mode of %s", toname);
  352.     if ((owner || group) && fchown(tofd, uid, gid) < 0)
  353. fail("cannot change owner of %s", toname);
  354.     /* Must check for delayed (NFS) write errors on close. */
  355.     if (close(tofd) < 0)
  356. fail("close reports write error on %s", toname);
  357.     close(fromfd);
  358. }
  359. free(toname);
  360.     }
  361.     free(cwd);
  362.     free(todir);
  363.     return 0;
  364. }