lemAutoRun  1.0
lemAutoRunFE.cxx
Go to the documentation of this file.
1 /********************************************************************************************
2 
3  lemAutoRunFE.cxx
4 
5 *********************************************************************************************
6 
7  begin : Andreas Suter, 2009/01/14
8  modfied: :
9  copyright : (C) 2009 by
10  email : andreas.suter@psi.ch
11 
12 ********************************************************************************************/
13 
14 /***************************************************************************
15  * *
16  * This program is free software; you can redistribute it and/or modify *
17  * it under the terms of the GNU General Public License as published by *
18  * the Free Software Foundation; either version 2 of the License, or *
19  * (at your option) any later version. *
20  * *
21  ***************************************************************************/
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <errno.h>
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <ctype.h>
36 
37 #include "midas.h"
38 #include "msystem.h"
39 
40 #define LAR_STATE_STOPPED 0
41 #define LAR_STATE_PAUSED 1
42 #define LAR_STATE_STARTING 2
43 #define LAR_STATE_RUNNING 3
44 #define LAR_STATE_LOAD 4
45 #define LAR_STATE_LOADING 5
46 #define LAR_STATE_NEXT 6
47 
48 extern INT EXPRT ss_system(const char *command);
49 extern INT ss_daemon_init(BOOL keep_stdout);
50 
51 /***************************************************************************/
52 // global variables
53 /***************************************************************************/
54 
55 int _done = FALSE;
56 
57 /***************************************************************************/
63 {
64  printf("\nSYNTAX: lemAutoRunFE [-h host] [-e experiment] [-D] |");
65  printf("\n [--help] |");
66  printf("\n frontend autorun handler for the LEM experiment.");
67  printf("\n host: host on which the experiment is running.");
68  printf("\n experiment: name of the MIDAS experiment.");
69  printf("\n -D: becoming a daemon.");
70  printf("\n --help: prints this help.");
71  printf("\n\n");
72 }
73 
74 /***************************************************************************/
80 void lar_fe_ctrlc_handler(int sig)
81 {
82  _done = TRUE;
83 }
84 
85 /***************************************************************************/
89 int lar_strip(char *str, char *result, size_t result_size)
90 {
91  unsigned int j;
92  unsigned int ws_start, ws_end;
93 
94  // count number of initial whitespaces
95  ws_start = 0;
96  for (unsigned int i=0; i<strlen(str); i++) {
97  if (isspace(str[i])) {
98  ws_start++;
99  } else {
100  break;
101  }
102  }
103 
104  // count number of ending whitespaces
105  ws_end = strlen(str)-1;
106  for (unsigned int i=strlen(str)-1; i>=0; i--) {
107  if (isspace(str[i])) {
108  ws_end--;
109  } else {
110  break;
111  }
112  }
113 
114  // check for potential whitespaces in str
115  for (unsigned int i=ws_start; i<ws_end; i++) {
116  if (isspace(str[i]))
117  return 1;
118  }
119 
120  // check that result string length is fitting
121  if (ws_end-ws_start+1 > result_size) {
122  return 2;
123  }
124 
125  // copy relevant parts from str to result
126  j=0;
127  for (unsigned int i=ws_start; i<=ws_end; i++) {
128  result[j++] = str[i];
129  }
130  result[j] = '\0';
131 
132  return 0;
133 }
134 
135 /***************************************************************************/
139 int lar_seq_name_check(HNDLE hDB) {
140 
141  HNDLE hKey;
142  int status, size;
143  char seqName[64], seqNameStripped[64];
144 
145  status = db_find_key(hDB, 0, "/AutoRun/Auto Run Sequence", &hKey);
146  if (status != DB_SUCCESS) {
147  return -1;
148  }
149 
150  size = sizeof(seqName);
151  status = db_get_data(hDB, hKey, seqName, &size, TID_STRING);
152  if (status != DB_SUCCESS) {
153  return -1;
154  }
155 
156  status = lar_strip(seqName, seqNameStripped, sizeof(seqNameStripped));
157  if (status != 0)
158  return -1;
159 
160  if (!strcmp(seqNameStripped, "none"))
161  return 1;
162 
163  return 0;
164 }
165 
166 /***************************************************************************/
174 int lar_substr_eq(char *a, char *b)
175 {
176  int len, i, eq = 1;
177 
178  if (strlen(a) > strlen(b))
179  len = strlen(b);
180  else
181  len = strlen(a);
182 
183  for (i=0; i<len; i++) {
184  if (a[i] != b[i]) {
185  eq = 0;
186  break;
187  }
188  }
189 
190  return eq;
191 }
192 
193 /***************************************************************************/
202 int lar_client_running(HNDLE hDB)
203 {
204  int status, i, size;
205  HNDLE hKey, subKey;
206  char str[NAME_LENGTH];
207  int found_autorun = 0;
208 
209  // get the system client key
210  status = db_find_key(hDB, 0, "/System/Clients", &hKey);
211  if (status != DB_SUCCESS) {
212  return -1;
213  }
214 
215  // go through the system clients and check if lemAutoRun is present
216  for (i=0; ; i++) {
217  // check if there is a subkey
218  if (db_enum_key(hDB, hKey, i, &subKey) == DB_NO_MORE_SUBKEYS)
219  break;
220 
221  // get the content of the variable Name from the subkey
222  size = sizeof(str);
223  status = db_get_value(hDB, subKey, "Name", str, &size, TID_STRING, FALSE);
224 
225  if (status != DB_SUCCESS) {
226  return -1;
227  }
228 
229  // check if lemAutoRun is found
230  if (!strcmp(str, "lemAutoRun1")) {
231  found_autorun = 1;
232  break;
233  }
234  }
235 
236  return found_autorun;
237 }
238 
239 /***************************************************************************/
243 void lar_check_auto_run_sequence(INT hDB, INT hKey, void *autoRunSeq)
244 {
245  char str[64];
246  char cmd[256];
247  char larseq[64];
248  int status;
249 
250  if (autoRunSeq == 0)
251  return;
252 
253  // strip whitespaces and make sure that the remaining name contains NO whitespaces!
254  // Examples: 'title.lar' -> allowed
255  // ' title.lar ' -> allowed
256  // '\ttitle.lar ' -> allowed
257  // 'ti tle.lar' -> NOT allowed
258  status = lar_strip((char *)autoRunSeq, larseq, sizeof(larseq));
259  if (status != 0) {
260  snprintf(cmd, sizeof(cmd), "Sequence name: '%s' contains 'illegal' characters.", (char*)autoRunSeq);
261  al_trigger_alarm("lemAutoRunFE", cmd, "Warning", cmd, AT_INTERNAL);
262  strcpy(str, "none");
263  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
264  return;
265  }
266 
267  if (strlen(larseq) == 0) {
268  strcpy(str, "none");
269  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
270  }
271 }
272 
273 /***************************************************************************/
277 void lar_check_next_autorun(INT hDB, INT hKey, void *next)
278 {
279  char str[64];
280  char nextAutoRun[1024];
281  int status;
282  char cmd[1024];
283 
284  if (next == nullptr)
285  return;
286 
287  // strip whitespaces and make sure that the remaining name contains NO whitespaces!
288  // Examples: 'title.lar' -> allowed
289  // ' title.lar ' -> allowed
290  // '\ttitle.lar ' -> allowed
291  // 'ti tle.lar' -> NOT allowed
292  status = lar_strip((char*)next, nextAutoRun, sizeof(nextAutoRun));
293  if (status != 0) {
294  snprintf(cmd, sizeof(cmd), "Next autorun name: '%s' contains 'illegal' characters.", (char*)next);
295  al_trigger_alarm("lemAutoRunFE", cmd, "Warning", cmd, AT_INTERNAL);
296  strcpy(str, "none");
297  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
298  return;
299  }
300 
301  // if next is set to 'none' nothing has to be done
302  if (!strcmp(nextAutoRun, "none")) {
303  return;
304  }
305 
306  // prepend the autoRun directory path to the nextAutoRun
307  memset(cmd, '\0', sizeof(cmd));
308  sprintf(cmd, "/home/nemu/autoRun/%s", nextAutoRun);
309  strcpy(nextAutoRun, cmd);
310 
311  // if next is set accidentely to '', i.e. empty, set it to 'none'
312  if (strlen(nextAutoRun) == 0) {
313  strcpy(str, "none");
314  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
315  return;
316  }
317 
318  // make sure the sequence name is anything but 'none'
319  if ((status = lar_seq_name_check(hDB)) != 0) {
320  snprintf(cmd, sizeof(cmd), "Next autorun name can only by set if a Sequence is set.");
321  al_trigger_alarm("lemAutoRunFE", cmd, "Warning", cmd, AT_INTERNAL);
322  strcpy(str, "none");
323  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
324  return;
325  }
326 
327  // validate the hopefully sensible autorun script
328  memset(cmd, '\0', sizeof(cmd));
329  char *path = getenv("MIDAS_PREFIX");
330  snprintf(cmd, sizeof(cmd), "%s/bin/lemAutoRun_validate", path);
331  pid_t p;
332  p = fork();
333  if (p == 0) { // child
334  execl(cmd, cmd, nextAutoRun, NULL);
335  } else { // parent
336  wait(&status);
337  if ( WIFEXITED(status) ) {
338  int ret = WEXITSTATUS(status);
339  if (ret != 0) {
340  snprintf(cmd, sizeof(cmd), "Next autorun '%s' is invalid (status=%d)! Fix it first! Will set it to 'none' for now.", nextAutoRun, ret);
341  al_trigger_alarm("lemAutoRunFE", cmd, "Warning", cmd, AT_INTERNAL);
342  strcpy(str, "none");
343  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
344  }
345  } else {
346  snprintf(cmd, sizeof(cmd), "Couldn't get exit status of next autorun validation for '%s'! Please try again! Will set it to 'none' for now.", nextAutoRun);
347  al_trigger_alarm("lemAutoRunFE", cmd, "Warning", cmd, AT_INTERNAL);
348  strcpy(str, "none");
349  db_set_data(hDB, hKey, str, sizeof(str), 1, TID_STRING);
350  }
351  }
352 }
353 
354 /***************************************************************************/
358 int main(int argc, char *argv[])
359 {
360  int unhappy = FALSE;
361  int status, size, i;
362  int daemon = 0;
363  char host[256], exp[256];
364  char cmd[128];
365  char str[32];
366  char autoRunSeq[64];
367  char nextFln[64];
368  char nextAutoRun[64];
369  HNDLE hDB;
370  HNDLE hKey, hKey2;
371  INT run_state;
372  INT val;
373  int autorun_present = 0;
374 
375  // get host name and default experiment
376  memset(host, 0, sizeof(host));
377  memset(exp, 0, sizeof(exp));
378  cm_get_environment(host, sizeof(host), exp, sizeof(exp));
379 
380  // check syntax
381  switch (argc) {
382  case 1:
383  unhappy = TRUE;
384  break;
385  case 2:
386  if (!strcmp(argv[1], "-D"))
387  daemon = 1;
388  else
389  unhappy = TRUE;
390  break;
391  case 3:
392  if (!strcmp(argv[1], "-h"))
393  strcpy(host, argv[2]);
394  else if (!strcmp(argv[1], "-e"))
395  strcpy(exp, argv[2]);
396  else if (!strcmp(argv[1], "-D"))
397  daemon = TRUE;
398  else
399  unhappy = TRUE;
400  break;
401  case 4:
402  if ((!strcmp(argv[1], "-h") || !strcmp(argv[1], "-e")) &&
403  (!strcmp(argv[3], "-D"))) {
404  if (!strcmp(argv[3], "-D"))
405  daemon = 1;
406  if (!strcmp(argv[1], "-h"))
407  strcpy(host, argv[2]);
408  else
409  strcpy(exp, argv[2]);
410  } else {
411  unhappy = TRUE;
412  }
413  break;
414  case 5:
415  if (!strcmp(argv[1], "-h") && !strcmp(argv[3], "-e")) {
416  strcpy(host, argv[2]);
417  strcpy(exp, argv[4]);
418  } else if (!strcmp(argv[3], "-h") && !strcmp(argv[1], "-e")) {
419  strcpy(host, argv[4]);
420  strcpy(exp, argv[2]);
421  } else {
422  unhappy = TRUE;
423  }
424  break;
425  case 6:
426  if (!strcmp(argv[5], "-D")) {
427  daemon = 1;
428  if (!strcmp(argv[1], "-h") || !strcmp(argv[3], "-e")) {
429  strcpy(host, argv[2]);
430  strcpy(exp, argv[4]);
431  } else if (!strcmp(argv[3], "-h") || !strcmp(argv[1], "-e")) {
432  strcpy(host, argv[4]);
433  strcpy(exp, argv[2]);
434  } else {
435  unhappy = TRUE;
436  }
437  } else {
438  unhappy = TRUE;
439  }
440  break;
441  default:
442  unhappy = TRUE;
443  break;
444  }
445 
446  if (unhappy) {
447  lar_fe_syntax();
448  return 0;
449  }
450 
451  if (daemon) {
452  printf("Becoming a daemon...\n");
453  ss_daemon_init(FALSE);
454  } else {
455  printf("\nlemAutoRunFE running ...\n");
456  printf("\n>> terminate from web-page, ODB, or CTRL-C\n\n");
457  }
458 
459  // register with midas
460  status = cm_connect_experiment(host, exp, "lemAutoRunFE", NULL);
461  if (status != CM_SUCCESS) {
462  cm_msg(MERROR, "lemAutoRunFE", "Couldn't register with MIDAS, will quit. status = %d", status);
463  return -1;
464  }
465 
466  // establish Ctrl-C handler
467  ss_ctrlc_handler(lar_fe_ctrlc_handler);
468 
469  // get handle to the ODB
470  cm_get_experiment_database(&hDB, NULL);
471 
472  // start a watchdog thread
473  cm_start_watchdog_thread();
474 
475  /* save watchdog timeout */
476  BOOL call_watchdog;
477  cm_get_watchdog_params(&call_watchdog, NULL);
478  cm_set_watchdog_params(call_watchdog, 60000);
479  // increase RPC timeout to 2min
480  rpc_set_timeout(RPC_HNDLE_MSERVER, 120000, &val);
481 
482  // get Auto Run Sequence
483  status = db_find_key(hDB, 0, "/AutoRun/Auto Run Sequence", &hKey);
484  if (status != DB_SUCCESS) {
485  cm_msg(MERROR, "lemAutoRunFE", "Coulnd't get the ODB key for /AutoRun/Auto Run Sequence, will quit.");
486  cm_disconnect_experiment();
487  return -1;
488  }
489  // hotlink autorun sequence
490  db_open_record(hDB, hKey, (void*)&autoRunSeq, sizeof(autoRunSeq), MODE_READ, &lar_check_auto_run_sequence, (void*)&autoRunSeq);
491 
492  // make sure AutoRun Run State is present in the ODB
493  status = db_find_key(hDB, 0, "/AutoRun/Run State", &hKey);
494  if (status != DB_SUCCESS) {
495  cm_msg(MERROR, "lemAutoRunFE", "Coulnd't get the ODB key for /AutoRun/Run State, will quit.");
496  cm_disconnect_experiment();
497  return -1;
498  }
499 
500  // get AutoRun Next from ODB
501  status = db_find_key(hDB, 0, "/AutoRun/Next", &hKey);
502  if (status != DB_SUCCESS) {
503  cm_msg(MERROR, "lemAutoRunFE", "Coulnd't get the ODB key for /AutoRun/Next, will quit.");
504  cm_disconnect_experiment();
505  return -1;
506  }
507  // hotlink autorun next
508  db_open_record(hDB, hKey, (void*)&nextAutoRun, sizeof(nextAutoRun), MODE_READ, &lar_check_next_autorun, (void*)&nextAutoRun);
509 
510  do {
511  // get current LEM autorun run state
512  size = sizeof(run_state);
513  status = db_get_value(hDB, 0, "/AutoRun/Run State", (void*)&run_state, &size, TID_INT, 0);
514  if (status != DB_SUCCESS) {
515  cm_msg(MERROR, "lemAutoRunFE", "Couldn't get the LEM autorun state, will quit.");
516  cm_disconnect_experiment();
517  return -1;
518  }
519 
520  // if Run State is changing to RUNNING start lemAutoRun if not already running
521  if ((run_state == LAR_STATE_LOAD) || (run_state == LAR_STATE_STARTING)) {
522 
523  // check if an lemAutoRun is underway
524  autorun_present = lar_client_running(hDB);
525  if (autorun_present < 0) {
526  cm_msg(MERROR, "lemAutoRunFE", "Couldn't get check clients, will quit.");
527  cm_disconnect_experiment();
528  return -1;
529  }
530 
531  if (autorun_present == 0) { // no lemAutoRun present
532  if (strlen(host) == 0)
533  sprintf(cmd, "lemAutoRun -e %s -D", exp);
534  else
535  sprintf(cmd, "lemAutoRun -h %s -e %s -D", host, exp);
536  cm_msg(MINFO, "lemAutoRunFE", "lemAutoRunFE: Will start autorun via '%s'", cmd);
537  ss_system(cmd);
538 
539  // switch to autorun state running or loading, depending on the run state
540  status = db_find_key(hDB, 0, "/AutoRun/Run State", &hKey);
541  if (status != DB_SUCCESS) {
542  cm_msg(MERROR, "lemAutoRunFE", "Coulnd't get the ODB key for /AutoRun/Run State, will quit.");
543  cm_disconnect_experiment();
544  return -1;
545  }
546  if (run_state == LAR_STATE_STARTING) {
547  val = LAR_STATE_RUNNING;
548  } else {
549  val = LAR_STATE_LOADING;
550  }
551  db_set_data(hDB, hKey, &val, sizeof(val), 1, TID_INT);
552  }
553  }
554 
555  // check if autorun needs to be stopped
556  if (run_state == LAR_STATE_STOPPED) {
557  // check if lemAutoRun is still present and if yes remove it
558  status = db_find_key(hDB, 0, "System/Clients", &hKey);
559  if (status != DB_SUCCESS) {
560  cm_msg(MERROR, "lemAutoRunFE", "cannot find System/Clients entry in ODB.");
561  } else {
562  autorun_present = lar_client_running(hDB);
563  if (autorun_present) {
564  strncpy(str, "lemAutoRun", sizeof(str));
565  cm_msg(MINFO, "lemAutoRunFE", "lemAutoRunFE: will shutdown '%s'", str);
566  cm_shutdown(str, FALSE);
567  }
568  }
569  }
570 
571  // check if there is a next autorun to be executed. LAR_STATE_NEXT will be set by lemAutoRun
572  if (run_state == LAR_STATE_NEXT) {
573  status = db_find_key(hDB, 0, "/AutoRun/Next", &hKey);
574  if (status != DB_SUCCESS) {
575  cm_msg(MERROR, "lemAutoRunFE", "cannot find '/AutoRun/Next' entry in ODB.");
576  } else {
577  // check if an autorun file name is present
578  size = sizeof(nextFln);
579  status = db_get_data(hDB, hKey, nextFln, &size, TID_STRING);
580  if (status == DB_SUCCESS) {
581  if (strcmp(nextFln, "none")) { // not none, i.e. something needs to be done
582  // copy Next to "Auto Run Sequence", and set Next == "none"
583  status = db_find_key(hDB, 0, "/AutoRun/Auto Run Sequence", &hKey2);
584  if (status != DB_SUCCESS) {
585  cm_msg(MERROR, "lemAutoRunFE", "cannot find '/AutoRun/Auto Run Sequence' entry in ODB.");
586  } else {
587  cm_msg(MINFO, "lemAutoRunFE", "will start NEXT autorun %s soon.", nextFln);
588  db_set_data(hDB, hKey2, nextFln, sizeof(nextFln), 1, TID_STRING);
589  strcpy(nextFln, "none");
590  db_set_data(hDB, hKey, nextFln, sizeof(nextFln), 1, TID_STRING);
591  // change run state to running such that the next autorun will be executed
592  val = LAR_STATE_STARTING;
593  status = db_find_key(hDB, 0, "/AutoRun/Run State", &hKey);
594  if (status != DB_SUCCESS)
595  cm_msg(MERROR, "lemAutoRunFE", "cannot get '/AutoRun/Run State' entry in ODB. Unlikely that NEXT autorun will start.");
596  else
597  db_set_data(hDB, hKey, &val, sizeof(val), 1, TID_INT);
598  }
599  }
600  } else {
601  cm_msg(MERROR, "lemAutoRunFE", "couldn't read /AutoRun/Next.");
602  }
603  }
604  }
605 
606  // check for shutdown messages and feed watchdog
607  status = cm_yield(1000);
608  if ((status == RPC_SHUTDOWN) || (status == SS_ABORT)) {
609  _done = TRUE;
610  }
611 
612  } while (!_done);
613 
614  // get current LEM autorun run state
615  size = sizeof(run_state);
616  status = db_get_value(hDB, 0, "/AutoRun/Run State", (void*)&run_state, &size, TID_INT, 0);
617  if (status != DB_SUCCESS) {
618  cm_msg(MERROR, "lemAutoRunFE", "Couldn't get the LEM autorun state, will quit.");
619  cm_disconnect_experiment();
620  return -1;
621  }
622  if (run_state == LAR_STATE_RUNNING) {
623  // wait a bit to give lemAutoRun a chance to stop by itself if it can
624  for (i=0; i<5; i++) {
625  status = cm_yield(100);
626  }
627  }
628 
629  // shutdown lemAutoRun if it is still running
630  if (run_state == LAR_STATE_RUNNING) {
631  // switch to autorun state stopped
632  status = db_find_key(hDB, 0, "/AutoRun/Run State", &hKey);
633  if (status != DB_SUCCESS) {
634  cm_msg(MERROR, "lemAutoRunFE", "Couldn't get the ODB key for /AutoRun/Run State, will quit.");
635  cm_disconnect_experiment();
636  return -1;
637  }
638  val = LAR_STATE_STOPPED;
639  db_set_data(hDB, hKey, &val, sizeof(val), 1, TID_INT);
640 
641  // wait a bit to give lemAutoRun a chance to stop by itself if it can
642  for (i=0; i<5; i++) {
643  status = cm_yield(100);
644  }
645 
646  cm_msg(MINFO, "lemAutoRunFE", "lemAutoRunFE: Will stop lemAutoRun as well...");
647  cm_shutdown("lemAutoRun", TRUE);
648  }
649 
650  cm_disconnect_experiment();
651 
652  return 0;
653 }
void lar_fe_syntax()
int lar_client_running(HNDLE hDB)
#define LAR_STATE_STARTING
void lar_check_auto_run_sequence(INT hDB, INT hKey, void *autoRunSeq)
#define LAR_STATE_LOADING
int lar_strip(char *str, char *result, size_t result_size)
INT ss_daemon_init(BOOL keep_stdout)
#define LAR_STATE_RUNNING
#define LAR_STATE_STOPPED
int lar_seq_name_check(HNDLE hDB)
int _done
termination flag for the main loop
#define LAR_STATE_NEXT
int main(int argc, char *argv[])
void lar_check_next_autorun(INT hDB, INT hKey, void *next)
#define LAR_STATE_LOAD
int lar_substr_eq(char *a, char *b)
void lar_fe_ctrlc_handler(int sig)
INT EXPRT ss_system(const char *command)