--- trunk/mkinitrd-magellan/busybox/coreutils/mv.c 2007/09/01 22:45:15 532 +++ trunk/mkinitrd-magellan/busybox/coreutils/mv.c 2010/05/30 11:32:42 984 @@ -3,6 +3,7 @@ * Mini mv implementation for busybox * * Copyright (C) 2000 by Matt Kraai + * SELinux support by Yuichi Nakamura * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ @@ -12,74 +13,66 @@ * Size reduction and improved error checking. */ -#include -#include -#include -#include -#include -#include -#include /* struct option */ -#include "busybox.h" +#include "libbb.h" #include "libcoreutils/coreutils.h" #if ENABLE_FEATURE_MV_LONG_OPTIONS -static const struct option mv_long_options[] = { - { "interactive", 0, NULL, 'i' }, - { "force", 0, NULL, 'f' }, - { 0, 0, 0, 0 } -}; +static const char mv_longopts[] ALIGN1 = + "interactive\0" No_argument "i" + "force\0" No_argument "f" + ; #endif #define OPT_FILEUTILS_FORCE 1 #define OPT_FILEUTILS_INTERACTIVE 2 -static const char fmt[] = "cannot overwrite %sdirectory with %sdirectory"; - +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_long_options; + applet_long_options = mv_longopts; #endif - opt_complementary = "f-i:i-f"; - flags = getopt32(argc, argv, "fi"); - if (optind + 2 > argc) { - bb_show_usage(); - } - - last = argv[argc - 1]; + // Need at least two arguments + // -f unsets -i, -i unsets -f + opt_complementary = "-2:f-i:i-f"; + flags = getopt32(argv, "fi"); + argc -= optind; argv += optind; + last = argv[argc - 1]; - if (optind + 2 == argc) { + 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))) { + 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! */ } @@ -91,10 +84,14 @@ struct stat source_stat; int source_exists; - if (errno != EXDEV || - (source_exists = cp_mv_stat(*argv, &source_stat)) < 1) { - bb_perror_msg("cannot rename '%s'", *argv); + if (errno != EXDEV + || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1 + ) { + 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,20 +105,27 @@ } } if (unlink(dest) < 0) { - bb_perror_msg("cannot remove '%s'", dest); + bb_perror_msg("can't remove '%s'", dest); goto RET_1; } } - if ((copy_file(*argv, dest, - FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS) >= 0) && - (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)) { + /* 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; +#endif + if ((copy_file(*argv, dest, copy_flag) >= 0) + && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0) + ) { goto RET_0; } } -RET_1: + RET_1: status = 1; } -RET_0: + RET_0: if (dest != last) { free((void *) dest); }