00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 #if defined(__linux__)
00033 
00034 #  include <stdint.h>
00035 
00036 #  include <sys/sysinfo.h>
00037 #  include <unistd.h>
00038 #endif
00039 
00040 #include <stdlib.h>
00041 #include <signal.h>
00042 #include <Basics.H>
00043 #include <OS.H>
00044 #include <FdStream.H>
00045 #include <VestaConfig.H>
00046 #include <TCP_sock.H>
00047 #include <SRPC.H>
00048 #include <VestaSource.H>
00049 #include <UniqueId.H>
00050 
00051 #include <sys/utsname.h>         
00052 #include <sys/sysinfo.h>         
00053 #if defined(__digital__)
00054 #  include <machine/hal_sysinfo.h> 
00055 #endif
00056 
00057 #include <sstream>
00058 
00059 #include "RunToolClient.H"
00060 #include "RunToolDaemon.H"
00061 #include "Launcher.h"
00062 
00063 extern "C" {
00064 #include "get_load.h"
00065 }
00066 
00067 using std::ios;
00068 using std::ifstream;
00069 using std::istringstream;
00070 using std::cout;
00071 using std::cin;
00072 using std::cerr;
00073 using std::endl;
00074 using FS::OFdStream;
00075 
00076 
00077 
00078 const Text DEVNULL("/dev/null");
00079 const int UNUSED = SYSERROR; 
00080 
00081 
00082 
00083 static void close_fd(fd_t &fd) throw ();     
00084 
00085 
00086 
00087 
00088 class std_info {
00089   public:
00090     sockaddr_in sock;      
00091     TCP_sock *s;           
00092     fd_t f;                
00093                            
00094     std_info() throw ();   
00095     ~std_info() throw ();  
00096 };
00097 
00098 std_info::std_info() throw ()
00099 {
00100     s = NULL;
00101     f = NO_FD;
00102 }
00103 
00104 std_info::~std_info() throw ()
00105 {
00106     if (s == NULL) close_fd(f); 
00107     else delete s;
00108 }
00109 
00110 typedef Sequence<Basics::cond*> CondSeq;
00111 
00112 
00113 
00114 
00115 
00116 
00117 
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 class children {
00126   public:
00127     static void init(int running, int pending) throw ();
00128     
00129 
00130 
00131 
00132 
00133     static bool my_turn() throw(); 
00134     
00135 
00136 
00137 
00138 
00139 
00140     static int wait_for(pid_t pid, SRPC *client,  bool &killed)
00141       throw ();
00142     
00143 
00144 
00145 
00146 
00147     static void killer_body() throw ();
00148     
00149 
00150 
00151     static void call_failed() throw ();
00152     
00153 
00154 
00155 
00156 
00157 
00158   private:
00159     
00160     class child_info {
00161       public:
00162         pid_t pid;            
00163         SRPC *client;         
00164         bool killed;          
00165 
00166         child_info() throw ()
00167         { this->pid = UNUSED; this->client = NULL;
00168           this->killed = false; }
00169     };
00170 
00171     
00172     static Basics::mutex mu;      
00173     static int maxChildren;       
00174     static int maxPending;        
00175     static child_info *info;      
00176     static int nInUse;            
00177     static int nPending;          
00178     static Basics::thread killer; 
00179                                   
00180     static CondSeq pending;       
00181                                   
00182                                   
00183 
00184     friend void Info(SRPC *srpc, int intfVersion, int procId) throw(SRPC::failure);
00185 };
00186 
00187 
00188 
00189 
00190 class req_data {
00191   public:
00192     
00193     Text stdin_file;          
00194     std_info out;             
00195     std_info err;             
00196     sockaddr_in fsroot_sock;  
00197     LongId fsroot_fh;         
00198     Text wd;                  
00199     chars_seq ev;             
00200     chars_seq argv;           
00201                               
00202     
00203     fd_t stdin_fd;            
00204     Text chroot_to;           
00205     fd_t error_pipe[2];       
00206       
00207 
00208 
00209 
00210 
00211                               
00212     req_data() throw ();      
00213     ~req_data() throw ();     
00214 };
00215 
00216 req_data::req_data() throw ()
00217 {
00218     
00219 
00220     stdin_fd = NO_FD;
00221     error_pipe[0] = NO_FD;
00222     error_pipe[1] = NO_FD;
00223 }
00224 
00225 req_data::~req_data() throw ()
00226 {
00227     close_fd(stdin_fd);
00228     close_fd(error_pipe[0]);
00229     close_fd(error_pipe[1]);
00230 }
00231 
00232 
00233 
00234 
00235 Basics::mutex children::mu;
00236 int children::maxChildren;
00237 int children::maxPending;
00238 int children::nInUse;
00239 int children::nPending;
00240 children::child_info *children::info;
00241 Basics::thread children::killer;
00242 CondSeq children::pending;
00243 
00244 
00245 static Text helper;                
00246 static chars_seq helper_switches;  
00247 static fd_t trouble_fd;            
00248 static bool debug_mode = false;    
00249 static Text volatile_root;         
00250 static Text sysname, release, version, machine;
00251 static FP::Tag uniqueid;
00252 static unsigned int cpus, cpuMHz, memKB;
00253 static int sync_after_tool = 1;
00254 
00255 
00256 
00257 struct call_failure { int code; Text msg; };
00258 
00259 static void call_failed(int c, const Text &m) throw (call_failure)
00260 {
00261     call_failure f;
00262     f.code = c;
00263     f.msg = m;
00264     throw(f);
00265 }
00266 
00267 static void fail_with_errno(const Text &m, int e = 0) throw (call_failure)
00268 {
00269     if (e == 0) e = errno;
00270     Text emsg = Basics::errno_Text(e);
00271     call_failed(implementation_error, m + " (" + emsg + ")");
00272 }
00273 
00274 static void PrintMsgWithErrno(const Text &msg) throw ()
00275 {
00276   int saved_errno = errno;
00277   cerr << "\n*** Error: " << msg;
00278   cerr << "("
00279        << Basics::errno_Text(saved_errno)
00280        << ")" << endl;
00281   cerr << "*** Continuing..." << endl;
00282 }
00283 
00284 static Text config_lookup(const Text &key) throw (call_failure)
00285 {
00286     try {
00287         Text val(VestaConfig::get_Text(RUN_TOOL_CONFIG_SECTION, key));
00288         return val;
00289     } catch (VestaConfig::failure f) {
00290         call_failed(implementation_error, f.msg);
00291     }
00292     return "";  
00293 }
00294 
00295 static void close_fd(fd_t &fd) throw()
00296 {
00297     if (fd == NO_FD) return;
00298     close(fd);
00299     fd = NO_FD;
00300 }
00301 
00302 static void move_fd(fd_t from_fd, fd_t to_fd) throw ()
00303 
00304 
00305 {
00306     dup2(from_fd, to_fd);
00307     close_fd(from_fd);
00308 }
00309 
00310 
00311 
00312 static void setup_stdin( req_data &d) throw (call_failure)
00313 
00314 
00315 {
00316     const Text f(d.stdin_file.Empty() ? DEVNULL : d.stdin_file);
00317     d.stdin_fd = open(f.cchars(), O_RDONLY, 0);
00318     if (d.stdin_fd < 0) fail_with_errno("Can't open stdin file " + f);
00319 }
00320 
00321 static void setup_std_info( std_info &i)
00322   throw (call_failure, TCP_sock::failure)
00323 
00324 {
00325     if (i.sock.sin_addr.s_addr == 0 && i.sock.sin_port == 0) {
00326         i.s = NULL;
00327         i.f = open(DEVNULL.cchars(), O_WRONLY, 0);
00328         if (i.f == SYSERROR) {
00329             fail_with_errno("Can't open " + DEVNULL + " for std{out,err}");
00330         }
00331     } else {
00332         
00333       i.s = NEW(TCP_sock);
00334         i.s->connect_to(i.sock);
00335         i.f = i.s->get_fd();
00336     }
00337 }
00338 
00339 
00340 
00341 
00342 static void simulate_child_failure(fd_t error_wr, fd_t fallback_wr,
00343                                    int r,
00344                                    const char *msg,
00345                                    int e = 0)
00346      throw ()
00347 {
00348   
00349   
00350   if (e == 0) e = errno;
00351   Text emsg = Basics::errno_Text(e);
00352 
00353   
00354   
00355   if((write(error_wr, msg, strlen(msg)) == SYSERROR) ||
00356      (write(error_wr, " (", 2) == SYSERROR) ||
00357      (write(error_wr, emsg.cchars(), emsg.Length()) == SYSERROR) ||
00358      (write(error_wr, ")\n", 2) == SYSERROR) ||
00359      ((fsync(error_wr) == SYSERROR) &&
00360       
00361       
00362       (errno != EINVAL)))
00363     {
00364       
00365       
00366       
00367       write(fallback_wr, msg, strlen(msg));
00368       write(fallback_wr, " (", 2);
00369       write(fallback_wr, emsg.cchars(), emsg.Length());
00370       write(fallback_wr, ")\n", 2);
00371       fsync(fallback_wr);
00372     }
00373 
00374   
00375   
00376   
00377   _exit(r);
00378 }
00379 
00380 
00381 
00382 static void *children_killer_body(void *arg) throw ()
00383 
00384 {
00385     children::killer_body();
00386     return (void *)NULL;
00387 }
00388 
00389 void children::init(int running, int pending) throw ()
00390 {
00391     children::nInUse = 0;
00392     children::nPending = 0;
00393     children::maxChildren = running;
00394     children::maxPending = pending;
00395     children::info = NEW_ARRAY(child_info, running);
00396     children::killer.fork_and_detach(children_killer_body, NULL);
00397 }
00398 
00399 bool children::my_turn() throw()
00400 {
00401   bool result;
00402 
00403   children::mu.lock();
00404   
00405   
00406   int nRunning =
00407     
00408     children::nInUse +
00409     
00410     
00411     (children::nPending - children::pending.size());
00412   assert(children::nPending >= children::pending.size());
00413   assert(nRunning >= 0);
00414 
00415   
00416   if(nRunning < children::maxChildren)
00417     {
00418       
00419       
00420       assert(children::pending.size() == 0);
00421 
00422       
00423       assert(children::nInUse < children::maxChildren);
00424       children::nInUse++;
00425       result = true;
00426     }
00427   
00428   else if(children::pending.size() < children::maxPending)
00429     {
00430       
00431       children::nPending++;
00432 
00433       
00434       assert(nRunning > 0);
00435 
00436       
00437       
00438       Basics::cond c;
00439       children::pending.addhi(&c);
00440       c.wait(children::mu);
00441 
00442       
00443       
00444       assert(children::nInUse < children::maxChildren);
00445       children::nPending--;
00446       children::nInUse++;
00447       result = true;
00448     }
00449   
00450   else
00451     {
00452       result = false;
00453     }
00454 
00455   children::mu.unlock();
00456 
00457   return result;
00458 }
00459 
00460 int children::wait_for(pid_t pid, SRPC *client,  bool &killed) throw ()
00461 
00462 
00463 
00464 
00465 
00466 
00467 {
00468     int status;      
00469     int slot = -1;   
00470 
00471     children::mu.lock();
00472 
00473     for(int i = 0; (i < children::maxChildren) && (slot < 0); i++)
00474       {
00475         if(children::info[i].pid == UNUSED)
00476           {
00477             slot = i; 
00478           }
00479       }
00480     assert(slot >= 0);
00481 
00482     
00483     assert(info[slot].pid == UNUSED);
00484     children::info[slot].pid = pid;
00485     children::info[slot].client = client;
00486 
00487     
00488     
00489     children::mu.unlock();
00490 
00491     
00492     pid_t done_pid = waitpid(pid, &status, 0);
00493     
00494     if(done_pid == SYSERROR)
00495     {
00496       int l_errno = errno;
00497       cerr << "waitpid(pid = " << pid << ") returned an error: "
00498            << strerror(l_errno) << " (" << l_errno << ")"
00499            << endl;
00500     }
00501     
00502     assert(done_pid == pid);
00503 
00504     
00505     
00506     children::mu.lock();
00507 
00508     
00509     killed = children::info[slot].killed;
00510     children::info[slot].pid = UNUSED;  
00511     children::nInUse--;
00512     children::info[slot].client = NULL; 
00513     children::info[slot].killed = false;
00514 
00515     
00516     
00517     if(children::pending.size() > 0)
00518       {
00519         Basics::cond *c = children::pending.remlo();
00520         assert(c != 0);
00521         c->signal();
00522       }
00523     assert(children::nPending >= children::pending.size());
00524 
00525     children::mu.unlock();
00526     return status;
00527 } 
00528 
00529 void children::killer_body() throw ()
00530 
00531 
00532 
00533 
00534 
00535 
00536 {
00537     while (true) {
00538         
00539         Basics::thread::pause(30);
00540 
00541         
00542         children::mu.lock();
00543         for (int i = 0; i < children::maxChildren; i++) {
00544             child_info *slot = children::info + i; 
00545             if (slot->pid != UNUSED && slot->client != NULL) {
00546                 
00547                 if (!slot->client->alive()) {
00548                     
00549                     int sig = (slot->killed) ? SIGKILL : SIGTERM;
00550                     if (kill(-slot->pid, sig) != 0) {
00551                       
00552                       
00553                       
00554                       
00555                       
00556                     } else {
00557                       slot->killed = true;
00558                     }
00559                 }
00560             }
00561         }
00562         children::mu.unlock();
00563     }
00564 } 
00565 
00566 void children::call_failed() throw ()
00567 {
00568   
00569   
00570   children::mu.lock();
00571   children::nInUse--;
00572 
00573   
00574   
00575   if(children::pending.size() > 0)
00576     {
00577       Basics::cond *c = children::pending.remlo();
00578       assert(c != 0);
00579       c->signal();
00580     }
00581   assert(children::nPending >= children::pending.size());
00582 
00583   
00584   children::mu.unlock();
00585 }
00586 
00587 
00588 
00589 static void RunTool(SRPC *srpc, int intfVersion) throw(SRPC::failure)
00590 {
00591   
00592   bool in_use_slot = false;
00593 
00594     try {
00595         req_data d; 
00596 
00597         
00598 
00599         srpc->recv_Text( d.stdin_file);
00600         d.out.sock = srpc->recv_socket();
00601         d.err.sock = srpc->recv_socket();
00602         d.fsroot_sock = srpc->recv_socket();
00603         int len = sizeof(d.fsroot_fh);
00604         srpc->recv_bytes_here( (char *)&d.fsroot_fh,  len);
00605         if (len != sizeof(d.fsroot_fh)) {
00606             call_failed(implementation_error, "Invalid fsroot");
00607         }
00608         srpc->recv_Text( d.wd);
00609         srpc->recv_chars_seq( d.ev);
00610         srpc->recv_chars_seq( d.argv);
00611         if (d.argv[0] == NULL) {
00612             call_failed(implementation_error, "Null command");
00613         }
00614         srpc->recv_end();
00615 
00616         
00617         if(!children::my_turn())
00618           {
00619             
00620             
00621             call_failed(client_error, "request denied: server too busy");
00622           }
00623         
00624         in_use_slot = true;
00625     
00626         
00627 
00628         unsigned int index;
00629         (void) d.fsroot_fh.getParent(&index);
00630         char arc[(sizeof(index) * 2) + 1];
00631         sprintf(arc, "%08x", index);
00632         d.chroot_to = volatile_root + PathnameSep + arc;
00633     
00634         
00635         setup_stdin( d);
00636         setup_std_info( d.out);
00637         setup_std_info( d.err);
00638 
00639         
00640         if (getenv("STOP_BEFORE_TOOL")) {
00641             cerr << "Stop before tool; root = " << d.chroot_to << endl;
00642             cerr << "Hit enter to continue: ";
00643             char enter;
00644             cin.get(enter);
00645         }
00646     
00647         
00648         if (pipe(d.error_pipe) == SYSERROR) {
00649             fail_with_errno("pipe call failed!");
00650         }
00651     
00652         
00653         
00654         
00655         
00656         
00657         
00658         
00659         
00660 
00661         
00662         Text wd(d.chroot_to + PathnameSep + d.wd);
00663 
00664         
00665         Text chdir_emsg("Can't establish working directory " + wd);
00666 
00667         
00668 
00669 
00670 
00671 
00672 
00673 
00674 
00675 
00676 
00677 
00678 
00679 
00680 
00681 
00682 
00683 
00684         char **helper_cmd =
00685           NEW_ARRAY(char *, 
00686                     1+                        
00687                     helper_switches.length()+ 
00688                     2+                        
00689                     2+                        
00690                     1+d.ev.length()+          
00691                     1+d.argv.length()+        
00692                     1);                       
00693         int i = 0; 
00694         helper_cmd[i++] = helper.chars();
00695         int j;
00696         for (j = 0; j < helper_switches.length(); ) {
00697           helper_cmd[i++] = helper_switches[j++];
00698         }
00699         helper_cmd[i++] = "-err";
00700         char error_wr[20];
00701         sprintf(error_wr, "%d", d.error_pipe[1]);
00702         helper_cmd[i++] = error_wr;
00703         helper_cmd[i++] = "-root";
00704         helper_cmd[i++] = d.chroot_to.chars();
00705         helper_cmd[i++] = "-env";
00706         for (j = 0; j < d.ev.length(); ) {
00707           helper_cmd[i++] = d.ev[j++];
00708         }
00709         helper_cmd[i++] = "-cmd";
00710         for (j = 0; j < d.argv.length(); ) {
00711           helper_cmd[i++] = d.argv[j++];
00712         }
00713         helper_cmd[i++] = NULL;
00714         
00715 
00716         
00717         pid_t child_pid = fork();
00718         switch (child_pid) {
00719           case -1:
00720             fail_with_errno("Couldn't fork process to execute command");
00721             break;                      
00722 
00723           
00724           case 0:
00725             
00726             ::setpgid(0, 0);
00727 
00728             
00729             close_fd(d.error_pipe[0]);
00730       
00731             
00732             move_fd(d.stdin_fd, STDIN_FILENO);
00733             move_fd(d.out.f, STDOUT_FILENO);
00734             move_fd(d.err.f, STDERR_FILENO);
00735       
00736             
00737 
00738             if (chdir(wd.chars()) == SYSERROR) {
00739               simulate_child_failure(d.error_pipe[1], trouble_fd,
00740                                      implementation_error,
00741                                      chdir_emsg.cchars());
00742             }
00743 
00744             
00745             execv(helper_cmd[0], helper_cmd);
00746 
00747             
00748             simulate_child_failure(d.error_pipe[1], trouble_fd,
00749                                    configuration_error,
00750                                    "Can't exec helper");
00751 
00752             
00753             _exit(implementation_error);
00754 
00755             
00756             break;
00757 
00758           
00759           default:
00760             
00761             if (debug_mode) {
00762                 OFdStream os(trouble_fd);
00763                 os << "\n*** Launching child process " << child_pid
00764                    << " ***" << endl;
00765             }
00766       
00767             
00768             close_fd(d.error_pipe[1]);
00769       
00770             
00771             bool child_killed;
00772             int s = children::wait_for(child_pid, srpc,  child_killed);
00773             
00774             in_use_slot = false;
00775 
00776             
00777             if (debug_mode) {
00778                 if (child_killed) {
00779                     cerr << "*** Child process " << child_pid
00780                          << " killed due to client termination ***" << endl;
00781                 } else {
00782                     cerr << "*** Finished child process " << child_pid
00783                          << ": exit status " << WEXITSTATUS(s)
00784                          << ", signal " << WTERMSIG(s) << " ***" << endl;
00785                 }
00786             }
00787 
00788             
00789             if (getenv("STOP_AFTER_TOOL")) {
00790                 cerr << "Stop after tool; root = " << d.chroot_to << endl;
00791                 cerr << "Hit enter to continue: ";
00792                 char enter;
00793                 cin.get(enter);
00794             } else if (WIFSIGNALED(s) && getenv("STOP_AFTER_TOOL_SIGNALED")) {
00795                 cerr << "Stop after tool signaled " << WTERMSIG(s)
00796                      << "; root = " << d.chroot_to << endl;
00797                 cerr << "Hit enter to continue: ";
00798                 char enter;
00799                 cin.get(enter);
00800             } else if (WIFEXITED(s) && WEXITSTATUS(s) &&
00801                        getenv("STOP_AFTER_TOOL_ERROR")) {
00802                 cerr << "Stop after tool error " << WEXITSTATUS(s)
00803                      << "; root = " << d.chroot_to << endl;
00804                 cerr << "Hit enter to continue: ";
00805                 char enter;
00806                 cin.get(enter);
00807             }
00808 
00809             
00810             Text msg("");
00811             while (true) {
00812                 char buf[100];
00813                 int ct = read(d.error_pipe[0], buf, sizeof(buf)-1);
00814                 if (ct == 0) break;
00815                 if (ct == SYSERROR)
00816                     fail_with_errno("Can't read from error_pipe!");
00817                 buf[ct] = 0;
00818                 msg += buf;
00819             }
00820             close_fd(d.error_pipe[0]);
00821       
00822             
00823             if (!msg.Empty()) {
00824                 
00825 
00826                 int r;
00827                 switch (WEXITSTATUS(s)) {
00828                   case unrecognized_switch:
00829                   case chroot_failure:
00830                   case wd_not_in_root:
00831                     r = configuration_error;
00832                     break;
00833                   case execve_failure:
00834                     r = client_error;
00835                     break;
00836                   default:
00837                     r = implementation_error;
00838                     break;
00839                 }
00840                 call_failed(r, msg);
00841                 
00842             }
00843       
00844             
00845 
00846             int i = sync_after_tool;
00847             while (i--) {
00848               
00849               
00850               
00851               
00852               
00853               
00854               
00855               
00856               
00857               
00858               
00859               
00860               
00861               
00862               
00863               ::sync();
00864             }
00865 
00866             
00867             srpc->send_int(WIFEXITED(s) ? WEXITSTATUS(s) : 0);
00868             srpc->send_int(WIFSIGNALED(s) ? WTERMSIG(s) : 0);
00869             if(intfVersion >= RUN_TOOL_CORE_VERSION) {
00870                     srpc->send_bool(WCOREDUMP(s) ? true : false);
00871             }
00872             srpc->send_end();
00873             break;
00874         } 
00875 
00876         
00877         delete [] helper_cmd;
00878         helper_cmd = NULL; 
00879     } 
00880     catch(const TCP_sock::failure &tf) {
00881         
00882         if(in_use_slot)
00883           {
00884             children::call_failed();
00885           }
00886 
00887         srpc->send_failure(implementation_error, "TCP failure: " + tf.msg);
00888     }
00889     catch(const call_failure &cf) {
00890         
00891         if(in_use_slot)
00892           {
00893             children::call_failed();
00894           }
00895 
00896         srpc->send_failure(cf.code, cf.msg);
00897     }
00898     catch (SRPC::failure) {
00899         
00900         
00901         
00902         if(in_use_slot)
00903           {
00904             children::call_failed();
00905           }
00906 
00907         throw;
00908     }
00909 
00910     
00911     
00912     assert(!in_use_slot);
00913 }
00914 
00915 void Info(SRPC *srpc, int intfVersion, int procId) throw(SRPC::failure)
00916 {
00917     float load = GetLoadPoint();
00918     children::mu.lock();
00919     int max_tools = children::maxChildren;
00920     int cur_tools, cur_pending, max_pending;
00921     if(intfVersion >= RUN_TOOL_LOAD_VERSION) {
00922             cur_tools = children::nInUse;
00923             cur_pending = children::nPending;
00924             max_pending = children::maxPending;
00925     } else {
00926             cur_tools = children::nInUse + children::nPending;
00927     }
00928     children::mu.unlock();
00929 
00930     try {
00931         
00932 
00933         
00934         srpc->recv_end();
00935     
00936         
00937         srpc->send_Text(sysname);
00938         srpc->send_Text(release);
00939         srpc->send_Text(version);
00940         srpc->send_Text(machine);
00941         srpc->send_int(cpus);
00942         srpc->send_int(cpuMHz);
00943         srpc->send_int(memKB);
00944         srpc->send_int(max_tools);
00945         srpc->send_int(cur_tools);
00946         if (intfVersion >= RUN_TOOL_LOAD_VERSION) {
00947                 srpc->send_float(load);
00948                 srpc->send_int(cur_pending);
00949                 srpc->send_int(max_pending);
00950         }
00951         if (procId != RUN_TOOL_OLDINFO) uniqueid.Send(*srpc);
00952         srpc->send_end();
00953 
00954     } 
00955     catch(const TCP_sock::failure &tf) {
00956         srpc->send_failure(implementation_error, "TCP failure: " + tf.msg);
00957     }
00958 }
00959 
00960 void 
00961 RunToolServer(SRPC *srpc, int intfVersion, int procId, void *arg)
00962   throw(SRPC::failure)
00963 
00964 
00965 
00966 {
00967   
00968   if(intfVersion > RUN_TOOL_INTERFACE_VERSION) { 
00969     srpc->send_failure(SRPC::version_skew,
00970                        "RunToolServer: Unsupported interface version");
00971     return;
00972   }
00973 
00974   
00975   switch (procId) {
00976   case RUN_TOOL_DOIT:
00977   case SRPC::default_proc_id:
00978     RunTool(srpc, intfVersion);
00979     break;
00980     
00981   case RUN_TOOL_OLDINFO:
00982   case RUN_TOOL_INFO:
00983     Info(srpc, intfVersion, procId);
00984     break;
00985 
00986   default:
00987     srpc->send_failure(SRPC::version_skew, "Unknown proc_id");
00988     break;
00989   }
00990 }
00991 
00992 #if defined(__linux__)
00993 
00994 
00995 
00996 
00997 
00998 
00999 
01000 static unsigned int get_hw_clock_freq()
01001 {
01002   ifstream pstr("/proc/cpuinfo");
01003 
01004   char line[1000];
01005 
01006   if(pstr.bad())
01007     {
01008       return 1; 
01009     }
01010 
01011   
01012 
01013   
01014   
01015   
01016 
01017   
01018   
01019   for(pstr.getline(line, sizeof(line));
01020       !pstr.eof();
01021       pstr.getline(line, sizeof(line)))
01022     {
01023       const char *l_digits;
01024 
01025       
01026       
01027       if(strncmp(line, "cycle frequency [Hz]", 20) == 0)
01028         {
01029           
01030           l_digits = strpbrk(line+20, "0123456789");
01031           if(l_digits != NULL)
01032             {
01033               
01034               int freq = atoi(l_digits);
01035               int l_result = (freq + 500000) / 1000000; 
01036               return l_result;
01037             }
01038         }
01039       
01040       
01041       else if(strncmp(line, "cpu MHz", 7) == 0)
01042         {
01043           
01044           l_digits = strpbrk(line+7, "0123456789");
01045           if(l_digits != NULL)
01046             {
01047               int l_result = atoi(l_digits);
01048               return l_result;
01049             }
01050         }
01051       
01052       
01053       else if((strncmp(line, "clock", 5) == 0) && isspace(line[5]))
01054         {
01055           
01056           l_digits = strpbrk(line+6, "0123456789");
01057           if(l_digits != NULL)
01058             {
01059               int l_result = atoi(l_digits);
01060               return l_result;
01061             }
01062         }
01063 
01064       
01065       while(pstr.fail())
01066         {
01067           
01068           pstr.clear(pstr.rdstate() & ~ios::failbit);
01069           
01070           
01071           pstr.getline(line, sizeof(line));
01072         }
01073     }
01074 
01075   
01076   
01077   return 1; 
01078 }
01079 
01080 
01081 
01082 
01083 
01084 
01085 
01086 
01087 
01088 
01089 
01090 
01091 
01092 
01093 static unsigned int get_n_cpus()
01094 {
01095   
01096   ifstream l_proc_stat("/proc/stat");
01097 
01098   
01099   unsigned int l_result = 0;
01100 
01101   
01102   char l_line[1000];
01103   for(l_proc_stat.getline(l_line, sizeof(l_line));
01104       !l_proc_stat.eof();
01105       l_proc_stat.getline(l_line, sizeof(l_line)))
01106     {
01107       
01108       if((strncmp(l_line, "cpu", 3) == 0) && isdigit(l_line[3]))
01109         {
01110           l_result++;
01111         }
01112 
01113       
01114       while(l_proc_stat.fail())
01115         {
01116           
01117           l_proc_stat.clear(l_proc_stat.rdstate() & ~ios::failbit);
01118           
01119           
01120           l_proc_stat.getline(l_line, sizeof(l_line));
01121         }
01122     }
01123 
01124   
01125   
01126   if(l_result > 0)
01127     {
01128       return l_result;
01129     }
01130 
01131   
01132   return 1;
01133 }
01134 
01135 #endif // defined (__linux__)
01136 
01137 
01138 
01139 void RunToolServerInit(int maxTools, int maxPending) throw(SRPC::failure)
01140 {
01141     
01142 
01143 
01144 
01145 
01146 
01147     try {
01148         if ((trouble_fd = dup(STDERR_FILENO)) == SYSERROR) {
01149             fail_with_errno(
01150               "Can't get file descriptor to report launcher errors");
01151         }
01152     } catch (const call_failure &f) {
01153         cerr << f.msg << endl;
01154         return;
01155     }
01156   
01157     
01158     static struct utsname u;
01159     uname(&u);
01160     sysname = u.sysname;
01161     release = u.release;
01162     version = u.version;
01163     machine = u.machine;
01164 
01165 #if defined(__digital__)    
01166     
01167     struct cpu_info cpuinfo;
01168     int start = 0;
01169     getsysinfo(GSI_CPU_INFO, (caddr_t) &cpuinfo, sizeof(cpuinfo),
01170                &start, NULL, NULL);
01171     cpus = cpuinfo.cpus_in_box;
01172     cpuMHz = cpuinfo.mhz;
01173     start = 0;
01174     getsysinfo(GSI_PHYSMEM, (caddr_t) &memKB, sizeof(memKB),
01175                &start, NULL, NULL);
01176 #elif defined (__linux__)
01177     
01178     
01179     
01180     
01181     
01182     
01183     
01184 
01185     cpus = get_n_cpus();
01186     cpuMHz = get_hw_clock_freq();
01187     memKB = ((((unsigned long) sysconf(_SC_PAGE_SIZE)) *
01188               ((unsigned long) sysconf(_SC_PHYS_PAGES)))
01189              / 1024);
01190     
01191     
01192     assert(cpus > 0);
01193     assert(cpuMHz > 0);
01194     assert(memKB > 0);
01195 #endif
01196 
01197     
01198     
01199     VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "sysname", sysname);
01200     VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "release", release);
01201     VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "version", version);
01202     VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "machine", machine);
01203     try {
01204       cpus = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "cpus");
01205     } catch (VestaConfig::failure) {  }
01206     try {
01207       cpuMHz = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "cpuMHz");
01208     } catch (VestaConfig::failure) {  }
01209     try {
01210       memKB = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "memKB");
01211     } catch (VestaConfig::failure) {  }
01212 
01213     
01214     uniqueid = UniqueId();
01215 
01216     
01217     helper = config_lookup("helper");
01218     try {
01219         Text val(VestaConfig::get_Text(RUN_TOOL_CONFIG_SECTION,
01220                                        "helper_switches"));
01221         istringstream is(val.chars());
01222         char s[100];
01223         while ( is >> s && strlen(s) != 0) {
01224             if (strcmp(s, "-d") == 0) {
01225                 int dbgfd;
01226                 try {
01227                     if ((dbgfd = dup(STDERR_FILENO)) == SYSERROR) {
01228                         fail_with_errno(
01229                           "Can't get file descriptor for debug output");
01230                     }
01231                 } catch (call_failure f) {
01232                     cerr << f.msg << '\n';
01233                     continue;
01234                 }
01235                 debug_mode = true;
01236                 helper_switches += "-dbg";
01237                 sprintf(s, "%d", dbgfd);
01238             }
01239             helper_switches += s;
01240         }
01241     } catch(const VestaConfig::failure &f) {
01242         
01243     }
01244     try {
01245       sync_after_tool = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION,
01246                                              "sync_after_tool");
01247     } catch(const VestaConfig::failure &f) {
01248         
01249     }
01250     if (debug_mode) {
01251         cout << "helper command = " << helper;
01252         for (int i = 0; i < helper_switches.length(); i++) {
01253             cout << " " << helper_switches[i];
01254         }
01255         cout << endl;
01256     }
01257 
01258     volatile_root = config_lookup("VolatileRootName");
01259     
01260     struct stat st;
01261     if (stat(volatile_root.cchars(), &st) < 0) {
01262       cerr << "Can't access volatile root (not mounted?): "
01263            << volatile_root + ": " << strerror(errno) << endl;
01264       exit(1);
01265     }
01266 
01267     children::init(maxTools, maxPending);
01268 }       
01269 
01270 void RunToolServerCleanup() throw ()
01271 {
01272     
01273 }