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

vcreate.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 // vcreate.C
00021 // Last modified on Sun Jun  5 21:52:05 EDT 2005 by ken@xorian.net         
00022 //      modified on Thu Jan 20 12:04:56 EST 2005 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 new package in the Vesta repository
00028 // See documentation in vcreate.1.mtex
00029 
00030 // !!Creating a package named "." or ".." is possible, but such a
00031 // package is inaccessible through the NFS interface.
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::cerr;
00051 using std::endl;
00052 
00053 Text program_name;
00054 
00055 void usage()
00056 {
00057   cerr << "Usage: " << program_name << endl <<
00058     "        [-q] [-Q] [-a | -A] [-f]" << endl <<
00059     "        [-o old-version | -O]" << endl <<
00060     "        [-m message | -M]" << endl <<
00061     "        [-h hints]" << endl <<
00062     "        [-R repos]" << endl <<
00063     "        package" << 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 defpkgpar, timefmt, repos, defhints;
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 package?
00080     // Defaults to on.
00081     bool acquire_mastership = false;
00082 
00083     defpkgpar = VestaConfig::get_Text("UserInterface",
00084                                       "DefaultPackageParent");
00085     timefmt = VestaConfig::get_Text("UserInterface", "TimeFormat");
00086     (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00087 
00088     bool prompt_msg = true, omit_msg = false;
00089     if(VestaConfig::is_set("UserInterface", "vcreate_message")) {
00090       if(!VestaConfig::get_bool("UserInterface", "vcreate_message")) {
00091         prompt_msg = false;
00092         omit_msg = true;
00093       }
00094     }
00095 
00096     time_t now = time(NULL);
00097     char timebuf[256];
00098     strftime(timebuf, sizeof(timebuf), timefmt.cchars(), localtime(&now));
00099     Text cuser(AccessControl::self()->user());
00100     Text user(cuser.Sub(0, cuser.FindChar('@')));
00101     Text lhost(VDirSurrogate::defaultHost());
00102     Text lport(VDirSurrogate::defaultPort());
00103     const int vlen = 7; // ==strlen("/vesta/")
00104     const Replicator::Flags rflags = (Replicator::Flags) 
00105       (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00106        Replicator::revive | Replicator::inclStubs | Replicator::latest);
00107 
00108     if(VestaConfig::is_set("UserInterface", "vcreate_acquires"))
00109       {
00110         acquire_mastership = VestaConfig::get_bool("UserInterface",
00111                                                    "vcreate_acquires");
00112       }
00113 
00114     //
00115     // Parse command line
00116     //
00117     bool quiet = false;
00118     bool query = false;
00119     bool force = false;
00120     bool omit_old = true;
00121 
00122     Text pkg, oldver, hints, message;
00123 
00124     opterr = 0;
00125     for (;;) {
00126       int c = getopt(argc, argv, "qQaAfo:Om:Mh:R:");
00127       if (c == EOF) break;
00128       switch (c) {
00129       case 'q':
00130         quiet = true;
00131         break;
00132       case 'Q':
00133         query = true;
00134         break;
00135       case 'a':
00136         acquire_mastership = true;
00137         break;
00138       case 'A':
00139         acquire_mastership = false;
00140         break;
00141       case 'f':
00142         force = true;
00143         break;
00144       case 'o':
00145         oldver = optarg;
00146         omit_old = false;
00147         break;
00148       case 'O':
00149         omit_old = true;
00150         break;
00151       case 'm':
00152         message = optarg;
00153         omit_msg = false;
00154         if(message == "-") {
00155           message = "";
00156           prompt_msg = true;
00157         }
00158         else 
00159           prompt_msg = false;
00160         break;
00161       case 'M':
00162         omit_msg = true;
00163         prompt_msg = false;
00164         break;
00165       case 'h':
00166         hints = optarg;
00167         break;
00168       case 'R':
00169         repos = optarg;
00170         default_repos = false;
00171         break;
00172       case '?':
00173       default:
00174         usage();
00175       }
00176     }
00177     if (argc != optind + 1) {
00178       usage();
00179     }
00180     pkg = Text(argv[optind]);
00181 
00182     //
00183     // Use a nondefault repository if specified, and automatically
00184     // add it to the hints if not already present.
00185     //
00186     if (!default_repos) {
00187       int colon = repos.FindCharR(':');
00188       if (colon == -1) {
00189         lhost = repos;
00190         repos = repos + ":" + lport;
00191       } else {
00192         lhost = repos.Sub(0, colon);
00193         lport = repos.Sub(colon+1);
00194       }
00195       hints = hints + " " + repos;
00196     }
00197     hints = hints + " " + defhints;
00198 
00199     // get change history message
00200     if (!query && prompt_msg) {  
00201       message = ReposUI::getMessage("package description");
00202     }
00203 
00204     //
00205     // Qualify and canonicalize names
00206     //
00207     Text cpkg, cparent, newpart, coldver, ccheckout, clatest, cslatest, cver0;
00208     cpkg = ReposUI::canonicalize(pkg, defpkgpar);
00209     ReposUI::split(cpkg, cparent, newpart, "package name");
00210     if (!omit_old) {
00211       coldver = ReposUI::canonicalize(oldver, defpkgpar);
00212     }
00213     ccheckout = cpkg + "/checkout";
00214     clatest = cpkg + "/latest";
00215     cslatest = cpkg + "/checkout/latest";
00216     cver0 = cpkg + "/0";
00217 
00218     //
00219     // Look up master of parent and sanity check
00220     //
00221     VestaSource* vs_mparent =
00222       ReposUI::filenameToMasterVS(cparent, hints);
00223     if (!force && !vs_mparent->inAttribs("type", "package-parent")) {
00224       cerr << program_name << ": " << cparent << " at " 
00225            << vs_mparent->host() << ":" << vs_mparent->port() 
00226            << " does not have type package-parent" << endl;
00227       exit(2);
00228     }
00229     Text mhost(vs_mparent->host());
00230     Text mport(vs_mparent->port());
00231     bool remote = (mhost != lhost || mport != lport);
00232     Text hint_dir;
00233     if(remote) {
00234       // find directory whose master-repository attribute needs to be updated
00235       hint_dir = ReposUI::getMasterHintDir(vs_mparent, cparent);
00236     }
00237 
00238     //
00239     // Look up oldver, first replicating it to the master repository
00240     // where we'll create the package if needed.
00241     //
00242     VestaSource* vs_moldver = NULL;
00243     VestaSource* vs_roldver = NULL;
00244     if (!omit_old) {
00245       vs_roldver = ReposUI::filenameToRealVS(coldver, hints);
00246       if (vs_roldver->type == VestaSource::stub) {
00247         cerr << program_name << ": " << coldver
00248              << " is not checked in yet" << endl;
00249         exit(2);
00250       } else if (vs_roldver->type == VestaSource::ghost) {
00251         cerr << program_name << ": " << coldver
00252              << " has been deleted" << endl;
00253         exit(2);
00254       }
00255 
00256       // find old version in master repository
00257       if(vs_roldver->host() == mhost && vs_roldver->port() == mport) {
00258         vs_moldver = vs_roldver;
00259       }
00260       else {
00261         try {
00262           vs_moldver = ReposUI::filenameToVS(coldver, mhost, mport);
00263           // If the target has a different type (e.g. stub or
00264           // ghost), we won't use it.
00265           if(vs_moldver->type != vs_roldver->type) {
00266             delete vs_moldver;
00267             vs_moldver = NULL;
00268           }
00269         }
00270         catch(...){
00271           // There is no old version in master repository
00272         }
00273         if(!vs_moldver && !query){
00274           // get a master replica 
00275           if (!quiet) {
00276             cout << "Replicating " << coldver << " from "
00277                  << vs_roldver->host() << ":" << vs_roldver->port()
00278                  << " to " << mhost << ":" << mport << endl;
00279           }
00280           Replicator repl(vs_roldver->host(), vs_roldver->port(),
00281                           mhost, mport);
00282           Replicator::DirectiveSeq direcs;
00283           Replicator::Directive d('+', coldver.Sub(vlen));
00284           direcs.addhi(d);
00285           repl.replicate(&direcs, rflags);
00286           vs_moldver = ReposUI::filenameToVS(coldver, mhost, mport);
00287         }
00288       }
00289     } // if(!omit_old)
00290 
00291       
00292     // Check to see if the package already exists.  If it's an empty
00293     // appendable directory, it'll be OK.
00294     VestaSource* vs_mpkg = 0;
00295     VestaSource::errorCode err = vs_mparent->lookupPathname(newpart.cchars(),
00296                                                             vs_mpkg);
00297     bool pkg_exists = (err != VestaSource::notFound);
00298 
00299     if (!quiet) {
00300       cout << "Creating package " << cpkg;
00301       if (remote) {
00302         cout << " at " << mhost << ":" << mport;
00303       }
00304       cout << endl;
00305     }
00306 
00307     if (query) {
00308       cerr << program_name << ": nothing done (-Q flag given)" << endl;
00309       exit(0);
00310     }
00311 
00312     //
00313     // Construct atomic action to create the package.
00314     //
00315     VestaSourceAtomic vsa(mhost, mport);
00316 
00317     // Declare parent directory and make sure it is master
00318     VestaSourceAtomic::VSIndex vsi_parent =
00319       vsa.decl(cparent, vs_mparent);
00320     vsa.testMaster(cparent, vsi_parent, true,
00321                    VestaSource::notMaster);
00322 
00323     // Wwe also insert the old version in the same action.
00324     VestaSourceAtomic::VSIndex vsi_oldver = -1;
00325     if(!omit_old) {
00326       assert(vs_moldver != 0);
00327       vsi_oldver = vsa.decl(coldver, vs_moldver);
00328       // Check that vs_moldver is an immutable directory, halt if not
00329       vsa.typeCheck(coldver, vsi_oldver, VestaSourceAtomic::
00330                     typebit(VestaSource::immutableDirectory),
00331                     VestaSource::inappropriateOp);
00332     } 
00333 
00334     // Make package directory or ensure that it is an empty appendable
00335     // directory.  This is the last step that should be able to halt,
00336     // so we just try it; no need to test first.
00337     VestaSourceAtomic::VSIndex vsi_pkg = -1;
00338     if(pkg_exists)
00339       {
00340         // Look up the package
00341         vsi_pkg = vsa.lookupPathname(cpkg, vsi_parent, newpart);
00342         // Make sure it's an appendable directory.
00343         vsa.typeCheck(cpkg, vsi_parent,
00344                       VestaSourceAtomic::
00345                       typebit(VestaSource::appendableDirectory),
00346                       VestaSource::inappropriateOp);
00347         // Make sure that it is completely empty.
00348         vsa.setTarget(cpkg,
00349                       VestaSource::notFound, VestaSource::notFound,
00350                       VestaSource::nameInUse);
00351         vsa.lookupIndex(cpkg, vsi_pkg, 1);
00352         // Return to normal error checking.
00353         vsa.setTarget(cpkg);
00354       }
00355     else
00356       {
00357         vsi_pkg = vsa.insertAppendableDirectory(cpkg, vsi_parent,
00358                                                 newpart, true,
00359                                                 VestaSource::dontReplace);
00360       }
00361 
00362     // Insert version 0 if applicable
00363     VestaSourceAtomic::VSIndex vsi_ver0 = -1;
00364     if (!omit_old) {
00365       vsi_ver0 =
00366         vsa.insertImmutableDirectory(cver0, vsi_pkg, "0", vsi_oldver, true,
00367                                      VestaSource::dontReplace);
00368     }
00369 
00370     // Insert "checkout" subdirectory.
00371     VestaSourceAtomic::VSIndex vsi_checkout =
00372       vsa.insertAppendableDirectory(ccheckout, vsi_pkg, "checkout", true,
00373                                     VestaSource::dontReplace);
00374 
00375     // Insert "latest" links
00376     VestaSourceAtomic::VSIndex vsi_latest =
00377       vsa.insertStub(clatest, vsi_pkg, "latest", true,
00378                      VestaSource::dontReplace);
00379     VestaSourceAtomic::VSIndex vsi_latest2 =
00380       vsa.insertStub(cslatest, vsi_checkout, "latest", true,
00381                      VestaSource::dontReplace);
00382 
00383     // Set attributes
00384     vsa.setAttrib(cpkg, vsi_pkg, "created-by", cuser);
00385     vsa.setAttrib(cpkg, vsi_pkg, "creation-time", timebuf);
00386     vsa.setAttrib(cpkg, vsi_pkg, "type", "package");
00387     if (!omit_old) {
00388       vsa.setAttrib(cpkg, vsi_pkg, "old-version", coldver);
00389     }
00390     // add message attribute
00391     if(!omit_msg && !message.Empty()) {
00392       vsa.setAttrib(cpkg, vsi_pkg, "message", message);
00393     }
00394     if (vsi_ver0 != -1) {
00395       vsa.setAttrib(cver0, vsi_ver0, "old-version", coldver);
00396     }
00397     vsa.setAttrib(ccheckout, vsi_checkout, "type", "checkout");
00398     vsa.setAttrib(clatest, vsi_latest, "symlink-to", "$LAST");
00399     vsa.setAttrib(cslatest, vsi_latest2, "symlink-to", "$LAST");
00400     // add next-packages attribute to the old version (master)
00401     if(!omit_old) {
00402       vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
00403       vsa.addAttrib(coldver + ": adding to next-packages", vsi_oldver,
00404                     "next-packages", cpkg);
00405       vsa.setTarget("");
00406     }
00407 
00408     //
00409     // Disable ^C signal to make it less likely that we will be
00410     // killed after having done the remote action but
00411     // before having finished the whole job.
00412     //
00413     signal(SIGINT, SIG_IGN);
00414 
00415     // Commit
00416     if (!vsa.run()) {
00417       VestaSource::errorCode err;
00418       if (vsa.lasterr == VestaSource::ok) {
00419         err = vsa.okreplace;
00420       } else {
00421         err = vsa.lasterr;
00422       }
00423       cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
00424            << ReposUI::errorCodeText(err) << endl;
00425       exit(2);
00426     }
00427 
00428     // check if the next-packages attribute was added to the old
00429     // version (master)
00430     if(!omit_old && !quiet) {
00431       if(!vs_moldver->inAttribs("next-packages", cpkg.cchars())) {
00432         cerr << program_name << ": warning: "  
00433           "next-packages attribute couldn't be added to version: "
00434              << coldver << " at " << mhost << ":" << mport << endl;
00435       }
00436     }
00437 
00438     // Done if master was local
00439     if (!remote) exit(0);
00440 
00441     //
00442     // Replicate the new package here
00443     //
00444     Replicator repl(mhost, mport, lhost, lport);
00445     Replicator::DirectiveSeq direcs;
00446     Replicator::Directive d('+', cpkg.Sub(vlen));
00447     direcs.addhi(d);
00448     repl.replicate(&direcs, rflags);
00449 
00450     //
00451     // Take mastership of the package and its checkout directory if
00452     // requested.  (We don't bother getting mastership of the "latest"
00453     // links.)
00454     //
00455     if(acquire_mastership)
00456       {
00457         err = VDirSurrogate::acquireMastership(cpkg.Sub(vlen).cchars(),
00458                                                lhost, lport, mhost, mport);
00459         if (err != VestaSource::ok) {
00460           cerr << program_name << ": error acquiring mastership of "
00461                << cpkg << ": " << ReposUI::errorCodeText(err) << endl;
00462           exit(2);
00463         }
00464         err = VDirSurrogate::acquireMastership(ccheckout.Sub(vlen).cchars(),
00465                                                lhost, lport, mhost, mport);
00466         if (err != VestaSource::ok) {
00467           cerr << program_name << ": error acquiring mastership of "
00468                << ccheckout << ": " << ReposUI::errorCodeText(err) << endl;
00469           exit(2);
00470         }
00471       }
00472 
00473     // add next-packages attribute to the old version in local repository
00474     if(!omit_old && !query) {
00475       VestaSource* vs_oldver = NULL;
00476       if(vs_roldver->host() == lhost && vs_roldver->port() == lport)
00477         {
00478           vs_oldver = vs_roldver;
00479         }
00480       else
00481         {
00482         try
00483           {
00484             vs_oldver = ReposUI::filenameToVS(coldver, lhost, lport);
00485           }
00486         catch(ReposUI::failure)
00487           {
00488             // old version not present in local repository: ignore
00489             vs_oldver = NULL;
00490           }
00491         }
00492 
00493       // if there is old version in local repository add the attribute
00494       if(vs_oldver) {
00495         err = vs_oldver->addAttrib("next-packages", cpkg.cchars());
00496         if(!quiet && (err  != VestaSource::ok)) {
00497           cerr << program_name << ": warning: "   
00498             "next-packages attribute couldn't be added to version: "
00499                << coldver << endl;
00500         }
00501       }
00502     } // if(!omit_old && !query)
00503     
00504     // Update master-repository hint
00505     Text master_hint = mhost + ":" + mport;
00506     VestaSource* vs_hint = NULL;
00507     vs_hint = ReposUI::filenameToVS(hint_dir, lhost, lport);
00508     if(!vs_hint->inAttribs("master-repository", master_hint.cchars())) {
00509       VestaSource::errorCode err = 
00510         vs_hint->setAttrib("master-repository", master_hint.cchars());
00511       if(!quiet && (err != VestaSource::ok)) {
00512         cerr << program_name 
00513              << ": warning: incorrect master-repository attribute of " 
00514              << hint_dir << " couldn't be updated (should be "
00515              << master_hint << ")" << endl;
00516       }
00517     }
00518 
00519   } catch (VestaConfig::failure f) {
00520     cerr << program_name << ": " << f.msg << endl;
00521     exit(2);
00522   } catch (SRPC::failure f) {
00523     cerr << program_name
00524          << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00525     exit(2);
00526   } catch (ReposUI::failure f) {
00527     cerr << program_name << ": " << f.msg << endl;
00528     exit(2);
00529   } catch(FS::Failure f) {
00530     cerr << program_name << ": " << f << endl;
00531     exit(2);
00532   }
00533 
00534   return 0;
00535 }

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