cleanups
[util-vserver.git] / util-vserver / src / vunify.cc
index 0faa03b..88b5c82 100644 (file)
        common package (RPM, same version), it does a hard link on non
        configuration file. It turns the file immutable after that.
 */
-#include <stdio.h>
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "vserver.hh"
+#include "util.h"
+
+#include <getopt.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -54,40 +61,76 @@ struct EXCLDIR{
                len = prefix.size();
        }
 };
+
+#define OPTION_TEST            1024
+#define OPTION_UNDO            1025
+#define OPTION_DEBUG           1026
+#define OPTION_NOFLAGS         1027
+#define OPTION_IMMUTABLE       1028
+#define OPTION_IMM_UNLINK      1029
+#define OPTION_EXCLDIR         1030
+#define OPTION_INCLDIR         1031
+
+static struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",                no_argument,       0, 'h' },
+  { "version",             no_argument,       0, 'v' },
+  { "test",                no_argument,       0, OPTION_TEST },
+  { "undo",                no_argument,       0, OPTION_UNDO },
+  { "debug",               no_argument,       0, OPTION_DEBUG },
+  { "noflags",             no_argument,       0, OPTION_NOFLAGS },
+  { "immutable",           no_argument,       0, OPTION_IMMUTABLE },
+  { "immutable-mayunlink", no_argument,       0, OPTION_IMM_UNLINK },
+  { "excldir",             required_argument, 0, OPTION_EXCLDIR },
+  { "incldir",             required_argument, 0, OPTION_INCLDIR },
+  { 0,0,0,0 }
+};
+  
+  
 static vector<EXCLDIR> excldirs;
 static vector<EXCLDIR> incldirs;
 
+static void
+showHelp(std::ostream &out, char const *, int exit_code)
+{
+  out << "Usage: \n"
+    "vunify [ options ] reference-server vservers ... -- packages\n"
+    "vunify [ options ] reference-server vservers ... -- ALL\n"
+    "\n"
+    "--test: Show what will be done, do not do it.\n"
+    "--undo: Put back the file in place, using copies from the\n"
+    "        reference server.\n"
+    "--debug: Prints some debugging messages.\n"
+    "--noflags: Do not put any immutable flags on the file\n"
+    "--immutable: Set the immutable_file bit on the files.\n"
+    "--immutable-mayunlink: Sets the immutable_link flag on files.\n"
+    "\n"
+    "--excldir: None of the files under a given directory will be unified\n"
+    "\tThe directory is expressed in absolute/logical form (relative\n"
+    "\tto the vserver root (ex: /var/log)\n"
+    "\n"
+    "--incldir: All the files under a given directory will be unified\n"
+    "\tThe directory is expressed in absolute/logical form (relative\n"
+    "\tto the vserver root (ex: /var/log)\n"
+    "\n"
+    "By default, the immutable_file and        immutable_link flags are\n"
+    "set on the files. So if you want no immutable flags, you must\n"
+    "use --noflags. If you want a single flag, you must use\n"
+    "--noflags first, then the --immutable or --immutable-mayunlink\n"
+    "flag.\n";
+
+  std::exit(exit_code);
+}
 
-static void usage()
+static void
+showVersion()
 {
-       cerr <<
-               "vunify version " << VERSION <<
-               "\n\n"
-               "vunify [ options ] reference-server vservers ... -- packages\n"
-               "vunify [ options ] reference-server vservers ... -- ALL\n"
-               "\n"
-               "--test: Show what will be done, do not do it.\n"
-               "--undo: Put back the file in place, using copies from the\n"
-               "        reference server.\n"
-               "--debug: Prints some debugging messages.\n"
-               "--noflags: Do not put any immutable flags on the file\n"
-               "--immutable: Set the immutable_file bit on the files.\n"
-               "--immutable-mayunlink: Sets the immutable_link flag on files.\n"
-               "\n"
-               "--excldir: None of the files under a given directory will be unified\n"
-               "\tThe directory is expressed in absolute/logical form (relative\n"
-               "\tto the vserver root (ex: /var/log)\n"
-               "\n"
-               "--incldir: All the files under a given directory will be unified\n"
-               "\tThe directory is expressed in absolute/logical form (relative\n"
-               "\tto the vserver root (ex: /var/log)\n"
-               "\n"
-               "By default, the immutable_file and     immutable_link flags are\n"
-               "set on the files. So if you want no immutable flags, you must\n"
-               "use --noflags. If you want a single flag, you must use\n"
-               "--noflags first, then the --immutable or --immutable-mayunlink\n"
-               "flag.\n"
-               ;
+  std::cout << "vunify " VERSION " -- unifies files of vservers\n"
+    "This program is part of " PACKAGE_STRING "\n\n"
+    "Copyright (C) 2003 Enrico Scholz\n"
+    VERSION_COPYRIGHT_DISCLAIMER;
+
+  std::exit(0);
 }
 
 static bool vunify_inside (vector<EXCLDIR> &dirs, const char *path)
@@ -102,24 +145,24 @@ static bool vunify_inside (vector<EXCLDIR> &dirs, const char *path)
        return found;
 }
 
-class PACKAGE_UNI: public PACKAGE{
+class PACKAGE_UNI: public Package{
 public:
        list<string> files;             // Files to unify
                                                        // This is loaded on demand
        PACKAGE_UNI(string &_name, string &_version)
-               : PACKAGE(_name,_version)
+               : Package(_name,_version)
        {
        }
        PACKAGE_UNI(const char *_name, const char *_version)
-               : PACKAGE (_name,_version)
+               : Package (_name,_version)
        {
        }
        PACKAGE_UNI(const string &line)
-               : PACKAGE (line)
+               : Package (line)
        {
        }
        // Load the file member of the package, but exclude configuration file
-       void loadfiles(const string &ref)
+       void loadfiles(Vserver const &ref)
        {
                if (files.empty()){
                        if (debug) cout << "Loading files for package " << name << endl;
@@ -166,7 +209,7 @@ template<class T>
                string title;
                public:
                printer (const char *_title): title(_title){}
-               void operator()(T a){
+               void operator()(T const &a){
                        cout << title << " " << a << endl;
                }
        };
@@ -175,7 +218,7 @@ template<class T>
 /*
        Load the list of all packages in a vserver
 */
-static void vunify_loadallpkg (string &refserver, list<PACKAGE_UNI> &packages)
+static void vunify_loadallpkg (Vserver const &refserver, list<PACKAGE_UNI> &packages)
 {
        FILE *fin = vutil_execdistcmd (K_PKGVERSION,refserver,NULL);
        if (fin != NULL){
@@ -196,48 +239,56 @@ static void vunify_loadallpkg (string &refserver, list<PACKAGE_UNI> &packages)
        the immutable flag is done
 */
 class file_unifier{
-       string &ref_server,&target_server;
-       int &ret;
-       public:
-       file_unifier(string &_ref, string &_target, int &_ret)
-               : ref_server(_ref),target_server(_target), ret(_ret)
-       {}
-       void operator()(const string &file)
-       {
-               string refpath = "/vservers/" + ref_server + file;
-               string dstpath = "/vservers/" + target_server + file;
-               if (debug) cout << "Unify " << refpath << " -> " << dstpath << endl;
-               struct stat st;
-               if (stat(refpath.c_str(),&st)==-1){
-                       if (debug) cout << "File " << refpath << " does not exist, ignored\n";
-               }else if (setext2flag(refpath.c_str(),false,ext2flags)==-1){
-                       ret = -1;
-               }else if (vbuild_unlink(dstpath.c_str())==-1){
-                       ret = -1;
-                       cerr << "Can't delete file " << dstpath
-                               << " (" << strerror(errno) << ")\n";
-               }else{
-                       if (undo){
-                               if (vbuild_file_copy(refpath.c_str(),dstpath.c_str(),st)==-1){
-                                       ret = -1;
-                                       cerr << "Can't copy file " << refpath << " to " << dstpath
-                                               << " (" << strerror(errno) << ")\n";
-                               }
-                       }else{
-                               if (vbuild_link(refpath.c_str(),dstpath.c_str())==-1){
-                                       ret = -1;
-                                       cerr << "Can't link file " << refpath << " to " << dstpath
-                                               << " (" << strerror(errno) << ")\n";
-                               }
-                       }
-                       // We put back the original immutable because other vservers
-                       // may be unified on it.
-                       if (setext2flag(refpath.c_str(),true,ext2flags)==-1){
-                               ret = -1;
-                       }
-               }
+    Vserver const      &ref_server;
+    Vserver const      &target_server;
+    int &ret;
+
+  public:
+    file_unifier(Vserver const &_ref, Vserver const &_target, int &_ret)
+      : ref_server(_ref),target_server(_target), ret(_ret)
+    {}
+
+    void operator()(const string &file)
+    {
+      std::string      refpath = ref_server.getVdir();
+      refpath                 += file;
+         
+      std::string      dstpath = target_server.getVdir();
+      dstpath              += file;
+         
+      if (debug) cout << "Unify " << refpath << " -> " << dstpath << endl;
+      struct stat st;
+      if (stat(refpath.c_str(),&st)==-1){
+       if (debug) cout << "File " << refpath << " does not exist, ignored\n";
+      }else if (setext2flag(refpath.c_str(),false,ext2flags)==-1){
+       ret = -1;
+      }else if (vbuild_unlink(dstpath.c_str())==-1){
+       ret = -1;
+       cerr << "Can't delete file " << dstpath
+            << " (" << strerror(errno) << ")\n";
+      }else{
+       if (undo){
+         if (vbuild_file_copy(refpath.c_str(),dstpath.c_str(),st)==-1){
+           ret = -1;
+           cerr << "Can't copy file " << refpath << " to " << dstpath
+                << " (" << strerror(errno) << ")\n";
+         }
+       }else{
+         if (vbuild_link(refpath.c_str(),dstpath.c_str())==-1){
+           ret = -1;
+           cerr << "Can't link file " << refpath << " to " << dstpath
+                << " (" << strerror(errno) << ")\n";
+         }
+       }
+         // We put back the original immutable because other vservers
+         // may be unified on it.
+       if (setext2flag(refpath.c_str(),true,ext2flags)==-1){
+         ret = -1;
        }
+      }
+    }
 };
+
 #if 0
 // Check if two package have the same name (but potentially different version)
 class same_name{
@@ -250,61 +301,66 @@ public:
        }
 };
 #endif
-// Predicate to decide if a package must be unified
+  // Predicate to decide if a package must be unified
 class package_unifier{
-public:
-       string &ref_server,&target_server;
-       list<PACKAGE_UNI> &target_packages;
-       int &ret;
-       package_unifier(string &_ref,
-                       string &_target,
-                       list<PACKAGE_UNI> &_target_packages,
-                       int &_ret)
-               : ref_server(_ref),target_server(_target)
-               , target_packages(_target_packages) , ret(_ret)
-       {}
-       void operator()(PACKAGE_UNI &pkg)
-       {
-               if (find(target_packages.begin(),target_packages.end(),pkg)
-                       !=target_packages.end()){
-                       // Ok, the package is also in the target vserver
-                       cout << "Unify pkg " << pkg << " from " << ref_server << " to "
-                               << target_server << endl;
-
-                       if (!testmode || debug){
-                               pkg.loadfiles(ref_server);
-                               for_each (pkg.files.begin(),pkg.files.end()
-                                       ,file_unifier(ref_server,target_server,ret));
-                       }
-               }else if (testmode){
-                       // The package is missing, in test mode we provide more information
-                       if (find_if(target_packages.begin(),target_packages.end(),same_name(pkg))
-                               !=target_packages.end()){
-                               cout << pkg << " exist in server " << target_server << " not unified\n";
-                       }else{
-                               cout << pkg << " does not exist in server " << target_server << endl;
-                       }
-               }
+  public:
+    Vserver const      &ref_server;
+    Vserver const      &target_server;
+    list<PACKAGE_UNI>  &target_packages;
+    int                        &ret;
+    
+    package_unifier(Vserver const &_ref,
+                   Vserver const &_target,
+                   list<PACKAGE_UNI> &_target_packages,
+                   int &_ret) :
+      ref_server(_ref),target_server(_target),
+      target_packages(_target_packages), ret(_ret)
+    {}
+    void operator()(PACKAGE_UNI &pkg)
+    {
+      if (find(target_packages.begin(),target_packages.end(),pkg)
+         !=target_packages.end()){
+         // Ok, the package is also in the target vserver
+       cout << "Unify pkg " << pkg << " from " << ref_server << " to "
+            << target_server << endl;
+
+       if (!testmode || debug){
+         pkg.loadfiles(ref_server);
+         for_each (pkg.files.begin(),pkg.files.end()
+                   ,file_unifier(ref_server,target_server,ret));
+       }
+      }else if (testmode){
+         // The package is missing, in test mode we provide more information
+       if (find_if(target_packages.begin(),target_packages.end(),same_name(pkg))
+           !=target_packages.end()){
+         cout << pkg << " exist in server " << target_server << " not unified\n";
+       }else{
+         cout << pkg << " does not exist in server " << target_server << endl;
        }
+      }
+    }
 };
 
 // For each vserver, find the common packages and unify them
 class server_unifier{
 public:
-       list<PACKAGE_UNI> &ref_packages;
-       string &ref_server;
-       int &ret;
-       server_unifier(string _ref_server, list<PACKAGE_UNI> &_packages, int &_ret)
-               : ref_packages(_packages),ref_server(_ref_server), ret(_ret)
-               {}
-       void operator()(string serv)
-       {
-               list<PACKAGE_UNI> pkgs;
-               vunify_loadallpkg (serv,pkgs);
-               for_each(ref_packages.begin(),ref_packages.end()
-                       ,package_unifier(ref_server,serv,pkgs,ret));
-       }
+    list<PACKAGE_UNI>  &ref_packages;
+    Vserver const      &ref_server;
+    int                        &ret;
+    
+    server_unifier(Vserver const &_ref_server, list<PACKAGE_UNI> &_packages, int &_ret)
+      : ref_packages(_packages),ref_server(_ref_server), ret(_ret)
+    {}
+    
+    void operator()(Vserver const &serv)
+    {
+      list<PACKAGE_UNI> pkgs;
+      vunify_loadallpkg (serv,pkgs);
+      for_each(ref_packages.begin(),ref_packages.end()
+              ,package_unifier(ref_server,serv,pkgs,ret));
+    }
 };
+
 class deleteif{
 public:
        char **argv0,**argvn;
@@ -324,65 +380,52 @@ public:
 
 int main (int argc, char *argv[])
 {
-       int ret = -1;
-       int i;
-       for (i=1; i<argc; i++){
-               const char *arg = argv[i];
-               //const char *opt = argv[i+1];
-               if (strcmp(arg,"--test")==0){
-                       testmode = true;
-               }else if (strcmp(arg,"--undo")==0){
-                       undo = true;
-               }else if (strcmp(arg,"--debug")==0){
-                       debug++;
-               }else if (strcmp(arg,"--noflags")==0){
-                       ext2flags = 0;
-               }else if (strcmp(arg,"--immutable")==0){
-                       ext2flags |= EXT2_IMMUTABLE_FILE_FL;
-               }else if (strcmp(arg,"--immutable-mayunlink")==0){
-                       ext2flags |= EXT2_IMMUTABLE_LINK_FL;
-               }else if (strcmp(arg,"--excldir")==0){
-                       i++;
-                       //excldirs[excldirs.size()] = EXCLDIR(argv[i]);
-                       excldirs.push_back (EXCLDIR(argv[i]));
-               }else if (strcmp(arg,"--incldir")==0){
-                       i++;
-                       incldirs.push_back (EXCLDIR(argv[i]));
-               }else{
-                       break;
-               }
-       }
-       if (i==argc){
-               usage();
-       }else{
-               string refserv = argv[i++];
-               list<string> vservers;
-               for (; i<argc && strcmp(argv[i],"--")!=0; i++){
-                       vservers.push_front (argv[i]);
-               }
-               for_each (vservers.begin(),vservers.end(),printer<string>("vservers"));
-               if (i == argc || strcmp(argv[i],"--")!=0){
-                       usage();
-               }else{
-                       i++;
-                       if (i < argc){
-                               list<PACKAGE_UNI> packages;
-                               vunify_loadallpkg (refserv,packages);
-                               if (i != argc-1 || strcmp(argv[i],"ALL")!=0){
-                                       // We keep only the packages supplied on the command line
-                                       packages.remove_if(deleteif (argv+i,argv+argc));
-                               }
-                               ret = 0;
-                               umask (0);
-                               for_each (vservers.begin(),vservers.end(),server_unifier(refserv,packages,ret));
-                       }else{
-                               usage();
-                       }
-               }
-       }
-       return ret;
-}
+  while (1) {
+    int                c = getopt_long(argc, argv, "hv", CMDLINE_OPTIONS, 0);
+    switch (c) {
+      case 'h'                 :  showHelp(std::cout, argv[0], 0); break;
+      case 'v'                 :  showVersion();                   break;
+      case OPTION_TEST         :  testmode = true; break;
+      case OPTION_UNDO         :  undo     = true; break;
+      case OPTION_DEBUG                :  ++debug;         break;
+      case OPTION_NOFLAGS      :  ext2flags = 0;   break;
+      case OPTION_IMMUTABLE    :  ext2flags |= EXT2_IMMUTABLE_FILE_FL; break;
+      case OPTION_IMM_UNLINK   :  ext2flags |= EXT2_IMMUTABLE_LINK_FL; break;
+      case OPTION_EXCLDIR      :  excldirs.push_back(EXCLDIR(optarg)); break;
+      case OPTION_INCLDIR      :  incldirs.push_back(EXCLDIR(optarg)); break;
+      default                  :
+       std::cerr << "Try '" << argv[0] << " --help' for more information." << std::endl;
+       return EXIT_FAILURE;
+    }
+  }
+
+  if (optind+1>=argc) {
+    std::cerr << "No vserver specified" << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  Vserver                      refserv(argv[optind++]);
+  std::vector<Vserver>         vservers;
+  while (optind<argc && strcmp(argv[optind], "--")!=0)
+    vservers.push_back(Vserver(argv[optind++]));
 
+  ++optind;
+  if (optind>=argc) {
+    std::cerr << "No packages specified" << std::endl;
+    return EXIT_FAILURE;
+  }
 
+  for_each (vservers.begin(),vservers.end(),printer<Vserver>("vservers"));
 
+  std::list<PACKAGE_UNI>       packages;
+  vunify_loadallpkg(refserv, packages);
+  
+  if (optind!=argc-1 || strcmp(argv[optind], "ALL")!=0)
+    packages.remove_if(deleteif(argv+optind, argv+argc));
 
+  int          ret = EXIT_SUCCESS;
+  umask(0);
+  for_each(vservers.begin(), vservers.end(), server_unifier(refserv,packages,ret));
+
+  return ret;
+}