Add an option to specify the xid the non-shared files should belong to.
[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 #define ENSC_WRAPPERS_VSERVER   1
44 #include <wrappers.h>
45
46 #define CMD_HELP                0x8000
47 #define CMD_VERSION             0x8001
48 #define CMD_XID                 0x8002
49
50 struct WalkdownInfo
51 {
52     PathInfo    state;
53     PathInfo    src;
54     PathInfo    dst;
55 };
56
57 struct Arguments {
58     unsigned int        verbosity;
59     xid_t               xid;
60 };
61
62 static struct WalkdownInfo              global_info;
63 static struct Arguments const *         global_args;
64
65 int wrapper_exit_code = 1;
66
67 struct option const
68 CMDLINE_OPTIONS[] = {
69   { "help",     no_argument,       0, CMD_HELP },
70   { "version",  no_argument,       0, CMD_VERSION },
71   { "xid",      required_argument, 0, CMD_XID },
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             " [--xid <xid>] <source> <absolute path to 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
136     /* skip files that already exist */
137     if (access(dst_path.d, F_OK)!=-1)
138       res = 0;
139     else if (S_ISREG(f_stat.st_mode) && Unify_isIUnlinkable(src_d_path.d) == unifyBUSY) {
140       Elink(src_d_path.d, dst_path.d);
141       res = 0;
142     }
143     else {
144       if (!Unify_copy(src_d_path.d, &f_stat, dst_path.d))
145         perror(ENSC_WRAPPERS_PREFIX "Unify_copy()");
146       else if (vc_set_iattr(dst_path.d, global_args->xid, 0, VC_IATTR_XID) == -1)
147         perror(ENSC_WRAPPERS_PREFIX "vc_set_iattr()");
148       else
149         res = 0;
150     }
151     if (S_ISDIR(f_stat.st_mode))
152       res = visitDir(dirname, &f_stat);
153   }
154
155   return res;
156 }
157
158 int main(int argc, char *argv[])
159 {
160   struct Arguments      args = {
161     .verbosity          =  0,
162     .xid                = VC_NOCTX,
163   };
164   uint64_t              res;
165   int                   num_args;
166
167   global_args = &args;
168   while (1) {
169     int         c = getopt_long(argc, argv, "+v",
170                                 CMDLINE_OPTIONS, 0);
171     if (c==-1) break;
172
173     switch (c) {
174       case CMD_HELP     :  showHelp(1, argv[0], 0);
175       case CMD_VERSION  :  showVersion();
176       case 'v'          :  args.verbosity++; break;
177       case CMD_XID      :  args.xid = Evc_xidopt2xid(optarg,true); break;
178       default           :
179         WRITE_MSG(2, "Try '");
180         WRITE_STR(2, argv[0]);
181         WRITE_MSG(2, " --help' for more information.\n");
182         return EXIT_FAILURE;
183         break;
184     }
185   }
186
187   num_args = argc - optind;
188   if (num_args < 1) {
189     WRITE_MSG(2, "Source is missing; try '");
190     WRITE_STR(2, argv[0]);
191     WRITE_MSG(2, " --help' for more information.\n");
192     return EXIT_FAILURE;
193   }
194   else if (num_args < 2) {
195     WRITE_MSG(2, "Destination is missing; try '");
196     WRITE_STR(2, argv[0]);
197     WRITE_MSG(2, " --help' for more information.\n");
198     return EXIT_FAILURE;
199   }
200   else if (num_args > 2) {
201     WRITE_MSG(2, "Too many arguments; try '");
202     WRITE_STR(2, argv[0]);
203     WRITE_MSG(2, " --help' for more information.\n");
204     return EXIT_FAILURE;
205   }
206   else if (*argv[optind+1] != '/') {
207     WRITE_MSG(2, "The destination must be an absolute path; try '");
208     WRITE_STR(2, argv[0]);
209     WRITE_MSG(2, " --help' for more information.\n");
210     return EXIT_FAILURE;
211   }
212   ENSC_PI_SETSTR(global_info.src, argv[optind]);
213   ENSC_PI_SETSTR(global_info.dst, argv[optind+1]);
214
215   if (global_args->verbosity>3)
216     WRITE_MSG(1, "Starting to traverse directories...\n");
217
218   Echdir(global_info.src.d);
219   res = visitDir("/", 0);
220   
221   return res>0 ? 1 : 0;
222 }