1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini cp implementation for busybox 4 * 5 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 6 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp> 7 * 8 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. 9 */ 10 11/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ 12 13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) 14 * 15 * Size reduction. 16 */ 17 18#include "libbb.h" 19#include "libcoreutils/coreutils.h" 20 21/* This is a NOEXEC applet. Be very careful! */ 22 23 24int cp_main(int argc, char **argv); 25int cp_main(int argc, char **argv) 26{ 27 struct stat source_stat; 28 struct stat dest_stat; 29 const char *last; 30 const char *dest; 31 int s_flags; 32 int d_flags; 33 int flags; 34 int status = 0; 35 enum { 36 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1), 37 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)), 38 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1), 39 OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2), 40 OPT_L = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3), 41 }; 42 43 // Soft- and hardlinking don't mix 44 // -P and -d are the same (-P is POSIX, -d is GNU) 45 // -r and -R are the same 46 // -a = -pdR 47 opt_complementary = "l--s:s--l:Pd:rR:apdR"; 48 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHL"); 49 /* Default behavior of cp is to dereference, so we don't have to do 50 * anything special when we are given -L. 51 * The behavior of -H is *almost* like -L, but not quite, so let's 52 * just ignore it too for fun. 53 if (flags & OPT_L) ... 54 if (flags & OPT_H) ... // deref command-line params only 55 */ 56 57#if ENABLE_SELINUX 58 if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) { 59 selinux_or_die(); 60 } 61#endif 62 63 flags ^= FILEUTILS_DEREFERENCE; /* The sense of this flag was reversed. */ 64 65 if (optind + 2 > argc) { 66 bb_show_usage(); 67 } 68 69 last = argv[argc - 1]; 70 argv += optind; 71 72 /* If there are only two arguments and... */ 73 if (optind + 2 == argc) { 74 s_flags = cp_mv_stat2(*argv, &source_stat, 75 (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); 76 if (s_flags < 0) 77 return EXIT_FAILURE; 78 d_flags = cp_mv_stat(last, &dest_stat); 79 if (d_flags < 0) 80 return EXIT_FAILURE; 81 82 /* ...if neither is a directory or... */ 83 if ( !((s_flags | d_flags) & 2) || 84 /* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */ 85 ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) 86 ) { 87 /* ...do a simple copy. */ 88 dest = xstrdup(last); 89 goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */ 90 } 91 } 92 93 do { 94 dest = concat_path_file(last, bb_get_last_path_component(*argv)); 95 DO_COPY: 96 if (copy_file(*argv, dest, flags) < 0) { 97 status = 1; 98 } 99 free((void*)dest); 100 } while (*++argv != last); 101 102 return status; 103} 104