removed everything an include <lib_internal/util.h> only
[util-vserver.git] / util-vserver / src / vcopy.c
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
38 #define ENSC_WRAPPERS_UNISTD    1
39 #define ENSC_WRAPPERS_FCNTL     1
40 #define ENSC_WRAPPERS_DIRENT    1
41 #include <wrappers.h>
42
43 #define CMD_HELP                0x8000
44 #define CMD_VERSION             0x8001
45 #define CMD_MANUALLY            0x8002
46 #define CMD_STRICT              0x8003
47
48 struct WalkdownInfo
49 {
50     PathInfo                            state;
51     struct MatchList                    dst_list;
52     struct MatchList                    src_list;
53 };
54
55 struct Arguments {
56     enum {mdMANUALLY, mdVSERVER}        mode;
57     bool                                do_dry_run;
58     unsigned int                        verbosity;
59     bool                                local_fs;
60     bool                                is_strict;
61 };
62
63 static struct WalkdownInfo              global_info;
64 static struct Arguments const *         global_args;
65
66 int wrapper_exit_code = 1;
67
68 struct option const
69 CMDLINE_OPTIONS[] = {
70   { "help",     no_argument,  0, CMD_HELP },
71   { "version",  no_argument,  0, CMD_VERSION },
72   { "manually", no_argument,  0, CMD_MANUALLY },
73   { "strict",   no_argument,  0, CMD_STRICT },
74   { 0,0,0,0 }
75 };
76
77 typedef enum { opUNIFY, opCOPY, opDIR, opSKIP } Operation;
78
79 static void
80 showHelp(int fd, char const *cmd, int res)
81 {
82   VSERVER_DECLARE_CMD(cmd);
83   
84   WRITE_MSG(fd, "Usage:\n  ");
85   WRITE_STR(fd, cmd);
86   WRITE_MSG(fd,
87             " [-nv] [--strict] <dst-vserver> <src-vserver>\n    or\n  ");
88   WRITE_STR(fd, cmd);
89   WRITE_MSG(fd,
90             " --manually [-nvx] [--] <dst-path> <dst-excludelist> <src-path> <src-excludelist>\n\n"
91             "  --manually      ...  unify generic paths; excludelists must be generated\n"
92             "                       manually\n"
93             "  --strict        ...  require an existing vserver configuration for dst-vserver;\n"
94             "                       by default, a base skeleton will be created but manual\n"
95             "                       configuration wil be still needed to make the new vserver work\n"
96             "  -n              ...  do not modify anything; just show what there will be\n"
97             "                       done (in combination with '-v')\n"
98             "  -v              ...  verbose mode\n"
99             "  -x              ...  do not cross filesystems; this is valid in manual\n"
100             "                       mode only and will be ignored for vserver unification\n\n"
101             "Please report bugs to " PACKAGE_BUGREPORT "\n");
102   exit(res);
103 }
104
105 static void
106 showVersion()
107 {
108   WRITE_MSG(1,
109             "vcopy " VERSION " -- copies directories and vserver files\n"
110             "This program is part of " PACKAGE_STRING "\n\n"
111             "Copyright (C) 2003,2004 Enrico Scholz\n"
112             VERSION_COPYRIGHT_DISCLAIMER);
113   exit(0);
114 }
115
116 int Global_getVerbosity() {
117   return global_args->verbosity;
118 }
119
120 bool Global_doRenew() {
121   return true;
122 }
123
124 #include "vserver-visitdir.hc"
125
126 static Operation
127 checkDirEntry(PathInfo const *path, struct stat const *st)
128 {
129   struct WalkdownInfo const * const     info     = &global_info;
130
131   if (S_ISDIR(st->st_mode)) return opDIR;
132   if (S_ISLNK(st->st_mode) ||
133       !S_ISREG(st->st_mode)) return opSKIP;
134   
135     // Check if it is in the exclude/include list of the destination vserver and
136     // abort when it is not matching an allowed entry
137   if (!MatchList_compare(&info->dst_list, path->d) ||
138       !MatchList_compare(&info->src_list, path->d)) return opCOPY;
139
140   return opUNIFY;
141 }
142
143 static bool
144 doit(Operation op,
145      PathInfo const *dst_path,
146      PathInfo const *src_path, struct stat const *exp_stat,
147      PathInfo const *show_path)
148 {
149   if (global_args->do_dry_run || global_args->verbosity>0) {
150     if      (op==opUNIFY)   WRITE_MSG(1, "linking  '");
151     else if (op==opCOPY)    WRITE_MSG(1, "copying  '");
152     else if (op==opDIR)     WRITE_MSG(1, "creating '");
153     else if (op==opSKIP)    WRITE_MSG(1, "skipping '");
154     else { assert(false); abort(); }
155
156     write(1, show_path->d, show_path->l);
157     WRITE_MSG(1, "'\n");
158   }
159
160   return (global_args->do_dry_run ||
161           ( op==opSKIP) ||
162           ( op==opUNIFY && Unify_unify(src_path->d, exp_stat, dst_path->d)) ||
163           ((op==opCOPY  ||
164             op==opDIR)  && Unify_copy (src_path->d, exp_stat, dst_path->d)));
165 }
166      
167 static uint64_t
168 visitDirEntry(struct dirent const *ent)
169 {
170   char const *                  dirname  = ent->d_name;
171   if (isDotfile(dirname)) return 0;
172
173   uint64_t                      res      = 1;
174   PathInfo                      src_path = global_info.state;
175   PathInfo                      src_d_path = {
176     .d = dirname,
177     .l = strlen(dirname)
178   };
179   char                          path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
180   struct stat                   f_stat = { .st_dev = 0 };
181
182   PathInfo_append(&src_path, &src_d_path, path_buf);
183
184   
185   if (lstat(dirname, &f_stat)==-1)
186     perror("lstat()");
187   else {
188     Operation           op       = checkDirEntry(&src_path, &f_stat);
189     PathInfo            dst_path = global_info.src_list.root;
190     char                dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
191
192     PathInfo_append(&dst_path, &src_path, dst_path_buf);
193     if (!doit(op, &dst_path, &src_d_path, &f_stat, &src_path))
194       perror(src_path.d);
195     else if (op==opDIR) {
196       res = visitDir(dirname, &f_stat);
197       if (!global_args->do_dry_run &&
198           !Unify_setTime(dst_path.d, &f_stat))
199         perror("utime()");
200     }
201     else
202       res = 0;
203   }
204
205   return res;
206 }
207
208 #include "vcopy-init.hc"
209
210 int main(int argc, char *argv[])
211 {
212   struct Arguments      args = {
213     .mode               =  mdVSERVER,
214     .do_dry_run         =  false,
215     .verbosity          =  0,
216     .local_fs           =  false,
217   };
218   uint64_t              res;
219
220   global_args = &args;
221   while (1) {
222     int         c = getopt_long(argc, argv, "nvcx",
223                                 CMDLINE_OPTIONS, 0);
224     if (c==-1) break;
225
226     switch (c) {
227       case CMD_HELP             :  showHelp(1, argv[0], 0);
228       case CMD_VERSION          :  showVersion();
229       case CMD_MANUALLY         :  args.mode       = mdMANUALLY; break;
230       case CMD_STRICT           :  args.is_strict  = true; break;
231       case 'n'                  :  args.do_dry_run = true; break;
232       case 'x'                  :  args.local_fs   = true; break;
233       case 'v'                  :  ++args.verbosity;       break;
234       default           :
235         WRITE_MSG(2, "Try '");
236         WRITE_STR(2, argv[0]);
237         WRITE_MSG(2, " --help\" for more information.\n");
238         return EXIT_FAILURE;
239         break;
240     }
241   }
242
243   if (argc==optind) {
244     WRITE_MSG(2, "No directory/vserver given\n");
245     return EXIT_FAILURE;
246   }
247
248   switch (args.mode) {
249     case mdMANUALLY     :  initModeManually(argc-optind, argv+optind); break;
250     case mdVSERVER      :  initModeVserver (argc-optind, argv+optind); break;
251     default             :  assert(false); return EXIT_FAILURE;
252   }
253
254   if (global_args->verbosity>3)
255     WRITE_MSG(1, "Starting to traverse directories...\n");
256
257   Echdir(global_info.src_list.root.d);
258   res = visitDir("/", 0);
259   
260 #ifndef NDEBUG
261   {
262     MatchList_destroy(&global_info.dst_list);
263     MatchList_destroy(&global_info.src_list);
264   }
265 #endif
266
267   return res>0 ? 1 : 0;
268 }