vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vcopy.c (8558B)


      1 // $Id$    --*- c -*--
      2 
      3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 //  
      5 // This program is free software; you can redistribute it and/or modify
      6 // it under the terms of the GNU General Public License as published by
      7 // the Free Software Foundation; version 2 of the License.
      8 //  
      9 // This program is distributed in the hope that it will be useful,
     10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 // GNU General Public License for more details.
     13 //  
     14 // You should have received a copy of the GNU General Public License
     15 // along with this program; if not, write to the Free Software
     16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     17 
     18 
     19 #ifdef HAVE_CONFIG_H
     20 #  include <config.h>
     21 #endif
     22 
     23 #include "util.h"
     24 #include "vserver.h"
     25 
     26 #include "lib_internal/matchlist.h"
     27 #include "lib_internal/unify.h"
     28 
     29 #include <unistd.h>
     30 #include <getopt.h>
     31 #include <fcntl.h>
     32 #include <dirent.h>
     33 #include <errno.h>
     34 #include <assert.h>
     35 #include <utime.h>
     36 #include <libgen.h>
     37 #include <sys/param.h>
     38 
     39 #define ENSC_WRAPPERS_UNISTD	1
     40 #define ENSC_WRAPPERS_FCNTL	1
     41 #define ENSC_WRAPPERS_DIRENT	1
     42 #include <wrappers.h>
     43 
     44 #define CMD_HELP		0x8000
     45 #define CMD_VERSION		0x8001
     46 #define CMD_MANUALLY		0x8002
     47 #define CMD_STRICT		0x8003
     48 
     49 struct WalkdownInfo
     50 {
     51     PathInfo				state;
     52     struct MatchList			dst_list;
     53     struct MatchList			src_list;
     54 };
     55 
     56 struct Arguments {
     57     enum {mdMANUALLY, mdVSERVER}	mode;
     58     bool				do_dry_run;
     59     unsigned int			verbosity;
     60     bool				local_fs;
     61     bool				is_strict;
     62 };
     63 
     64 static struct WalkdownInfo		global_info;
     65 static struct Arguments const *		global_args;
     66 
     67 int wrapper_exit_code = 1;
     68 
     69 struct option const
     70 CMDLINE_OPTIONS[] = {
     71   { "help",     no_argument,  0, CMD_HELP },
     72   { "version",  no_argument,  0, CMD_VERSION },
     73   { "manually", no_argument,  0, CMD_MANUALLY },
     74   { "strict",   no_argument,  0, CMD_STRICT },
     75   { 0,0,0,0 }
     76 };
     77 
     78 typedef enum { opUNIFY, opCOPY, opDIR, opSKIP }	Operation;
     79 
     80 static void
     81 showHelp(int fd, char const *cmd, int res)
     82 {
     83   VSERVER_DECLARE_CMD(cmd);
     84   
     85   WRITE_MSG(fd, "Usage:\n  ");
     86   WRITE_STR(fd, cmd);
     87   WRITE_MSG(fd,
     88 	    " [-nv] [--strict] <dst-vserver> <src-vserver>\n    or\n  ");
     89   WRITE_STR(fd, cmd);
     90   WRITE_MSG(fd,
     91 	    " --manually [-nvx] [--] <dst-path> <dst-excludelist> <src-path> <src-excludelist>\n\n"
     92  	    "  --manually      ...  unify generic paths; excludelists must be generated\n"
     93 	    "                       manually\n"
     94 	    "  --strict        ...  require an existing vserver configuration for dst-vserver;\n"
     95 	    "                       by default, a base skeleton will be created but manual\n"
     96 	    "                       configuration wil be still needed to make the new vserver work\n"
     97 	    "  -n              ...  do not modify anything; just show what there will be\n"
     98 	    "                       done (in combination with '-v')\n"
     99 	    "  -v              ...  verbose mode\n"
    100 	    "  -x              ...  do not cross filesystems; this is valid in manual\n"
    101 	    "                       mode only and will be ignored for vserver unification\n\n"
    102 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
    103   exit(res);
    104 }
    105 
    106 static void
    107 showVersion()
    108 {
    109   WRITE_MSG(1,
    110 	    "vcopy " VERSION " -- copies directories and vserver files\n"
    111 	    "This program is part of " PACKAGE_STRING "\n\n"
    112 	    "Copyright (C) 2003,2004 Enrico Scholz\n"
    113 	    VERSION_COPYRIGHT_DISCLAIMER);
    114   exit(0);
    115 }
    116 
    117 int Global_getVerbosity() {
    118   return global_args->verbosity;
    119 }
    120 
    121 bool Global_doRenew() {
    122   return true;
    123 }
    124 
    125 #include "vserver-visitdir.hc"
    126 
    127 static Operation
    128 checkDirEntry(PathInfo const *path, struct stat const *st)
    129 {
    130   struct WalkdownInfo const * const	info = &global_info;
    131   MatchType				res;
    132 
    133   // when marked as 'skip' in the first excludelist already, we do not need to
    134   // visit the second one since it could not change that.
    135   res=MatchList_compare(&info->dst_list, path->d);
    136   if (res!=stSKIP) {
    137     MatchType		tmp = MatchList_compare(&info->src_list, path->d);
    138 
    139     // stINCLUDE gets overridden by stEXCLUDE+stSKIP, and stEXCLUDE by stSKIP.
    140     // Using the MAX() macro is a hack but it works
    141     res=MAX(res,tmp);
    142   }
    143 
    144   // non-skipped directories are marked as opDIR
    145   if (res!=stSKIP && S_ISDIR(st->st_mode))
    146     return opDIR;
    147 
    148   // non-skipped symlinks will be copied always
    149   if (res!=stSKIP && S_ISLNK(st->st_mode))
    150     return opCOPY;
    151 
    152   // skipped files or non regular files (character/block devices) will be skipped
    153   // always
    154   if (res==stSKIP || !S_ISREG(st->st_mode))
    155     return opSKIP;
    156 
    157   switch (res) {
    158     case stINCLUDE	:  return opUNIFY;
    159     case stEXCLUDE	:  return opCOPY;
    160     case stSKIP		:  assert(false); // already handled above
    161     default		:  assert(false); abort();
    162   }
    163 }
    164 
    165 static bool
    166 doit(Operation op,
    167      PathInfo const *dst_path,
    168      PathInfo const *src_path, struct stat const *exp_stat,
    169      PathInfo const *show_path)
    170 {
    171 #if 0
    172   struct stat		st;
    173 
    174   if (lstat(dst_path->d, &st)!=-1) {
    175     if (global_args->do_keep &&
    176 	(!S_ISDIR(exp_stat->st_mode) || S_ISDIR(st.st_mode))) {
    177       // when keep-mode is enable and, do nothing
    178       if (global_args->do_dry_run || global_args->verbosity>1) {
    179 	WRITE_MSG(1, "keeping  '");
    180 	write(1, show_path->d, show_path->l);
    181 	WRITE_MSG(1, "'\n");
    182       }
    183       return true;
    184     }
    185     
    186   }
    187 #endif
    188   
    189   if (global_args->do_dry_run || global_args->verbosity>1) {
    190     if      (op==opUNIFY)   WRITE_MSG(1, "linking  '");
    191     else if (op==opCOPY)    WRITE_MSG(1, "copying  '");
    192     else if (op==opDIR)     WRITE_MSG(1, "creating '");
    193     else if (op==opSKIP)    WRITE_MSG(1, "skipping '");
    194     else { assert(false); abort(); }
    195 
    196     Vwrite(1, show_path->d, show_path->l);
    197     WRITE_MSG(1, "'\n");
    198   }
    199 
    200   return (global_args->do_dry_run ||
    201 	  ( op==opSKIP) ||
    202 	  ( op==opUNIFY && Unify_unify(src_path->d, exp_stat, dst_path->d, false)) ||
    203 	  ((op==opCOPY  ||
    204 	    op==opDIR)  && Unify_copy (src_path->d, exp_stat, dst_path->d)));
    205 }
    206      
    207 static uint64_t
    208 visitDirEntry(struct dirent const *ent)
    209 {
    210   char const *			dirname  = ent->d_name;
    211   if (isDotfile(dirname)) return 0;
    212 
    213   uint64_t			res      = 1;
    214   PathInfo			src_path = global_info.state;
    215   PathInfo			src_d_path = {
    216     .d = dirname,
    217     .l = strlen(dirname)
    218   };
    219   char				path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
    220   struct stat			f_stat = { .st_dev = 0 };
    221 
    222   PathInfo_append(&src_path, &src_d_path, path_buf);
    223 
    224   
    225   if (lstat(dirname, &f_stat)==-1)
    226     perror("lstat()");
    227   else {
    228     Operation		op       = checkDirEntry(&src_path, &f_stat);
    229     PathInfo		dst_path = global_info.dst_list.root;
    230     char		dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
    231 
    232     PathInfo_append(&dst_path, &src_path, dst_path_buf);
    233     if (!doit(op, &dst_path, &src_d_path, &f_stat, &src_path))
    234       perror(src_path.d);
    235     else if (op==opDIR) {
    236       res = visitDir(dirname, &f_stat);
    237       if (!global_args->do_dry_run &&
    238 	  !Unify_setTime(dst_path.d, &f_stat))
    239 	perror("utime()");
    240     }
    241     else
    242       res = 0;
    243   }
    244 
    245   return res;
    246 }
    247 
    248 #include "vcopy-init.hc"
    249 
    250 int main(int argc, char *argv[])
    251 {
    252   struct Arguments	args = {
    253     .mode		=  mdVSERVER,
    254     .do_dry_run		=  false,
    255     .verbosity		=  0,
    256     .local_fs		=  false,
    257   };
    258   uint64_t		res;
    259 
    260   global_args = &args;
    261   while (1) {
    262     int		c = getopt_long(argc, argv, "nvcx",
    263 				CMDLINE_OPTIONS, 0);
    264     if (c==-1) break;
    265 
    266     switch (c) {
    267       case CMD_HELP		:  showHelp(1, argv[0], 0);
    268       case CMD_VERSION		:  showVersion();
    269       case CMD_MANUALLY		:  args.mode       = mdMANUALLY; break;
    270       case CMD_STRICT		:  args.is_strict  = true; break;
    271       case 'n'			:  args.do_dry_run = true; break;
    272       case 'x'			:  args.local_fs   = true; break;
    273       case 'v'			:  ++args.verbosity;       break;
    274       default		:
    275 	WRITE_MSG(2, "Try '");
    276 	WRITE_STR(2, argv[0]);
    277 	WRITE_MSG(2, " --help' for more information.\n");
    278 	return EXIT_FAILURE;
    279 	break;
    280     }
    281   }
    282 
    283   if (argc==optind) {
    284     WRITE_MSG(2, "No directory/vserver given\n");
    285     return EXIT_FAILURE;
    286   }
    287 
    288   switch (args.mode) {
    289     case mdMANUALLY	:  initModeManually(argc-optind, argv+optind); break;
    290     case mdVSERVER	:  initModeVserver (argc-optind, argv+optind); break;
    291     default		:  assert(false); return EXIT_FAILURE;
    292   }
    293 
    294   if (global_args->verbosity>3)
    295     WRITE_MSG(1, "Starting to traverse directories...\n");
    296 
    297   Echdir(global_info.src_list.root.d);
    298   res = visitDir("/", 0);
    299   
    300 #ifndef NDEBUG
    301   {
    302     MatchList_destroy(&global_info.dst_list);
    303     MatchList_destroy(&global_info.src_list);
    304   }
    305 #endif
    306 
    307   return res>0 ? 1 : 0;
    308 }