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

vattrib.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 // vattrib.C
00021 // Last modified on Sun Jun  5 18:31:36 EDT 2005 by ken@xorian.net         
00022 //      modified on Fri Nov 12 10:22:15 EST 2004 by irina.furman@intel.com 
00023 //      modified on Tue Apr 22 22:02:30 EDT 2003 by scott@scooter.cx
00024 //      modified on Wed Jul 11 22:03:49 PDT 2001 by mann
00025 //
00026 // Read or modify attributes of a source in the Vesta repository.
00027 // See vattrib.1.mtex for documentation.
00028 //
00029 
00030 #include <Basics.H>
00031 #include <Text.H>
00032 #include <VestaConfig.H>
00033 #include <VestaSource.H>
00034 #include <VDirSurrogate.H>
00035 #if !defined(__sun__)
00036 extern "C" {
00037 #include <getopt.h>
00038 }
00039 #endif
00040 #include "ReposUI.H"
00041 
00042 #include <iomanip>
00043 
00044 using std::cout;
00045 using std::cerr;
00046 using std::endl;
00047 using std::setw;
00048 Text program_name;
00049 bool multiple;
00050 Text timefmt;
00051 
00052 void
00053 Usage()
00054 {
00055     cerr << "Usage: " << program_name <<
00056       " [-q] [-t timestamp] [-m] [-T] [-L] [-R repos] [-M] [-H hints]" 
00057          << endl <<
00058       "        { -x |" << endl <<
00059       "          -i attrib value |" << endl <<
00060       "          -g attrib |" << endl <<
00061       "          -G attrib |" << endl <<
00062       "          -n | [-l] | -h |" << endl <<
00063       "          -s attrib value |" << endl <<
00064       "          -c attrib |" << endl <<
00065       "          -a attrib value |" << endl <<
00066       "          -r attrib value |" << endl <<
00067       "          -C value }" << endl <<
00068       "        [source...]" << endl << endl;
00069     exit(3);
00070 }
00071 
00072 bool
00073 coutValueCallback(void* closure, const char* value)
00074 {
00075   if(closure != 0)
00076     {
00077       Text *indent = (Text *) closure;
00078       cout << *indent;
00079     }
00080   cout << value << endl;
00081   return true;
00082 }
00083 
00084 struct listAllClosure {
00085   VestaSource* sourceVS;
00086   Text indent;
00087 };
00088 
00089 bool
00090 listAllCallback(void* closure, const char* value)
00091 {
00092   listAllClosure* cl = (listAllClosure*) closure;
00093   cout << cl->indent << value << endl;
00094   Text indent = cl->indent + "\t";
00095   cl->sourceVS->getAttrib(value, coutValueCallback, (void *) &indent);
00096   return true;
00097 }
00098 
00099 bool
00100 coutHistoryCallback(void* closure, VestaSource::attribOp op,
00101                     const char* name, const char* value,
00102                     time_t timestamp)
00103 {
00104     char timebuf[256];
00105     strftime(timebuf, sizeof(timebuf), timefmt.cchars(), localtime(&timestamp));
00106     const char *op_string = VestaSource::attribOpString(op);
00107     // chop off the "op" from the start of the string
00108     if((op_string[0] == 'o') && (op_string[0] == 'p'))
00109       {
00110         op_string += 2;
00111       }
00112     cout  << ' ' << timebuf << ' '
00113       << setw(6) << op_string +2 << ' '
00114       << name << '\t' << value << endl;
00115     return true;
00116 }
00117 
00118 
00119 // In order to allow vattrib on multiple sources we parse command line first, 
00120 // remembering each source and it's flags into Action structure, 
00121 // where each Action contains pointer to the next one. If there is Usage
00122 // problem vattrib terminates parsing process. At the end of parsing
00123 // process all sources are found and we have a list of Actions to perform. 
00124 // If there is Usage problem vattrib terminates the parsing process. 
00125 // Main while loop performs each Action from the list.
00126 
00127 
00128 typedef struct ActionFlags {
00129   int quiet_flag;
00130   int exist_flag;
00131   int in_flag;
00132   int get_flag;
00133   int getone_flag;
00134   int list_flag;
00135   int listall_flag;
00136   int history_flag;
00137   int set_flag;
00138   int clear_flag;
00139   int add_flag;
00140   int remove_flag;
00141   int type_flag;
00142   int master_flag;
00143   int compare_flag;
00144   int last_modified_flag; 
00145 } ActionFlags;
00146 
00147 
00148 typedef struct Action {
00149   ActionFlags flags;
00150   time_t timestamp;
00151   Text attrib;
00152   Text value;
00153   Text csource;
00154   VestaSource* sourceVS;  
00155 
00156   Action();
00157   ~Action() {}
00158 } Action; 
00159 
00160 Action::Action()
00161   : timestamp(0), sourceVS(0)
00162 {
00163   memset(&flags, 0, sizeof(ActionFlags));
00164 }
00165 
00166 void
00167 commandLineParsing(int argc, char* argv[], Sequence<Action*>& list, 
00168                    Text& lhost, Text& lport) throw()
00169 {
00170   int new_action_ind = 1;
00171   multiple = false;
00172   
00173   bool done = false;
00174   if((optind < argc) && (argv[optind][0] != '-'))
00175     done = true;
00176 
00177   Text repos, hints;
00178   bool at_master = false;
00179   Action* current = NEW(Action);
00180 
00181   // Get default hints
00182   Text defhints;
00183   (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00184  
00185   while(new_action_ind) {
00186     int c;
00187     new_action_ind = 0;
00188    
00189     while(!done) {
00190       int args = 0;
00191 
00192       c = getopt(argc, argv, "qt:xigGnlhscarCTLmR:MH:");
00193       if(c == EOF) break;
00194       switch (c) {
00195       case 'q': current->flags.quiet_flag++; continue;
00196       case 't':
00197         current->timestamp = strtol(optarg, NULL, 0);
00198         continue;
00199 
00200       case 'x': current->flags.exist_flag++; break;
00201       case 'i': current->flags.in_flag++; args = 2; break;
00202       case 'g': current->flags.get_flag++; args = 1; break;
00203       case 'G': current->flags.getone_flag++; args = 1; break;
00204       case 'n': current->flags.list_flag++; break;
00205       case 'l': current->flags.listall_flag++; break;
00206       case 'h': current->flags.history_flag++; break;
00207       case 's': current->flags.set_flag++; args = 2; break;
00208       case 'c': current->flags.clear_flag++; args = 1; break;
00209       case 'a': current->flags.add_flag++; args = 2; break;
00210       case 'r': current->flags.remove_flag++; args = 2; break;
00211       case 'C': current->flags.compare_flag++; args = 1; break;
00212 
00213       case 'T': current->flags.type_flag++; break;
00214       case 'm': current->flags.master_flag++; break;
00215       case 'L': current->flags.last_modified_flag++; break;
00216       case 'R': repos = optarg; break;
00217       case 'M': at_master = true; break;
00218       case 'H': hints = optarg; break;
00219 
00220       case '?':
00221       default:
00222          Usage();
00223       } //switch
00224 
00225       // get attrib and value parameters of the current action 
00226       if(current->attrib == "" && current->value == ""){
00227         switch(args) {
00228         case 2:
00229           if(optind + 2 > argc)
00230             Usage();
00231           current->attrib = argv[optind++];
00232           current->value = argv[optind++];
00233           break;
00234         case 1:
00235           if(optind + 1 > argc)
00236             Usage();
00237           current->attrib = argv[optind];
00238           current->value = argv[optind];
00239           optind++;
00240           break;
00241         default: break;
00242         } 
00243       }
00244      
00245       // check if all flags for current source were read
00246       if((optind >= argc) || ((optind < argc) && (argv[optind][0] != '-'))) {
00247         done = true; 
00248       }
00249 
00250     }//while
00251     done = false;
00252 
00253     // get current source and the first index of next action
00254     Text source;
00255     if(optind < argc){
00256       source = argv[optind];
00257       if(optind + 1 < argc) {
00258         if(!multiple)
00259           multiple = true;
00260         new_action_ind = optind + 1;
00261       }
00262       else
00263         new_action_ind = 0;
00264     }
00265     else
00266       source = ".";
00267 
00268     // validate flags
00269     // check that -q -m is not used with -T or/and -L flag
00270     if(current->flags.master_flag && current->flags.quiet_flag &&
00271        (current->flags.last_modified_flag || current->flags.type_flag)) {
00272       cerr << program_name 
00273            << ": flags -q -m can not be used with other flags" << endl;
00274       Usage();
00275     }
00276 
00277     if(current->flags.quiet_flag && 
00278        !(current->flags.exist_flag || current->flags.in_flag || 
00279          current->flags.getone_flag || current->flags.compare_flag ||
00280          current->flags.master_flag)) {
00281       cerr << program_name
00282            << ": -q flag is meaningful only with -m, -x, -i, -G or -C"
00283            << endl;
00284       Usage();
00285     }
00286 
00287     switch (current->flags.exist_flag + current->flags.in_flag + 
00288             current->flags.get_flag + current->flags.getone_flag + 
00289             current->flags.list_flag + current->flags.listall_flag +
00290             current->flags.history_flag + current->flags.set_flag + 
00291             current->flags.clear_flag + current->flags.add_flag + 
00292             current->flags.remove_flag + current->flags.compare_flag){
00293       case 0:
00294         if(!current->flags.master_flag && !current->flags.type_flag &&
00295            !current->flags.last_modified_flag){
00296           current->flags.listall_flag++;
00297           current->flags.type_flag++;
00298           current->flags.master_flag++;
00299         }
00300         break;
00301       case 1:
00302         // -q -m should not be used with one of 
00303         // -x, -i, -g, -G, -n, -l, -h, -s, -c, -a, -r, -C  
00304         if(current->flags.master_flag && current->flags.quiet_flag) {
00305           cerr << program_name 
00306                << ": flags -q -m can not be used with other flags" << endl;
00307           Usage();
00308         }
00309         break;
00310       default:
00311         cerr << program_name 
00312              << ": flags -x, -i, -g, -G, -n, -l, -h, -s, -c, -a, -r, -C "
00313              << endl << "are mutually exclusive" << endl;
00314         Usage();
00315     }
00316 
00317     if(current->timestamp != 0 && 
00318        !(current->flags.set_flag || current->flags.clear_flag || 
00319          current->flags.add_flag || current->flags.remove_flag)) {
00320       cerr << program_name
00321            << ": -t flag is meaningful only with -s, -c, -a, or -r"
00322            << endl;
00323       Usage();
00324     }
00325 
00326     // validate flags for multiple call
00327     if(multiple) {
00328       if(current->flags.in_flag) {
00329         cerr << program_name
00330              << ": -i flag cannot be used with multiple objects" << endl;
00331         Usage();
00332       }
00333       else if(current->flags.compare_flag){
00334         cerr << program_name
00335              << ": -C flag cannot be used with multiple objects" << endl;
00336         Usage();
00337       }
00338       else if(current->flags.exist_flag) {
00339         cerr << program_name
00340              << ": -x flag cannot be used with multiple objects" << endl;
00341         Usage();
00342       }
00343       else if(current->flags.master_flag && current->flags.quiet_flag) {
00344         cerr << program_name
00345              << ": -q -m flag cannot be used with multiple objects" << endl;
00346         Usage();
00347       }
00348     }
00349 
00350     // get current VestaSource pointer
00351     Text host, port;
00352     if (repos != "") {
00353       int colon = repos.FindCharR(':');
00354       if (colon == -1) {
00355         host = repos;
00356         port = lport;
00357         repos = repos + ":" + lport;
00358       } else {
00359         host = repos.Sub(0, colon);
00360         port = repos.Sub(colon+1);
00361       }
00362       hints = hints + " " + repos;
00363     }
00364     else {
00365       host = lhost;
00366       port = lport;
00367     }
00368     hints = hints + " " + defhints;
00369     
00370     bool got_next_source; 
00371     do {
00372       got_next_source = false;
00373       try {
00374         current->csource = ReposUI::canonicalize(source);
00375         if(at_master) {
00376           current->sourceVS = 
00377             ReposUI::filenameToMasterVS(current->csource, hints);
00378         } else {
00379           current->sourceVS = 
00380             ReposUI::filenameToVS(current->csource, host, port);
00381         }
00382       }
00383       catch (ReposUI::failure f) {
00384         cerr << program_name << ": " << f.msg << endl;
00385         exit(2);
00386       }
00387       list.addhi(current);
00388 
00389       // create new Action for next source
00390       if(new_action_ind && new_action_ind < argc) {
00391         Action* new_act = NEW(Action);
00392         // the same action for next source
00393         if(argv[new_action_ind][0] != '-') {
00394           new_act->flags = current->flags;
00395           new_act->timestamp = current->timestamp;
00396           new_act->attrib = current->attrib;
00397           new_act->value = current->value;
00398           source = argv[new_action_ind];
00399           new_action_ind++;
00400           got_next_source = true;
00401         }
00402         current = new_act;
00403       }
00404     } while(got_next_source);
00405 
00406 
00407     if(new_action_ind == argc)
00408       new_action_ind = 0;
00409   } //while
00410 
00411 }
00412 
00413 
00414 
00415 int
00416 main(int argc, char* argv[])
00417 {
00418   program_name = argv[0];
00419 
00420   Sequence<Action*> list; 
00421 
00422   try {
00423     timefmt = VestaConfig::get_Text("UserInterface", "TimeFormat");
00424     Text lhost(VDirSurrogate::defaultHost());
00425     Text lport(VDirSurrogate::defaultPort());
00426     Text lrepos = lhost + ":" + lport;
00427     commandLineParsing(argc, argv, list, lhost, lport);
00428     int actions_num = list.size();
00429     
00430     for(int i = 0; i < actions_num; i++) {
00431       Action* current = list.remlo();
00432       
00433       Text source = current->csource;
00434       Text repos = current->sourceVS->host() + ":" +  
00435         current->sourceVS->port();
00436 
00437       if(multiple && !current->flags.quiet_flag && 
00438          (current->flags.master_flag || current->flags.type_flag ||
00439           current->flags.last_modified_flag || current->flags.get_flag ||
00440           current->flags.list_flag || current->flags.listall_flag || 
00441           current->flags.history_flag || current->flags.getone_flag)) {
00442         cout << source.cchars() << " ";
00443         if(repos != lrepos)
00444           cout << "(" << repos << ") "; 
00445         if(!current->flags.master_flag && !current->flags.type_flag)
00446           cout << endl;
00447       }
00448       if(current->flags.master_flag) {
00449         if(current->sourceVS->master)
00450           if(current->flags.quiet_flag) exit(0); 
00451           else cout << "master";
00452         else
00453           if(current->flags.quiet_flag) exit(1);
00454           else cout << "nonmaster";
00455         if (current->flags.type_flag)
00456           cout << " ";
00457         else
00458           cout << endl;
00459       }
00460 
00461       if(current->flags.type_flag) {
00462         cout << VestaSource::typeTagString(current->sourceVS->type) 
00463              << endl;
00464       }
00465       
00466       if (current->flags.last_modified_flag){
00467         time_t time = current->sourceVS->timestamp();
00468         switch(int(time)) {
00469         case 2:
00470         case -1:
00471           cerr << source << ": no timestamp" << endl;
00472           break;
00473         default:
00474           char timebuf[256];
00475           strftime(timebuf, sizeof(timebuf), timefmt.cchars(), 
00476                    localtime(&time));
00477           if(multiple)
00478             cout << '\t';
00479           cout << timebuf << endl;
00480           break;
00481         }
00482       }
00483       
00484       if(current->flags.exist_flag) {
00485         if(current->sourceVS->hasAttribs()) {
00486           if(!current->flags.quiet_flag)
00487             cout << "true" << endl;
00488           exit(0);
00489         } else {
00490           if (!current->flags.quiet_flag)
00491             cout << "false" << endl;
00492           exit(1);
00493         }       
00494       }     
00495 
00496       bool require_attribs_flags = current->flags.in_flag ||
00497         current->flags.get_flag || current->flags.getone_flag ||
00498         current->flags.list_flag || current->flags.listall_flag ||
00499         current->flags.history_flag || current->flags.set_flag ||
00500         current->flags.clear_flag || current->flags.add_flag ||
00501         current->flags.remove_flag;
00502 
00503       if(require_attribs_flags && !current->sourceVS->hasAttribs()) {
00504         if(!current->flags.quiet_flag) {
00505           cerr << program_name << ": " << source.cchars()
00506                << " does not have attributes" << endl;
00507         }
00508         exit(2);
00509       }
00510       
00511       if (current->flags.in_flag) {
00512         if(current->sourceVS->inAttribs(current->attrib.cchars(), 
00513                                         current->value.cchars())){
00514           if(!current->flags.quiet_flag)
00515             cout << "true" << endl;
00516           exit(0);
00517         } else {
00518           if(!current->flags.quiet_flag)
00519             cout << "false" << endl;
00520           exit(1);
00521         }
00522       } 
00523       else if(current->flags.compare_flag) {
00524         const char* typestr = current->value.cchars();
00525         if(strcmp(VestaSource::typeTagString(current->sourceVS->type),
00526                   typestr) == 0) {
00527           if(!current->flags.quiet_flag) 
00528             cout << "true" << endl;
00529           exit(0);
00530         } 
00531         else {
00532           if(strcmp(typestr, "immutableFile") !=0 &&
00533              strcmp(typestr, "mutableFile") !=0 &&
00534              strcmp(typestr, "immutableDirectory") !=0 &&
00535              strcmp(typestr, "appendableDirectory") !=0 &&
00536              strcmp(typestr, "mutableDirectory") !=0 &&
00537              strcmp(typestr, "ghost") !=0 &&
00538              strcmp(typestr, "stub")!=0) {
00539             cerr << program_name << ": " << typestr  
00540                  << ": invalid type string" << endl;
00541             exit (2);
00542           }
00543           else {
00544             if(!current->flags.quiet_flag)
00545               cout << "false" << endl;
00546             exit(1);
00547           }
00548         }
00549       }
00550       else if(current->flags.get_flag) {
00551         Text indent = multiple ? "\t" : "";
00552         current->sourceVS->getAttrib(current->attrib.cchars(), 
00553                                      coutValueCallback, (void *) &indent);
00554       } else if(current->flags.getone_flag) {
00555         char* val = current->sourceVS->getAttrib(current->attrib.cchars());
00556         if(val == NULL) {
00557           if(!current->flags.quiet_flag) {
00558             cerr << program_name
00559                  << ": no value for attribute " << current->attrib << endl;
00560           }
00561           exit(1);
00562         }
00563         if(multiple)
00564           cout << '\t';
00565         cout << val << endl;
00566         delete val;
00567       } else if(current->flags.list_flag) {
00568         Text indent = multiple ? "\t" : "";
00569         current->sourceVS->listAttribs(coutValueCallback, (void *) &indent);
00570       } else if(current->flags.listall_flag) {
00571         listAllClosure cl;
00572         cl.sourceVS = current->sourceVS;
00573         cl.indent = multiple ? "\t" : "";
00574         current->sourceVS->listAttribs(listAllCallback, &cl);
00575       } else if(current->flags.history_flag) {
00576         current->sourceVS->getAttribHistory(coutHistoryCallback, NULL);
00577       } else if (current->flags.set_flag || current->flags.clear_flag ||
00578                  current->flags.add_flag || current->flags.remove_flag){
00579         VestaSource::attribOp op;
00580         if(current->flags.set_flag) {
00581           op = VestaSource::opSet;
00582         } else if(current->flags.clear_flag) {
00583           op = VestaSource::opClear;
00584           current->value = "";
00585         } else if(current->flags.add_flag) {
00586           op = VestaSource::opAdd;
00587         } else {
00588           assert(current->flags.remove_flag);
00589           op = VestaSource::opRemove;
00590         }               
00591         VestaSource::errorCode err =
00592           current->sourceVS->writeAttrib(op, current->attrib.cchars(),
00593                                          current->value.cchars(), NULL, 
00594                                          current->timestamp);
00595         if (err != VestaSource::ok) {
00596           Text msg = program_name + ":";
00597           if(multiple) {
00598             msg = msg + " " + source; 
00599             if(repos != lrepos)
00600               msg = msg + " at " + repos; 
00601           }
00602           msg = msg + " on writeAttrib: " +  ReposUI::errorCodeText(err);
00603           cerr << msg << endl;
00604           exit(2);
00605         }
00606       }
00607 
00608       delete current;
00609     }
00610     
00611   } catch (VestaConfig::failure f) {
00612     cerr << program_name << ": " << f.msg << endl;
00613     exit(2);
00614   } catch (SRPC::failure f) {
00615     cerr << program_name
00616          << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00617     exit(2);
00618   } catch (ReposUI::failure f) {
00619     cerr << program_name << ": " << f.msg << endl;
00620     exit(2);
00621   }
00622   
00623   return 0;
00624 }
00625 
00626 
00627 
00628 

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