VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/nsprpub/config/nsinstall.c@ 2426

Last change on this file since 2426 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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) && !defined(VMS)
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
87static char *
88my_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#ifdef LINUX
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)
112extern int fchmod(int fildes, mode_t mode);
113#endif
114
115#ifdef QNX
116#define d_ino d_stat.st_ino
117#endif
118
119static void
120usage(void)
121{
122 fprintf(stderr,
123 "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
124 " %*s [-DdltR] file [file ...] directory\n",
125 program, (int)strlen(program), "");
126 exit(2);
127}
128
129static int
130mkdirs(char *path, mode_t mode)
131{
132 char *cp;
133 struct stat sb;
134 int res;
135
136 while (*path == '/' && path[1] == '/')
137 path++;
138 while ((cp = strrchr(path, '/')) && cp[1] == '\0')
139 *cp = '\0';
140 if (cp && cp != path) {
141 *cp = '\0';
142 if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
143 mkdirs(path, mode) < 0) {
144 return -1;
145 }
146 *cp = '/';
147 }
148 res = mkdir(path, mode);
149 if ((res != 0) && (errno == EEXIST))
150 return 0;
151 else
152 return res;
153}
154
155static uid_t
156touid(char *owner)
157{
158 struct passwd *pw;
159 uid_t uid;
160 char *cp;
161
162 pw = getpwnam(owner);
163 if (pw)
164 return pw->pw_uid;
165 uid = strtol(owner, &cp, 0);
166 if (uid == 0 && cp == owner)
167 fail("cannot find uid for %s", owner);
168 return uid;
169}
170
171static gid_t
172togid(char *group)
173{
174 struct group *gr;
175 gid_t gid;
176 char *cp;
177
178 gr = getgrnam(group);
179 if (gr)
180 return gr->gr_gid;
181 gid = strtol(group, &cp, 0);
182 if (gid == 0 && cp == group)
183 fail("cannot find gid for %s", group);
184 return gid;
185}
186
187int
188main(int argc, char **argv)
189{
190 int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
191 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 program = argv[0];
199 cwd = linkname = linkprefix = owner = group = 0;
200 onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0;
201
202 while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
203 switch (opt) {
204 case 'C':
205 cwd = optarg;
206 break;
207 case 'D':
208 onlydir = 1;
209 break;
210 case 'd':
211 dodir = 1;
212 break;
213 case 'l':
214 dolink = 1;
215 break;
216 case 'L':
217 linkprefix = optarg;
218 lplen = strlen(linkprefix);
219 dolink = 1;
220 break;
221 case 'R':
222 dolink = dorelsymlink = 1;
223 break;
224 case 'm':
225 mode = strtoul(optarg, &cp, 8);
226 if (mode == 0 && cp == optarg)
227 usage();
228 break;
229 case 'o':
230 owner = optarg;
231 break;
232 case 'g':
233 group = optarg;
234 break;
235 case 't':
236 dotimes = 1;
237 break;
238 default:
239 usage();
240 }
241 }
242
243 argc -= optind;
244 argv += optind;
245 if (argc < 2 - onlydir)
246 usage();
247
248 todir = argv[argc-1];
249 if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
250 mkdirs(todir, 0777) < 0) {
251 fail("cannot make directory %s", todir);
252 }
253 if (onlydir)
254 return 0;
255
256 if (!cwd) {
257#ifdef GETCWD_CAN_MALLOC
258 cwd = getcwd(0, PATH_MAX);
259#else
260 cwd = malloc(PATH_MAX + 1);
261 cwd = getcwd(cwd, PATH_MAX);
262#endif
263 }
264 xchdir(todir);
265#ifdef GETCWD_CAN_MALLOC
266 todir = getcwd(0, PATH_MAX);
267#else
268 todir = malloc(PATH_MAX + 1);
269 todir = getcwd(todir, PATH_MAX);
270#endif
271 tdlen = strlen(todir);
272 xchdir(cwd);
273 tdlen = strlen(todir);
274
275 uid = owner ? touid(owner) : -1;
276 gid = group ? togid(group) : -1;
277
278 while (--argc > 0) {
279 name = *argv++;
280 len = strlen(name);
281 base = xbasename(name);
282 bnlen = strlen(base);
283 toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
284 sprintf(toname, "%s/%s", todir, base);
285 exists = (lstat(toname, &tosb) == 0);
286
287 if (dodir) {
288 /* -d means create a directory, always */
289 if (exists && !S_ISDIR(tosb.st_mode)) {
290 (void) unlink(toname);
291 exists = 0;
292 }
293 if (!exists && mkdir(toname, mode) < 0)
294 fail("cannot make directory %s", toname);
295 if ((owner || group) && chown(toname, uid, gid) < 0)
296 fail("cannot change owner of %s", toname);
297 } else if (dolink) {
298 if (*name == '/') {
299 /* source is absolute pathname, link to it directly */
300 linkname = 0;
301 } else {
302 if (linkprefix) {
303 /* -L implies -l and prefixes names with a $cwd arg. */
304 len += lplen + 1;
305 linkname = (char*)xmalloc(len + 1);
306 sprintf(linkname, "%s/%s", linkprefix, name);
307 } else if (dorelsymlink) {
308 /* Symlink the relative path from todir to source name. */
309 linkname = (char*)xmalloc(PATH_MAX);
310
311 if (*todir == '/') {
312 /* todir is absolute: skip over common prefix. */
313 lplen = relatepaths(todir, cwd, linkname);
314 strcpy(linkname + lplen, name);
315 } else {
316 /* todir is named by a relative path: reverse it. */
317 reversepath(todir, name, len, linkname);
318 xchdir(cwd);
319 }
320
321 len = strlen(linkname);
322 }
323 name = linkname;
324 }
325
326 /* Check for a pre-existing symlink with identical content. */
327 if (exists &&
328 (!S_ISLNK(tosb.st_mode) ||
329 readlink(toname, buf, sizeof buf) != len ||
330 strncmp(buf, name, len) != 0)) {
331 (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
332 exists = 0;
333 }
334 if (!exists && symlink(name, toname) < 0)
335 fail("cannot make symbolic link %s", toname);
336#ifdef HAVE_LCHOWN
337 if ((owner || group) && lchown(toname, uid, gid) < 0)
338 fail("cannot change owner of %s", toname);
339#endif
340
341 if (linkname) {
342 free(linkname);
343 linkname = 0;
344 }
345 } else {
346 /* Copy from name to toname, which might be the same file. */
347 fromfd = open(name, O_RDONLY);
348 if (fromfd < 0 || fstat(fromfd, &sb) < 0)
349 fail("cannot access %s", name);
350 if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
351 (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
352 tofd = open(toname, O_CREAT | O_WRONLY, 0666);
353 if (tofd < 0)
354 fail("cannot create %s", toname);
355
356 bp = buf;
357 while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
358 while ((wc = write(tofd, bp, cc)) > 0) {
359 if ((cc -= wc) == 0)
360 break;
361 bp += wc;
362 }
363 if (wc < 0)
364 fail("cannot write to %s", toname);
365 }
366 if (cc < 0)
367 fail("cannot read from %s", name);
368
369 if (ftruncate(tofd, sb.st_size) < 0)
370 fail("cannot truncate %s", toname);
371 /*
372 ** On OpenVMS we can't chmod() until the file is closed, and we
373 ** have to utime() last since fchown/chmod alter the timestamps.
374 */
375#ifndef VMS
376 if (dotimes) {
377 utb.actime = sb.st_atime;
378 utb.modtime = sb.st_mtime;
379 if (utime(toname, &utb) < 0)
380 fail("cannot set times of %s", toname);
381 }
382#ifdef HAVE_FCHMOD
383 if (fchmod(tofd, mode) < 0)
384#else
385 if (chmod(toname, mode) < 0)
386#endif
387 fail("cannot change mode of %s", toname);
388#endif
389 if ((owner || group) && fchown(tofd, uid, gid) < 0)
390 fail("cannot change owner of %s", toname);
391
392 /* Must check for delayed (NFS) write errors on close. */
393 if (close(tofd) < 0)
394 fail("cannot write to %s", toname);
395 close(fromfd);
396#ifdef VMS
397 if (chmod(toname, mode) < 0)
398 fail("cannot change mode of %s", toname);
399 if (dotimes) {
400 utb.actime = sb.st_atime;
401 utb.modtime = sb.st_mtime;
402 if (utime(toname, &utb) < 0)
403 fail("cannot set times of %s", toname);
404 }
405#endif
406 }
407
408 free(toname);
409 }
410
411 free(cwd);
412 free(todir);
413 return 0;
414}
415
416/*
417** Pathname subroutines.
418**
419** Brendan Eich, 8/29/95
420*/
421
422char *program;
423
424void
425fail(char *format, ...)
426{
427 int error;
428 va_list ap;
429
430#ifdef USE_REENTRANT_LIBC
431 R_STRERROR_INIT_R();
432#endif
433
434 error = errno;
435 fprintf(stderr, "%s: ", program);
436 va_start(ap, format);
437 vfprintf(stderr, format, ap);
438 va_end(ap);
439 if (error)
440
441#ifdef USE_REENTRANT_LIBC
442 R_STRERROR_R(errno);
443 fprintf(stderr, ": %s", r_strerror_r);
444#else
445 fprintf(stderr, ": %s", strerror(errno));
446#endif
447
448 putc('\n', stderr);
449 exit(1);
450}
451
452char *
453getcomponent(char *path, char *name)
454{
455 if (*path == '\0')
456 return 0;
457 if (*path == '/') {
458 *name++ = '/';
459 } else {
460 do {
461 *name++ = *path++;
462 } while (*path != '/' && *path != '\0');
463 }
464 *name = '\0';
465 while (*path == '/')
466 path++;
467 return path;
468}
469
470#ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL
471/* Sigh. The static buffer in Unixware's readdir is too small. */
472struct dirent * readdir(DIR *d)
473{
474 static struct dirent *buf = NULL;
475#define MAX_PATH_LEN 1024
476
477
478 if(buf == NULL)
479 buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
480;
481 return(readdir_r(d, buf));
482}
483#endif
484
485char *
486ino2name(ino_t ino, char *dir)
487{
488 DIR *dp;
489 struct dirent *ep;
490 char *name;
491
492 dp = opendir("..");
493 if (!dp)
494 fail("cannot read parent directory");
495 for (;;) {
496 if (!(ep = readdir(dp)))
497 fail("cannot find current directory");
498 if (ep->d_ino == ino)
499 break;
500 }
501 name = xstrdup(ep->d_name);
502 closedir(dp);
503 return name;
504}
505
506void *
507xmalloc(size_t size)
508{
509 void *p = malloc(size);
510 if (!p)
511 fail("cannot allocate %u bytes", size);
512 return p;
513}
514
515char *
516xstrdup(char *s)
517{
518 return strcpy((char*)xmalloc(strlen(s) + 1), s);
519}
520
521char *
522xbasename(char *path)
523{
524 char *cp;
525
526 while ((cp = strrchr(path, '/')) && cp[1] == '\0')
527 *cp = '\0';
528 if (!cp) return path;
529 return cp + 1;
530}
531
532void
533xchdir(char *dir)
534{
535 if (chdir(dir) < 0)
536 fail("cannot change directory to %s", dir);
537}
538
539int
540relatepaths(char *from, char *to, char *outpath)
541{
542 char *cp, *cp2;
543 int len;
544 char buf[NAME_MAX];
545
546 assert(*from == '/' && *to == '/');
547 for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
548 if (*cp == '\0')
549 break;
550 while (cp[-1] != '/')
551 cp--, cp2--;
552 if (cp - 1 == to) {
553 /* closest common ancestor is /, so use full pathname */
554 len = strlen(strcpy(outpath, to));
555 if (outpath[len] != '/') {
556 outpath[len++] = '/';
557 outpath[len] = '\0';
558 }
559 } else {
560 len = 0;
561 while ((cp2 = getcomponent(cp2, buf)) != 0) {
562 strcpy(outpath + len, "../");
563 len += 3;
564 }
565 while ((cp = getcomponent(cp, buf)) != 0) {
566 sprintf(outpath + len, "%s/", buf);
567 len += strlen(outpath + len);
568 }
569 }
570 return len;
571}
572
573void
574reversepath(char *inpath, char *name, int len, char *outpath)
575{
576 char *cp, *cp2;
577 char buf[NAME_MAX];
578 struct stat sb;
579
580 cp = strcpy(outpath + PATH_MAX - (len + 1), name);
581 cp2 = inpath;
582 while ((cp2 = getcomponent(cp2, buf)) != 0) {
583 if (strcmp(buf, ".") == 0)
584 continue;
585 if (strcmp(buf, "..") == 0) {
586 if (stat(".", &sb) < 0)
587 fail("cannot stat current directory");
588 name = ino2name(sb.st_ino, "..");
589 len = strlen(name);
590 cp -= len + 1;
591 strcpy(cp, name);
592 cp[len] = '/';
593 free(name);
594 xchdir("..");
595 } else {
596 cp -= 3;
597 strncpy(cp, "../", 3);
598 xchdir(buf);
599 }
600 }
601 strcpy(outpath, cp);
602}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette