3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vbuild.cc by Jacques Gelinas
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 This utility is used to build a new vserver using a reference vserver.
22 It uses hard link whenever possible instead of duplicating files.
23 Once done, it sets the immutable bits.
31 #include <sys/ioctl.h>
50 EXCLDIR(const char *s)
57 static vector<EXCLDIR> excldirs;
60 static int ext2flags = EXT2_IMMUTABLE_FILE_FL | EXT2_IMMUTABLE_LINK_FL;
74 "vbuild version " << VERSION <<
76 "vbuild [ options ] reference-server new-vservers\n"
78 "--test: Show what will be done, do not do it.\n"
79 "--debug: Prints some debugging messages.\n"
81 "--excldir: None of the files under a given directory will be copied\n"
82 "\tThe directory is expressed in absolute/logical form (relative\n"
83 "\tto the vserver root (ex: /var/log)\n"
86 "--noflags: Do not put any immutable flags on the file\n"
87 "--immutable: Set the immutable_file bit on the files.\n"
88 "--immutable-mayunlink: Sets the immutable_link flag on files.\n"
89 "--stats: Produce statistics on the number of file linked\n"
90 " copied and so on.\n"
92 "By default, the immutable_file and immutable_link flags are\n"
93 "set on the files. So if you want no immutable flags, you must\n"
94 "use --noflags. If you want a single flag, you must use\n"
95 "--noflags first, then the --immutable or --immutable-mayunlink\n"
101 Return true if a directory lies inside a directory set
103 static bool vbuild_inside (vector<EXCLDIR> &dirs, const char *path)
106 for (unsigned i=0; i<dirs.size(); i++){
107 if (strncmp(dirs[i].prefix.c_str(),path,dirs[i].len)==0){
117 static int vbuild_copy (
120 dev_t dev, // We stay on the same volume
125 if (debug > 0) printf ("Copying directory %s\n",logical_dir.c_str());
126 DIR *dir = opendir (refserv.c_str());
128 fprintf (stderr,"Can't open directory %s (%s)\n",refserv.c_str()
132 bool copy_files = !vbuild_inside(excldirs,logical_dir.c_str());
135 while (ret == 0 && (ent=readdir(dir))!=NULL){
136 if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0){
139 string file = refserv + "/" + ent->d_name;
141 if (vutil_lstat(file.c_str(),st) == -1){
143 }else if (st.st_dev != dev){
144 if (debug > 0) printf ("Ignore sub-directory %s\n",file.c_str());
146 string newfile = newserv + "/" + ent->d_name;
147 if (S_ISDIR(st.st_mode)){
148 if (vbuild_mkdir (newfile.c_str(),st.st_mode)==-1){
149 fprintf (stderr,"Can't mkdir %s (%s)\n"
150 ,newfile.c_str(),strerror(errno));
154 if (vbuild_chown(newfile.c_str(),st.st_uid,st.st_gid)==-1){
155 fprintf (stderr,"Can't chown %s (%s)\n"
156 ,newfile.c_str(),strerror(errno));
159 ret |= vbuild_copy (file,newfile,dev
160 ,logical_dir + ent->d_name,files);
162 }else if (S_ISLNK(st.st_mode)){
164 int len = readlink(file.c_str(),path,sizeof(path)-1);
166 fprintf (stderr,"Can't readlink %s (%s)\n"
167 ,file.c_str(),strerror(errno));
172 if (vbuild_symlink (path,newfile.c_str())==-1){
173 fprintf (stderr,"Can't symlink %s to %s (%s)\n",
174 newfile.c_str(),path,strerror(errno));
177 }else if (S_ISBLK(st.st_mode)
178 || S_ISCHR(st.st_mode)
179 || S_ISFIFO(st.st_mode)){
181 if (vbuild_mknod (newfile.c_str(),st.st_mode,st.st_rdev)==-1){
182 fprintf (stderr,"Can't mknod %s (%s)\n"
183 ,newfile.c_str(),strerror(errno));
186 }else if (S_ISSOCK(st.st_mode)){
188 }else if (copy_files){
189 // Ok, this is a file. We either copy it or do a link
190 string logical_file = logical_dir + ent->d_name;
191 if (files.find (logical_file)==files.end()){
192 if (debug > 1) printf ("Copying file %s\n",file.c_str());
193 if (vbuild_file_copy (file.c_str(),newfile.c_str(),st)==-1){
194 fprintf (stderr,"Can't copy %s to %s (%s)\n",
195 file.c_str(),newfile.c_str(),strerror(errno));
198 stats.size_copy += st.st_size;
202 if (debug > 2) printf ("Linking file %s\n",file.c_str());
203 setext2flag (file.c_str(),false,ext2flags);
205 if (vbuild_link (file.c_str(),newfile.c_str())==-1){
206 fprintf (stderr,"Can't link %s to %s (%s)\n",
207 file.c_str(),newfile.c_str(),strerror(errno));
210 setext2flag (file.c_str(),true,ext2flags);
221 prepareVserver(Vserver const UNUSED &src, char const UNUSED *dst)
226 int main (int argc, char *argv[])
229 bool statistics = false;
231 for (i=1; i<argc; i++){
232 const char *arg = argv[i];
233 //const char *opt = argv[i+1];
234 if (strcmp(arg,"--test")==0){
236 }else if (strcmp(arg,"--debug")==0){
238 }else if (strcmp(arg,"--stats")==0){
240 }else if (strcmp(arg,"--noflags")==0){
242 }else if (strcmp(arg,"--immutable")==0){
243 ext2flags |= EXT2_IMMUTABLE_FILE_FL;
244 }else if (strcmp(arg,"--immutable-mayunlink")==0){
245 ext2flags |= EXT2_IMMUTABLE_LINK_FL;
246 }else if (strcmp(arg,"--excldir")==0){
248 excldirs.push_back (EXCLDIR(argv[i]));
256 Vserver refserv(argv[i++]);
258 prepareVserver(refserv, argv[i]);
259 Vserver newserv(argv[i]);
260 list<Package> packages;
261 // Load the files which are not configuration files from
263 vutil_loadallpkg (refserv,packages);
265 for (list<Package>::iterator it=packages.begin(); it!=packages.end(); it++){
266 (*it).loadfiles(refserv,files);
268 // Now, we do a recursive copy of refserv into newserv
270 // Check if it is on the same volume
271 struct stat refst,newst;
272 if (vutil_lstat(refserv.getVdir().c_str(),refst)!=-1
273 && vutil_lstat(newserv.getVdir().c_str(),newst)!=1){
274 if (refst.st_dev != newst.st_dev){
275 fprintf (stderr,"Can't vbuild %s because it is not on the same volume as %s\n",
276 newserv.getVdir().c_str(),refserv.getVdir().c_str());
278 stats.nbdir = stats.nblink = stats.nbcopy = stats.nbsymlink = 0;
281 ret = vbuild_copy (refserv.getVdir(),newserv.getVdir(),refst.st_dev,"",files);
283 printf ("Directory created: %d\n",stats.nbdir);
284 printf ("Files copied : %d\n",stats.nbcopy);
285 printf ("Bytes copied : %ld\n",stats.size_copy);
286 printf ("Files linked : %d\n",stats.nblink);
287 printf ("Files symlinked : %d\n",stats.nbsymlink);
288 printf ("Special files : %d\n",stats.nbspc);