VirtualBox

source: kBuild/trunk/src/gmake/kmkbuiltin/install.c@ 621

Last change on this file since 621 was 557, checked in by bird, 18 years ago

Initial Mac OS X / Darwin bootstrapping.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.7 KB
Line 
1/*
2 * Copyright (c) 1987, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1987, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
43#endif /* not lint */
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: src/usr.bin/xinstall/xinstall.c,v 1.66 2005/01/25 14:34:57 ssouhlal Exp $");
47#endif
48
49#ifndef _MSC_VER
50#include <sys/param.h>
51#ifdef USE_MMAP
52#include <sys/mman.h>
53#endif
54#include <sys/mount.h>
55#include <sys/wait.h>
56#include <sys/time.h>
57#endif
58#include <sys/stat.h>
59
60#include <ctype.h>
61#include "err.h"
62#include <errno.h>
63#include <fcntl.h>
64#ifndef _MSC_VER
65#include <grp.h>
66#include <paths.h>
67#include <pwd.h>
68#endif
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#ifndef _MSC_VER
73#include <sysexits.h>
74#include <unistd.h>
75#else
76#include "mscfakes.h"
77#endif
78#if defined(__EMX__) || defined(_MSC_VER)
79# include <process.h>
80#endif
81
82extern void * setmode(const char *p);
83extern mode_t getmode(const void *bbox, mode_t omode);
84
85#ifndef __unused
86# define __unused
87#endif
88
89#ifndef MAXBSIZE
90# define MAXBSIZE 16384
91#endif
92
93/* Bootstrap aid - this doesn't exist in most older releases */
94#ifndef MAP_FAILED
95#define MAP_FAILED ((void *)-1) /* from <sys/mman.h> */
96#endif
97
98#define MAX_CMP_SIZE (16 * 1024 * 1024)
99
100#define DIRECTORY 0x01 /* Tell install it's a directory. */
101#define SETFLAGS 0x02 /* Tell install to set flags. */
102#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
103#define BACKUP_SUFFIX ".old"
104
105#ifndef O_BINARY
106# define O_BINARY 0
107#endif
108
109#ifndef EFTYPE
110# define EFTYPE EINVAL
111#endif
112
113static gid_t gid;
114static uid_t uid;
115static int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose;
116static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
117static const char *suffix = BACKUP_SUFFIX;
118
119static int copy(int, const char *, int, const char *, off_t);
120static int compare(int, const char *, size_t, int, const char *, size_t);
121static int create_newfile(const char *, int, struct stat *);
122static int create_tempfile(const char *, char *, size_t);
123static int install(const char *, const char *, u_long, u_int);
124static int install_dir(char *);
125static u_long numeric_id(const char *, const char *);
126static int strip(const char *);
127#ifdef USE_MMAP
128static int trymmap(int);
129#endif
130static int usage(void);
131
132int
133kmk_builtin_install(int argc, char *argv[])
134{
135 struct stat from_sb, to_sb;
136 mode_t *set;
137 u_long fset = 0;
138 int ch, no_target;
139 u_int iflags;
140 char *flags;
141 const char *group, *owner, *to_name;
142
143 /* reinitialize globals */
144 mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
145 suffix = BACKUP_SUFFIX;
146 gid = 0;
147 uid = 0;
148 dobackup = docompare = dodir = dopreserve = dostrip = nommap = safecopy = verbose = 0;
149
150 /* reset getopt and set progname. */
151 g_progname = argv[0];
152 opterr = 1;
153 optarg = NULL;
154 optopt = 0;
155#if defined(__FreeBSD__) || defined(__EMX__) || defined(__APPLE__)
156 optreset = 1;
157 optind = 1;
158#else
159 optind = 0; /* init */
160#endif
161
162 iflags = 0;
163 group = owner = NULL;
164 while ((ch = getopt(argc, argv, "B:bCcdf:g:Mm:o:pSsv")) != -1)
165 switch((char)ch) {
166 case 'B':
167 suffix = optarg;
168 /* FALLTHROUGH */
169 case 'b':
170 dobackup = 1;
171 break;
172 case 'C':
173 docompare = 1;
174 break;
175 case 'c':
176 /* For backwards compatibility. */
177 break;
178 case 'd':
179 dodir = 1;
180 break;
181 case 'f':
182#ifdef UF_IMMUTABLE
183 flags = optarg;
184 if (strtofflags(&flags, &fset, NULL))
185 return errx(EX_USAGE, "%s: invalid flag", flags);
186 iflags |= SETFLAGS;
187#else
188 (void)flags;
189#endif
190 break;
191 case 'g':
192 group = optarg;
193 break;
194 case 'M':
195 nommap = 1;
196 break;
197 case 'm':
198#ifdef __EMX__
199 if (!(set = bsd_setmode(optarg)))
200#else
201 if (!(set = setmode(optarg)))
202#endif
203 return errx(EX_USAGE, "invalid file mode: %s",
204 optarg);
205 mode = getmode(set, 0);
206 free(set);
207 break;
208 case 'o':
209 owner = optarg;
210 break;
211 case 'p':
212 docompare = dopreserve = 1;
213 break;
214 case 'S':
215 safecopy = 1;
216 break;
217 case 's':
218 dostrip = 1;
219 break;
220 case 'v':
221 verbose = 1;
222 break;
223 case '?':
224 default:
225 return usage();
226 }
227 argc -= optind;
228 argv += optind;
229
230 /* some options make no sense when creating directories */
231 if (dostrip && dodir) {
232 warnx("-d and -s may not be specified together");
233 return usage();
234 }
235
236 /* must have at least two arguments, except when creating directories */
237 if (argc == 0 || (argc == 1 && !dodir))
238 return usage();
239
240 /* need to make a temp copy so we can compare stripped version */
241 if (docompare && dostrip)
242 safecopy = 1;
243
244 /* get group and owner id's */
245 if (group != NULL) {
246#ifndef _MSC_VER
247 struct group *gp;
248 if ((gp = getgrnam(group)) != NULL)
249 gid = gp->gr_gid;
250 else
251#endif
252 {
253 gid = (gid_t)numeric_id(group, "group");
254 if (gid == (gid_t)-1)
255 return 1;
256 }
257 } else
258 gid = (gid_t)-1;
259
260 if (owner != NULL) {
261#ifndef _MSC_VER
262 struct passwd *pp;
263 if ((pp = getpwnam(owner)) != NULL)
264 uid = pp->pw_uid;
265 else
266#endif
267 {
268 uid = (uid_t)numeric_id(owner, "user");
269 if (uid == (uid_t)-1)
270 return 1;
271 }
272 } else
273 uid = (uid_t)-1;
274
275 if (dodir) {
276 for (; *argv != NULL; ++argv) {
277 int rc = install_dir(*argv);
278 if (rc)
279 return rc;
280 }
281 return EX_OK;
282 /* NOTREACHED */
283 }
284
285 no_target = stat(to_name = argv[argc - 1], &to_sb);
286 if (!no_target && S_ISDIR(to_sb.st_mode)) {
287 for (; *argv != to_name; ++argv) {
288 int rc = install(*argv, to_name, fset, iflags | DIRECTORY);
289 if (rc)
290 return rc;
291 }
292 return EX_OK;
293 }
294
295 /* can't do file1 file2 directory/file */
296 if (argc != 2) {
297 warnx("wrong number or types of arguments");
298 return usage();
299 }
300
301 if (!no_target) {
302 if (stat(*argv, &from_sb))
303 return err(EX_OSERR, "%s", *argv);
304 if (!S_ISREG(to_sb.st_mode)) {
305 errno = EFTYPE;
306 return err(EX_OSERR, "%s", to_name);
307 }
308 if (to_sb.st_dev == from_sb.st_dev &&
309 to_sb.st_dev != 0 &&
310 to_sb.st_ino == from_sb.st_ino &&
311 to_sb.st_ino != 0)
312 return errx(EX_USAGE,
313 "%s and %s are the same file", *argv, to_name);
314 }
315 return install(*argv, to_name, fset, iflags);
316}
317
318static u_long
319numeric_id(const char *name, const char *type)
320{
321 u_long val;
322 char *ep;
323
324 /*
325 * XXX
326 * We know that uid_t's and gid_t's are unsigned longs.
327 */
328 errno = 0;
329 val = strtoul(name, &ep, 10);
330 if (errno)
331 return err(-1, "%s", name);
332 if (*ep != '\0')
333 return errx(-1, "unknown %s %s", type, name);
334 return (val);
335}
336
337/*
338 * install --
339 * build a path name and install the file
340 */
341static int
342install(const char *from_name, const char *to_name, u_long fset, u_int flags)
343{
344 struct stat from_sb, temp_sb, to_sb;
345 struct timeval tvb[2];
346 int devnull, files_match, from_fd, serrno, target;
347 int tempcopy, temp_fd, to_fd;
348 char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
349 int rc = EX_OK;
350
351 files_match = 0;
352 from_fd = -1;
353 to_fd = -1;
354 temp_fd = -1;
355
356 /* If try to install NULL file to a directory, fails. */
357 if (flags & DIRECTORY
358#if defined(__EMX__) || defined(_MSC_VER)
359 || ( stricmp(from_name, _PATH_DEVNULL)
360 && stricmp(from_name, "nul")
361#ifdef __EMX__
362 && stricmp(from_name, "/dev/nul")
363#endif
364 )
365#else
366 || strcmp(from_name, _PATH_DEVNULL)
367#endif
368 ) {
369 if (stat(from_name, &from_sb))
370 return err(EX_OSERR, "%s", from_name);
371 if (!S_ISREG(from_sb.st_mode)) {
372 errno = EFTYPE;
373 return err(EX_OSERR, "%s", from_name);
374 }
375 /* Build the target path. */
376 if (flags & DIRECTORY) {
377 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
378 to_name,
379 (p = strrchr(from_name, '/')) ? ++p : from_name);
380 to_name = pathbuf;
381 }
382 devnull = 0;
383 } else {
384 devnull = 1;
385 }
386
387 target = stat(to_name, &to_sb) == 0;
388
389 /* Only install to regular files. */
390 if (target && !S_ISREG(to_sb.st_mode)) {
391 errno = EFTYPE;
392 warn("%s", to_name);
393 return EX_OK;
394 }
395
396 /* Only copy safe if the target exists. */
397 tempcopy = safecopy && target;
398
399 if (!devnull && (from_fd = open(from_name, O_RDONLY | O_BINARY, 0)) < 0)
400 return err(EX_OSERR, "%s", from_name);
401
402 /* If we don't strip, we can compare first. */
403 if (docompare && !dostrip && target) {
404 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
405 rc = err(EX_OSERR, "%s", to_name);
406 goto l_done;
407 }
408 if (devnull)
409 files_match = to_sb.st_size == 0;
410 else
411 files_match = !(compare(from_fd, from_name,
412 (size_t)from_sb.st_size, to_fd,
413 to_name, (size_t)to_sb.st_size));
414
415 /* Close "to" file unless we match. */
416 if (!files_match) {
417 (void)close(to_fd);
418 to_fd = -1;
419 }
420 }
421
422 if (!files_match) {
423 if (tempcopy) {
424 to_fd = create_tempfile(to_name, tempfile,
425 sizeof(tempfile));
426 if (to_fd < 0) {
427 rc = err(EX_OSERR, "%s", tempfile);
428 goto l_done;
429 }
430 } else {
431 if ((to_fd = create_newfile(to_name, target,
432 &to_sb)) < 0) {
433 rc = err(EX_OSERR, "%s", to_name);
434 goto l_done;
435 }
436 if (verbose)
437 (void)printf("install: %s -> %s\n",
438 from_name, to_name);
439 }
440 if (!devnull) {
441 rc = copy(from_fd, from_name, to_fd,
442 tempcopy ? tempfile : to_name, from_sb.st_size);
443 if (rc)
444 goto l_done;
445 }
446 }
447
448 if (dostrip) {
449#if defined(__EMX__) || defined(_MSC_VER)
450 /* close before we strip. */
451 close(to_fd);
452 to_fd = -1;
453#endif
454 rc = strip(tempcopy ? tempfile : to_name);
455 if (rc)
456 goto l_done;
457
458 /*
459 * Re-open our fd on the target, in case we used a strip
460 * that does not work in-place -- like GNU binutils strip.
461 */
462#if !defined(__EMX__) && !defined(_MSC_VER)
463 close(to_fd);
464#endif
465 to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY | O_BINARY, 0);
466 if (to_fd < 0) {
467 rc = err(EX_OSERR, "stripping %s", to_name);
468 goto l_done;
469 }
470 }
471
472 /*
473 * Compare the stripped temp file with the target.
474 */
475 if (docompare && dostrip && target) {
476 temp_fd = to_fd;
477
478 /* Re-open to_fd using the real target name. */
479 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
480 rc = err(EX_OSERR, "%s", to_name);
481 goto l_done;
482 }
483
484 if (fstat(temp_fd, &temp_sb)) {
485 serrno = errno;
486 (void)unlink(tempfile);
487 errno = serrno;
488 rc = err(EX_OSERR, "%s", tempfile);
489 goto l_done;
490 }
491
492 if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
493 to_name, (size_t)to_sb.st_size) == 0) {
494 /*
495 * If target has more than one link we need to
496 * replace it in order to snap the extra links.
497 * Need to preserve target file times, though.
498 */
499#if !defined(_MSC_VER) && !defined(__EMX__)
500 if (to_sb.st_nlink != 1) {
501 tvb[0].tv_sec = to_sb.st_atime;
502 tvb[0].tv_usec = 0;
503 tvb[1].tv_sec = to_sb.st_mtime;
504 tvb[1].tv_usec = 0;
505 (void)utimes(tempfile, tvb);
506 } else
507#endif
508 {
509
510 files_match = 1;
511 (void)unlink(tempfile);
512 }
513 (void) close(temp_fd);
514 temp_fd = -1;
515 }
516 }
517
518 /*
519 * Move the new file into place if doing a safe copy
520 * and the files are different (or just not compared).
521 */
522 if (tempcopy && !files_match) {
523#ifdef UF_IMMUTABLE
524 /* Try to turn off the immutable bits. */
525 if (to_sb.st_flags & NOCHANGEBITS)
526 (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
527#endif
528 if (dobackup) {
529 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name,
530 suffix) != strlen(to_name) + strlen(suffix)) {
531 unlink(tempfile);
532 rc = errx(EX_OSERR, "%s: backup filename too long",
533 to_name);
534 goto l_done;
535 }
536 if (verbose)
537 (void)printf("install: %s -> %s\n", to_name, backup);
538 if (rename(to_name, backup) < 0) {
539 serrno = errno;
540 unlink(tempfile);
541 errno = serrno;
542 rc = err(EX_OSERR, "rename: %s to %s", to_name,
543 backup);
544 goto l_done;
545 }
546 }
547 if (verbose)
548 (void)printf("install: %s -> %s\n", from_name, to_name);
549 if (rename(tempfile, to_name) < 0) {
550 serrno = errno;
551 unlink(tempfile);
552 errno = serrno;
553 rc = err(EX_OSERR, "rename: %s to %s",
554 tempfile, to_name);
555 goto l_done;
556 }
557
558 /* Re-open to_fd so we aren't hosed by the rename(2). */
559 (void) close(to_fd);
560 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
561 rc = err(EX_OSERR, "%s", to_name);
562 goto l_done;
563 }
564 }
565
566 /*
567 * Preserve the timestamp of the source file if necessary.
568 */
569 if (dopreserve && !files_match && !devnull) {
570 tvb[0].tv_sec = from_sb.st_atime;
571 tvb[0].tv_usec = 0;
572 tvb[1].tv_sec = from_sb.st_mtime;
573 tvb[1].tv_usec = 0;
574 (void)utimes(to_name, tvb);
575 }
576
577 if (fstat(to_fd, &to_sb) == -1) {
578 serrno = errno;
579 (void)unlink(to_name);
580 errno = serrno;
581 rc = err(EX_OSERR, "%s", to_name);
582 goto l_done;
583 }
584
585 /*
586 * Set owner, group, mode for target; do the chown first,
587 * chown may lose the setuid bits.
588 */
589#ifdef UF_IMMUTABLE
590 if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
591 (uid != (uid_t)-1 && uid != to_sb.st_uid) ||
592 (mode != (to_sb.st_mode & ALLPERMS))) {
593 /* Try to turn off the immutable bits. */
594 if (to_sb.st_flags & NOCHANGEBITS)
595 (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS);
596 }
597#endif
598
599 if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
600 (uid != (uid_t)-1 && uid != to_sb.st_uid))
601 if (fchown(to_fd, uid, gid) == -1) {
602 serrno = errno;
603 (void)unlink(to_name);
604 errno = serrno;
605 rc = err(EX_OSERR,"%s: chown/chgrp", to_name);
606 goto l_done;
607 }
608
609 if (mode != (to_sb.st_mode & ALLPERMS))
610 if (fchmod(to_fd, mode)) {
611 serrno = errno;
612 (void)unlink(to_name);
613 errno = serrno;
614 rc = err(EX_OSERR, "%s: chmod", to_name);
615 goto l_done;
616 }
617
618 /*
619 * If provided a set of flags, set them, otherwise, preserve the
620 * flags, except for the dump flag.
621 * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just
622 * trying to turn off UF_NODUMP. If we're trying to set real flags,
623 * then warn if the the fs doesn't support it, otherwise fail.
624 */
625#ifdef UF_IMMUTABLE
626 if (!devnull && (flags & SETFLAGS ||
627 (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) &&
628 fchflags(to_fd,
629 flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
630 if (flags & SETFLAGS) {
631 if (errno == EOPNOTSUPP)
632 warn("%s: chflags", to_name);
633 else {
634 serrno = errno;
635 (void)unlink(to_name);
636 errno = serrno;
637 rc = err(EX_OSERR, "%s: chflags", to_name);
638 goto l_done;
639 }
640 }
641 }
642#endif
643
644l_done:
645 if (to_fd >= 0)
646 (void)close(to_fd);
647 if (temp_fd >= 0)
648 (void)close(temp_fd);
649 if (!devnull)
650 (void)close(from_fd);
651 return rc;
652}
653
654/*
655 * compare --
656 * compare two files; non-zero means files differ
657 */
658static int
659compare(int from_fd, const char *from_name __unused, size_t from_len,
660 int to_fd, const char *to_name __unused, size_t to_len)
661{
662 char *p, *q;
663 int rv;
664 int done_compare;
665
666 rv = 0;
667 if (from_len != to_len)
668 return 1;
669
670 if (from_len <= MAX_CMP_SIZE) {
671#ifdef USE_MMAP
672 done_compare = 0;
673 if (trymmap(from_fd) && trymmap(to_fd)) {
674 p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
675 if (p == (char *)MAP_FAILED)
676 goto out;
677 q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
678 if (q == (char *)MAP_FAILED) {
679 munmap(p, from_len);
680 goto out;
681 }
682
683 rv = memcmp(p, q, from_len);
684 munmap(p, from_len);
685 munmap(q, from_len);
686 done_compare = 1;
687 }
688 out:
689#else
690 (void)p; (void)q;
691 done_compare = 0;
692#endif
693 if (!done_compare) {
694 char buf1[MAXBSIZE];
695 char buf2[MAXBSIZE];
696 int n1, n2;
697
698 rv = 0;
699 lseek(from_fd, 0, SEEK_SET);
700 lseek(to_fd, 0, SEEK_SET);
701 while (rv == 0) {
702 n1 = read(from_fd, buf1, sizeof(buf1));
703 if (n1 == 0)
704 break; /* EOF */
705 else if (n1 > 0) {
706 n2 = read(to_fd, buf2, n1);
707 if (n2 == n1)
708 rv = memcmp(buf1, buf2, n1);
709 else
710 rv = 1; /* out of sync */
711 } else
712 rv = 1; /* read failure */
713 }
714 lseek(from_fd, 0, SEEK_SET);
715 lseek(to_fd, 0, SEEK_SET);
716 }
717 } else
718 rv = 1; /* don't bother in this case */
719
720 return rv;
721}
722
723/*
724 * create_tempfile --
725 * create a temporary file based on path and open it
726 */
727int
728create_tempfile(const char *path, char *temp, size_t tsize)
729{
730 char *p;
731
732 (void)strncpy(temp, path, tsize);
733 temp[tsize - 1] = '\0';
734 if ((p = strrchr(temp, '/')) != NULL)
735 p++;
736 else
737 p = temp;
738 (void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p);
739 temp[tsize - 1] = '\0';
740 return (mkstemp(temp));
741}
742
743/*
744 * create_newfile --
745 * create a new file, overwriting an existing one if necessary
746 */
747int
748create_newfile(const char *path, int target, struct stat *sbp)
749{
750 char backup[MAXPATHLEN];
751 int saved_errno = 0;
752 int newfd;
753
754 if (target) {
755 /*
756 * Unlink now... avoid ETXTBSY errors later. Try to turn
757 * off the append/immutable bits -- if we fail, go ahead,
758 * it might work.
759 */
760#ifdef UF_IMMUTABLE
761 if (sbp->st_flags & NOCHANGEBITS)
762 (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS);
763#endif
764
765 if (dobackup) {
766 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s",
767 path, suffix) != strlen(path) + strlen(suffix)) {
768 errx(EX_OSERR, "%s: backup filename too long",
769 path);
770 errno = ENAMETOOLONG;
771 return -1;
772 }
773 (void)snprintf(backup, MAXPATHLEN, "%s%s",
774 path, suffix);
775 if (verbose)
776 (void)printf("install: %s -> %s\n",
777 path, backup);
778 if (rename(path, backup) < 0) {
779 err(EX_OSERR, "rename: %s to %s", path, backup);
780 return -1;
781 }
782 } else
783 if (unlink(path) < 0)
784 saved_errno = errno;
785 }
786
787 newfd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
788 if (newfd < 0 && saved_errno != 0)
789 errno = saved_errno;
790 return newfd;
791}
792
793/*
794 * copy --
795 * copy from one file to another
796 */
797static int
798copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
799 off_t size)
800{
801 int nr, nw;
802 int serrno;
803 char *p, buf[MAXBSIZE];
804 int done_copy;
805
806 /* Rewind file descriptors. */
807 if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
808 return err(EX_OSERR, "lseek: %s", from_name);
809 if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
810 return err(EX_OSERR, "lseek: %s", to_name);
811
812 /*
813 * Mmap and write if less than 8M (the limit is so we don't totally
814 * trash memory on big files. This is really a minor hack, but it
815 * wins some CPU back.
816 */
817 done_copy = 0;
818#ifdef USE_MMAP
819 if (size <= 8 * 1048576 && trymmap(from_fd) &&
820 (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED,
821 from_fd, (off_t)0)) != (char *)MAP_FAILED) {
822 if ((nw = write(to_fd, p, size)) != size) {
823 serrno = errno;
824 (void)unlink(to_name);
825 errno = nw > 0 ? EIO : serrno;
826 err(EX_OSERR, "%s", to_name);
827 }
828 done_copy = 1;
829 }
830#else
831 (void)p;
832#endif
833 if (!done_copy) {
834 while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
835 if ((nw = write(to_fd, buf, nr)) != nr) {
836 serrno = errno;
837 (void)unlink(to_name);
838 errno = nw > 0 ? EIO : serrno;
839 return err(EX_OSERR, "%s", to_name);
840 }
841 if (nr != 0) {
842 serrno = errno;
843 (void)unlink(to_name);
844 errno = serrno;
845 return err(EX_OSERR, "%s", from_name);
846 }
847 }
848 return EX_OK;
849}
850
851/*
852 * strip --
853 * use strip(1) to strip the target file
854 */
855static int
856strip(const char *to_name)
857{
858#if defined(__EMX__) || defined(_MSC_VER)
859 const char *stripbin = getenv("STRIPBIN");
860 if (stripbin == NULL)
861 stripbin = "strip";
862 return spawnlp(P_WAIT, stripbin, stripbin, to_name, NULL);
863#else
864 const char *stripbin;
865 int serrno, status;
866
867 switch (fork()) {
868 case -1:
869 serrno = errno;
870 (void)unlink(to_name);
871 errno = serrno;
872 err(EX_TEMPFAIL, "fork");
873 case 0:
874 stripbin = getenv("STRIPBIN");
875 if (stripbin == NULL)
876 stripbin = "strip";
877 execlp(stripbin, stripbin, to_name, (char *)NULL);
878 err(EX_OSERR, "exec(%s)", stripbin);
879 default:
880 if (wait(&status) == -1 || status) {
881 serrno = errno;
882 (void)unlink(to_name);
883 errno = serrno;
884 err(EX_SOFTWARE, "wait");
885 /* NOTREACHED */
886 }
887 }
888#endif
889}
890
891/*
892 * install_dir --
893 * build directory heirarchy
894 */
895static int
896install_dir(char *path)
897{
898 char *p;
899 struct stat sb;
900 int ch;
901
902 for (p = path;; ++p)
903 if (!*p || (p != path && *p == '/')) {
904 ch = *p;
905 *p = '\0';
906 if (stat(path, &sb)) {
907 if (errno != ENOENT || mkdir(path, 0755) < 0) {
908 return err(EX_OSERR, "mkdir %s", path);
909 /* NOTREACHED */
910 } else if (verbose)
911 (void)printf("install: mkdir %s\n",
912 path);
913 } else if (!S_ISDIR(sb.st_mode))
914 return errx(EX_OSERR, "%s exists but is not a directory", path);
915 if (!(*p = ch))
916 break;
917 }
918
919 if ((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid))
920 warn("chown %u:%u %s", uid, gid, path);
921 if (chmod(path, mode))
922 warn("chmod %o %s", mode, path);
923 return EX_OK;
924}
925
926/*
927 * usage --
928 * print a usage message and die
929 */
930static int
931usage()
932{
933 (void)fprintf(stderr,
934"usage: install [-bCcpSsv] [-B suffix] [-f flags] [-g group] [-m mode]\n"
935" [-o owner] file1 file2\n"
936" install [-bCcpSsv] [-B suffix] [-f flags] [-g group] [-m mode]\n"
937" [-o owner] file1 ... fileN directory\n"
938" install -d [-v] [-g group] [-m mode] [-o owner] directory ...\n");
939 return EX_USAGE;
940}
941
942#ifdef USE_MMAP
943/*
944 * trymmap --
945 * return true (1) if mmap should be tried, false (0) if not.
946 */
947static int
948trymmap(int fd)
949{
950/*
951 * The ifdef is for bootstrapping - f_fstypename doesn't exist in
952 * pre-Lite2-merge systems.
953 */
954#ifdef MFSNAMELEN
955 struct statfs stfs;
956
957 if (nommap || fstatfs(fd, &stfs) != 0)
958 return (0);
959 if (strcmp(stfs.f_fstypename, "ufs") == 0 ||
960 strcmp(stfs.f_fstypename, "cd9660") == 0)
961 return (1);
962#endif
963 return (0);
964}
965#endif
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