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.
30 #include <sys/ioctl.h>
44 static bool undo = false;
46 static int ext2flags = EXT2_IMMUTABLE_FILE_FL | EXT2_IMMUTABLE_LINK_FL;
50 EXCLDIR(const char *s)
57 static vector<EXCLDIR> excldirs;
58 static vector<EXCLDIR> incldirs;
64 "vunify version " << VERSION <<
66 "vunify [ options ] reference-server vservers ... -- packages\n"
67 "vunify [ options ] reference-server vservers ... -- ALL\n"
69 "--test: Show what will be done, do not do it.\n"
70 "--undo: Put back the file in place, using copies from the\n"
71 " reference server.\n"
72 "--debug: Prints some debugging messages.\n"
73 "--noflags: Do not put any immutable flags on the file\n"
74 "--immutable: Set the immutable_file bit on the files.\n"
75 "--immutable-mayunlink: Sets the immutable_link flag on files.\n"
77 "--excldir: None of the files under a given directory will be unified\n"
78 "\tThe directory is expressed in absolute/logical form (relative\n"
79 "\tto the vserver root (ex: /var/log)\n"
81 "--incldir: All 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 "By default, the immutable_file and immutable_link flags are\n"
86 "set on the files. So if you want no immutable flags, you must\n"
87 "use --noflags. If you want a single flag, you must use\n"
88 "--noflags first, then the --immutable or --immutable-mayunlink\n"
93 static bool vunify_inside (vector<EXCLDIR> &dirs, const char *path)
96 for (unsigned i=0; i<dirs.size(); i++){
97 if (strncmp(dirs[i].prefix.c_str(),path,dirs[i].len)==0){
105 class PACKAGE_UNI: public PACKAGE{
107 list<string> files; // Files to unify
108 // This is loaded on demand
109 PACKAGE_UNI(string &_name, string &_version)
110 : PACKAGE(_name,_version)
113 PACKAGE_UNI(const char *_name, const char *_version)
114 : PACKAGE (_name,_version)
117 PACKAGE_UNI(const string &line)
121 // Load the file member of the package, but exclude configuration file
122 void loadfiles(const string &ref)
125 if (debug) cout << "Loading files for package " << name << endl;
127 namever = name + '-' + version;
128 FILE *fin = vutil_execdistcmd (K_UNIFILES,ref,namever.c_str());
131 while (fgets(tmp,sizeof(tmp)-1,fin)!=NULL){
132 int last = strlen(tmp)-1;
133 if (last >= 0 && tmp[last] == '\n') tmp[last] = '\0';
134 bool must_unify = false;
135 int type = 0; // K_UNIFILES only report unify-able files
136 if(type == 0 && !vunify_inside(excldirs,tmp)){
138 }else if(vunify_inside(incldirs,tmp)){
142 files.push_front (tmp);
144 cout << "Package " << name << " exclude " << tmp << endl;
148 if (debug) cout << "Done\n";
154 static ostream & operator << (ostream &c, const PACKAGE_UNI &p)
156 return c << p.name << "-" << p.version;
161 cout << "xx " << a << endl;
168 printer (const char *_title): title(_title){}
169 void operator()(T a){
170 cout << title << " " << a << endl;
176 Load the list of all packages in a vserver
178 static void vunify_loadallpkg (string &refserver, list<PACKAGE_UNI> &packages)
180 FILE *fin = vutil_execdistcmd (K_PKGVERSION,refserver,NULL);
183 while (fgets(line,sizeof(line)-1,fin)!=NULL){
184 // fprintf (stderr,"line: %s",line);
185 int last = strlen(line)-1;
186 if (last >= 0 && line[last] == '\n') line[last] = '\0';
187 packages.push_back (PACKAGE_UNI(line));
194 Object to unify a file
195 The file is first removed, then a hard link is made and then
196 the immutable flag is done
199 string &ref_server,&target_server;
202 file_unifier(string &_ref, string &_target, int &_ret)
203 : ref_server(_ref),target_server(_target), ret(_ret)
205 void operator()(const string &file)
207 string refpath = "/vservers/" + ref_server + file;
208 string dstpath = "/vservers/" + target_server + file;
209 if (debug) cout << "Unify " << refpath << " -> " << dstpath << endl;
211 if (stat(refpath.c_str(),&st)==-1){
212 if (debug) cout << "File " << refpath << " does not exist, ignored\n";
213 }else if (setext2flag(refpath.c_str(),false,ext2flags)==-1){
215 }else if (vbuild_unlink(dstpath.c_str())==-1){
217 cerr << "Can't delete file " << dstpath
218 << " (" << strerror(errno) << ")\n";
221 if (vbuild_file_copy(refpath.c_str(),dstpath.c_str(),st)==-1){
223 cerr << "Can't copy file " << refpath << " to " << dstpath
224 << " (" << strerror(errno) << ")\n";
227 if (vbuild_link(refpath.c_str(),dstpath.c_str())==-1){
229 cerr << "Can't link file " << refpath << " to " << dstpath
230 << " (" << strerror(errno) << ")\n";
233 // We put back the original immutable because other vservers
234 // may be unified on it.
235 if (setext2flag(refpath.c_str(),true,ext2flags)==-1){
242 // Check if two package have the same name (but potentially different version)
246 same_name(PACKAGE_UNI &_pkg) : pkg(_pkg) {}
247 bool operator()(const PACKAGE_UNI &p)
249 return pkg.name == p.name;
253 // Predicate to decide if a package must be unified
254 class package_unifier{
256 string &ref_server,&target_server;
257 list<PACKAGE_UNI> &target_packages;
259 package_unifier(string &_ref,
261 list<PACKAGE_UNI> &_target_packages,
263 : ref_server(_ref),target_server(_target)
264 , target_packages(_target_packages) , ret(_ret)
266 void operator()(PACKAGE_UNI &pkg)
268 if (find(target_packages.begin(),target_packages.end(),pkg)
269 !=target_packages.end()){
270 // Ok, the package is also in the target vserver
271 cout << "Unify pkg " << pkg << " from " << ref_server << " to "
272 << target_server << endl;
274 if (!testmode || debug){
275 pkg.loadfiles(ref_server);
276 for_each (pkg.files.begin(),pkg.files.end()
277 ,file_unifier(ref_server,target_server,ret));
280 // The package is missing, in test mode we provide more information
281 if (find_if(target_packages.begin(),target_packages.end(),same_name(pkg))
282 !=target_packages.end()){
283 cout << pkg << " exist in server " << target_server << " not unified\n";
285 cout << pkg << " does not exist in server " << target_server << endl;
291 // For each vserver, find the common packages and unify them
292 class server_unifier{
294 list<PACKAGE_UNI> &ref_packages;
297 server_unifier(string _ref_server, list<PACKAGE_UNI> &_packages, int &_ret)
298 : ref_packages(_packages),ref_server(_ref_server), ret(_ret)
300 void operator()(string serv)
302 list<PACKAGE_UNI> pkgs;
303 vunify_loadallpkg (serv,pkgs);
304 for_each(ref_packages.begin(),ref_packages.end()
305 ,package_unifier(ref_server,serv,pkgs,ret));
310 char **argv0,**argvn;
311 deleteif(char **_argv0, char **_argvn): argv0(_argv0),argvn(_argvn){}
312 bool operator()(const PACKAGE_UNI &pkg)
315 for (char **pt = argv0; pt < argvn; pt++){
316 if (pkg.name == *pt){
325 int main (int argc, char *argv[])
329 for (i=1; i<argc; i++){
330 const char *arg = argv[i];
331 //const char *opt = argv[i+1];
332 if (strcmp(arg,"--test")==0){
334 }else if (strcmp(arg,"--undo")==0){
336 }else if (strcmp(arg,"--debug")==0){
338 }else if (strcmp(arg,"--noflags")==0){
340 }else if (strcmp(arg,"--immutable")==0){
341 ext2flags |= EXT2_IMMUTABLE_FILE_FL;
342 }else if (strcmp(arg,"--immutable-mayunlink")==0){
343 ext2flags |= EXT2_IMMUTABLE_LINK_FL;
344 }else if (strcmp(arg,"--excldir")==0){
346 //excldirs[excldirs.size()] = EXCLDIR(argv[i]);
347 excldirs.push_back (EXCLDIR(argv[i]));
348 }else if (strcmp(arg,"--incldir")==0){
350 incldirs.push_back (EXCLDIR(argv[i]));
358 string refserv = argv[i++];
359 list<string> vservers;
360 for (; i<argc && strcmp(argv[i],"--")!=0; i++){
361 vservers.push_front (argv[i]);
363 for_each (vservers.begin(),vservers.end(),printer<string>("vservers"));
364 if (i == argc || strcmp(argv[i],"--")!=0){
369 list<PACKAGE_UNI> packages;
370 vunify_loadallpkg (refserv,packages);
371 if (i != argc-1 || strcmp(argv[i],"ALL")!=0){
372 // We keep only the packages supplied on the command line
373 packages.remove_if(deleteif (argv+i,argv+argc));
377 for_each (vservers.begin(),vservers.end(),server_unifier(refserv,packages,ret));