|
Isis 3.0 Object Programmers' Reference |
Home |
00001 #include "IsisDebug.h" 00002 00003 #include <cstdio> 00004 #include <sstream> 00005 #include <unistd.h> 00006 #include <sys/wait.h> 00007 #include <errno.h> 00008 extern int errno; 00009 #include <QString> 00010 #include <iostream> 00011 #include <sstream> 00012 #include <QCoreApplication> 00013 00014 #include "Application.h" 00015 #include "UserInterface.h" 00016 #include "Gui.h" 00017 #include "Constants.h" 00018 #include "Message.h" 00019 #include "SessionLog.h" 00020 #include "System.h" 00021 #include "Preference.h" 00022 #include "iException.h" 00023 #include "CubeManager.h" 00024 00048 namespace Isis { 00049 Application *iApp = NULL; 00050 00060 Application::Application (int argc, char *argv[]) { 00061 // Init socket communications 00062 p_socket = -1; 00063 p_childSocket = -1; 00064 p_socketFile = ""; 00065 p_ui = NULL; 00066 00067 // Save the application name 00068 p_appName = argv[0]; 00069 00070 // Get the starting wall clock time 00071 p_datetime = DateTime(&p_startTime); 00072 00073 // Init 00074 p_startClock = 0; 00075 p_startDirectIO = 0; 00076 p_startPageFaults = 0; 00077 p_startProcessSwaps = 0; 00078 p_BatchlistPass = 0; 00079 00080 // Get the starting cpu time, direct I/Os, page faults, and swaps 00081 p_startClock = clock(); 00082 p_startDirectIO = DirectIO(); 00083 p_startPageFaults = PageFaults(); 00084 p_startProcessSwaps = ProcessSwaps(); 00085 00086 // Create user interface and log 00087 try { 00088 Isis::Filename f = std::string(argv[0]) + ".xml"; 00089 00090 // Create preferences 00091 Isis::Preference::Preferences(f.Name() == "unitTest.xml"); 00092 00093 if (!f.Exists()) { 00094 f = "$ISISROOT/bin/xml/" + f.Name(); 00095 if (!f.Exists()) { 00096 std::string message = Isis::Message::FileOpen(f.Expanded()); 00097 throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); 00098 } 00099 } 00100 std::string xmlfile = f.Expanded(); 00101 00102 p_ui = new Isis::UserInterface(xmlfile,argc,argv); 00103 if (!p_ui->IsInteractive()) { 00104 new QCoreApplication(argc,argv); 00105 } 00106 00107 } catch (Isis::iException &e) { 00108 exit(e.Report()); 00109 } 00110 00111 iApp = this; 00112 } 00113 00115 Application::~Application () { 00116 if (HasParent()) { 00117 SendParentData("DONE",""); 00118 close(p_childSocket); 00119 } 00120 00121 if (p_socket >= 0) { 00122 close(p_socket); 00123 remove(p_socketFile.c_str()); 00124 } 00125 00126 if(p_ui) { 00127 delete p_ui; 00128 } 00129 } 00130 00138 int Application::Exec(void (*funct)()) { 00139 int status = 0; 00140 try { 00141 if (p_ui->IsInteractive()) { 00142 p_ui->TheGui()->Exec(funct); 00143 } else { 00144 if (p_ui->BatchListSize() > 0) { 00145 for (int i=0; i<p_ui->BatchListSize(); i++) { 00146 try { 00147 p_ui->SetBatchList(i); 00148 00149 if (i != 0) { 00150 p_datetime = DateTime(&p_startTime); 00151 p_startClock = clock(); 00152 p_startDirectIO = DirectIO(); 00153 p_startPageFaults = PageFaults(); 00154 p_startProcessSwaps = ProcessSwaps(); 00155 SessionLog::TheLog(true); 00156 } 00157 00158 funct(); 00159 Application::FunctionCleanup(); 00160 p_BatchlistPass++; 00161 } catch (Isis::iException &e) { 00162 p_ui->SetErrorList(i); 00163 status = Application::FunctionError(e); 00164 if (p_ui->AbortOnError()) { 00165 for (int j=(i+1); j<p_ui->BatchListSize(); j++) { 00166 p_ui->SetErrorList(j); 00167 p_BatchlistPass++; 00168 } 00169 break; 00170 } 00171 } 00172 } 00173 } else { 00174 p_ui->SaveHistory(); 00175 // The gui checks everything but not the command line mode so 00176 // verify if necessary. Batchlist verifies on SetBatchList 00177 p_ui->VerifyAll(); 00178 funct(); 00179 Application::FunctionCleanup(); 00180 } 00181 } 00182 } catch (Isis::iException &e) { 00183 status = Application::FunctionError(e); 00184 } 00185 00186 #if 0 00187 catch (std::exception &e) { 00188 std::string message = e.what (); 00189 Isis::iExceptionSystem i(message,_FILEINFO_); 00190 status = i.Report(); 00191 } catch (...) { 00192 std::string message = "Unknown error expection"; 00193 Isis::iExceptionSystem i(message,_FILEINFO_); 00194 status = i.Report(); 00195 } 00196 #endif 00197 00198 return status; 00199 } 00200 00206 PvlObject Application::History() { 00207 PvlObject history(p_ui->ProgramName()); 00208 history += Isis::PvlKeyword("IsisVersion",Isis::version); 00209 history += Isis::PvlKeyword("ProgramVersion",p_ui->Version()); 00210 QString path = QCoreApplication::applicationDirPath(); 00211 history += Isis::PvlKeyword("ProgramPath", path); 00212 history += Isis::PvlKeyword("ExecutionDateTime",p_datetime); 00213 history += Isis::PvlKeyword("HostName",HostName()); 00214 history += Isis::PvlKeyword("UserName",UserName()); 00215 history += Isis::PvlKeyword("Description",p_ui->Brief()); 00216 00217 // Add the user parameters 00218 Isis::Pvl pvl; 00219 p_ui->CommandLine(pvl); 00220 history.AddGroup(pvl.FindGroup("UserParameters")); 00221 00222 return history; 00223 } 00224 00230 PvlGroup Application::Accounting () { 00231 // Grab the ending time to compute connect time 00232 time_t endTime = time(NULL); 00233 double seconds = difftime (endTime,p_startTime); 00234 int minutes = (int) (seconds / 60.0); 00235 seconds = seconds - minutes * 60.0; 00236 int hours = minutes / 60; 00237 minutes = minutes - hours * 60; 00238 char temp[80]; 00239 sprintf(temp,"%02d:%02d:%04.1f",hours,minutes,seconds); 00240 std::string conTime = temp; 00241 00242 // Grab the ending cpu time to compute total cpu time 00243 clock_t endClock = clock(); 00244 seconds = (double(endClock) - (double)p_startClock) / CLOCKS_PER_SEC; 00245 minutes = (int) (seconds / 60.0); 00246 seconds = seconds - minutes * 60.0; 00247 hours = minutes / 60; 00248 minutes = minutes - hours * 60; 00249 sprintf(temp,"%02d:%02d:%04.1f",hours,minutes,seconds); 00250 std::string cpuTime = temp; 00251 00252 // Add this information to the log 00253 PvlGroup acct("Accounting"); 00254 acct += Isis::PvlKeyword("ConnectTime",conTime); 00255 acct += Isis::PvlKeyword("CpuTime",cpuTime); 00256 00257 // Not sure if these are really valuable. If deemed so then 00258 // uncomment and complete private methods (DirectIO, Pagefaults, and 00259 // ProcessSwaps). 00260 //int directIO = DirectIO(); 00261 //int pageFaults = PageFaults(); 00262 //int processSwaps = ProcessSwaps(); 00263 //acct += Isis::PvlKeyword("DirectIo",directIO); 00264 //acct += Isis::PvlKeyword("PageFaults",pageFaults); 00265 //acct += Isis::PvlKeyword("ProcessSwaps",processSwaps); 00266 00267 return acct; 00268 } 00269 00275 int Application::DirectIO() { 00276 return 0 - p_startDirectIO; 00277 } 00278 00284 int Application::PageFaults() { 00285 return 0 - p_startPageFaults; 00286 } 00287 00293 int Application::ProcessSwaps() { 00294 return 0 - p_startProcessSwaps; 00295 } 00296 00302 void Application::Log(PvlGroup &results) { 00303 // Add it to the log file 00304 static bool blankLine = false; 00305 SessionLog::TheLog().AddResults(results); 00306 00307 // See if the log file will be written to the terminal/gui 00308 if (SessionLog::TheLog().TerminalOutput()) return; 00309 00310 // See if we should write the info to our parents gui 00311 if (HasParent()) { 00312 std::ostringstream ostr; 00313 if (blankLine) ostr << std::endl; 00314 ostr << results << std::endl; 00315 std::string data = ostr.str(); 00316 SendParentData (std::string("LOG"),data); 00317 } 00318 00319 // Otherwise see if we need to write to our gui 00320 else if (iApp->GetUserInterface().IsInteractive()) { 00321 std::ostringstream ostr; 00322 if (blankLine) ostr << std::endl; 00323 ostr << results << std::endl; 00324 iApp->GetUserInterface().TheGui()->Log(ostr.str()); 00325 iApp->GetUserInterface().TheGui()->ShowLog(); 00326 } 00327 00328 // Otherwise its command line mode 00329 else { 00330 if (blankLine) std::cout << std::endl; 00331 std::cout << results << std::endl; 00332 } 00333 blankLine = true; 00334 } 00335 00341 void Application::GuiLog(Pvl &results) { 00342 // See if we should write the info to our parents gui 00343 if (HasParent()) { 00344 std::ostringstream ostr; 00345 ostr << results << std::endl; 00346 std::string data = ostr.str(); 00347 SendParentData (std::string("LOG"),data); 00348 } 00349 00350 // Otherwise see if we need to write to our gui 00351 else if (iApp->GetUserInterface().IsInteractive()) { 00352 std::ostringstream ostr; 00353 ostr << results << std::endl; 00354 iApp->GetUserInterface().TheGui()->Log(ostr.str()); 00355 iApp->GetUserInterface().TheGui()->ShowLog(); 00356 } 00357 } 00358 00364 void Application::GuiLog(PvlGroup &results) { 00365 // See if we should write the info to our parents gui 00366 if (HasParent()) { 00367 std::ostringstream ostr; 00368 ostr << results << std::endl; 00369 std::string data = ostr.str(); 00370 SendParentData (std::string("LOG"),data); 00371 } 00372 00373 // Otherwise see if we need to write to our gui 00374 else if (iApp->GetUserInterface().IsInteractive()) { 00375 std::ostringstream ostr; 00376 ostr << results << std::endl; 00377 iApp->GetUserInterface().TheGui()->Log(ostr.str()); 00378 iApp->GetUserInterface().TheGui()->ShowLog(); 00379 } 00380 } 00381 00387 void Application::GuiLog(std::string &results) { 00388 // See if we should write the info to our parents gui 00389 if (HasParent()) { 00390 SendParentData (std::string("LOG"),results); 00391 } 00392 00393 // Otherwise see if we need to write to our gui 00394 else if (iApp->GetUserInterface().IsInteractive()) { 00395 iApp->GetUserInterface().TheGui()->Log(results); 00396 iApp->GetUserInterface().TheGui()->ShowLog(); 00397 } 00398 } 00399 00405 Isis::UserInterface &Application::GetUserInterface() { 00406 return *iApp->p_ui; 00407 } 00408 00414 bool Application::HasParent () { 00415 if (iApp == NULL) return false; 00416 if (iApp->p_ui == NULL) return false; 00417 if (iApp->p_ui->ParentId() == 0) return false; 00418 return true; 00419 } 00420 00426 void Application::SendParentErrors (Isis::PvlObject &errors) { 00427 for (int i=0; i<errors.Groups(); i++) { 00428 std::ostringstream ostr; 00429 ostr << errors.Group(i) << std::endl; 00430 std::string data = ostr.str(); 00431 SendParentData (std::string("ERROR"),data); 00432 } 00433 } 00434 00445 int Application::p_childSocket = -1; 00446 void Application::SendParentData(const std::string code, const std::string &message) { 00447 // See if we need to connect to the parent 00448 if (p_childSocket < 0) { 00449 std::string socketFile = "/tmp/isis_" + Isis::iString(iApp->GetUserInterface().ParentId()); 00450 sockaddr_un socketName; 00451 socketName.sun_family = AF_UNIX; 00452 strcpy(socketName.sun_path,socketFile.c_str()); 00453 p_childSocket = socket(PF_UNIX,SOCK_STREAM,0); 00454 if (p_childSocket == -1) { 00455 std::string msg = "Unable to create child-to-parent socket [" + 00456 socketFile + "]"; 00457 std::cout << msg << std::endl; 00458 throw Isis::iException::Message(Isis::iException::System, 00459 msg,_FILEINFO_); 00460 } 00461 00462 errno = 0; 00463 int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family); 00464 int status = connect(p_childSocket,(struct sockaddr *)&socketName,len); 00465 if (status == -1) { 00466 std::string msg = "Unable to connect to parent [" + 00467 Isis::iString(iApp->GetUserInterface().ParentId()) + "] errno = " + 00468 iString(errno); 00469 std::cout << msg << std::endl; 00470 throw Isis::iException::Message(Isis::iException::System, 00471 msg,_FILEINFO_); 00472 } 00473 } 00474 00475 // Have connection so build data string and send it 00476 std::string data = code; 00477 data += char(27); 00478 if (message != "") { 00479 data += message; 00480 data += char(27); 00481 } 00482 00483 if (send (p_childSocket,data.c_str(),data.size(),0) < 0) { 00484 std::string msg = "Unable to send to parent [" + 00485 Isis::iString(iApp->GetUserInterface().ParentId()) + "]"; 00486 std::cout << msg << std::endl; 00487 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00488 } 00489 } 00490 00496 void Application::FunctionCleanup() { 00497 CubeManager::CleanUp(); 00498 00499 SessionLog::TheLog().Write(); 00500 00501 if (SessionLog::TheLog().TerminalOutput()) { 00502 if (HasParent()) { 00503 std::ostringstream ostr; 00504 ostr << SessionLog::TheLog() << std::endl; 00505 std::string data = ostr.str(); 00506 SendParentData (std::string("LOG"),data); 00507 } else if (p_ui->IsInteractive()) { 00508 std::ostringstream ostr; 00509 ostr << SessionLog::TheLog() << std::endl; 00510 p_ui->TheGui()->Log(ostr.str()); 00511 p_ui->TheGui()->ShowLog(); 00512 } else { 00513 std::cout << SessionLog::TheLog() << std::endl; 00514 } 00515 } 00516 00517 // If debugging flag on write debugging log 00518 if (p_ui->GetInfoFlag()) { 00519 std::string filename = p_ui->GetInfoFileName(); 00520 Pvl log; 00521 iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName; 00522 if (p_BatchlistPass == 0) { 00523 std::stringstream ss ; 00524 ss << SessionLog::TheLog(); 00525 ss.clear(); 00526 ss >> log; 00527 PvlGroup uname = Isis::GetUnameInfo(); 00528 PvlGroup env = Isis::GetEnviromentInfo(); 00529 log.AddGroup(uname); 00530 log.AddGroup(env); 00531 } 00532 00533 // Write to file 00534 if (filename.compare("") != 0) { 00535 00536 if (p_BatchlistPass == 0) { 00537 std::ofstream debugingLog (filename.c_str()); 00538 if (!debugingLog.good()) { 00539 std::string msg = "Error opening debugging log file [" + filename + "]"; 00540 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00541 } 00542 debugingLog << log << std::endl; 00543 debugingLog << "\n############### User Preferences ################\n" << std::endl; 00544 debugingLog << Preference::Preferences(); 00545 debugingLog << "\n############## System Disk Space ################\n" << std::endl; 00546 debugingLog << SystemDiskSpace() << std::endl; 00547 debugingLog << "\n############ Executable Information #############\n" << std::endl; 00548 debugingLog << GetLibraryDependencies(app) << std::endl; 00549 debugingLog.close(); 00550 } else { 00551 std::ofstream debugingLog (filename.c_str(),std::ios_base::app); 00552 debugingLog << SessionLog::TheLog() << std::endl; 00553 debugingLog.close(); 00554 } 00555 } else { // Write to std out 00556 if (p_BatchlistPass == 0) { 00557 std::cout << log << std::endl; 00558 std::cout << "\n############### User Preferences ################\n" << std::endl; 00559 std::cout << Preference::Preferences(); 00560 std::cout << "\n############## System Disk Space ################\n" << std::endl; 00561 std::cout << SystemDiskSpace() << std::endl; 00562 std::cout << "\n############ Executable Information #############\n" << std::endl; 00563 std::cout << GetLibraryDependencies(app) << std::endl; 00564 } else { 00565 std::cout << SessionLog::TheLog() << std::endl; 00566 } 00567 } 00568 } 00569 00570 00571 } 00572 00582 int Application::FunctionError(Isis::iException &e) { 00583 Pvl errors = e.PvlErrors(); 00584 SessionLog::TheLog().AddError(errors); 00585 SessionLog::TheLog().Write(); 00586 00587 if (HasParent()) { 00588 SendParentErrors(errors); 00589 } else if (p_ui->IsInteractive()) { 00590 if (e.IsPvlFormat()) { 00591 std::ostringstream ostr; 00592 ostr << errors << std::endl; 00593 p_ui->TheGui()->LoadMessage(ostr.str()); 00594 } else { 00595 p_ui->TheGui()->LoadMessage(e.Errors()); 00596 } 00597 } else if (SessionLog::TheLog().TerminalOutput()) { 00598 std::cerr << SessionLog::TheLog() << std::endl; 00599 } else if (e.IsPvlFormat()) { 00600 std::cerr << errors << std::endl; 00601 } else { 00602 std::cerr << e.Errors() << std::endl; 00603 } 00604 00605 // If debugging flag on write debugging log 00606 if (p_ui->GetInfoFlag()) { 00607 std::string filename = p_ui->GetInfoFileName(); 00608 Pvl log; 00609 iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName; 00610 if (p_BatchlistPass == 0) { 00611 std::stringstream ss ; 00612 ss << SessionLog::TheLog(); 00613 ss.clear(); 00614 ss >> log; 00615 PvlGroup uname = Isis::GetUnameInfo(); 00616 PvlGroup env = Isis::GetEnviromentInfo(); 00617 log.AddGroup(uname); 00618 log.AddGroup(env); 00619 } 00620 00621 // Write to file 00622 if (filename.compare("") != 0) { 00623 if (p_BatchlistPass == 0) { 00624 std::ofstream debugingLog (filename.c_str()); 00625 if (!debugingLog.good()) { 00626 std::string msg = "Error opening debugging log file [" + filename + "]"; 00627 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00628 } 00629 debugingLog << log << std::endl; 00630 debugingLog << "\n############### User Preferences ################\n" << std::endl; 00631 debugingLog << Preference::Preferences(); 00632 debugingLog << "\n############ System Disk Space #############\n" << std::endl; 00633 debugingLog << SystemDiskSpace() << std::endl; 00634 debugingLog << "\n############ Executable Information #############\n" << std::endl; 00635 debugingLog << GetLibraryDependencies(app) << std::endl; 00636 debugingLog.close(); 00637 } else { 00638 std::ofstream debugingLog (filename.c_str(),std::ios_base::app); 00639 debugingLog << SessionLog::TheLog() << std::endl; 00640 debugingLog.close(); 00641 } 00642 } else { // Write to std out 00643 if (p_BatchlistPass == 0) { 00644 std::cout << log << std::endl; 00645 std::cout << "\n############### User Preferences ################\n" << std::endl; 00646 std::cout << Preference::Preferences(); 00647 std::cout << "\n############ System Disk Space #############\n" << std::endl; 00648 std::cout << SystemDiskSpace() << std::endl; 00649 std::cout << "\n############ Executable Information #############\n" << std::endl; 00650 std::cout << GetLibraryDependencies(app) << std::endl; 00651 } else { 00652 std::cout << SessionLog::TheLog() << std::endl; 00653 } 00654 } 00655 } 00656 00657 int errorType = (int)e.Type(); 00658 e.Clear(); 00659 return errorType; 00660 } 00661 00668 void Application::GuiReportError(Isis::iException &e) { 00669 Pvl errors = e.PvlErrors(); 00670 if (e.Type() == Isis::iException::Cancel) { 00671 e.Clear (); 00672 p_ui->TheGui()->ProgressText ("Stopped"); 00673 } 00674 if (e.IsPvlFormat()) { 00675 std::ostringstream ostr; 00676 ostr << errors << std::endl; 00677 p_ui->TheGui()->LoadMessage(ostr.str()); 00678 } else { 00679 p_ui->TheGui()->LoadMessage(e.Errors()); 00680 } 00681 00682 if (p_ui->TheGui()->ShowWarning ()) exit (0); 00683 p_ui->TheGui()->ProgressText ("Error"); 00684 e.Clear(); 00685 } 00686 00693 QString Application::p_appName("Unknown"); 00694 std::string Application::Name() { 00695 return p_appName.toStdString(); 00696 } 00697 00705 void Application::UpdateProgress(const std::string &text, bool print) { 00706 if (HasParent()) { 00707 std::string msg = p_ui->ProgramName() + ": " + text; 00708 SendParentData(std::string("PROGRESSTEXT"),msg); 00709 } else if (p_ui->IsInteractive()) { 00710 p_ui->TheGui()->ProgressText(text); 00711 } else if (print) { 00712 std::string msg = p_ui->ProgramName() + ": " + text; 00713 std::cout << msg << std::endl; 00714 } 00715 } 00716 00724 void Application::UpdateProgress(int percent, bool print) { 00725 if (HasParent()) { 00726 std::string data = Isis::iString(percent); 00727 SendParentData(std::string("PROGRESS"),data); 00728 } else if (p_ui->IsInteractive()) { 00729 p_ui->TheGui()->Progress(percent); 00730 } else if (print) { 00731 if (percent < 100) { 00732 std::cout << percent << "% Processed\r" << std::flush; 00733 } else { 00734 std::cout << percent << "% Processed" << std::endl; 00735 } 00736 } 00737 } 00738 00745 void Application::ProcessGuiEvents() { 00746 if (p_ui->IsInteractive()) { 00747 bool cancel = p_ui->TheGui()->ProcessEvents(); 00748 if (cancel) { 00749 throw Isis::iException::Message(Isis::iException::Cancel,"",_FILEINFO_); 00750 } 00751 } 00752 } 00753 00764 void Application::Exec(const std::string &program, const std::string ¶meters) { 00765 // Setup the command line 00766 Isis::Filename bin(program); 00767 if (!bin.Exists()) { 00768 bin = "$ISISROOT/bin/" + program; 00769 } 00770 //Isis::Filename bin("$ISISROOT/bin/"+program); 00771 std::string command = bin.Expanded() + " " + parameters; 00772 00773 // If we are interactive we must do an asychronous execute 00774 // so we can watch our socket 00775 if (p_ui->IsInteractive()) { 00776 p_pid = getpid(); 00777 pid_t childPid; 00778 if ((childPid = fork()) == -1) { 00779 std::string msg = "Unable to execute command [" + command + "]"; 00780 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00781 } 00782 00783 if (childPid != 0) { 00784 EstablishConnections(); 00785 ParentFork(command,program); 00786 ProcessGuiEvents(); 00787 } else { 00788 ChildFork(command); 00789 } 00790 } 00791 // Handle command line programs invoked by GUI programs 00792 else if (HasParent()) { 00793 SendParentData("DISCONNECT",""); 00794 close(p_childSocket); 00795 p_childSocket = -1; 00796 command += " -pid=" + Isis::iString((int)p_ui->ParentId()); 00797 Isis::System(command); 00798 SendParentData("RECONNECT",""); 00799 } 00800 // Otherwise just execute the command and wait for it to finish 00801 else { 00802 Isis::System(command); 00803 } 00804 } 00805 00815 void Application::EstablishConnections() { 00816 if (p_socket != -1) return; 00817 00818 // Create a socket 00819 if ((p_socket = socket(PF_UNIX,SOCK_STREAM,0)) == -1) { 00820 std::string msg = "Unable to create socket"; 00821 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00822 } 00823 00824 // Get the process id and create a unique filename 00825 p_socketFile = "/tmp/isis_" + Isis::iString((int)p_pid); 00826 00827 // Bind the file to the socket 00828 p_socketName.sun_family = AF_UNIX; 00829 strcpy(p_socketName.sun_path,p_socketFile.c_str()); 00830 int len = strlen(p_socketName.sun_path) + sizeof(p_socketName.sun_family); 00831 if (bind(p_socket,(struct sockaddr *)&p_socketName,len) == -1) { 00832 std::string msg = "Unable to bind to socket [" + p_socketFile + "]"; 00833 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00834 } 00835 00836 // Set up to listen to the socket 00837 if (listen(p_socket,5) == -1) { 00838 std::string msg = "Unable to listen to socket [" + p_socketFile + "]"; 00839 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00840 } 00841 } 00842 00848 void Application::ChildFork(const std::string &commandLine) { 00849 // The child fork doesn't have the socket 00850 p_socket = -1; 00851 00852 // Append the pid as an argument 00853 std::string command = commandLine + " -pid=" + Isis::iString((int)p_pid); 00854 00855 // Run the command 00856 int status = system (command.c_str()); 00857 00858 int childSocket = socket(PF_UNIX,SOCK_STREAM,0); 00859 if (childSocket == -1) { 00860 std::cout << "couldn't create socket to parent fork" << std::endl << std::flush; 00861 // What should we dooo???? How do we stop the parent? 00862 exit(255); 00863 } 00864 00865 sockaddr_un socketName; 00866 socketName.sun_family = AF_UNIX; 00867 iString socketFile = "/tmp/isis_" + Isis::iString((int)p_pid); 00868 strcpy(socketName.sun_path,socketFile.c_str()); 00869 00870 int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family); 00871 if (connect(childSocket,(struct sockaddr *)&socketName,len) == -1) { 00872 std::cout << "couldn't connect to parent fork" << std::endl << std::flush; 00873 // What should we dooo???? How do we stop the parent? 00874 exit(255); 00875 } 00876 00877 if (status != 0) { 00878 char terminate[10] = "TERMINATE"; 00879 terminate[9] = 27; // escape character 00880 if (send (childSocket,terminate,sizeof(terminate),0) < 0) { 00881 std::cout << "couldn't send terminate to parent fork" << std::endl << std::flush; 00882 // What should we dooo???? How do we stop the parent? 00883 exit(255); 00884 } 00885 } else { 00886 char success[8] = "SUCCESS"; 00887 success[7] = 27; // escape character 00888 if (send (childSocket,success,sizeof(success),0) < 0) { 00889 std::cout << "couldn't send success to parent fork" << std::endl << std::flush; 00890 // What should we dooo???? How do we stop the parent? 00891 exit(255); 00892 } 00893 } 00894 00895 close(childSocket); 00896 exit(0); 00897 } 00898 00909 void Application::ParentFork(const std::string &command, const std::string &program) { 00910 // Try to accept a connection from the program our child fork executed. If 00911 // the program we ran failed to start then we are waiting for the connection 00912 // in the child fork 00913 p_buffer = ""; 00914 p_queue.clear(); 00915 00916 int childForkDone = false; 00917 while (!childForkDone) { 00918 int childSocket = -1; 00919 while (childSocket == -1) { 00920 errno = 0; 00921 socklen_t len = sizeof(p_socketName); 00922 childSocket = accept(p_socket, (struct sockaddr *)&p_socketName, &len); 00923 if (childSocket == -1) { 00924 if (errno != EINTR) { 00925 std::cout << "accept errno = " << errno << std::endl << std::flush; 00926 std::string msg = "Unable to accept socket connection [" + 00927 p_socketFile + "] from child process"; 00928 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00929 } 00930 } 00931 } 00932 00933 // Looks like we are the parent so we must wait for input to come from 00934 // the child. 00935 bool done = false; 00936 while (!done) { 00937 WaitForCommand(childSocket); 00938 00939 while (p_queue.size() > 0) { 00940 if (p_queue[0] == "DONE") { 00941 p_queue.erase(p_queue.begin()); 00942 done = true; 00943 } else if (p_queue[0] == "DISCONNECT") { 00944 p_queue.erase(p_queue.begin()); 00945 done = true; 00946 } else if (p_queue[0] == "RECONNECT") { 00947 p_queue.erase(p_queue.begin()); 00948 } else if (p_queue[0] == "SUCCESS") { 00949 p_queue.erase(p_queue.begin()); 00950 done = true; 00951 childForkDone = true; 00952 } else if (p_queue[0] == "TERMINATE") { 00953 // Should only happen if child fork could not fire off the process 00954 p_queue.erase(p_queue.begin()); 00955 std::string msg = "Unable to execute command [" + command + "]"; 00956 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 00957 } else if (p_queue[0] == "ERROR") { 00958 p_queue.erase(p_queue.begin()); 00959 while (p_queue.size() == 0) WaitForCommand(childSocket); 00960 std::stringstream str; 00961 str << p_queue[0]; 00962 p_queue.erase(p_queue.begin()); 00963 00964 Isis::Pvl error; 00965 str >> error; 00966 00967 for (int i=0; i<error.Groups(); i++) { 00968 Isis::PvlGroup &g = error.Group(i); 00969 std::string eclass = g["Class"]; 00970 std::string emsg = g["Message"]; 00971 int ecode = g["Code"]; 00972 std::string efile = g["File"]; 00973 int eline = g["Line"]; 00974 00975 Isis::iException::Message((Isis::iException::errType)ecode, 00976 emsg,(char *)efile.c_str(),eline); 00977 } 00978 } else if (p_queue[0] == "PROGRESSTEXT") { 00979 p_queue.erase(p_queue.begin()); 00980 while (p_queue.size() == 0) WaitForCommand(childSocket); 00981 p_ui->TheGui()->ProgressText(p_queue[0]); 00982 p_ui->TheGui()->Progress(0); 00983 p_queue.erase(p_queue.begin()); 00984 } else if (p_queue[0] == "PROGRESS") { 00985 p_queue.erase(p_queue.begin()); 00986 while (p_queue.size() == 0) WaitForCommand(childSocket); 00987 p_ui->TheGui()->Progress(Isis::iString(p_queue[0]).ToInteger()); 00988 p_queue.erase(p_queue.begin()); 00989 } else if (p_queue[0] == "LOG") { 00990 p_queue.erase(p_queue.begin()); 00991 while (p_queue.size() == 0) WaitForCommand(childSocket); 00992 00993 std::stringstream str; 00994 str << p_queue[0]; 00995 p_queue.erase(p_queue.begin()); 00996 00997 p_ui->TheGui()->Log(str.str()); 00998 } else { 00999 std::string msg = "Unknown command [" + p_queue[0]; 01000 msg += "] on socket [" + p_socketFile + "]"; 01001 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 01002 } 01003 ProcessGuiEvents(); 01004 } 01005 } 01006 close(childSocket); 01007 } 01008 } 01009 01019 void Application::WaitForCommand (int childSocket) { 01020 01021 // Now we are ready to receive commands from our child (like in real 01022 // life) so receive the command 01023 int bytes; 01024 char buf[1024*1024]; 01025 if ((bytes = recv(childSocket,&buf,1024*1024,0)) < 0) { 01026 std::string msg = "Unable to read from socket [" + p_socketFile + "]"; 01027 throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); 01028 } 01029 01030 // Push everything onto our string buffer 01031 for (int i=0; i<bytes; i++) p_buffer += buf[i]; 01032 01033 // Move esc delimited strings to our command queue 01034 std::string::size_type pos; 01035 while ((pos = p_buffer.find(27)) != std::string::npos) { 01036 p_queue.push_back(p_buffer.substr(0,pos)); 01037 p_buffer.erase(0,pos+1); 01038 } 01039 } 01040 01048 std::string Application::DateTime (time_t *curtime) { 01049 time_t startTime = time(NULL); 01050 if (curtime != 0) *curtime = startTime; 01051 struct tm *tmbuf = localtime(&startTime); 01052 char timestr[80]; 01053 strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf); 01054 return(std::string) timestr; 01055 } 01056 01062 std::string Application::UserName () { 01063 std::string user = "Unknown"; 01064 char *userPtr = getenv("USER"); 01065 if (userPtr != NULL) user = userPtr; 01066 return user; 01067 } 01068 01074 std::string Application::HostName () { 01075 std::string host = "Unknown"; 01076 char *hostPtr = getenv("HOST"); 01077 if (hostPtr == NULL) hostPtr = getenv ("HOSTNAME"); 01078 if (hostPtr != NULL) host = hostPtr; 01079 return host; 01080 } 01081 01082 } //end namespace isis 01083