3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vunify.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.
22 This utility is used to unify (using hard links) two or more
24 It compares the each vserver with the first one and for every
25 common package (RPM, same version), it does a hard link on non
26 configuration file. It turns the file immutable after that.
34 #include <sys/ioctl.h>
48 static bool undo = false;
50 static int ext2flags = EXT2_IMMUTABLE_FILE_FL | EXT2_IMMUTABLE_LINK_FL;
54 EXCLDIR(const char *s)
61 static vector<EXCLDIR> excldirs;
62 static vector<EXCLDIR> incldirs;
68 "vunify version " << VERSION <<
70 "vunify [ options ] reference-server vservers ... -- packages\n"
71 "vunify [ options ] reference-server vservers ... -- ALL\n"
73 "--test: Show what will be done, do not do it.\n"
74 "--undo: Put back the file in place, using copies from the\n"
75 " reference server.\n"
76 "--debug: Prints some debugging messages.\n"
77 "--noflags: Do not put any immutable flags on the file\n"
78 "--immutable: Set the immutable_file bit on the files.\n"
79 "--immutable-mayunlink: Sets the immutable_link flag on files.\n"
81 "--excldir: None of the files under a given directory will be unified\n"
82 "\tThe directory is expressed in absolute/logical form (relative\n"
83 "\tto the vserver root (ex: /var/log)\n"
85 "--incldir: All the files under a given directory will be unified\n"
86 "\tThe directory is expressed in absolute/logical form (relative\n"
87 "\tto the vserver root (ex: /var/log)\n"
89 "By default, the immutable_file and immutable_link flags are\n"
90 "set on the files. So if you want no immutable flags, you must\n"
91 "use --noflags. If you want a single flag, you must use\n"
92 "--noflags first, then the --immutable or --immutable-mayunlink\n"
97 static bool vunify_inside (vector<EXCLDIR> &dirs, const char *path)
100 for (unsigned i=0; i<dirs.size(); i++){
101 if (strncmp(dirs[i].prefix.c_str(),path,dirs[i].len)==0){
109 class PACKAGE_UNI: public Package{
111 list<string> files; // Files to unify
112 // This is loaded on demand
113 PACKAGE_UNI(string &_name, string &_version)
114 : Package(_name,_version)
117 PACKAGE_UNI(const char *_name, const char *_version)
118 : Package (_name,_version)
121 PACKAGE_UNI(const string &line)
125 // Load the file member of the package, but exclude configuration file
126 void loadfiles(const string &ref)
129 if (debug) cout << "Loading files for package " << name << endl;
131 namever = name + '-' + version;
132 FILE *fin = vutil_execdistcmd (K_UNIFILES,ref,namever.c_str());
135 while (fgets(tmp,sizeof(tmp)-1,fin)!=NULL){
136 int last = strlen(tmp)-1;
137 if (last >= 0 && tmp[last] == '\n') tmp[last] = '\0';
138 bool must_unify = false;
139 int type = 0; // K_UNIFILES only report unify-able files
140 if(type == 0 && !vunify_inside(excldirs,tmp)){
142 }else if(vunify_inside(incldirs,tmp)){
146 files.push_front (tmp);
148 cout << "Package " << name << " exclude " << tmp << endl;
152 if (debug) cout << "Done\n";
158 static ostream & operator << (ostream &c, const PACKAGE_UNI &p)
160 return c << p.name << "-" << p.version;
165 cout << "xx " << a << endl;
172 printer (const char *_title): title(_title){}
173 void operator()(T a){
174 cout << title << " " << a << endl;
180 Load the list of all packages in a vserver
182 static void vunify_loadallpkg (string &refserver, list<PACKAGE_UNI> &packages)
184 FILE *fin = vutil_execdistcmd (K_PKGVERSION,refserver,NULL);
187 while (fgets(line,sizeof(line)-1,fin)!=NULL){
188 // fprintf (stderr,"line: %s",line);
189 int last = strlen(line)-1;
190 if (last >= 0 && line[last] == '\n') line[last] = '\0';
191 packages.push_back (PACKAGE_UNI(line));
198 Object to unify a file
199 The file is first removed, then a hard link is made and then
200 the immutable flag is done
203 string &ref_server,&target_server;
206 file_unifier(string &_ref, string &_target, int &_ret)
207 : ref_server(_ref),target_server(_target), ret(_ret)
209 void operator()(const string &file)
211 string refpath = "/vservers/" + ref_server + file;
212 string dstpath = "/vservers/" + target_server + file;
213 if (debug) cout << "Unify " << refpath << " -> " << dstpath << endl;
215 if (stat(refpath.c_str(),&st)==-1){
216 if (debug) cout << "File " << refpath << " does not exist, ignored\n";
217 }else if (setext2flag(refpath.c_str(),false,ext2flags)==-1){
219 }else if (vbuild_unlink(dstpath.c_str())==-1){
221 cerr << "Can't delete file " << dstpath
222 << " (" << strerror(errno) << ")\n";
225 if (vbuild_file_copy(refpath.c_str(),dstpath.c_str(),st)==-1){
227 cerr << "Can't copy file " << refpath << " to " << dstpath
228 << " (" << strerror(errno) << ")\n";
231 if (vbuild_link(refpath.c_str(),dstpath.c_str())==-1){
233 cerr << "Can't link file " << refpath << " to " << dstpath
234 << " (" << strerror(errno) << ")\n";
237 // We put back the original immutable because other vservers
238 // may be unified on it.
239 if (setext2flag(refpath.c_str(),true,ext2flags)==-1){
246 // Check if two package have the same name (but potentially different version)
250 same_name(PACKAGE_UNI &_pkg) : pkg(_pkg) {}
251 bool operator()(const PACKAGE_UNI &p)
253 return pkg.name == p.name;
257 // Predicate to decide if a package must be unified
258 class package_unifier{
260 string &ref_server,&target_server;
261 list<PACKAGE_UNI> &target_packages;
263 package_unifier(string &_ref,
265 list<PACKAGE_UNI> &_target_packages,
267 : ref_server(_ref),target_server(_target)
268 , target_packages(_target_packages) , ret(_ret)
270 void operator()(PACKAGE_UNI &pkg)
272 if (find(target_packages.begin(),target_packages.end(),pkg)
273 !=target_packages.end()){
274 // Ok, the package is also in the target vserver
275 cout << "Unify pkg " << pkg << " from " << ref_server << " to "
276 << target_server << endl;
278 if (!testmode || debug){
279 pkg.loadfiles(ref_server);
280 for_each (pkg.files.begin(),pkg.files.end()
281 ,file_unifier(ref_server,target_server,ret));
284 // The package is missing, in test mode we provide more information
285 if (find_if(target_packages.begin(),target_packages.end(),same_name(pkg))
286 !=target_packages.end()){
287 cout << pkg << " exist in server " << target_server << " not unified\n";
289 cout << pkg << " does not exist in server " << target_server << endl;
295 // For each vserver, find the common packages and unify them
296 class server_unifier{
298 list<PACKAGE_UNI> &ref_packages;
301 server_unifier(string _ref_server, list<PACKAGE_UNI> &_packages, int &_ret)
302 : ref_packages(_packages),ref_server(_ref_server), ret(_ret)
304 void operator()(string serv)
306 list<PACKAGE_UNI> pkgs;
307 vunify_loadallpkg (serv,pkgs);
308 for_each(ref_packages.begin(),ref_packages.end()
309 ,package_unifier(ref_server,serv,pkgs,ret));
314 char **argv0,**argvn;
315 deleteif(char **_argv0, char **_argvn): argv0(_argv0),argvn(_argvn){}
316 bool operator()(const PACKAGE_UNI &pkg)
319 for (char **pt = argv0; pt < argvn; pt++){
320 if (pkg.name == *pt){
329 int main (int argc, char *argv[])
333 for (i=1; i<argc; i++){
334 const char *arg = argv[i];
335 //const char *opt = argv[i+1];
336 if (strcmp(arg,"--test")==0){
338 }else if (strcmp(arg,"--undo")==0){
340 }else if (strcmp(arg,"--debug")==0){
342 }else if (strcmp(arg,"--noflags")==0){
344 }else if (strcmp(arg,"--immutable")==0){
345 ext2flags |= EXT2_IMMUTABLE_FILE_FL;
346 }else if (strcmp(arg,"--immutable-mayunlink")==0){
347 ext2flags |= EXT2_IMMUTABLE_LINK_FL;
348 }else if (strcmp(arg,"--excldir")==0){
350 //excldirs[excldirs.size()] = EXCLDIR(argv[i]);
351 excldirs.push_back (EXCLDIR(argv[i]));
352 }else if (strcmp(arg,"--incldir")==0){
354 incldirs.push_back (EXCLDIR(argv[i]));
362 string refserv = argv[i++];
363 list<string> vservers;
364 for (; i<argc && strcmp(argv[i],"--")!=0; i++){
365 vservers.push_front (argv[i]);
367 for_each (vservers.begin(),vservers.end(),printer<string>("vservers"));
368 if (i == argc || strcmp(argv[i],"--")!=0){
373 list<PACKAGE_UNI> packages;
374 vunify_loadallpkg (refserv,packages);
375 if (i != argc-1 || strcmp(argv[i],"ALL")!=0){
376 // We keep only the packages supplied on the command line
377 packages.remove_if(deleteif (argv+i,argv+argc));
381 for_each (vservers.begin(),vservers.end(),server_unifier(refserv,packages,ret));