Add vclone, to help with cloning guests.
[util-vserver.git] / src / vclone.c
1 // $Id$    --*- 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 #define CMD_SOURCE              0x8002
48 #define CMD_DEST                0x8003
49
50 struct WalkdownInfo
51 {
52     PathInfo    state;
53     PathInfo    src;
54     PathInfo    dst;
55 };
56
57 struct Arguments {
58     unsigned int        verbosity;
59 };
60
61 static struct WalkdownInfo              global_info;
62 static struct Arguments const *         global_args;
63
64 int wrapper_exit_code = 1;
65
66 struct option const
67 CMDLINE_OPTIONS[] = {
68   { "help",     no_argument,       0, CMD_HELP },
69   { "version",  no_argument,       0, CMD_VERSION },
70   { "source",   required_argument, 0, CMD_SOURCE },
71   { "dest",     required_argument, 0, CMD_DEST },
72   { 0,0,0,0 }
73 };
74
75
76 static void
77 showHelp(int fd, char const *cmd, int res)
78 {
79   VSERVER_DECLARE_CMD(cmd);
80   
81   WRITE_MSG(fd, "Usage:\n  ");
82   WRITE_STR(fd, cmd);
83   WRITE_MSG(fd,
84             " --source <source> --dest <destination>\n\n"
85             "Please report bugs to " PACKAGE_BUGREPORT "\n");
86   exit(res);
87 }
88
89 static void
90 showVersion()
91 {
92   WRITE_MSG(1,
93             "vclone " VERSION " -- clones a guest\n"
94             "This program is part of " PACKAGE_STRING "\n\n"
95             "Copyright (C) 2007 Daniel Hokka Zakrisson\n"
96             VERSION_COPYRIGHT_DISCLAIMER);
97   exit(0);
98 }
99
100 int Global_getVerbosity() {
101   return global_args->verbosity;
102 }
103
104 bool Global_doRenew() {
105   return true;
106 }
107
108 #include "vserver-visitdir.hc"
109
110 static uint64_t
111 visitDirEntry(struct dirent const *ent)
112 {
113   char const *                  dirname  = ent->d_name;
114   if (isDotfile(dirname)) return 0;
115
116   uint64_t                      res      = 1;
117   PathInfo                      src_path = global_info.state;
118   PathInfo                      src_d_path = {
119     .d = dirname,
120     .l = strlen(dirname)
121   };
122   char                          path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
123   struct stat                   f_stat = { .st_dev = 0 };
124
125   PathInfo_append(&src_path, &src_d_path, path_buf);
126
127   
128   if (lstat(dirname, &f_stat)==-1)
129     perror(ENSC_WRAPPERS_PREFIX "lstat()");
130   else {
131     PathInfo            dst_path = global_info.dst;
132     char                dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
133
134     PathInfo_append(&dst_path, &src_path, dst_path_buf);
135     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       if (S_ISDIR(f_stat.st_mode))
145         res = visitDir(dirname, &f_stat);
146       else
147         res = 0;
148     }
149   }
150
151   return res;
152 }
153
154 int main(int argc, char *argv[])
155 {
156   struct Arguments      args = {
157     .verbosity          =  0,
158   };
159   uint64_t              res;
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       case CMD_SOURCE   :  ENSC_PI_SETSTR(global_info.src, optarg); break;
171       case CMD_DEST     :  ENSC_PI_SETSTR(global_info.dst, optarg); break;
172       default           :
173         WRITE_MSG(2, "Try '");
174         WRITE_STR(2, argv[0]);
175         WRITE_MSG(2, " --help' for more information.\n");
176         return EXIT_FAILURE;
177         break;
178     }
179   }
180
181   if (global_args->verbosity>3)
182     WRITE_MSG(1, "Starting to traverse directories...\n");
183
184   Echdir(global_info.src.d);
185   res = visitDir("/", 0);
186   
187   return res>0 ? 1 : 0;
188 }