00001 #include <sys/wait.h>
00002 #include <pthread.h>
00003 #include "jsoc.h"
00004 #include "cmdparams.h"
00005 #include "timer.h"
00006 #include "util.h"
00007
00108 #define kDRMSSERVERLOG "drmslog"
00109 #define kDRMSSERVERLOGDEF "/tmp"
00110 #define kDRMSRUNLOG "drmsrunlog"
00111 #define kSERVER "server"
00112 #define kNOTSPECIFIED "notspecified"
00113
00114 #define kDELSCRIPTFLAG "d"
00115 #define kVERBOSEFLAGA "v"
00116 #define kVERBOSEFLAGB "V"
00117 #define kVERBOSEFLAGC "verbose"
00118 #define kDOLOGFLAG "L"
00119 #define kDRMSERVERENV "/tmp/drms_server_env"
00120 #define kTIMEOUT "to"
00121 #define kTIMEOUTDEF "15"
00122 #define kRETENTION "DRMS_RETENTION"
00123 #define kRETENTIONDEF "NoTsPeCiFiED"
00124 #define kNEWSURETENTION "DRMS_NEWSURETENTION"
00125 #define kNEWSURETENTIONDEF "NoTsPeCiFiED"
00126
00127
00128 enum RUNstat_enum
00129 {
00130 kSTAT_SIGTHREAD = -7,
00131 kSTAT_SIGMASK = -6,
00132 kSTAT_MUTEX = -5,
00133 kSTAT_DRMSSERVERWONTSTART = -4,
00134 kSTAT_TERMINATE = -3,
00135 kSTAT_ARGERROR = -2,
00136 kSTAT_HELP = -1,
00137 kSTAT_COMMIT = 0,
00138 kSTAT_ABORT = 1,
00139 kSTAT_SCRIPTFAILURE = 2,
00140 kSTAT_KILLFAILED = 3,
00141 kSTAT_DRMSSERVERFAILURE = 4,
00142 kSTAT_ENVTIMEOUT = 5
00143 };
00144
00145 typedef enum RUNstat_enum RUNstat_enum_t;
00146
00147 ModuleArgs_t module_args[] =
00148 {
00149
00150
00151
00152 {ARG_STRING, kDRMSSERVERLOG, kDRMSSERVERLOGDEF, "The path to the drms_server log files."},
00153 {ARG_STRING, kDRMSRUNLOG, kNOTSPECIFIED, "The path to the drms_run log files."},
00154 {ARG_STRING, kSERVER, "drms_server", "The path to the drms_server to run."},
00155 {ARG_DOUBLE, kTIMEOUT, kTIMEOUTDEF, "Time limit, in seconds, to find drms_server's environment file."},
00156 {ARG_STRING, kRETENTION, kRETENTIONDEF, "Minimum retention, in days, for all SUs fetched during DRMS session."},
00157 {ARG_STRING, kNEWSURETENTION, kNEWSURETENTIONDEF, "Retention, in days, for all SUs created during DRMS session."},
00158 {ARG_FLAG, kDELSCRIPTFLAG, NULL, "Indicates that the script file should be deleted after use."},
00159 {ARG_FLAG, kVERBOSEFLAGA, NULL, "Print diagnostic messages."},
00160 {ARG_FLAG, kVERBOSEFLAGB, NULL, "Print diagnostic messages."},
00161 {ARG_FLAG, kVERBOSEFLAGC, NULL, "Print diagnostic messages."},
00162 {ARG_FLAG, kDOLOGFLAG, NULL, "Write drms_server output to a logfile in an SUDIR."},
00163 {ARG_END}
00164 };
00165
00166 ModuleArgs_t *gModArgs = module_args;
00167
00168
00169 CmdParams_t cmdparams;
00170
00171 static int gTerminate = 0;
00172 static pthread_mutex_t gSiglock;
00173 static pthread_t gSigthreadid;
00174
00175 static int TerminationTime()
00176 {
00177 int rv = 0;
00178
00179 pthread_mutex_lock(&gSiglock);
00180 rv = (gTerminate == 1);
00181 pthread_mutex_unlock(&gSiglock);
00182
00183 return rv;
00184 }
00185
00186 static void SetTerminate(int val)
00187 {
00188 pthread_mutex_lock(&gSiglock);
00189 gTerminate = val;
00190 pthread_mutex_unlock(&gSiglock);
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 void *sigthread(void *arg)
00204 {
00205 int status;
00206 int signo;
00207 sigset_t *sigmask = (sigset_t *)arg;
00208
00209
00210 if((status = pthread_sigmask(SIG_BLOCK, sigmask, NULL)))
00211 {
00212 fprintf(stderr, "pthread_sigmask call failed with status = %d\n", status);
00213 fprintf(stderr, "Unable to initialize signal thread.\n");
00214 return NULL;
00215 }
00216
00217 while (1)
00218 {
00219 if ((status = sigwait(sigmask, &signo)) != 0)
00220 {
00221 if (status != EINTR)
00222 {
00223 fprintf(stderr,"sigwait error, errcode=%d.\n",status);
00224 break;
00225 }
00226 }
00227
00228 if (signo == SIGUSR1)
00229 {
00230 break;
00231 }
00232 else if (signo == SIGINT)
00233 {
00234
00235 SetTerminate(1);
00236 break;
00237 }
00238 }
00239
00240
00241 return NULL;
00242 }
00243
00244 static void DRMSrunExit(int status)
00245 {
00246 pthread_kill(gSigthreadid, SIGUSR1);
00247
00248 pthread_join(gSigthreadid, NULL);
00249 pthread_mutex_destroy(&gSiglock);
00250 exit(status);
00251 }
00252
00253
00254 int main(int argc, char *argv[])
00255 {
00256 pid_t pid = 0;
00257 pid_t pidret = 0;
00258 char envfile[PATH_MAX];
00259 char cmd[PATH_MAX];
00260 const char *script = NULL;
00261 const char *serverlog = NULL;
00262 const char *server = NULL;
00263 const char *drmsrunlog = NULL;
00264 double timeout = 15;
00265 int delscr = 0;
00266 int verbose = 0;
00267 int dolog = 0;
00268 int abort = 0;
00269 float elapsed = 0;
00270 struct stat stbuf;
00271 int status = 0;
00272 RUNstat_enum_t runstat = kSTAT_COMMIT;
00273 char *passargs = NULL;
00274 size_t szpassargs = 0;
00275 const char *argcmdlinestr = NULL;
00276 int argacc = 0;
00277 int iarg = 0;
00278
00279
00280 sigset_t sigmask;
00281 sigemptyset(&sigmask);
00282 sigaddset(&sigmask, SIGINT);
00283 sigaddset(&sigmask, SIGUSR1);
00284
00285
00286 if ((status = pthread_mutex_init(&gSiglock, NULL)) != 0)
00287 {
00288 fprintf(stderr, "pthread_mutex_init call failed with status = %d\n", status);
00289 exit(kSTAT_MUTEX);
00290 }
00291
00292
00293 if ((status = pthread_sigmask(SIG_BLOCK, &sigmask, NULL)) != 0)
00294 {
00295 fprintf(stderr, "pthread_sigmask call failed with status = %d\n", status);
00296 pthread_mutex_destroy(&gSiglock);
00297 exit(kSTAT_SIGMASK);
00298 }
00299
00300
00301 if((status = pthread_create(&gSigthreadid, NULL, &sigthread, (void *)&sigmask)) != 0)
00302 {
00303 fprintf(stderr,"Signal-thread creation failed: %d\n", status);
00304 DRMSrunExit(kSTAT_SIGTHREAD);
00305 }
00306
00307 if ((status = cmdparams_parse(&cmdparams, argc, argv)) == -1)
00308 {
00309 fprintf(stderr,"Error: Command line parsing failed. Aborting.\n");
00310 DRMSrunExit(kSTAT_ARGERROR);
00311 }
00312 else if (status == CMDPARAMS_QUERYMODE)
00313 {
00314 cmdparams_usage(argv[0]);
00315 DRMSrunExit(kSTAT_HELP);
00316 }
00317 else if (status == CMDPARAMS_NODEFAULT)
00318 {
00319 fprintf(stderr, "For usage, type %s [-H|--help]\n", argv[0]);
00320 DRMSrunExit(kSTAT_ARGERROR);
00321 }
00322
00323 if (TerminationTime())
00324 {
00325 DRMSrunExit(kSTAT_TERMINATE);
00326 }
00327
00328 script = cmdparams_getarg(&cmdparams, 1);
00329 serverlog = cmdparams_get_str(&cmdparams, kDRMSSERVERLOG, NULL);
00330 drmsrunlog = cmdparams_get_str(&cmdparams, kDRMSRUNLOG, NULL);
00331 server = cmdparams_get_str(&cmdparams, kSERVER, NULL);
00332 timeout = cmdparams_get_double(&cmdparams, kTIMEOUT, NULL);
00333 delscr = cmdparams_isflagset(&cmdparams, kDELSCRIPTFLAG);
00334 verbose = (cmdparams_isflagset(&cmdparams, kVERBOSEFLAGA) ||
00335 cmdparams_isflagset(&cmdparams, kVERBOSEFLAGB) ||
00336 cmdparams_isflagset(&cmdparams, kVERBOSEFLAGC));
00337 dolog = cmdparams_isflagset(&cmdparams, kDOLOGFLAG);
00338
00339
00340 szpassargs = 32;
00341 passargs = malloc(sizeof(char) * szpassargs);
00342
00343 while (cmdparams_getargument(&cmdparams, iarg, NULL, NULL, &argcmdlinestr, &argacc))
00344 {
00345 if (!argacc && argcmdlinestr)
00346 {
00347 passargs = base_strcatalloc(passargs, argcmdlinestr, &szpassargs);
00348 passargs = base_strcatalloc(passargs, " ", &szpassargs);
00349 }
00350
00351 iarg++;
00352 }
00353
00354 if (TerminationTime())
00355 {
00356 DRMSrunExit(kSTAT_TERMINATE);
00357 }
00358
00359 if ((pid = fork()) == -1)
00360 {
00361
00362 pid = getpid();
00363 fprintf(stderr, "Failed to start drms_server.\n");
00364 runstat = kSTAT_DRMSSERVERWONTSTART;
00365 }
00366 else if (pid > 0)
00367 {
00368
00369 FILE *fptr = NULL;
00370 FILE *actstdout = stdout;
00371 FILE *actstderr = stderr;
00372 FILE *efptr = NULL;
00373 char sulogdir[PATH_MAX];
00374 char logfile[PATH_MAX];
00375 int waitforit = 0;
00376
00377 if (strcmp(drmsrunlog, kNOTSPECIFIED) != 0)
00378 {
00379 snprintf(logfile, sizeof(logfile), "%s/drmsrun_%llu.log", drmsrunlog, (unsigned long long)pid);
00380 fptr = fopen(logfile, "w");
00381 }
00382
00383 if (fptr)
00384 {
00385 actstdout = fptr;
00386 actstderr = fptr;
00387 }
00388
00389 if (verbose)
00390 {
00391 fprintf(actstdout, "Loading environment for drms_server pid %llu.\n", (unsigned long long)pid);
00392 }
00393
00394 snprintf(envfile, sizeof(envfile), "%s.%llu", kDRMSERVERENV, (unsigned long long)pid);
00395
00396 if (verbose)
00397 {
00398 time_t now;
00399 time(&now);
00400 fprintf(actstdout, "Start looking for environment file %s at %s\n", envfile, ctime(&now));
00401 }
00402
00403
00404 StartTimer(25);
00405
00406 while (1)
00407 {
00408 elapsed = StopTimer(25);
00409 if (elapsed > timeout)
00410 {
00411 runstat = kSTAT_ENVTIMEOUT;
00412 abort = 1;
00413
00414 fprintf(actstderr,
00415 "Time out - couldn't find environment file for drms_server pid %llu.\n",
00416 (unsigned long long)pid);
00417
00418 break;
00419 }
00420
00421 if (!stat(envfile, &stbuf) && S_ISREG(stbuf.st_mode))
00422 {
00423 if (verbose)
00424 {
00425 fprintf(actstdout, "Found environment file for drms_server pid %llu.\n", (unsigned long long)pid);
00426 }
00427
00428 break;
00429 }
00430
00431 sleep(1);
00432 }
00433
00434 if (TerminationTime())
00435 {
00436 runstat = kSTAT_TERMINATE;
00437 abort = 1;
00438 }
00439
00440 if (runstat == kSTAT_COMMIT)
00441 {
00442 *sulogdir = '\0';
00443
00444 if (dolog)
00445 {
00446
00447 efptr = fopen(envfile, "r");
00448
00449 if (efptr)
00450 {
00451 char *psudir = NULL;
00452 char line[LINE_MAX];
00453 char *end = NULL;
00454
00455 while (fgets(line, LINE_MAX, efptr) != NULL)
00456 {
00457 if (strstr(line, "DRMS_SUDIR="))
00458 {
00459 if ((psudir = strchr(line, '/')) != NULL)
00460 {
00461 end = strchr(line, ';');
00462 if (end)
00463 {
00464 *end = '\0';
00465 }
00466 snprintf(sulogdir, sizeof(sulogdir), "%s", psudir);
00467 }
00468
00469 break;
00470 }
00471 }
00472
00473 fclose(efptr);
00474 }
00475 }
00476
00477
00478
00479
00480 snprintf(cmd, sizeof(cmd), "source %s; %s %s", envfile, script, passargs);
00481 if (verbose)
00482 {
00483 fprintf(actstdout, "Running cmd '%s' on drms_server pid %llu.\n", cmd, (unsigned long long)pid);
00484 }
00485
00486 if (TerminationTime())
00487 {
00488 runstat = kSTAT_TERMINATE;
00489 abort = 1;
00490 }
00491 else
00492 {
00493 status = system(cmd);
00494
00495 if (status == -1)
00496 {
00497 runstat = kSTAT_SCRIPTFAILURE;
00498 abort = 1;
00499 fprintf(actstderr, "Could not execute '%s' properly; bailing.\n", script);
00500 }
00501 else if (WIFEXITED(status) && WEXITSTATUS(status))
00502 {
00503
00504
00505 if ((WEXITSTATUS(status) & 0x7F) == SIGINT)
00506 {
00507
00508
00509 SetTerminate(1);
00510 runstat = kSTAT_TERMINATE;
00511 abort = 1;
00512 }
00513 else
00514 {
00515
00516
00517
00518 runstat = kSTAT_ABORT;
00519 abort = 1;
00520 }
00521 }
00522 }
00523 }
00524
00525 if (verbose)
00526 {
00527 fprintf(actstdout, "About to kill drms_server pid %llu.\n", (unsigned long long)pid);
00528 }
00529
00530
00531
00532
00533
00534 if (runstat == kSTAT_COMMIT && dolog && *sulogdir)
00535 {
00536
00537 char sulogfile[PATH_MAX];
00538 int ioerr;
00539
00540 snprintf(logfile, sizeof(logfile), "%s/drmsserver_%llu.log", serverlog, (unsigned long long)pid);
00541 snprintf(sulogfile, sizeof(sulogfile), "%s/command.txt", sulogdir);
00542
00543 if (!stat(logfile, &stbuf))
00544 {
00545 if (CopyFile(logfile, sulogfile, &ioerr) != stbuf.st_size)
00546 {
00547 fprintf(stderr, "Failed to copy drms log file to log-file SU.\n");
00548 }
00549 }
00550 }
00551
00552 waitforit = 0;
00553 if (abort)
00554 {
00555 char proclink[PATH_MAX];
00556 char ppath[PATH_MAX];
00557
00558 snprintf(proclink, sizeof(proclink), "/proc/%i/exe", pid);
00559
00560 if (runstat == kSTAT_ABORT)
00561 {
00562
00563
00564
00565
00566 int nx;
00567
00568 nx = 0;
00569 while (nx < 5 && (readlink(proclink, ppath, sizeof(ppath)) != -1))
00570 {
00571
00572 sleep(1);
00573 nx++;
00574 }
00575 }
00576
00577 if (readlink(proclink, ppath, sizeof(ppath)) != -1)
00578 {
00579 kill(pid, SIGTERM);
00580 waitforit = 1;
00581 }
00582 }
00583 else
00584 {
00585 kill(pid, SIGUSR1);
00586 waitforit = 1;
00587 }
00588
00589 if (waitforit)
00590 {
00591 pidret = waitpid(pid, &status, 0);
00592
00593 if (pidret != pid)
00594 {
00595 fprintf(actstderr, "pid of killed drms_server does not match pid in kill syscall.\n");
00596 runstat = kSTAT_KILLFAILED;
00597 }
00598 else if (WIFEXITED(status))
00599 {
00600
00601
00602
00603 if (WEXITSTATUS(status) != 0 && WEXITSTATUS(status) != 1)
00604 {
00605
00606 fprintf(actstderr,
00607 "drms_server failed to shut down properly, returned '%d'.\n",
00608 (int)WEXITSTATUS(status));
00609 runstat = kSTAT_DRMSSERVERFAILURE;
00610 }
00611 }
00612 }
00613
00614
00615 unlink(envfile);
00616
00617 if (delscr)
00618 {
00619 unlink(script);
00620 }
00621
00622 DRMSrunExit(runstat);
00623 }
00624 else
00625 {
00626
00627 if (passargs)
00628 {
00629 free(passargs);
00630 }
00631
00632 pid = getpid();
00633 char logfile[PATH_MAX];
00634 char tmp[128] = {0};
00635 int fd;
00636 const char *retention = NULL;
00637 const char *newsuretention = NULL;
00638 char **drmsargs = NULL;
00639
00640 snprintf(logfile,
00641 sizeof(logfile),
00642 "%s/drmsserver_%llu.log",
00643 serverlog,
00644 (unsigned long long)pid);
00645
00646 drmsargs = (char **)calloc(128, sizeof(char *));
00647
00648 iarg = 0;
00649 drmsargs[iarg++] = strdup(server);
00650 drmsargs[iarg++] = strdup("-f");
00651
00652 if (verbose)
00653 {
00654 drmsargs[iarg++] = strdup("-V");
00655 }
00656
00657 if (dolog)
00658 {
00659 drmsargs[iarg++] = strdup("-L");
00660 }
00661
00662 snprintf(tmp, sizeof(tmp), "shenvfile=%s", kDRMSERVERENV);
00663 drmsargs[iarg++] = strdup(tmp);
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 retention = cmdparams_get_str(&cmdparams, kRETENTION, NULL);
00685 if (strcmp(retention, kRETENTIONDEF) != 0)
00686 {
00687 snprintf(tmp, sizeof(tmp), "DRMS_RETENTION=%s", retention);
00688 drmsargs[iarg++] = strdup(tmp);
00689 }
00690
00691 newsuretention = cmdparams_get_str(&cmdparams, kNEWSURETENTION, NULL);
00692 if (strcmp(newsuretention, kNEWSURETENTIONDEF) != 0)
00693 {
00694 snprintf(tmp, sizeof(tmp), "DRMS_NEWSURETENTION=%s", newsuretention);
00695 drmsargs[iarg++] = strdup(tmp);
00696 }
00697
00698 fd = open(logfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
00699 dup2(fd, 1);
00700 dup2(1, 2);
00701
00702
00703
00704
00705 execvp(server, drmsargs);
00706
00707
00708 }
00709
00710 if (passargs)
00711 {
00712 free(passargs);
00713 }
00714
00715 DRMSrunExit(runstat);
00716 }