Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

vmkdir.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // vmkdir.C
00021 // Last modified on Sun Jun  5 21:53:18 EDT 2005 by ken@xorian.net         
00022 //      modified on Mon Nov 15 12:10:03 EST 2004 by irina.furman@intel.com 
00023 //      modified on Wed Jul 11 22:24:38 PDT 2001 by mann  
00024 //      modified on Tue May  4 11:34:41 PDT 1999 by heydon
00025 //
00026 
00027 // Create a directory in the Vesta repository.  Provides an
00028 // alternative to the NFS interface on platofrms with obstinate NFS
00029 // client code (e.g. some of the Linux 2.4 series).
00030 
00031 // See documentation in vmkdir.1.mtex
00032 
00033 #include <Basics.H>
00034 #include <Text.H>
00035 #include <VestaConfig.H>
00036 #include <VestaSource.H>
00037 #include <VDirSurrogate.H>
00038 #include <VestaSourceAtomic.H>
00039 #include <Replicator.H>
00040 #include <signal.h>
00041 #include "ReposUI.H"
00042 
00043 #if !defined(__sun__)
00044 extern "C" {
00045 #include <getopt.h>
00046 }
00047 #endif
00048 
00049 using std::cout;
00050 using std::cin;
00051 using std::cerr;
00052 using std::endl;
00053 using std::flush;
00054 
00055 Text program_name;
00056 
00057 void usage()
00058 {
00059   cerr << "Usage: " << program_name << endl <<
00060     "        [-q] [-Q] [-a | -A] [-p] [-f]" << endl <<
00061     "        [-h hints]" << endl <<
00062     "        [-R repos]" << endl <<
00063     "        directory" << endl << endl;
00064   exit(1);
00065 }
00066 
00067 int
00068 main(int argc, char* argv[])
00069 {
00070   program_name = argv[0];
00071   try {
00072     //
00073     // Read config file
00074     //
00075     Text repos;
00076     bool default_repos = true;
00077 
00078     // If the parent directory is mastered remotely, should we have
00079     // the local repository acquire mastership of the created
00080     // directory?  Defaults to on.
00081     bool acquire_mastership = false;
00082 
00083     Text cuser(AccessControl::self()->user());
00084     Text user(cuser.Sub(0, cuser.FindChar('@')));
00085     Text lhost(VDirSurrogate::defaultHost());
00086     Text lport(VDirSurrogate::defaultPort());
00087     const int vlen = 7; // ==strlen("/vesta/")
00088     const Replicator::Flags rflags = (Replicator::Flags) 
00089       (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00090        Replicator::revive | Replicator::inclStubs | Replicator::latest);
00091 
00092     if(VestaConfig::is_set("UserInterface", "vmkdir_acquires"))
00093       {
00094         acquire_mastership = VestaConfig::get_bool("UserInterface",
00095                                                    "vmkdir_acquires");
00096       }
00097     Text defhints;
00098     (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00099 
00100     //
00101     // Parse command line
00102     //
00103     bool quiet = false;
00104     bool query = false;
00105     bool force = false;
00106 
00107     // Should we set the type attribute on the created directory to
00108     // package-parent?
00109     bool set_package_parent = false;
00110 
00111     Text dir, oldver, hints;
00112 
00113     opterr = 0;
00114     for (;;) {
00115       int c = getopt(argc, argv, "qQaApfh:R:");
00116       if (c == EOF) break;
00117       switch (c) {
00118       case 'q':
00119         quiet = true;
00120         break;
00121       case 'Q':
00122         query = true;
00123         break;
00124       case 'a':
00125         acquire_mastership = true;
00126         break;
00127       case 'A':
00128         acquire_mastership = false;
00129         break;
00130       case 'p':
00131         set_package_parent = true;
00132         break;
00133       case 'f':
00134         force = true;
00135         break;
00136       case 'h':
00137         hints = optarg;
00138         break;
00139       case 'R':
00140         repos = optarg;
00141         default_repos = false;
00142         break;
00143       case '?':
00144       default:
00145         usage();
00146       }
00147     }
00148     if (argc != optind + 1) {
00149       usage();
00150     }
00151     dir = Text(argv[optind]);
00152 
00153     //
00154     // Use a nondefault repository if specified, and automatically
00155     // add it to the hints if not already present.
00156     //
00157     if (!default_repos) {
00158       int colon = repos.FindCharR(':');
00159       if (colon == -1) {
00160         lhost = repos;
00161         repos = repos + ":" + lport;
00162       } else {
00163         lhost = repos.Sub(0, colon);
00164         lport = repos.Sub(colon+1);
00165       }
00166       hints = hints + " " + repos;
00167     }
00168     hints = hints + " " + defhints;
00169 
00170     //
00171     // Qualify and canonicalize names
00172     //
00173     Text cdir, cparent, newpart;
00174     cdir = ReposUI::canonicalize(dir);
00175     ReposUI::split(cdir, cparent, newpart, "directory name");
00176 
00177     // Is the parent the appendable root?
00178     bool parent_is_app_root =
00179       (strcmp(cparent.cchars(), "/vesta") == 0);
00180 
00181     // Is the directory to be created in the mutable root?
00182     bool in_mutable_root = 
00183       (strncmp(cdir.cchars(), "/vesta-work/", 12)  == 0);
00184 
00185     // The volatile root is often mounted inside the mutable root
00186     // (i.e. /vesta-work/.volatile).  We'll refuse to create a
00187     // directory in the volatile root.
00188     Text volatileRoot = VestaConfig::get_Text("Run_Tool", "VolatileRootName");
00189     if(volatileRoot[volatileRoot.Length()-1] != '/')
00190       {
00191         volatileRoot += "/";
00192       }
00193     if(strncmp(dir.cchars(),
00194                volatileRoot.cchars(), volatileRoot.Length()) == 0)
00195       {
00196         cerr << program_name << ": " << dir
00197              << " is inside the volatile root ("
00198              << volatileRoot << ")" << endl;
00199         exit(2);
00200       }
00201 
00202     //
00203     // Look up parent and sanity check
00204     //
00205     VestaSource* vs_mparent;
00206     if(parent_is_app_root)
00207       {
00208         // Special case: there is no master of the appendable root.
00209         // User must be the wizard to have permission to create here.
00210         vs_mparent = VDirSurrogate::repositoryRoot(lhost, lport);
00211       }
00212     else if(in_mutable_root)
00213       {
00214         // Local repository is always the master of the mutable root.
00215         vs_mparent = ReposUI::filenameToVS(cparent, lhost, lport);
00216       }
00217     else
00218       {
00219         // If it's not in the mutable root or a top-level child of the
00220         // appendable root, find the master of the parent.
00221         vs_mparent = ReposUI::filenameToMasterVS(cparent, hints);
00222         if (!force)
00223           {
00224             // Be default, don't allow the user to created directories
00225             // within a package, branch, checkout, or session directory.
00226 
00227             if(vs_mparent->inAttribs("type", "package"))
00228               {
00229                 cerr << program_name << ": " << cparent
00230                      << " has type package" << endl;
00231                 exit(2);
00232               }
00233             // This case is a little redundant, because branches normally
00234             // also have "package" in their type (see the vbranch man
00235             // page).  Can't hurt to check though.
00236             else if(vs_mparent->inAttribs("type", "branch"))
00237               {
00238                 cerr << program_name << ": " << cparent
00239                      << " has type branch" << endl;
00240                 exit(2);
00241               }
00242             else if(vs_mparent->inAttribs("type", "checkout"))
00243               {
00244                 cerr << program_name << ": " << cparent
00245                      << " has type checkout" << endl;
00246                 exit(2);
00247               }
00248             else if(vs_mparent->inAttribs("type", "session"))
00249               {
00250                 cerr << program_name << ": " << cparent
00251                      << " has type session" << endl;
00252                 exit(2);
00253               }
00254           }
00255       }
00256     Text mhost(vs_mparent->host());
00257     Text mport(vs_mparent->port());
00258     bool remote = (mhost != lhost || mport != lport);
00259     Text hint_dir;
00260     if(remote) {
00261       // find directory whose master-repository attribute needs to be updated
00262       hint_dir = ReposUI::getMasterHintDir(vs_mparent, cparent);
00263     }
00264 
00265 
00266     // If the directory to be created is in the mutable root or
00267     // directly below the appendable root, it must be local.
00268     assert(!remote || (!parent_is_app_root && !in_mutable_root));
00269 
00270     if (!quiet) {
00271       cout << "Creating directory " << cdir;
00272       if (remote) {
00273         cout << " at " << mhost << ":" << mport;
00274       }
00275       cout << endl;
00276     }
00277 
00278     if (query) {
00279       cerr << program_name << ": nothing done (-Q flag given)" << endl;
00280       exit(0);
00281     }
00282 
00283     // Creating a top-level directory beneath the appendable root is a
00284     // rare occurrence that has special rules to avoid violating the
00285     // replication invariant.
00286     if(parent_is_app_root)
00287       {
00288         cout << endl
00289              << "Warning: Top-level directories must be unique.  (If they"
00290              << endl
00291              << "         aren't, you can can violate the replication"
00292              << endl
00293              << "         invariant.)" << endl << endl
00294              << "         The recommend method is to base top-level" << endl
00295              << "         directory names on a domain or e-mail address that"
00296              << endl
00297              << "         you own." << endl << endl
00298              << "Are you sure you want to proceed (y/n)? " << flush;
00299 
00300         const int BuffLen = 20; char buff[BuffLen];
00301         cin.getline(buff, BuffLen);
00302         if (buff[0] != 'y')
00303           {
00304             cout << "Not creating " << cdir << endl;
00305             exit(0);
00306           }
00307       }
00308 
00309     //
00310     // Construct atomic action to create the directory.  (This is a
00311     // little bit of overkill, but it ensures that the package-parent
00312     // attribute gets added in the same action.)
00313     //
00314     VestaSourceAtomic vsa(mhost, mport);
00315 
00316     // Declare parent directory and make sure it is master
00317     VestaSourceAtomic::VSIndex vsi_parent =
00318       vsa.decl(cparent, vs_mparent);
00319     if(!parent_is_app_root)
00320       {
00321         vsa.testMaster(cparent, vsi_parent, true,
00322                        VestaSource::notMaster);
00323       }
00324 
00325     // Make directory.  This is the last step that should be able to
00326     // halt, so we just try it; no need to test first.
00327     VestaSourceAtomic::VSIndex vsi_dir;
00328     if(in_mutable_root)
00329       {
00330         vsi_dir =
00331           vsa.insertMutableDirectory(cdir, vsi_parent,
00332                                      newpart, -1, true,
00333                                      VestaSource::dontReplace);
00334       }
00335     else
00336       {
00337         vsi_dir =
00338           vsa.insertAppendableDirectory(cdir, vsi_parent,
00339                                         newpart, true,
00340                                         VestaSource::dontReplace);
00341       }
00342 
00343     // Set attributes
00344     if(set_package_parent && !in_mutable_root)
00345       {
00346         vsa.setAttrib(cdir, vsi_dir, "type", "package-parent");
00347       }
00348 
00349     //
00350     // Disable ^C signal to make it less likely that we will be
00351     // killed after having done the remote action but
00352     // before having finished the whole job.
00353     //
00354     signal(SIGINT, SIG_IGN);
00355 
00356     // Commit
00357     if (!vsa.run()) {
00358       VestaSource::errorCode err;
00359       if (vsa.lasterr == VestaSource::ok) {
00360         err = vsa.okreplace;
00361       } else {
00362         err = vsa.lasterr;
00363       }
00364       cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
00365            << ReposUI::errorCodeText(err) << endl;
00366       if((err == VestaSource::noPermission) && parent_is_app_root)
00367         {
00368           cerr << "(Maybe you need to be " 
00369                << VestaConfig::get_Text("Repository", "vwizard_user")
00370                << "?)" << endl;
00371         }
00372       exit(2);
00373     }
00374 
00375     // Done if master was local (or was a special case that's always
00376     // local)
00377     if (!remote || parent_is_app_root || in_mutable_root) exit(0);
00378 
00379     //
00380     // Replicate the new directory here
00381     //
00382     Replicator repl(mhost, mport, lhost, lport);
00383     Replicator::DirectiveSeq direcs;
00384     Replicator::Directive d('+', cdir.Sub(vlen));
00385     direcs.addhi(d);
00386     repl.replicate(&direcs, rflags);
00387 
00388     //
00389     // Take mastership of the directory if requested.
00390     //
00391     if(acquire_mastership)
00392       {
00393         VestaSource::errorCode err =
00394           VDirSurrogate::acquireMastership(cdir.Sub(vlen).cchars(),
00395                                            lhost, lport, mhost, mport);
00396         if (err != VestaSource::ok) {
00397           cerr << program_name << ": error acquiring mastership of "
00398                << cdir << ": " << ReposUI::errorCodeText(err) << endl;
00399           exit(2);
00400         }
00401       }
00402 
00403     // Update master-repository hint
00404     Text master_hint = mhost + ":" + mport;
00405     VestaSource* vs_hint = NULL;
00406     vs_hint = ReposUI::filenameToVS(hint_dir, lhost, lport);
00407     if(!vs_hint->inAttribs("master-repository", master_hint.cchars())) {
00408       VestaSource::errorCode err = 
00409         vs_hint->setAttrib("master-repository", master_hint.cchars());
00410       if(!quiet && (err != VestaSource::ok)) {
00411         cerr << program_name 
00412              << ": warning: incorrect master-repository attribute of " 
00413              << hint_dir << " couldn't be updated (should be "
00414              << master_hint << ")" << endl;
00415       }
00416     }
00417 
00418   } catch (VestaConfig::failure f) {
00419     cerr << program_name << ": " << f.msg << endl;
00420     exit(2);
00421   } catch (SRPC::failure f) {
00422     cerr << program_name
00423          << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00424     exit(2);
00425   } catch (ReposUI::failure f) {
00426     cerr << program_name << ": " << f.msg << endl;
00427     exit(2);
00428   }
00429 
00430   return 0;
00431 }

Generated on Mon May 8 00:48:56 2006 for Vesta by  doxygen 1.4.2