X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fvcopy.c;fp=src%2Fvcopy.c;h=5fd86383b583c583a07d4fe89a409f1ff6bae97a;hb=8cf13bb177d92c93eb73dc8939777150536c2d00;hp=0000000000000000000000000000000000000000;hpb=6bf3f95de36c804c97716b2d0bdf10680c559044;p=util-vserver.git diff --git a/src/vcopy.c b/src/vcopy.c new file mode 100644 index 0000000..5fd8638 --- /dev/null +++ b/src/vcopy.c @@ -0,0 +1,308 @@ +// $Id: vcopy.c,v 1.5 2005/03/24 12:44:17 ensc Exp $ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "util.h" +#include "vserver.h" + +#include "lib_internal/matchlist.h" +#include "lib_internal/unify.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENSC_WRAPPERS_UNISTD 1 +#define ENSC_WRAPPERS_FCNTL 1 +#define ENSC_WRAPPERS_DIRENT 1 +#include + +#define CMD_HELP 0x8000 +#define CMD_VERSION 0x8001 +#define CMD_MANUALLY 0x8002 +#define CMD_STRICT 0x8003 + +struct WalkdownInfo +{ + PathInfo state; + struct MatchList dst_list; + struct MatchList src_list; +}; + +struct Arguments { + enum {mdMANUALLY, mdVSERVER} mode; + bool do_dry_run; + unsigned int verbosity; + bool local_fs; + bool is_strict; +}; + +static struct WalkdownInfo global_info; +static struct Arguments const * global_args; + +int wrapper_exit_code = 1; + +struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, CMD_HELP }, + { "version", no_argument, 0, CMD_VERSION }, + { "manually", no_argument, 0, CMD_MANUALLY }, + { "strict", no_argument, 0, CMD_STRICT }, + { 0,0,0,0 } +}; + +typedef enum { opUNIFY, opCOPY, opDIR, opSKIP } Operation; + +static void +showHelp(int fd, char const *cmd, int res) +{ + VSERVER_DECLARE_CMD(cmd); + + WRITE_MSG(fd, "Usage:\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " [-nv] [--strict] \n or\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " --manually [-nvx] [--] \n\n" + " --manually ... unify generic paths; excludelists must be generated\n" + " manually\n" + " --strict ... require an existing vserver configuration for dst-vserver;\n" + " by default, a base skeleton will be created but manual\n" + " configuration wil be still needed to make the new vserver work\n" + " -n ... do not modify anything; just show what there will be\n" + " done (in combination with '-v')\n" + " -v ... verbose mode\n" + " -x ... do not cross filesystems; this is valid in manual\n" + " mode only and will be ignored for vserver unification\n\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "vcopy " VERSION " -- copies directories and vserver files\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2003,2004 Enrico Scholz\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +int Global_getVerbosity() { + return global_args->verbosity; +} + +bool Global_doRenew() { + return true; +} + +#include "vserver-visitdir.hc" + +static Operation +checkDirEntry(PathInfo const *path, struct stat const *st) +{ + struct WalkdownInfo const * const info = &global_info; + MatchType res; + + // when marked as 'skip' in the first excludelist already, we do not need to + // visit the second one since it could not change that. + res=MatchList_compare(&info->dst_list, path->d); + if (res!=stSKIP) { + MatchType tmp = MatchList_compare(&info->src_list, path->d); + + // stINCLUDE gets overridden by stEXCLUDE+stSKIP, and stEXCLUDE by stSKIP. + // Using the MAX() macro is a hack but it works + res=MAX(res,tmp); + } + + // non-skipped directories are marked as opDIR + if (res!=stSKIP && S_ISDIR(st->st_mode)) + return opDIR; + + // non-skipped symlinks will be copied always + if (res!=stSKIP && S_ISLNK(st->st_mode)) + return opCOPY; + + // skipped files or non regular files (character/block devices) will be skipped + // always + if (res==stSKIP || !S_ISREG(st->st_mode)) + return opSKIP; + + switch (res) { + case stINCLUDE : return opUNIFY; + case stEXCLUDE : return opCOPY; + case stSKIP : assert(false); // already handled above + default : assert(false); abort(); + } +} + +static bool +doit(Operation op, + PathInfo const *dst_path, + PathInfo const *src_path, struct stat const *exp_stat, + PathInfo const *show_path) +{ +#if 0 + struct stat st; + + if (lstat(dst_path->d, &st)!=-1) { + if (global_args->do_keep && + (!S_ISDIR(exp_stat->st_mode) || S_ISDIR(st.st_mode))) { + // when keep-mode is enable and, do nothing + if (global_args->do_dry_run || global_args->verbosity>1) { + WRITE_MSG(1, "keeping '"); + write(1, show_path->d, show_path->l); + WRITE_MSG(1, "'\n"); + } + return true; + } + + } +#endif + + if (global_args->do_dry_run || global_args->verbosity>1) { + if (op==opUNIFY) WRITE_MSG(1, "linking '"); + else if (op==opCOPY) WRITE_MSG(1, "copying '"); + else if (op==opDIR) WRITE_MSG(1, "creating '"); + else if (op==opSKIP) WRITE_MSG(1, "skipping '"); + else { assert(false); abort(); } + + Vwrite(1, show_path->d, show_path->l); + WRITE_MSG(1, "'\n"); + } + + return (global_args->do_dry_run || + ( op==opSKIP) || + ( op==opUNIFY && Unify_unify(src_path->d, exp_stat, dst_path->d, false)) || + ((op==opCOPY || + op==opDIR) && Unify_copy (src_path->d, exp_stat, dst_path->d))); +} + +static uint64_t +visitDirEntry(struct dirent const *ent) +{ + char const * dirname = ent->d_name; + if (isDotfile(dirname)) return 0; + + uint64_t res = 1; + PathInfo src_path = global_info.state; + PathInfo src_d_path = { + .d = dirname, + .l = strlen(dirname) + }; + char path_buf[ENSC_PI_APPSZ(src_path, src_d_path)]; + struct stat f_stat = { .st_dev = 0 }; + + PathInfo_append(&src_path, &src_d_path, path_buf); + + + if (lstat(dirname, &f_stat)==-1) + perror("lstat()"); + else { + Operation op = checkDirEntry(&src_path, &f_stat); + PathInfo dst_path = global_info.dst_list.root; + char dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)]; + + PathInfo_append(&dst_path, &src_path, dst_path_buf); + if (!doit(op, &dst_path, &src_d_path, &f_stat, &src_path)) + perror(src_path.d); + else if (op==opDIR) { + res = visitDir(dirname, &f_stat); + if (!global_args->do_dry_run && + !Unify_setTime(dst_path.d, &f_stat)) + perror("utime()"); + } + else + res = 0; + } + + return res; +} + +#include "vcopy-init.hc" + +int main(int argc, char *argv[]) +{ + struct Arguments args = { + .mode = mdVSERVER, + .do_dry_run = false, + .verbosity = 0, + .local_fs = false, + }; + uint64_t res; + + global_args = &args; + while (1) { + int c = getopt_long(argc, argv, "nvcx", + CMDLINE_OPTIONS, 0); + if (c==-1) break; + + switch (c) { + case CMD_HELP : showHelp(1, argv[0], 0); + case CMD_VERSION : showVersion(); + case CMD_MANUALLY : args.mode = mdMANUALLY; break; + case CMD_STRICT : args.is_strict = true; break; + case 'n' : args.do_dry_run = true; break; + case 'x' : args.local_fs = true; break; + case 'v' : ++args.verbosity; break; + default : + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help\" for more information.\n"); + return EXIT_FAILURE; + break; + } + } + + if (argc==optind) { + WRITE_MSG(2, "No directory/vserver given\n"); + return EXIT_FAILURE; + } + + switch (args.mode) { + case mdMANUALLY : initModeManually(argc-optind, argv+optind); break; + case mdVSERVER : initModeVserver (argc-optind, argv+optind); break; + default : assert(false); return EXIT_FAILURE; + } + + if (global_args->verbosity>3) + WRITE_MSG(1, "Starting to traverse directories...\n"); + + Echdir(global_info.src_list.root.d); + res = visitDir("/", 0); + +#ifndef NDEBUG + { + MatchList_destroy(&global_info.dst_list); + MatchList_destroy(&global_info.src_list); + } +#endif + + return res>0 ? 1 : 0; +}