f4a994bcb72fd52f08cd2ff929d5e494b6ab1b46
[util-vserver.git] / src / vclone.c
1 // $Id: vclone.c 2494 2007-02-11 00:45:04Z dhozac $    --*- c -*--
2
3 // Copyright (C) 2007 Daniel Hokka Zakrisson
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/pathinfo.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_PREFIX    "vclone: "
40 #define ENSC_WRAPPERS_UNISTD    1
41 #define ENSC_WRAPPERS_FCNTL     1
42 #define ENSC_WRAPPERS_DIRENT    1
43 #include <wrappers.h>
44
45 #define CMD_HELP                0x8000
46 #define CMD_VERSION             0x8001
47
48 struct WalkdownInfo
49 {
50     PathInfo    state;
51     PathInfo    src;
52     PathInfo    dst;
53 };
54
55 struct Arguments {
56     unsigned int        verbosity;
57 };
58
59 static struct WalkdownInfo              global_info;
60 static struct Arguments const *         global_args;
61
62 int wrapper_exit_code = 1;
63
64 struct option const
65 CMDLINE_OPTIONS[] = {
66   { "help",     no_argument,       0, CMD_HELP },
67   { "version",  no_argument,       0, CMD_VERSION },
68   { 0,0,0,0 }
69 };
70
71
72 static void
73 showHelp(int fd, char const *cmd, int res)
74 {
75   VSERVER_DECLARE_CMD(cmd);
76   
77   WRITE_MSG(fd, "Usage:\n  ");
78   WRITE_STR(fd, cmd);
79   WRITE_MSG(fd,
80             " <source> <absolute path to destination>\n\n"
81             "Please report bugs to " PACKAGE_BUGREPORT "\n");
82   exit(res);
83 }
84
85 static void
86 showVersion()
87 {
88   WRITE_MSG(1,
89             "vclone " VERSION " -- clones a guest\n"
90             "This program is part of " PACKAGE_STRING "\n\n"
91             "Copyright (C) 2007 Daniel Hokka Zakrisson\n"
92             VERSION_COPYRIGHT_DISCLAIMER);
93   exit(0);
94 }
95
96 int Global_getVerbosity() {
97   return global_args->verbosity;
98 }
99
100 bool Global_doRenew() {
101   return true;
102 }
103
104 #include "vserver-visitdir.hc"
105
106 static uint64_t
107 visitDirEntry(struct dirent const *ent)
108 {
109   char const *                  dirname  = ent->d_name;
110   if (isDotfile(dirname)) return 0;
111
112   uint64_t                      res      = 1;
113   PathInfo                      src_path = global_info.state;
114   PathInfo                      src_d_path = {
115     .d = dirname,
116     .l = strlen(dirname)
117   };
118   char                          path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
119   struct stat                   f_stat = { .st_dev = 0 };
120
121   PathInfo_append(&src_path, &src_d_path, path_buf);
122
123   
124   if (lstat(dirname, &f_stat)==-1)
125     perror(ENSC_WRAPPERS_PREFIX "lstat()");
126   else {
127     PathInfo            dst_path = global_info.dst;
128     char                dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
129
130     PathInfo_append(&dst_path, &src_path, dst_path_buf);
131
132     /* skip files that already exist */
133     if (access(dst_path.d, F_OK)!=-1)
134       res = 0;
135     else if (S_ISREG(f_stat.st_mode) && Unify_isIUnlinkable(src_d_path.d) == unifyBUSY) {
136       Elink(src_d_path.d, dst_path.d);
137       res = 0;
138     }
139     else {
140       if (!Unify_copy(src_d_path.d, &f_stat, dst_path.d)) {
141         perror(ENSC_WRAPPERS_PREFIX "Unify_copy()");
142         exit(wrapper_exit_code);
143       }
144       res = 0;
145     }
146     if (S_ISDIR(f_stat.st_mode))
147       res = visitDir(dirname, &f_stat);
148   }
149
150   return res;
151 }
152
153 int main(int argc, char *argv[])
154 {
155   struct Arguments      args = {
156     .verbosity          =  0,
157   };
158   uint64_t              res;
159   int                   num_args;
160
161   global_args = &args;
162   while (1) {
163     int         c = getopt_long(argc, argv, "+",
164                                 CMDLINE_OPTIONS, 0);
165     if (c==-1) break;
166
167     switch (c) {
168       case CMD_HELP     :  showHelp(1, argv[0], 0);
169       case CMD_VERSION  :  showVersion();
170       default           :
171         WRITE_MSG(2, "Try '");
172         WRITE_STR(2, argv[0]);
173         WRITE_MSG(2, " --help' for more information.\n");
174         return EXIT_FAILURE;
175         break;
176     }
177   }
178
179   num_args = argc - optind;
180   if (num_args < 1) {
181     WRITE_MSG(2, "Source is missing; try '");
182     WRITE_STR(2, argv[0]);
183     WRITE_MSG(2, " --help' for more information.\n");
184     return EXIT_FAILURE;
185   }
186   else if (num_args < 2) {
187     WRITE_MSG(2, "Destination is missing; try '");
188     WRITE_STR(2, argv[0]);
189     WRITE_MSG(2, " --help' for more information.\n");
190     return EXIT_FAILURE;
191   }
192   else if (num_args > 2) {
193     WRITE_MSG(2, "Too many arguments; try '");
194     WRITE_STR(2, argv[0]);
195     WRITE_MSG(2, " --help' for more information.\n");
196     return EXIT_FAILURE;
197   }
198   else if (*argv[optind+1] != '/') {
199     WRITE_MSG(2, "The destination must be an absolute path; try '");
200     WRITE_STR(2, argv[0]);
201     WRITE_MSG(2, " --help' for more information.\n");
202     return EXIT_FAILURE;
203   }
204   ENSC_PI_SETSTR(global_info.src, argv[optind]);
205   ENSC_PI_SETSTR(global_info.dst, argv[optind+1]);
206
207   if (global_args->verbosity>3)
208     WRITE_MSG(1, "Starting to traverse directories...\n");
209
210   Echdir(global_info.src.d);
211   res = visitDir("/", 0);
212   
213   return res>0 ? 1 : 0;
214 }