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