VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/cp.c@ 3192

Last change on this file since 3192 was 3192, checked in by bird, 7 years ago

kmkbuiltin: funnel output thru output.c (usually via err.c).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1/*
2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * David Hitz of Auspex Systems Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#if 0
34#ifndef lint
35static char const copyright[] =
36"@(#) Copyright (c) 1988, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94";
42#endif /* not lint */
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.50 2004/04/06 20:06:44 markm Exp $");
45#endif
46
47/*
48 * Cp copies source files to target files.
49 *
50 * The global PATH_T structure "to" always contains the path to the
51 * current target file. Since fts(3) does not change directories,
52 * this path can be either absolute or dot-relative.
53 *
54 * The basic algorithm is to initialize "to" and use fts(3) to traverse
55 * the file hierarchy rooted in the argument list. A trivial case is the
56 * case of 'cp file1 file2'. The more interesting case is the case of
57 * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
58 * path (relative to the root of the traversal) is appended to dir (stored
59 * in "to") to form the final target path.
60 */
61
62#include "config.h"
63#include <sys/types.h>
64#include <sys/stat.h>
65
66#include "err.h"
67#include <errno.h>
68#include "fts.h"
69#include <limits.h>
70#include <signal.h>
71#include <stdio.h>
72#include <stdlib.h>
73#include <string.h>
74#include <unistd.h>
75#include "getopt.h"
76#include "k/kDefs.h"
77#ifdef _MSC_VER
78# include "mscfakes.h"
79#endif
80#include "cp_extern.h"
81#include "kmkbuiltin.h"
82#include "kbuild_protection.h"
83
84#if defined(_MSC_VER) || defined(__gnu_linux__) || defined(__linux__)
85extern size_t strlcpy(char *, const char *, size_t);
86#endif
87
88
89#ifndef S_IFWHT
90#define S_IFWHT 0
91#define S_ISWHT(s) 0
92#define undelete(s) (-1)
93#endif
94
95#ifndef S_ISTXT
96#ifdef S_ISVTX
97#define S_ISTXT S_ISVTX
98#else
99#define S_ISTXT 0
100#endif
101#endif /* !S_ISTXT */
102
103#ifndef __unused
104# define __unused
105#endif
106
107#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
108# define IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
109#else
110# define IS_SLASH(ch) ((ch) == '/')
111#endif
112
113#define STRIP_TRAILING_SLASH(p) { \
114 while ((p).p_end > (p).p_path + 1 && IS_SLASH((p).p_end[-1])) \
115 *--(p).p_end = 0; \
116}
117
118/* have wrappers for globals in cp_extern! */
119
120static KBUILDPROTECTION g_ProtData;
121const char *cp_argv0;
122static char emptystring[] = "";
123
124PATH_T to = { to.p_path, emptystring, "" };
125
126int fflag, iflag, nflag, pflag, vflag;
127static int Rflag, rflag;
128volatile sig_atomic_t info;
129static int cp_ignore_non_existing, cp_changed_only;
130
131enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
132
133enum cp_arg {
134 CP_OPT_HELP = 261,
135 CP_OPT_VERSION,
136 CP_OPT_IGNORE_NON_EXISTING,
137 CP_OPT_CHANGED,
138 CP_OPT_DISABLE_PROTECTION,
139 CP_OPT_ENABLE_PROTECTION,
140 CP_OPT_ENABLE_FULL_PROTECTION,
141 CP_OPT_DISABLE_FULL_PROTECTION,
142 CP_OPT_PROTECTION_DEPTH
143};
144static struct option long_options[] =
145{
146 { "help", no_argument, 0, CP_OPT_HELP },
147 { "version", no_argument, 0, CP_OPT_VERSION },
148 { "ignore-non-existing", no_argument, 0, CP_OPT_IGNORE_NON_EXISTING },
149 { "changed", no_argument, 0, CP_OPT_CHANGED },
150 { "disable-protection", no_argument, 0, CP_OPT_DISABLE_PROTECTION },
151 { "enable-protection", no_argument, 0, CP_OPT_ENABLE_PROTECTION },
152 { "enable-full-protection", no_argument, 0, CP_OPT_ENABLE_FULL_PROTECTION },
153 { "disable-full-protection", no_argument, 0, CP_OPT_DISABLE_FULL_PROTECTION },
154 { "protection-depth", required_argument, 0, CP_OPT_PROTECTION_DEPTH },
155 { 0, 0, 0, 0 },
156};
157
158
159static int copy(PKMKBUILTINCTX pCtx, char *[], enum op, int);
160static int mastercmp(const FTSENT **, const FTSENT **);
161#ifdef SIGINFO
162static void siginfo(int __unused);
163#endif
164static int usage(PKMKBUILTINCTX, int);
165
166int
167kmk_builtin_cp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
168{
169 struct stat to_stat, tmp_stat;
170 enum op type;
171 int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash, rc;
172 char *target;
173
174 /* init globals */
175 cp_argv0 = argv[0];
176 to.p_end = to.p_path;
177 to.target_end = emptystring;
178 memset(to.p_path, 0, sizeof(to.p_path));
179 fflag = iflag = nflag = pflag = vflag = Rflag = rflag = 0;
180 info = 0;
181 cp_ignore_non_existing = cp_changed_only = 0;
182 kBuildProtectionInit(&g_ProtData, pCtx);
183
184 /* reset getopt and set progname. */
185 opterr = 1;
186 optarg = NULL;
187 optopt = 0;
188 optind = 0; /* init */
189
190 Hflag = Lflag = Pflag = 0;
191 while ((ch = getopt_long(argc, argv, "HLPRfinprv", long_options, NULL)) != -1)
192 switch (ch) {
193 case 'H':
194 Hflag = 1;
195 Lflag = Pflag = 0;
196 break;
197 case 'L':
198 Lflag = 1;
199 Hflag = Pflag = 0;
200 break;
201 case 'P':
202 Pflag = 1;
203 Hflag = Lflag = 0;
204 break;
205 case 'R':
206 Rflag = 1;
207 break;
208 case 'f':
209 fflag = 1;
210 iflag = nflag = 0;
211 break;
212 case 'i':
213 iflag = 1;
214 fflag = nflag = 0;
215 break;
216 case 'n':
217 nflag = 1;
218 fflag = iflag = 0;
219 break;
220 case 'p':
221 pflag = 1;
222 break;
223 case 'r':
224 rflag = 1;
225 break;
226 case 'v':
227 vflag = 1;
228 break;
229 case CP_OPT_HELP:
230 usage(pCtx, 0);
231 kBuildProtectionTerm(&g_ProtData);
232 return 0;
233 case CP_OPT_VERSION:
234 kBuildProtectionTerm(&g_ProtData);
235 return kbuild_version(argv[0]);
236 case CP_OPT_IGNORE_NON_EXISTING:
237 cp_ignore_non_existing = 1;
238 break;
239 case CP_OPT_CHANGED:
240 cp_changed_only = 1;
241 break;
242 case CP_OPT_DISABLE_PROTECTION:
243 kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
244 break;
245 case CP_OPT_ENABLE_PROTECTION:
246 kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
247 break;
248 case CP_OPT_ENABLE_FULL_PROTECTION:
249 kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
250 break;
251 case CP_OPT_DISABLE_FULL_PROTECTION:
252 kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
253 break;
254 case CP_OPT_PROTECTION_DEPTH:
255 if (kBuildProtectionSetDepth(&g_ProtData, optarg)) {
256 kBuildProtectionTerm(&g_ProtData);
257 return 1;
258 }
259 break;
260 default:
261 kBuildProtectionTerm(&g_ProtData);
262 return usage(pCtx, 1);
263 }
264 argc -= optind;
265 argv += optind;
266
267 if (argc < 2) {
268 kBuildProtectionTerm(&g_ProtData);
269 return usage(pCtx, 1);
270 }
271
272 fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
273 if (rflag) {
274 if (Rflag) {
275 kBuildProtectionTerm(&g_ProtData);
276 return errx(pCtx, 1,
277 "the -R and -r options may not be specified together.");
278 }
279 if (Hflag || Lflag || Pflag)
280 errx(pCtx, 1,
281 "the -H, -L, and -P options may not be specified with the -r option.");
282 fts_options &= ~FTS_PHYSICAL;
283 fts_options |= FTS_LOGICAL;
284 }
285 if (Rflag) {
286 if (Hflag)
287 fts_options |= FTS_COMFOLLOW;
288 if (Lflag) {
289 fts_options &= ~FTS_PHYSICAL;
290 fts_options |= FTS_LOGICAL;
291 }
292 } else {
293 fts_options &= ~FTS_PHYSICAL;
294 fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
295 }
296#ifdef SIGINFO
297 (void)signal(SIGINFO, siginfo);
298#endif
299
300 /* Save the target base in "to". */
301 target = argv[--argc];
302 if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) {
303 kBuildProtectionTerm(&g_ProtData);
304 return errx(pCtx, 1, "%s: name too long", target);
305 }
306 to.p_end = to.p_path + strlen(to.p_path);
307 if (to.p_path == to.p_end) {
308 *to.p_end++ = '.';
309 *to.p_end = 0;
310 }
311 have_trailing_slash = IS_SLASH(to.p_end[-1]);
312 if (have_trailing_slash)
313 STRIP_TRAILING_SLASH(to);
314 to.target_end = to.p_end;
315
316 /* Set end of argument list for fts(3). */
317 argv[argc] = NULL;
318
319 /*
320 * Cp has two distinct cases:
321 *
322 * cp [-R] source target
323 * cp [-R] source1 ... sourceN directory
324 *
325 * In both cases, source can be either a file or a directory.
326 *
327 * In (1), the target becomes a copy of the source. That is, if the
328 * source is a file, the target will be a file, and likewise for
329 * directories.
330 *
331 * In (2), the real target is not directory, but "directory/source".
332 */
333 r = stat(to.p_path, &to_stat);
334 if (r == -1 && errno != ENOENT) {
335 kBuildProtectionTerm(&g_ProtData);
336 return err(pCtx, 1, "stat: %s", to.p_path);
337 }
338 if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
339 /*
340 * Case (1). Target is not a directory.
341 */
342 if (argc > 1) {
343 kBuildProtectionTerm(&g_ProtData);
344 return usage(pCtx, 1);
345 }
346 /*
347 * Need to detect the case:
348 * cp -R dir foo
349 * Where dir is a directory and foo does not exist, where
350 * we want pathname concatenations turned on but not for
351 * the initial mkdir().
352 */
353 if (r == -1) {
354 if (rflag || (Rflag && (Lflag || Hflag)))
355 stat(*argv, &tmp_stat);
356 else
357 lstat(*argv, &tmp_stat);
358
359 if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
360 type = DIR_TO_DNE;
361 else
362 type = FILE_TO_FILE;
363 } else
364 type = FILE_TO_FILE;
365
366 if (have_trailing_slash && type == FILE_TO_FILE) {
367 kBuildProtectionTerm(&g_ProtData);
368 if (r == -1)
369 return errx(pCtx, 1, "directory %s does not exist",
370 to.p_path);
371 else
372 return errx(pCtx, 1, "%s is not a directory", to.p_path);
373 }
374 } else
375 /*
376 * Case (2). Target is a directory.
377 */
378 type = FILE_TO_DIR;
379
380 /* Finally, check that the "to" directory isn't protected. */
381 rc = 1;
382 if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_CP_")
383 && !kBuildProtectionEnforce(&g_ProtData,
384 Rflag || rflag
385 ? KBUILDPROTECTIONTYPE_RECURSIVE
386 : KBUILDPROTECTIONTYPE_FULL,
387 to.p_path)) {
388 rc = copy(pCtx, argv, type, fts_options);
389 }
390
391 kBuildProtectionTerm(&g_ProtData);
392 return rc;
393}
394
395#ifdef KMK_BUILTIN_STANDALONE
396int main(int argc, char **argv, char **envp)
397{
398 KMKBUILTINCTX Ctx = { "kmk_cp", NULL };
399 return kmk_builtin_cp(argc, argv, envp, &Ctx);
400}
401#endif
402
403static int
404copy(PKMKBUILTINCTX pCtx, char *argv[], enum op type, int fts_options)
405{
406 struct stat to_stat;
407 FTS *ftsp;
408 FTSENT *curr;
409 int base = 0, dne, badcp, rval;
410 size_t nlen;
411 char *p, *target_mid;
412 mode_t mask, mode;
413
414 /*
415 * Keep an inverted copy of the umask, for use in correcting
416 * permissions on created directories when not using -p.
417 */
418 mask = ~umask(0777);
419 umask(~mask);
420
421 if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
422 return err(pCtx, 1, "fts_open");
423 for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
424 int copied = 0;
425
426 switch (curr->fts_info) {
427 case FTS_NS:
428 if ( cp_ignore_non_existing
429 && curr->fts_errno == ENOENT) {
430 if (vflag) {
431 warnx(pCtx, "fts: %s: %s", curr->fts_path,
432 strerror(curr->fts_errno));
433 }
434 continue;
435 }
436 /* fall thru */
437 case FTS_DNR:
438 case FTS_ERR:
439 warnx(pCtx, "fts: %s: %s",
440 curr->fts_path, strerror(curr->fts_errno));
441 badcp = rval = 1;
442 continue;
443 case FTS_DC: /* Warn, continue. */
444 warnx(pCtx, "%s: directory causes a cycle", curr->fts_path);
445 badcp = rval = 1;
446 continue;
447 default:
448 ;
449 }
450
451 /*
452 * If we are in case (2) or (3) above, we need to append the
453 * source name to the target name.
454 */
455 if (type != FILE_TO_FILE) {
456 /*
457 * Need to remember the roots of traversals to create
458 * correct pathnames. If there's a directory being
459 * copied to a non-existent directory, e.g.
460 * cp -R a/dir noexist
461 * the resulting path name should be noexist/foo, not
462 * noexist/dir/foo (where foo is a file in dir), which
463 * is the case where the target exists.
464 *
465 * Also, check for "..". This is for correct path
466 * concatenation for paths ending in "..", e.g.
467 * cp -R .. /tmp
468 * Paths ending in ".." are changed to ".". This is
469 * tricky, but seems the easiest way to fix the problem.
470 *
471 * XXX
472 * Since the first level MUST be FTS_ROOTLEVEL, base
473 * is always initialized.
474 */
475 if (curr->fts_level == FTS_ROOTLEVEL) {
476 if (type != DIR_TO_DNE) {
477 p = strrchr(curr->fts_path, '/');
478#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
479 if (strrchr(curr->fts_path, '\\') > p)
480 p = strrchr(curr->fts_path, '\\');
481#endif
482 base = (p == NULL) ? 0 :
483 (int)(p - curr->fts_path + 1);
484
485 if (!strcmp(&curr->fts_path[base],
486 ".."))
487 base += 1;
488 } else
489 base = curr->fts_pathlen;
490 }
491
492 p = &curr->fts_path[base];
493 nlen = curr->fts_pathlen - base;
494 target_mid = to.target_end;
495 if (!IS_SLASH(*p) && !IS_SLASH(target_mid[-1]))
496 *target_mid++ = '/';
497 *target_mid = 0;
498 if (target_mid - to.p_path + nlen >= PATH_MAX) {
499 warnx(pCtx, "%s%s: name too long (not copied)",
500 to.p_path, p);
501 badcp = rval = 1;
502 continue;
503 }
504 (void)strncat(target_mid, p, nlen);
505 to.p_end = target_mid + nlen;
506 *to.p_end = 0;
507 STRIP_TRAILING_SLASH(to);
508 }
509
510 if (curr->fts_info == FTS_DP) {
511 /*
512 * We are nearly finished with this directory. If we
513 * didn't actually copy it, or otherwise don't need to
514 * change its attributes, then we are done.
515 */
516 if (!curr->fts_number)
517 continue;
518 /*
519 * If -p is in effect, set all the attributes.
520 * Otherwise, set the correct permissions, limited
521 * by the umask. Optimise by avoiding a chmod()
522 * if possible (which is usually the case if we
523 * made the directory). Note that mkdir() does not
524 * honour setuid, setgid and sticky bits, but we
525 * normally want to preserve them on directories.
526 */
527 if (pflag) {
528 if (setfile(pCtx, curr->fts_statp, -1))
529 rval = 1;
530 } else {
531 mode = curr->fts_statp->st_mode;
532 if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
533 ((mode | S_IRWXU) & mask) != (mode & mask))
534 if (chmod(to.p_path, mode & mask) != 0){
535 warn(pCtx, "chmod: %s", to.p_path);
536 rval = 1;
537 }
538 }
539 continue;
540 }
541
542 /* Not an error but need to remember it happened */
543 if (stat(to.p_path, &to_stat) == -1)
544 dne = 1;
545 else {
546 if (to_stat.st_dev == curr->fts_statp->st_dev &&
547 to_stat.st_dev != 0 &&
548 to_stat.st_ino == curr->fts_statp->st_ino &&
549 to_stat.st_ino != 0) {
550 warnx(pCtx, "%s and %s are identical (not copied).",
551 to.p_path, curr->fts_path);
552 badcp = rval = 1;
553 if (S_ISDIR(curr->fts_statp->st_mode))
554 (void)fts_set(ftsp, curr, FTS_SKIP);
555 continue;
556 }
557 if (!S_ISDIR(curr->fts_statp->st_mode) &&
558 S_ISDIR(to_stat.st_mode)) {
559 warnx(pCtx, "cannot overwrite directory %s with "
560 "non-directory %s",
561 to.p_path, curr->fts_path);
562 badcp = rval = 1;
563 continue;
564 }
565 dne = 0;
566 }
567
568 switch (curr->fts_statp->st_mode & S_IFMT) {
569#ifdef S_IFLNK
570 case S_IFLNK:
571 /* Catch special case of a non-dangling symlink */
572 if ((fts_options & FTS_LOGICAL) ||
573 ((fts_options & FTS_COMFOLLOW) &&
574 curr->fts_level == 0)) {
575 if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
576 badcp = rval = 1;
577 } else {
578 if (copy_link(pCtx, curr, !dne))
579 badcp = rval = 1;
580 }
581 break;
582#endif
583 case S_IFDIR:
584 if (!Rflag && !rflag) {
585 warnx(pCtx, "%s is a directory (not copied).",
586 curr->fts_path);
587 (void)fts_set(ftsp, curr, FTS_SKIP);
588 badcp = rval = 1;
589 break;
590 }
591 /*
592 * If the directory doesn't exist, create the new
593 * one with the from file mode plus owner RWX bits,
594 * modified by the umask. Trade-off between being
595 * able to write the directory (if from directory is
596 * 555) and not causing a permissions race. If the
597 * umask blocks owner writes, we fail..
598 */
599 if (dne) {
600 if (mkdir(to.p_path,
601 curr->fts_statp->st_mode | S_IRWXU) < 0)
602 return err(pCtx, 1, "mkdir: %s", to.p_path);
603 } else if (!S_ISDIR(to_stat.st_mode)) {
604 errno = ENOTDIR;
605 return err(pCtx, 1, "to-mode: %s", to.p_path);
606 }
607 /*
608 * Arrange to correct directory attributes later
609 * (in the post-order phase) if this is a new
610 * directory, or if the -p flag is in effect.
611 */
612 curr->fts_number = pflag || dne;
613 break;
614#ifdef S_IFBLK
615 case S_IFBLK:
616#endif
617 case S_IFCHR:
618 if (Rflag) {
619 if (copy_special(pCtx, curr->fts_statp, !dne))
620 badcp = rval = 1;
621 } else {
622 if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
623 badcp = rval = 1;
624 }
625 break;
626#ifdef S_IFIFO
627 case S_IFIFO:
628#endif
629 if (Rflag) {
630 if (copy_fifo(pCtx, curr->fts_statp, !dne))
631 badcp = rval = 1;
632 } else {
633 if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
634 badcp = rval = 1;
635 }
636 break;
637 default:
638 if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
639 badcp = rval = 1;
640 break;
641 }
642 if (vflag && !badcp)
643 kmk_builtin_ctx_printf(pCtx, 0, copied ? "%s -> %s\n" : "%s matches %s - not copied\n",
644 curr->fts_path, to.p_path);
645 }
646 if (errno)
647 return err(pCtx, 1, "fts_read");
648 return (rval);
649}
650
651/*
652 * mastercmp --
653 * The comparison function for the copy order. The order is to copy
654 * non-directory files before directory files. The reason for this
655 * is because files tend to be in the same cylinder group as their
656 * parent directory, whereas directories tend not to be. Copying the
657 * files first reduces seeking.
658 */
659static int
660mastercmp(const FTSENT **a, const FTSENT **b)
661{
662 int a_info, b_info;
663
664 a_info = (*a)->fts_info;
665 if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
666 return (0);
667 b_info = (*b)->fts_info;
668 if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
669 return (0);
670 if (a_info == FTS_D)
671 return (-1);
672 if (b_info == FTS_D)
673 return (1);
674 return (0);
675}
676
677#ifdef SIGINFO
678static void
679siginfo(int sig __unused)
680{
681
682 info = 1;
683}
684#endif
685
686
687static int
688usage(PKMKBUILTINCTX pCtx, int fIsErr)
689{
690 kmk_builtin_ctx_printf(pCtx, fIsErr,
691"usage: %s [options] src target\n"
692" or: %s [options] src1 ... srcN directory\n"
693" or: %s --help\n"
694" or: %s --version\n"
695"\n"
696"Options:\n"
697" -R Recursive copy.\n"
698" -H Follow symbolic links on the commandline. Only valid with -R.\n"
699" -L Follow all symbolic links. Only valid with -R.\n"
700" -P Do not follow symbolic links. Default. Only valid with -R\n"
701" -f Force. Overrides -i and -n.\n"
702" -i Iteractive. Overrides -n and -f.\n"
703" -n Don't overwrite any files. Overrides -i and -f.\n"
704" -v Verbose.\n"
705" --ignore-non-existing\n"
706" Don't fail if the specified source file doesn't exist.\n"
707" --changed\n"
708" Only copy if changed (i.e. compare first).\n"
709" --disable-protection\n"
710" Will disable the protection file protection applied with -R.\n"
711" --enable-protection\n"
712" Will enable the protection file protection applied with -R.\n"
713" --enable-full-protection\n"
714" Will enable the protection file protection for all operations.\n"
715" --disable-full-protection\n"
716" Will disable the protection file protection for all operations.\n"
717" --protection-depth\n"
718" Number or path indicating the file protection depth. Default: %d\n"
719"\n"
720"Environment:\n"
721" KMK_CP_DISABLE_PROTECTION\n"
722" Same as --disable-protection. Overrides command line.\n"
723" KMK_CP_ENABLE_PROTECTION\n"
724" Same as --enable-protection. Overrides everyone else.\n"
725" KMK_CP_ENABLE_FULL_PROTECTION\n"
726" Same as --enable-full-protection. Overrides everyone else.\n"
727" KMK_CP_DISABLE_FULL_PROTECTION\n"
728" Same as --disable-full-protection. Overrides command line.\n"
729" KMK_CP_PROTECTION_DEPTH\n"
730" Same as --protection-depth. Overrides command line.\n"
731"\n"
732"The file protection of the top %d layers of the file hierarchy is there\n"
733"to try prevent makefiles from doing bad things to your system. This\n"
734"protection is not bulletproof, but should help prevent you from shooting\n"
735"yourself in the foot.\n"
736 ,
737 pCtx->pszProgName, pCtx->pszProgName,
738 pCtx->pszProgName, pCtx->pszProgName,
739 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
740 return 1;
741}
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