X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=coreutils%2Fmv.c;h=b9f8f698255aef3152025eed64dbd099cf68b495;hb=16bcd504a32e6a7bf2015ffb241133f9ead6100b;hp=1d29770602b68ad4cab362eed707d182cc1524da;hpb=6666ac42a5cd63a8b18ec72f6c1364f31ef53921;p=oweals%2Fbusybox.git diff --git a/coreutils/mv.c b/coreutils/mv.c index 1d2977060..b9f8f6982 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -5,52 +5,68 @@ * Copyright (C) 2000 by Matt Kraai * SELinux support by Yuichi Nakamura * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) * * Size reduction and improved error checking. */ +//config:config MV +//config: bool "mv (10 kb)" +//config: default y +//config: help +//config: mv is used to move or rename files or directories. -#include -#include -#include -#include /* struct option */ -#include "libbb.h" -#include "libcoreutils/coreutils.h" +//applet:IF_MV(APPLET_NOEXEC(mv, mv, BB_DIR_BIN, BB_SUID_DROP, mv)) +/* NOEXEC despite cases when it can be a "runner" (mv LARGE_DIR OTHER_FS) */ -#if ENABLE_FEATURE_MV_LONG_OPTIONS -static const char mv_longopts[] ALIGN1 = - "interactive\0" No_argument "i" - "force\0" No_argument "f" - ; -#endif +//kbuild:lib-$(CONFIG_MV) += mv.o -#define OPT_FILEUTILS_FORCE 1 -#define OPT_FILEUTILS_INTERACTIVE 2 +//usage:#define mv_trivial_usage +//usage: "[-fin] SOURCE DEST\n" +//usage: "or: mv [-fin] SOURCE... DIRECTORY" +//usage:#define mv_full_usage "\n\n" +//usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" +//usage: "\n -f Don't prompt before overwriting" +//usage: "\n -i Interactive, prompt before overwrite" +//usage: "\n -n Don't overwrite an existing file" +//usage: +//usage:#define mv_example_usage +//usage: "$ mv /tmp/foo /bin/bar\n" -static const char fmt[] ALIGN1 = - "cannot overwrite %sdirectory with %sdirectory"; +#include "libbb.h" +#include "libcoreutils/coreutils.h" -int mv_main(int argc, char **argv); +int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) { struct stat dest_stat; const char *last; const char *dest; - unsigned long flags; + unsigned flags; int dest_exists; int status = 0; int copy_flag = 0; -#if ENABLE_FEATURE_MV_LONG_OPTIONS - applet_long_options = mv_longopts; -#endif - // Need at least two arguments - // -f unsets -i, -i unsets -f - opt_complementary = "-2:f-i:i-f"; - flags = getopt32(argv, "fi"); +#define OPT_FORCE (1 << 0) +#define OPT_INTERACTIVE (1 << 1) +#define OPT_NOCLOBBER (1 << 2) +#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) + /* Need at least two arguments. + * If more than one of -f, -i, -n is specified , only the final one + * takes effect (it unsets previous options). + */ + flags = getopt32long(argv, "^" + "finv" + "\0" + "-2:f-in:i-fn:n-fi", + "interactive\0" No_argument "i" + "force\0" No_argument "f" + "no-clobber\0" No_argument "n" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + ); argc -= optind; argv += optind; last = argv[argc - 1]; @@ -58,43 +74,51 @@ int mv_main(int argc, char **argv) if (argc == 2) { dest_exists = cp_mv_stat(last, &dest_stat); if (dest_exists < 0) { - return 1; + return EXIT_FAILURE; } - if (!(dest_exists & 2)) { + if (!(dest_exists & 2)) { /* last is not a directory */ dest = last; goto DO_MOVE; } } do { - dest = concat_path_file(last, bb_get_last_path_component(*argv)); + dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); dest_exists = cp_mv_stat(dest, &dest_stat); if (dest_exists < 0) { goto RET_1; } DO_MOVE: - if (dest_exists && !(flags & OPT_FILEUTILS_FORCE) - && ((access(dest, W_OK) < 0 && isatty(0)) - || (flags & OPT_FILEUTILS_INTERACTIVE)) - ) { - if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { - goto RET_1; /* Ouch! fprintf failed! */ - } - if (!bb_ask_confirmation()) { + if (dest_exists) { + if (flags & OPT_NOCLOBBER) goto RET_0; + if (!(flags & OPT_FORCE) + && ((access(dest, W_OK) < 0 && isatty(0)) + || (flags & OPT_INTERACTIVE)) + ) { + if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { + goto RET_1; /* Ouch! fprintf failed! */ + } + if (!bb_ask_y_confirmation()) { + goto RET_0; + } } } + if (rename(*argv, dest) < 0) { struct stat source_stat; int source_exists; if (errno != EXDEV - || (source_exists = cp_mv_stat(*argv, &source_stat)) < 1 + || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1 ) { - bb_perror_msg("cannot rename '%s'", *argv); + bb_perror_msg("can't rename '%s'", *argv); } else { + static const char fmt[] ALIGN1 = + "can't overwrite %sdirectory with %sdirectory"; + if (dest_exists) { if (dest_exists == 3) { if (source_exists != 3) { @@ -108,10 +132,13 @@ int mv_main(int argc, char **argv) } } if (unlink(dest) < 0) { - bb_perror_msg("cannot remove '%s'", dest); + bb_perror_msg("can't remove '%s'", dest); goto RET_1; } } + /* FILEUTILS_RECUR also prevents nasties like + * "read from device and write contents to dst" + * instead of "create same device node" */ copy_flag = FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS; #if ENABLE_SELINUX copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; @@ -126,6 +153,9 @@ int mv_main(int argc, char **argv) status = 1; } RET_0: + if (flags & OPT_VERBOSE) { + printf("'%s' -> '%s'\n", *argv, dest); + } if (dest != last) { free((void *) dest); }