VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/install.c@ 3112

Last change on this file since 3112 was 3112, checked in by bird, 8 years ago

install.c: removed the unused MMAP code paths (missing unmap in the copy case, so not something we can use inside kmk without fixing it).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.9 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#include "config.h"
50#ifndef _MSC_VER
51# include <sys/param.h>
52# if !defined(__HAIKU__) && !defined(__gnu_hurd__)
53# include <sys/mount.h>
54# endif
55# include <sys/wait.h>
56# include <sys/time.h>
57#endif /* !_MSC_VER */
58#include <sys/stat.h>
59
60#include <ctype.h>
61#include "err.h"
62#include <errno.h>
63#include <fcntl.h>
64#include <grp.h>
65#include <paths.h>
66#include <pwd.h>
67#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70#ifndef __HAIKU__
71# include <sysexits.h>
72#endif
73#ifdef __NetBSD__
74# include <util.h>
75# define strtofflags(a, b, c) string_to_flags(a, b, c)
76#endif
77#include <unistd.h>
78#if defined(__EMX__) || defined(_MSC_VER)
79# include <process.h>
80#endif
81#include "getopt.h"
82#ifdef __sun__
83# include "solfakes.h"
84#endif
85#ifdef _MSC_VER
86# include "mscfakes.h"
87#endif
88#ifdef __HAIKU__
89# include "haikufakes.h"
90#endif
91#include "kmkbuiltin.h"
92#include "k/kDefs.h" /* for K_OS */
93
94
95extern void * bsd_setmode(const char *p);
96extern mode_t bsd_getmode(const void *bbox, mode_t omode);
97
98#ifndef __unused
99# define __unused
100#endif
101
102#ifndef MAXBSIZE
103# define MAXBSIZE 0x20000
104#endif
105
106/* Bootstrap aid - this doesn't exist in most older releases */
107#ifndef MAP_FAILED
108#define MAP_FAILED ((void *)-1) /* from <sys/mman.h> */
109#endif
110
111#define MAX_CMP_SIZE (16 * 1024 * 1024)
112
113#define DIRECTORY 0x01 /* Tell install it's a directory. */
114#define SETFLAGS 0x02 /* Tell install to set flags. */
115#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
116#define BACKUP_SUFFIX ".old"
117
118#ifndef O_BINARY
119# define O_BINARY 0
120#endif
121
122#ifndef EFTYPE
123# define EFTYPE EINVAL
124#endif
125
126#if defined(__WIN32__) || defined(__WIN64__) || defined(__OS2__)
127# define IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
128#else
129# define IS_SLASH(ch) ((ch) == '/')
130#endif
131
132static gid_t gid;
133static uid_t uid;
134static int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose, mode_given;
135static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
136static const char *suffix = BACKUP_SUFFIX;
137static int ignore_perm_errors;
138static int hard_link_files_when_possible;
139
140static struct option long_options[] =
141{
142 { "help", no_argument, 0, 261 },
143 { "version", no_argument, 0, 262 },
144 { "ignore-perm-errors", no_argument, 0, 263 },
145 { "no-ignore-perm-errors", no_argument, 0, 264 },
146 { "hard-link-files-when-possible", no_argument, 0, 265 },
147 { "no-hard-link-files-when-possible", no_argument, 0, 266 },
148 { 0, 0, 0, 0 },
149};
150
151
152static int copy(int, const char *, int, const char *, off_t);
153static int compare(int, const char *, size_t, int, const char *, size_t);
154static int create_newfile(const char *, int, struct stat *);
155static int create_tempfile(const char *, char *, size_t);
156static int install(const char *, const char *, u_long, u_int);
157static int install_dir(char *);
158static u_long numeric_id(const char *, const char *);
159static int strip(const char *);
160static int usage(FILE *);
161static char *last_slash(const char *);
162
163int
164kmk_builtin_install(int argc, char *argv[], char ** envp)
165{
166 struct stat from_sb, to_sb;
167 mode_t *set;
168 u_long fset = 0;
169 int ch, no_target;
170 u_int iflags;
171 char *flags;
172 const char *group, *owner, *to_name;
173 (void)envp;
174
175 /* reinitialize globals */
176 mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
177 suffix = BACKUP_SUFFIX;
178 gid = 0;
179 uid = 0;
180 dobackup = docompare = dodir = dopreserve = dostrip = nommap = safecopy = verbose = mode_given = 0;
181 ignore_perm_errors = geteuid() != 0;
182 hard_link_files_when_possible = 0;
183
184 /* reset getopt and set progname. */
185 g_progname = argv[0];
186 opterr = 1;
187 optarg = NULL;
188 optopt = 0;
189 optind = 0; /* init */
190
191 iflags = 0;
192 group = owner = NULL;
193 while ((ch = getopt_long(argc, argv, "B:bCcdf:g:Mm:o:pSsv", long_options, NULL)) != -1)
194 switch(ch) {
195 case 'B':
196 suffix = optarg;
197 /* FALLTHROUGH */
198 case 'b':
199 dobackup = 1;
200 break;
201 case 'C':
202 docompare = 1;
203 break;
204 case 'c':
205 /* For backwards compatibility. */
206 break;
207 case 'd':
208 dodir = 1;
209 break;
210 case 'f':
211#if defined(UF_IMMUTABLE) && K_OS != K_OS_GNU_KFBSD && K_OS != K_OS_GNU_HURD
212 flags = optarg;
213 if (strtofflags(&flags, &fset, NULL))
214 return errx(EX_USAGE, "%s: invalid flag", flags);
215 iflags |= SETFLAGS;
216#else
217 (void)flags;
218#endif
219 break;
220 case 'g':
221 group = optarg;
222 break;
223 case 'M':
224 nommap = 1;
225 break;
226 case 'm':
227 if (!(set = bsd_setmode(optarg)))
228 return errx(EX_USAGE, "invalid file mode: %s",
229 optarg);
230 mode = bsd_getmode(set, 0);
231 free(set);
232 mode_given = 1;
233 break;
234 case 'o':
235 owner = optarg;
236 break;
237 case 'p':
238 docompare = dopreserve = 1;
239 break;
240 case 'S':
241 safecopy = 1;
242 break;
243 case 's':
244 dostrip = 1;
245 break;
246 case 'v':
247 verbose = 1;
248 break;
249 case 261:
250 usage(stdout);
251 return 0;
252 case 262:
253 return kbuild_version(argv[0]);
254 case 263:
255 ignore_perm_errors = 1;
256 break;
257 case 264:
258 ignore_perm_errors = 0;
259 break;
260 case 265:
261 hard_link_files_when_possible = 1;
262 break;
263 case 266:
264 hard_link_files_when_possible = 0;
265 break;
266 case '?':
267 default:
268 return usage(stderr);
269 }
270 argc -= optind;
271 argv += optind;
272
273 /* some options make no sense when creating directories */
274 if (dostrip && dodir) {
275 warnx("-d and -s may not be specified together");
276 return usage(stderr);
277 }
278
279 /* must have at least two arguments, except when creating directories */
280 if (argc == 0 || (argc == 1 && !dodir))
281 return usage(stderr);
282
283 /* need to make a temp copy so we can compare stripped version */
284 if (docompare && dostrip)
285 safecopy = 1;
286
287 /* get group and owner id's */
288 if (group != NULL) {
289#ifndef _MSC_VER
290 struct group *gp;
291 if ((gp = getgrnam(group)) != NULL)
292 gid = gp->gr_gid;
293 else
294#endif
295 {
296 gid = (gid_t)numeric_id(group, "group");
297 if (gid == (gid_t)-1)
298 return 1;
299 }
300 } else
301 gid = (gid_t)-1;
302
303 if (owner != NULL) {
304#ifndef _MSC_VER
305 struct passwd *pp;
306 if ((pp = getpwnam(owner)) != NULL)
307 uid = pp->pw_uid;
308 else
309#endif
310 {
311 uid = (uid_t)numeric_id(owner, "user");
312 if (uid == (uid_t)-1)
313 return 1;
314 }
315 } else
316 uid = (uid_t)-1;
317
318 if (dodir) {
319 for (; *argv != NULL; ++argv) {
320 int rc = install_dir(*argv);
321 if (rc)
322 return rc;
323 }
324 return EX_OK;
325 /* NOTREACHED */
326 }
327
328 no_target = stat(to_name = argv[argc - 1], &to_sb);
329 if (!no_target && S_ISDIR(to_sb.st_mode)) {
330 for (; *argv != to_name; ++argv) {
331 int rc = install(*argv, to_name, fset, iflags | DIRECTORY);
332 if (rc)
333 return rc;
334 }
335 return EX_OK;
336 }
337
338 /* can't do file1 file2 directory/file */
339 if (argc != 2) {
340 warnx("wrong number or types of arguments");
341 return usage(stderr);
342 }
343
344 if (!no_target) {
345 if (stat(*argv, &from_sb))
346 return err(EX_OSERR, "%s", *argv);
347 if (!S_ISREG(to_sb.st_mode)) {
348 errno = EFTYPE;
349 return err(EX_OSERR, "%s", to_name);
350 }
351 if (to_sb.st_dev == from_sb.st_dev &&
352 to_sb.st_dev != 0 &&
353 to_sb.st_ino == from_sb.st_ino &&
354 to_sb.st_ino != 0 &&
355 !hard_link_files_when_possible)
356 return errx(EX_USAGE,
357 "%s and %s are the same file", *argv, to_name);
358 }
359 return install(*argv, to_name, fset, iflags);
360}
361
362static u_long
363numeric_id(const char *name, const char *type)
364{
365 u_long val;
366 char *ep;
367
368 /*
369 * XXX
370 * We know that uid_t's and gid_t's are unsigned longs.
371 */
372 errno = 0;
373 val = strtoul(name, &ep, 10);
374 if (errno)
375 return err(-1, "%s", name);
376 if (*ep != '\0')
377 return errx(-1, "unknown %s %s", type, name);
378 return (val);
379}
380
381/*
382 * install --
383 * build a path name and install the file
384 */
385static int
386install(const char *from_name, const char *to_name, u_long fset, u_int flags)
387{
388 struct stat from_sb, temp_sb, to_sb;
389 struct timeval tvb[2];
390 int devnull, files_match, from_fd, serrno, target;
391 int tempcopy, temp_fd, to_fd;
392 char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
393 int rc = EX_OK;
394
395 files_match = 0;
396 from_fd = -1;
397 to_fd = -1;
398 temp_fd = -1;
399
400 /* If try to install NULL file to a directory, fails. */
401 if (flags & DIRECTORY
402#if defined(__EMX__) || defined(_MSC_VER)
403 || ( stricmp(from_name, _PATH_DEVNULL)
404 && stricmp(from_name, "nul")
405# ifdef __EMX__
406 && stricmp(from_name, "/dev/nul")
407# endif
408 )
409#else
410 || strcmp(from_name, _PATH_DEVNULL)
411#endif
412 ) {
413 if (stat(from_name, &from_sb))
414 return err(EX_OSERR, "%s", from_name);
415 if (!S_ISREG(from_sb.st_mode)) {
416 errno = EFTYPE;
417 return err(EX_OSERR, "%s", from_name);
418 }
419 /* Build the target path. */
420 if (flags & DIRECTORY) {
421 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
422 to_name,
423 (p = last_slash(from_name)) ? ++p : from_name);
424 to_name = pathbuf;
425 }
426 devnull = 0;
427 } else {
428 devnull = 1;
429 }
430
431 target = stat(to_name, &to_sb) == 0;
432
433 /* Only install to regular files. */
434 if (target && !S_ISREG(to_sb.st_mode)) {
435 errno = EFTYPE;
436 warn("%s", to_name);
437 return EX_OK;
438 }
439
440 /* Only copy safe if the target exists. */
441 tempcopy = safecopy && target;
442
443 /* Try hard linking if wanted and possible. */
444 if (hard_link_files_when_possible)
445 {
446#ifdef KBUILD_OS_OS2
447 const char *why_not = "not supported on OS/2";
448#else
449 const char *why_not = NULL;
450 if (devnull) {
451 why_not = "/dev/null";
452 } else if (dostrip) {
453 why_not = "strip (-s)";
454 } else if (docompare) {
455 why_not = "compare (-C)";
456 } else if (dobackup) {
457 why_not = "backup (-b/-B)";
458 } else if (safecopy) {
459 why_not = "safe copy (-S)";
460 } else if (lstat(from_name, &temp_sb)) {
461 why_not = "lstat on source failed";
462 } else if (S_ISLNK(temp_sb.st_mode)) {
463 why_not = "symlink";
464 } else if (!S_ISREG(temp_sb.st_mode)) {
465 why_not = "not regular file";
466# if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
467 } else if ((mode & S_IWUSR) != (from_sb.st_mode & S_IWUSR)) {
468# else
469 } else if (mode != (from_sb.st_mode & ALLPERMS)) {
470# endif
471 printf("install: warning: Not hard linking, mode differs: 0%03o, desires 0%03o\n"
472 "install: src path '%s'\n"
473 "install: dst path '%s'\n",
474 (from_sb.st_mode & ALLPERMS), mode, from_name, to_name);
475 why_not = NULL;
476 } else if (uid != (uid_t)-1 && gid != from_sb.st_uid) {
477 why_not = "uid mismatch";
478 } else if (gid != (gid_t)-1 && gid != from_sb.st_gid) {
479 why_not = "gid mismatch";
480 } else {
481 int rcLink = link(from_name, to_name);
482 if (rcLink != 0 && errno == EEXIST) {
483 unlink(to_name);
484 rcLink = link(from_name, to_name);
485 }
486 if (rcLink == 0) {
487 if (verbose)
488 printf("install: %s -> %s (hardlinked)\n", from_name, to_name);
489 goto l_done;
490 }
491 if (verbose)
492 printf("install: hard linking '%s' to '%s' failed: %s\n",
493 to_name, from_name, strerror(errno));
494 why_not = NULL;
495 }
496#endif
497 if (verbose && why_not)
498 printf("install: not hard linking '%s' to '%s' because: %s\n",
499 to_name, from_name, why_not);
500
501 /* Can't hard link or we failed, continue as nothing happend. */
502 }
503
504 if (!devnull && (from_fd = open(from_name, O_RDONLY | O_BINARY, 0)) < 0)
505 return err(EX_OSERR, "%s", from_name);
506
507 /* If we don't strip, we can compare first. */
508 if (docompare && !dostrip && target) {
509 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
510 rc = err(EX_OSERR, "%s", to_name);
511 goto l_done;
512 }
513 if (devnull)
514 files_match = to_sb.st_size == 0;
515 else
516 files_match = !(compare(from_fd, from_name,
517 (size_t)from_sb.st_size, to_fd,
518 to_name, (size_t)to_sb.st_size));
519
520 /* Close "to" file unless we match. */
521 if (!files_match) {
522 (void)close(to_fd);
523 to_fd = -1;
524 }
525 }
526
527 if (!files_match) {
528 if (tempcopy) {
529 to_fd = create_tempfile(to_name, tempfile,
530 sizeof(tempfile));
531 if (to_fd < 0) {
532 rc = err(EX_OSERR, "%s", tempfile);
533 goto l_done;
534 }
535 } else {
536 if ((to_fd = create_newfile(to_name, target,
537 &to_sb)) < 0) {
538 rc = err(EX_OSERR, "%s", to_name);
539 goto l_done;
540 }
541 if (verbose)
542 (void)printf("install: %s -> %s\n",
543 from_name, to_name);
544 }
545 if (!devnull) {
546 rc = copy(from_fd, from_name, to_fd,
547 tempcopy ? tempfile : to_name, from_sb.st_size);
548 if (rc)
549 goto l_done;
550 }
551 }
552
553 if (dostrip) {
554#if defined(__EMX__) || defined(_MSC_VER)
555 /* close before we strip. */
556 close(to_fd);
557 to_fd = -1;
558#endif
559 rc = strip(tempcopy ? tempfile : to_name);
560 if (rc)
561 goto l_done;
562
563 /*
564 * Re-open our fd on the target, in case we used a strip
565 * that does not work in-place -- like GNU binutils strip.
566 */
567#if !defined(__EMX__) && !defined(_MSC_VER)
568 close(to_fd);
569#endif
570 to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY | O_BINARY, 0);
571 if (to_fd < 0) {
572 rc = err(EX_OSERR, "stripping %s", to_name);
573 goto l_done;
574 }
575 }
576
577 /*
578 * Compare the stripped temp file with the target.
579 */
580 if (docompare && dostrip && target) {
581 temp_fd = to_fd;
582
583 /* Re-open to_fd using the real target name. */
584 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
585 rc = err(EX_OSERR, "%s", to_name);
586 goto l_done;
587 }
588
589 if (fstat(temp_fd, &temp_sb)) {
590 serrno = errno;
591 (void)unlink(tempfile);
592 errno = serrno;
593 rc = err(EX_OSERR, "%s", tempfile);
594 goto l_done;
595 }
596
597 if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
598 to_name, (size_t)to_sb.st_size) == 0) {
599 /*
600 * If target has more than one link we need to
601 * replace it in order to snap the extra links.
602 * Need to preserve target file times, though.
603 */
604#if !defined(_MSC_VER) && !defined(__EMX__)
605 if (to_sb.st_nlink != 1) {
606 tvb[0].tv_sec = to_sb.st_atime;
607 tvb[0].tv_usec = 0;
608 tvb[1].tv_sec = to_sb.st_mtime;
609 tvb[1].tv_usec = 0;
610 (void)utimes(tempfile, tvb);
611 } else
612#endif
613 {
614
615 files_match = 1;
616 (void)unlink(tempfile);
617 }
618 (void) close(temp_fd);
619 temp_fd = -1;
620 }
621 }
622
623 /*
624 * Move the new file into place if doing a safe copy
625 * and the files are different (or just not compared).
626 */
627 if (tempcopy && !files_match) {
628#ifdef UF_IMMUTABLE
629 /* Try to turn off the immutable bits. */
630 if (to_sb.st_flags & NOCHANGEBITS)
631 (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
632#endif
633 if (dobackup) {
634 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name,
635 suffix) != strlen(to_name) + strlen(suffix)) {
636 unlink(tempfile);
637 rc = errx(EX_OSERR, "%s: backup filename too long",
638 to_name);
639 goto l_done;
640 }
641 if (verbose)
642 (void)printf("install: %s -> %s\n", to_name, backup);
643 if (rename(to_name, backup) < 0) {
644 serrno = errno;
645 unlink(tempfile);
646 errno = serrno;
647 rc = err(EX_OSERR, "rename: %s to %s", to_name,
648 backup);
649 goto l_done;
650 }
651 }
652 if (verbose)
653 (void)printf("install: %s -> %s\n", from_name, to_name);
654 if (rename(tempfile, to_name) < 0) {
655 serrno = errno;
656 unlink(tempfile);
657 errno = serrno;
658 rc = err(EX_OSERR, "rename: %s to %s",
659 tempfile, to_name);
660 goto l_done;
661 }
662
663 /* Re-open to_fd so we aren't hosed by the rename(2). */
664 (void) close(to_fd);
665 if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
666 rc = err(EX_OSERR, "%s", to_name);
667 goto l_done;
668 }
669 }
670
671 /*
672 * Preserve the timestamp of the source file if necessary.
673 */
674 if (dopreserve && !files_match && !devnull) {
675 tvb[0].tv_sec = from_sb.st_atime;
676 tvb[0].tv_usec = 0;
677 tvb[1].tv_sec = from_sb.st_mtime;
678 tvb[1].tv_usec = 0;
679 (void)utimes(to_name, tvb);
680 }
681
682 if (fstat(to_fd, &to_sb) == -1) {
683 serrno = errno;
684 (void)unlink(to_name);
685 errno = serrno;
686 rc = err(EX_OSERR, "%s", to_name);
687 goto l_done;
688 }
689
690 /*
691 * Set owner, group, mode for target; do the chown first,
692 * chown may lose the setuid bits.
693 */
694#ifdef UF_IMMUTABLE
695 if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
696 (uid != (uid_t)-1 && uid != to_sb.st_uid) ||
697 (mode != (to_sb.st_mode & ALLPERMS))) {
698 /* Try to turn off the immutable bits. */
699 if (to_sb.st_flags & NOCHANGEBITS)
700 (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS);
701 }
702#endif
703
704 if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
705 (uid != (uid_t)-1 && uid != to_sb.st_uid))
706 if (fchown(to_fd, uid, gid) == -1) {
707 if (errno == EPERM && ignore_perm_errors) {
708 warn("%s: ignoring chown uid=%d gid=%d failure", to_name, (int)uid, (int)gid);
709 } else {
710 serrno = errno;
711 (void)unlink(to_name);
712 errno = serrno;
713 rc = err(EX_OSERR,"%s: chown/chgrp", to_name);
714 goto l_done;
715 }
716 }
717
718 if (mode != (to_sb.st_mode & ALLPERMS))
719 if (fchmod(to_fd, mode)) {
720 serrno = errno;
721 if (serrno == EPERM && ignore_perm_errors) {
722 fchmod(to_fd, mode & (ALLPERMS & ~0007000));
723 errno = errno;
724 warn("%s: ignoring chmod 0%o failure", to_name, (int)(mode & ALLPERMS));
725 } else {
726 serrno = errno;
727 (void)unlink(to_name);
728 errno = serrno;
729 rc = err(EX_OSERR, "%s: chmod", to_name);
730 goto l_done;
731 }
732 }
733
734 /*
735 * If provided a set of flags, set them, otherwise, preserve the
736 * flags, except for the dump flag.
737 * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just
738 * trying to turn off UF_NODUMP. If we're trying to set real flags,
739 * then warn if the the fs doesn't support it, otherwise fail.
740 */
741#ifdef UF_IMMUTABLE
742 if (!devnull && (flags & SETFLAGS ||
743 (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) &&
744 fchflags(to_fd,
745 flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
746 if (flags & SETFLAGS) {
747 if (errno == EOPNOTSUPP)
748 warn("%s: chflags", to_name);
749 else {
750 serrno = errno;
751 (void)unlink(to_name);
752 errno = serrno;
753 rc = err(EX_OSERR, "%s: chflags", to_name);
754 goto l_done;
755 }
756 }
757 }
758#endif
759
760l_done:
761 if (to_fd >= 0)
762 (void)close(to_fd);
763 if (temp_fd >= 0)
764 (void)close(temp_fd);
765 if (from_fd >= 0 && !devnull)
766 (void)close(from_fd);
767 return rc;
768}
769
770/*
771 * compare --
772 * compare two files; non-zero means files differ
773 */
774static int
775compare(int from_fd, const char *from_name __unused, size_t from_len,
776 int to_fd, const char *to_name __unused, size_t to_len)
777{
778 char buf1[MAXBSIZE];
779 char buf2[MAXBSIZE];
780 int n1, n2;
781 int rv;
782
783 if (from_len != to_len)
784 return 1;
785
786 if (from_len <= MAX_CMP_SIZE) {
787 rv = 0;
788 lseek(from_fd, 0, SEEK_SET);
789 lseek(to_fd, 0, SEEK_SET);
790 while (rv == 0) {
791 n1 = read(from_fd, buf1, sizeof(buf1));
792 if (n1 == 0)
793 break; /* EOF */
794 else if (n1 > 0) {
795 n2 = read(to_fd, buf2, n1);
796 if (n2 == n1)
797 rv = memcmp(buf1, buf2, n1);
798 else
799 rv = 1; /* out of sync */
800 } else
801 rv = 1; /* read failure */
802 }
803 lseek(from_fd, 0, SEEK_SET);
804 lseek(to_fd, 0, SEEK_SET);
805 } else
806 rv = 1; /* don't bother in this case */
807
808 return rv;
809}
810
811/*
812 * create_tempfile --
813 * create a temporary file based on path and open it
814 */
815int
816create_tempfile(const char *path, char *temp, size_t tsize)
817{
818 char *p;
819
820 (void)strncpy(temp, path, tsize);
821 temp[tsize - 1] = '\0';
822 if ((p = last_slash(temp)) != NULL)
823 p++;
824 else
825 p = temp;
826 (void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p);
827 temp[tsize - 1] = '\0';
828 return (mkstemp(temp));
829}
830
831/*
832 * create_newfile --
833 * create a new file, overwriting an existing one if necessary
834 */
835int
836create_newfile(const char *path, int target, struct stat *sbp)
837{
838 char backup[MAXPATHLEN];
839 int saved_errno = 0;
840 int newfd;
841
842 if (target) {
843 /*
844 * Unlink now... avoid ETXTBSY errors later. Try to turn
845 * off the append/immutable bits -- if we fail, go ahead,
846 * it might work.
847 */
848#ifdef UF_IMMUTABLE
849 if (sbp->st_flags & NOCHANGEBITS)
850 (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS);
851#endif
852
853 if (dobackup) {
854 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s",
855 path, suffix) != strlen(path) + strlen(suffix)) {
856 errx(EX_OSERR, "%s: backup filename too long",
857 path);
858 errno = ENAMETOOLONG;
859 return -1;
860 }
861 (void)snprintf(backup, MAXPATHLEN, "%s%s",
862 path, suffix);
863 if (verbose)
864 (void)printf("install: %s -> %s\n",
865 path, backup);
866 if (rename(path, backup) < 0) {
867 err(EX_OSERR, "rename: %s to %s", path, backup);
868 return -1;
869 }
870 } else
871 if (unlink(path) < 0)
872 saved_errno = errno;
873 }
874
875 newfd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
876 if (newfd < 0 && saved_errno != 0)
877 errno = saved_errno;
878 return newfd;
879}
880
881/*
882 * copy --
883 * copy from one file to another
884 */
885static int
886copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
887 off_t size)
888{
889 int nr, nw;
890 int serrno;
891 char buf[MAXBSIZE];
892
893 (void)size;
894
895 /* Rewind file descriptors. */
896 if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
897 return err(EX_OSERR, "lseek: %s", from_name);
898 if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
899 return err(EX_OSERR, "lseek: %s", to_name);
900
901 while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
902 if ((nw = write(to_fd, buf, nr)) != nr) {
903 serrno = errno;
904 (void)unlink(to_name);
905 errno = nw > 0 ? EIO : serrno;
906 return err(EX_OSERR, "%s", to_name);
907 }
908 if (nr != 0) {
909 serrno = errno;
910 (void)unlink(to_name);
911 errno = serrno;
912 return err(EX_OSERR, "%s", from_name);
913 }
914 return EX_OK;
915}
916
917/*
918 * strip --
919 * use strip(1) to strip the target file
920 */
921static int
922strip(const char *to_name)
923{
924#if defined(__EMX__) || defined(_MSC_VER)
925 const char *stripbin = getenv("STRIPBIN");
926 if (stripbin == NULL)
927 stripbin = "strip";
928 return spawnlp(P_WAIT, stripbin, stripbin, to_name, NULL);
929#else
930 const char *stripbin;
931 int serrno, status;
932 pid_t pid;
933
934 pid = fork();
935 switch (pid) {
936 case -1:
937 serrno = errno;
938 (void)unlink(to_name);
939 errno = serrno;
940 return err(EX_TEMPFAIL, "fork");
941 case 0:
942 stripbin = getenv("STRIPBIN");
943 if (stripbin == NULL)
944 stripbin = "strip";
945 execlp(stripbin, stripbin, to_name, (char *)NULL);
946 err(EX_OSERR, "exec(%s)", stripbin);
947 exit(EX_OSERR);
948 default:
949 if (waitpid(pid, &status, 0) == -1 || status) {
950 serrno = errno;
951 (void)unlink(to_name);
952 errno = serrno;
953 return err(EX_SOFTWARE, "waitpid");
954 /* NOTREACHED */
955 }
956 }
957 return 0;
958#endif
959}
960
961/*
962 * install_dir --
963 * build directory heirarchy
964 */
965static int
966install_dir(char *path)
967{
968 char *p;
969 struct stat sb;
970 int ch;
971
972 for (p = path;; ++p)
973 if ( !*p
974 || ( p != path
975 && IS_SLASH(*p)
976#if defined(_MSC_VER) /* stat("C:") fails (VC++ v10). Just skip it since it's unnecessary. */
977 && (p - path != 2 || p[-1] != ':')
978#endif
979 )) {
980 ch = *p;
981 *p = '\0';
982 if (stat(path, &sb)) {
983 if (errno != ENOENT || mkdir(path, 0755) < 0) {
984 return err(EX_OSERR, "mkdir %s", path);
985 /* NOTREACHED */
986 } else if (verbose)
987 (void)printf("install: mkdir %s\n",
988 path);
989 } else if (!S_ISDIR(sb.st_mode))
990 return errx(EX_OSERR, "%s exists but is not a directory", path);
991 if (!(*p = ch))
992 break;
993 }
994
995 if ((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid))
996 warn("chown %u:%u %s", uid, gid, path);
997 if (chmod(path, mode))
998 warn("chmod %o %s", mode, path);
999 return EX_OK;
1000}
1001
1002/*
1003 * usage --
1004 * print a usage message and die
1005 */
1006static int
1007usage(FILE *pf)
1008{
1009 fprintf(pf,
1010"usage: %s [-bCcpSsv] [--[no-]hard-link-files-when-possible]\n"
1011" [--[no-]ignore-perm-errors] [-B suffix] [-f flags]\n"
1012" [-g group] [-m mode] [-o owner] file1 file2\n"
1013" or: %s [-bCcpSsv] [--[no-]ignore-perm-errors] [-B suffix] [-f flags]\n"
1014" [-g group] [-m mode] [-o owner] file1 ... fileN directory\n"
1015" or: %s -d [-v] [-g group] [-m mode] [-o owner] directory ...\n"
1016" or: %s --help\n"
1017" or: %s --version\n",
1018 g_progname, g_progname, g_progname, g_progname, g_progname);
1019 return EX_USAGE;
1020}
1021
1022/* figures out where the last slash or colon is. */
1023static char *
1024last_slash(const char *path)
1025{
1026#if defined(__WIN32__) || defined(__WIN64__) || defined(__OS2__)
1027 char *p = (char *)strrchr(path, '/');
1028 if (p)
1029 {
1030 char *p2 = strrchr(p, '\\');
1031 if (p2)
1032 p = p2;
1033 }
1034 else
1035 {
1036 p = (char *)strrchr(path, '\\');
1037 if (!p && isalpha(path[0]) && path[1] == ':')
1038 p = (char *)&path[1];
1039 }
1040 return p;
1041#else
1042 return strrchr(path, '/');
1043#endif
1044}
1045
Note: See TracBrowser for help on using the repository browser.

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