Line data Source code
1 : /********************************************************************\
2 : Name: lazylogger.c
3 : Created by: Pierre-Andre Amaudruz
4 :
5 : Contents: Disk to Tape copier for background job.
6 :
7 : $Id$
8 :
9 : \********************************************************************/
10 :
11 : #undef NDEBUG // midas required assert() to be always enabled
12 :
13 : #include "midas.h"
14 : #include "msystem.h"
15 : #include "mstrlcpy.h"
16 :
17 : #ifdef HAVE_FTPLIB
18 :
19 : #include "ftplib.h"
20 :
21 : #endif
22 :
23 : #include <libgen.h> // basename()
24 : #include <mutex>
25 : #include <iostream>
26 :
27 : #ifdef HAVE_CURL
28 : #include <curl/curl.h>
29 : #endif
30 :
31 : #define URL_SIZE 256
32 :
33 : #include "mdsupport.h"
34 : #include <assert.h>
35 :
36 : #include <vector>
37 : #include <string>
38 : #include <algorithm>
39 :
40 : #define NOTHING_TODO 0
41 : #define FORCE_EXIT 1
42 : #define EXIT_REQUEST 2
43 : #define TRY_LATER 3
44 :
45 : #define NEW_FILE 1
46 : #define REMOVE_FILE 2
47 : #define REMOVE_ENTRY 3
48 : #define MAX_LAZY_CHANNEL 100
49 : #define TRACE
50 : #define LOG_TYPE_SCRIPT (-1)
51 : #define DONTOPENZIP 0
52 :
53 : BOOL debug = FALSE;
54 : BOOL nodelete = FALSE;
55 :
56 : typedef struct {
57 : std::string filename;
58 : INT runno;
59 : double size;
60 : } DIRLOG;
61 :
62 : typedef std::vector<DIRLOG> DIRLOGLIST;
63 :
64 0 : bool cmp_dirlog1(const DIRLOG &a, const DIRLOG &b) {
65 0 : if (a.runno < b.runno)
66 0 : return true;
67 :
68 0 : if (a.runno > b.runno)
69 0 : return false;
70 :
71 0 : const char *sa = a.filename.c_str();
72 0 : const char *sb = b.filename.c_str();
73 :
74 : while (1) {
75 0 : if (*sa == 0) // sa is shorter
76 0 : return true;
77 :
78 0 : if (*sb == 0) // sb is shorter
79 0 : return false;
80 :
81 : //printf("cmp char %c %c\n", *sa, *sb);
82 :
83 0 : if (*sa < *sb)
84 0 : return true;
85 :
86 0 : if (*sa > *sb)
87 0 : return false;
88 :
89 : // at this point, *sa == *sb
90 :
91 0 : if (isdigit(*sa)) {
92 0 : int ia = strtoul(sa, (char **) &sa, 10);
93 0 : int ib = strtoul(sb, (char **) &sb, 10);
94 :
95 : //printf("cmp int %d %d\n", ia, ib);
96 :
97 0 : if (ia < ib)
98 0 : return true;
99 :
100 0 : if (ia > ib)
101 0 : return false;
102 :
103 : // at this point, ia == ib
104 0 : continue;
105 0 : }
106 :
107 0 : sa++;
108 0 : sb++;
109 0 : }
110 : }
111 :
112 0 : bool cmp_dirlog(const DIRLOG &a, const DIRLOG &b) {
113 0 : bool r = cmp_dirlog1(a, b);
114 : //printf("compare %s %s yields %d\n", a.filename.c_str(), b.filename.c_str(), r);
115 0 : return r;
116 : }
117 :
118 : #ifndef MAX_FILE_PATH
119 : #define MAX_FILE_PATH 128 // must match value of 128 in LAZY_SETTINGS_STRING
120 : #endif
121 :
122 : #define LAZY_SETTINGS_STRING "\
123 : Period = INT : 10\n\
124 : Maintain free space (%) = INT : 0\n\
125 : Stay behind = INT : 0\n\
126 : Alarm Class = STRING : [32]\n\
127 : Running condition = STRING : [128] ALWAYS\n\
128 : Data dir = STRING : [256] \n\
129 : Data format = STRING : [8] MIDAS\n\
130 : Filename format = STRING : [128] run%05d.mid\n\
131 : Backup type = STRING : [8] Tape\n\
132 : Execute after rewind = STRING : [64]\n\
133 : Path = STRING : [128] \n\
134 : Capacity (Bytes) = FLOAT : 5e9\n\
135 : List label= STRING : [128] \n\
136 : Execute before writing file = STRING : [64]\n\
137 : Execute after writing file = STRING : [64]\n\
138 : Modulo.Position = STRING : [8]\n\
139 : Copy Delay = INT : 0\n\
140 : Tape Data Append = BOOL : y\n\
141 : "
142 : #define LAZY_STATISTICS_STRING "\
143 : Backup file = STRING : [128] none \n\
144 : File size (Bytes) = DOUBLE : 0.0\n\
145 : KBytes copied = DOUBLE : 0.0\n\
146 : Total Bytes copied = DOUBLE : 0.0\n\
147 : Copy progress (%) = DOUBLE : 0\n\
148 : Copy Rate (Bytes per s) = DOUBLE : 0\n\
149 : Backup status (%) = DOUBLE : 0\n\
150 : Number of Files = INT : 0\n\
151 : Current Lazy run = INT : 0\n\
152 : "
153 :
154 : typedef struct {
155 : INT period; /* time dela in lazy_main */
156 : INT pupercent; /* 0:100 % of disk space to keep free */
157 : INT staybehind; /* keep x run file between current Acq and backup
158 : -x same as x but starting from oldest */
159 : char alarm[32]; /* Alarm Class */
160 : char condition[128]; /* key condition */
161 : char dir[256]; /* path to the data dir */
162 : char format[8]; /* Data format (MIDAS) */
163 : char backfmt[MAX_FILE_PATH]; /* format for the run files run%05d.mid */
164 : char type[8]; /* Backup device type (Disk, Tape, Ftp, Script) */
165 : char command[64]; /* command to run after rewind */
166 : char path[MAX_FILE_PATH]; /* backup device name */
167 : float capacity; /* backup device max byte size */
168 : char backlabel[MAX_FILE_PATH]; /* label of the array in ~/list. if empty like active = 0 */
169 : char commandBefore[64]; /* command to run Before writing a file */
170 : char commandAfter[64]; /* command to run After writing a file */
171 : char modulo[8]; /* Modulo for multiple lazy client */
172 : INT copy_delay; /* Delay copy after STOP transition in seconds */
173 : BOOL tapeAppend; /* Flag for appending data to the Tape */
174 : } LAZY_SETTING;
175 : LAZY_SETTING lazy;
176 :
177 : typedef struct {
178 : char backfile[MAX_FILE_PATH]; /* current or last lazy file done (for info only) */
179 : double file_size; /* file size in bytes */
180 : double cur_size; /* current bytes copied */
181 : double cur_dev_size; /* Total bytes backup on device */
182 : double progress; /* copy % */
183 : double copy_rate; /* copy rate Kb/s */
184 : double bckfill; /* backup fill % */
185 : INT nfiles; /* # of backuped files */
186 : INT cur_run; /* current or last lazy run number done (for info only) */
187 : } LAZY_STATISTICS;
188 : LAZY_STATISTICS lazyst;
189 :
190 : typedef struct {
191 : HNDLE hKey;
192 : BOOL active;
193 : char name[32];
194 : } LAZY_INFO;
195 :
196 : LAZY_INFO lazyinfo[MAX_LAZY_CHANNEL] = {{0, FALSE, "Tape"}};
197 :
198 : INT channel = -1;
199 :
200 : /* Globals */
201 : INT lazy_semaphore;
202 : HNDLE hDB, hKey, pcurrent_hKey;
203 : double lastsz;
204 : HNDLE hKeyst;
205 : INT run_state, hDev;
206 : BOOL msg_flag;
207 : BOOL convert_flag = FALSE;
208 : BOOL copy_continue = TRUE;
209 : INT data_fmt, dev_type;
210 : char lazylog[MAX_STRING_LENGTH];
211 : BOOL full_bck_flag = FALSE, maintain_touched = FALSE;
212 : INT blockn = 0;
213 : BOOL stop_transition = FALSE;
214 : BOOL delay_start = FALSE;
215 : DWORD lazy_time = 0;
216 :
217 : #define WATCHDOG_TIMEOUT 60000 /* 60 sec for tape access */
218 :
219 : /* prototypes */
220 : INT moduloCheck(INT lModulo, INT lPosition, INT lrun);
221 :
222 : BOOL lazy_file_exists(char *dir, char *file);
223 :
224 : INT lazy_main(INT, LAZY_INFO *, int max_event_size);
225 :
226 : INT lazy_copy(char *dev, char *file, int max_event_size);
227 :
228 : INT lazy_load_params(HNDLE hDB, HNDLE hKey);
229 :
230 : INT build_log_list(const char *fmt, const char *dir, DIRLOGLIST *plog);
231 :
232 : INT build_done_list_odb(HNDLE, INT **);
233 :
234 : void lazy_settings_hotlink(HNDLE hDB, HNDLE hKey, void *info);
235 :
236 : void lazy_maintain_check(HNDLE hKey, LAZY_INFO *pLall);
237 :
238 0 : void print_dirlog(const DIRLOGLIST *dirlog) {
239 0 : for (unsigned i = 0; i < dirlog->size(); i++)
240 0 : printf("%d: %s, run %d, size %12.0f\n",
241 : i,
242 0 : (*dirlog)[i].filename.c_str(),
243 0 : (*dirlog)[i].runno,
244 0 : (*dirlog)[i].size);
245 0 : };
246 :
247 : // STOP Transition callback
248 0 : INT lazy_trstop(INT rn, char *error) {
249 0 : printf("lazy has detected a STOP transition\n");
250 0 : stop_transition = TRUE;
251 0 : return CM_SUCCESS;
252 : }
253 :
254 : /*------------------------------------------------------------------*/
255 0 : INT lazy_run_extract(const char *name)
256 : /********************************************************************\
257 : Routine: lazy_run_extract
258 : Purpose: extract the contigious digit at the right side from the
259 : string to make up a run number.
260 : Input:
261 : char * name string to search
262 : Output:
263 : Function value:
264 : INT run number
265 : 0 if no extraction
266 : \********************************************************************/
267 : {
268 : #if 0
269 : char run_str[256];
270 : int j;
271 :
272 : mstrlcpy(run_str, name, sizeof(run_str));
273 : if (strlen(run_str) < 2)
274 : return 0;
275 :
276 : for (j = strlen(run_str) - 1; j >= 0 && !isdigit(run_str[j]); j--)
277 : run_str[j] = 0;
278 :
279 : for (j = strlen(run_str) - 1; j >= 0 && isdigit(run_str[j]); j--);
280 :
281 : return atoi(run_str + j + 1);
282 : #endif
283 :
284 0 : while (*name && !isdigit(*name))
285 0 : name++;
286 :
287 0 : if (*name == 0)
288 0 : return 0;
289 :
290 0 : return atoi(name);
291 : }
292 :
293 : /*------------------------------------------------------------------*/
294 0 : INT lazy_file_remove(const char *pufile) {
295 : INT fHandle, status;
296 :
297 0 : if (nodelete) {
298 0 : printf("lazy_file_remove: running in nodelete mode (-n switch), will not remove \'%s\'\n", pufile);
299 0 : return !SS_SUCCESS;
300 : }
301 :
302 : /* open device */
303 0 : fHandle = open(pufile, O_RDONLY, 0644);
304 0 : if (fHandle == -1)
305 0 : return SS_INVALID_NAME;
306 :
307 0 : close(fHandle);
308 :
309 0 : status = ss_file_remove((char *) pufile);
310 0 : if (status != 0)
311 0 : return SS_FILE_ERROR;
312 0 : return SS_SUCCESS;
313 : }
314 :
315 : /*------------------------------------------------------------------*/
316 0 : INT lazy_log_update(INT action, INT run, const char *label, const char *file, DWORD perf_time) {
317 : char str[1024];
318 :
319 0 : strcpy(str, "no action");
320 :
321 : /* log Lazy logger to midas.log only */
322 0 : if (action == NEW_FILE) {
323 : /* keep track of number of file on that channel */
324 0 : lazyst.nfiles++;
325 :
326 0 : if (equal_ustring(lazy.type, "FTP"))
327 0 : sprintf(str, "%s[%i]: (cp:%.1fs) %s %1.3lfMB file COPIED",
328 0 : label, lazyst.nfiles, (double) perf_time / 1000., lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
329 0 : else if (equal_ustring(lazy.type, "SFTP"))
330 0 : sprintf(str, "%s[%i]: (cp:%.1fs) %s %1.3lfMB file COPIED",
331 0 : label, lazyst.nfiles, (double) perf_time / 1000., lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
332 0 : else if (equal_ustring(lazy.type, "Script")) {
333 0 : sprintf(str, "%s[%i]: (cp:%.1fs) %s %1.3lfMB file NEW",
334 0 : label, lazyst.nfiles, (double) perf_time / 1000., lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
335 0 : } else if (equal_ustring(lazy.type, "Disk")) {
336 0 : if (lazy.path[0] != 0)
337 0 : if (lazy.path[strlen(lazy.path) - 1] != DIR_SEPARATOR)
338 0 : strcat(lazy.path, DIR_SEPARATOR_STR);
339 0 : sprintf(str, "%s[%i]: (cp:%.1fs) %s%s %1.3lfMB file NEW",
340 0 : label, lazyst.nfiles, (double) perf_time / 1000.,
341 0 : lazy.path, lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
342 0 : } else if (equal_ustring(lazy.type, "Tape")) {
343 : /* June 2002, use variable blockn from the real tape position */
344 0 : sprintf(str, "%s[%i]: (cp:%.1fs) %s/%s %1.3lfMB file NEW (position at block %d)",
345 0 : label, lazyst.nfiles, (double) perf_time / 1000.,
346 0 : lazy.path, lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0, blockn);
347 0 : if (lazy.commandAfter[0]) {
348 : char cmd[1024];
349 0 : sprintf(cmd, "%s %s %i %s/%s %1.3lf %d", lazy.commandAfter,
350 : lazy.backlabel, lazyst.nfiles, lazy.path, lazyst.backfile,
351 0 : lazyst.file_size / 1024.0 / 1024.0, blockn);
352 0 : cm_msg(MINFO, "Lazy", "Exec post file write script:%s", cmd);
353 0 : ss_system(cmd);
354 : }
355 : }
356 0 : } else if (action == REMOVE_FILE)
357 0 : sprintf(str, "%i (rm:%dms) %s file REMOVED", run, perf_time, file);
358 :
359 0 : else if (action == REMOVE_ENTRY)
360 0 : sprintf(str, "%s run#%i entry REMOVED", label, run);
361 :
362 : /* Now add this info to a special log file */
363 0 : cm_msg1(MINFO, "lazy", "lazy_log_update", "%s", str);
364 :
365 0 : return 0;
366 : }
367 :
368 : /*------------------------------------------------------------------*/
369 0 : INT moduloCheck(INT lModulo, INT lPosition, INT lrun)
370 : /********************************************************************\
371 : Routine: moduleCheck
372 : Purpose: return valid run number in case of Modulo function enabled
373 : or zero if not.
374 : Input:
375 : lModulo : number of lazy channel
376 : lPosition : Position of the current channel
377 : lrun : current run to test
378 : Function value:
379 : valid run number (0=skip run)
380 : \********************************************************************/
381 : {
382 0 : if (lModulo) {
383 0 : if ((lrun % lModulo) == lPosition)
384 0 : return lrun;
385 : else
386 0 : return 0;
387 : } else
388 0 : return lrun;
389 : }
390 :
391 : /*------------------------------------------------------------------*/
392 0 : INT build_log_list(const char *fmt, const char *xdir, DIRLOGLIST *dlist)
393 : /********************************************************************\
394 : Routine: build_log_list
395 : Purpose: build an internal directory file list from the disk directory
396 : Input:
397 : * fmt format of the file to search for (ie:run%05d.ybs)
398 : * dir path to the directory for the search
399 : Output:
400 : **plog internal file list struct
401 : Function value:
402 : number of elements
403 : \********************************************************************/
404 : {
405 : char str[MAX_FILE_PATH];
406 : char dir[MAX_FILE_PATH];
407 : char *dot;
408 0 : int lModulo = 0, lPosition = 0;
409 :
410 0 : mstrlcpy(dir, xdir, sizeof(dir));
411 :
412 0 : while (fmt) {
413 : /* substitue %xx by * */
414 0 : mstrlcpy(str, fmt, sizeof(str));
415 :
416 0 : fmt = strchr(fmt, ',');
417 0 : if (fmt)
418 0 : fmt++;
419 :
420 0 : char *s = strchr(str, ',');
421 0 : if (s)
422 0 : *s = 0;
423 :
424 0 : if (strchr(str, '%')) {
425 0 : *strchr(str, '%') = '*';
426 0 : if (strchr(str, '.'))
427 0 : strcpy((strchr(str, '*') + 1), strchr(str, '.'));
428 : }
429 :
430 0 : char *list = NULL;
431 :
432 : /* create dir listing with given criteria */
433 0 : int nfile = ss_file_find(dir, str, &list);
434 :
435 : /* check */
436 : /*
437 : for (j=0;j<nfile;j++)
438 : printf ("list[%i]:%s\n",j, list+j*MAX_STRING_LENGTH);
439 : */
440 :
441 0 : std::vector<std::string> flist;
442 0 : for (int j = 0; j < nfile; j++)
443 0 : flist.push_back(list + j * MAX_STRING_LENGTH);
444 :
445 0 : free(list);
446 :
447 : /* Check Modulo option */
448 0 : if (lazy.modulo[0]) {
449 : /* Modulo enabled, extract modulo and position */
450 0 : dot = strchr(lazy.modulo, '.');
451 0 : if (dot) {
452 0 : *dot = '\0';
453 0 : lModulo = atoi(lazy.modulo);
454 0 : lPosition = atoi(dot + 1);
455 0 : *dot = '.';
456 : }
457 : }
458 :
459 : /* fill structure */
460 0 : for (unsigned j = 0 ; j < flist.size(); j++) {
461 : INT lrun;
462 : /* extract run number */
463 0 : lrun = lazy_run_extract((char *) flist[j].c_str());
464 : /* apply the modulo if enabled */
465 0 : lrun = moduloCheck(lModulo, lPosition, lrun);
466 : /* if modulo enable skip */
467 0 : if (lrun == 0)
468 0 : continue;
469 :
470 0 : std::string s = dir;
471 0 : s += flist[j];
472 :
473 0 : DIRLOG d;
474 0 : d.filename = flist[j];
475 0 : d.runno = lrun;
476 0 : d.size = ss_file_size((char *) s.c_str());
477 :
478 0 : dlist->push_back(d);
479 0 : }
480 0 : }
481 :
482 0 : sort(dlist->begin(), dlist->end(), cmp_dirlog);
483 :
484 0 : return dlist->size();
485 : }
486 :
487 : /*------------------------------------------------------------------*/
488 0 : INT build_done_list_odb(HNDLE hLch, INT **pdo)
489 : /********************************************************************\
490 : Routine: build_done_list
491 : Purpose: build a sorted internal /lazy/list list (pdo) tree.
492 : Input:
493 : HNDLE Key of the Lazy channel
494 : **pdo /lazy_xxx/list run listing
495 : Output:
496 : **pdo /lazy_xxx/list run listing
497 : Function value: number of elements
498 : \********************************************************************/
499 : {
500 : HNDLE hKey, hSubkey;
501 : KEY key;
502 : INT i, j, size, tot_nelement, nelement, temp;
503 :
504 0 : if (db_find_key(hDB, hLch, "List", &hKey) != DB_SUCCESS) {
505 0 : return 0;
506 : }
507 :
508 0 : tot_nelement = 0;
509 0 : for (i = 0;; i++) {
510 0 : db_enum_key(hDB, hKey, i, &hSubkey);
511 0 : if (!hSubkey)
512 0 : break;
513 0 : db_get_key(hDB, hSubkey, &key);
514 0 : nelement = key.num_values;
515 0 : *pdo = (INT *) realloc(*pdo, sizeof(INT) * (tot_nelement + nelement));
516 0 : size = nelement * sizeof(INT);
517 0 : db_get_data(hDB, hSubkey, (char *) (*pdo + tot_nelement), &size, TID_INT);
518 0 : tot_nelement += nelement;
519 : }
520 :
521 : if (0) {
522 : printf("read pdo: %d\n", tot_nelement);
523 : for (i = 0; i < tot_nelement; i++)
524 : printf("%d: %d\n", i, (*pdo)[i]);
525 : }
526 :
527 : /* expand compressed run numbers */
528 0 : for (i = 0; i < tot_nelement; i++)
529 0 : if ((*pdo)[i] < 0) {
530 0 : int first = (*pdo)[i - 1];
531 0 : int last = -(*pdo)[i];
532 0 : int nruns = last - first + 1;
533 0 : assert(nruns > 1);
534 :
535 0 : *pdo = (INT *) realloc(*pdo, sizeof(INT) * (tot_nelement + nruns - 2));
536 0 : assert(*pdo != NULL);
537 :
538 0 : memmove((*pdo) + i + nruns - 1, (*pdo) + i + 1, sizeof(INT) * (tot_nelement - i - 1));
539 :
540 0 : for (j = 1; j < nruns; j++)
541 0 : (*pdo)[i + j - 1] = first + j;
542 :
543 0 : tot_nelement += nruns - 2;
544 : }
545 :
546 : if (0) {
547 : printf("uncompressed pdo: %d\n", tot_nelement);
548 : for (i = 0; i < tot_nelement; i++)
549 : printf("%d: %d\n", i, (*pdo)[i]);
550 : }
551 :
552 : /* sort array of integers */
553 0 : for (j = 0; j < tot_nelement - 1; j++) {
554 0 : for (i = j + 1; i < tot_nelement; i++) {
555 0 : if (*(*pdo + j) > *(*pdo + i)) {
556 0 : memcpy(&temp, (*pdo + i), sizeof(INT));
557 0 : memcpy((*pdo + i), (*pdo + j), sizeof(INT));
558 0 : memcpy((*pdo + j), &temp, sizeof(INT));
559 : }
560 : }
561 : }
562 :
563 : if (0) {
564 : printf("sorted pdo: %d\n", tot_nelement);
565 : for (i = 0; i < tot_nelement; i++)
566 : printf(" %d\n", (*pdo)[i]);
567 : }
568 :
569 0 : return tot_nelement;
570 : }
571 :
572 0 : std::string list_filename(const char *lazyname, const char *listname) {
573 0 : std::string s(cm_get_path());
574 0 : s += ".Lazy_";
575 0 : s += lazyname;
576 0 : s += ".";
577 0 : s += listname;
578 0 : return s;
579 0 : }
580 :
581 0 : void load_done_list(const char *lazyname, const DIRLOGLIST *dirlist, DIRLOGLIST *dlist) {
582 0 : FILE *fp = fopen(list_filename(lazyname, "donelist").c_str(), "r");
583 0 : if (!fp)
584 0 : return;
585 :
586 : while (1) {
587 : char str[256];
588 0 : char *s = fgets(str, sizeof(str), fp);
589 0 : if (!s)
590 0 : break;
591 :
592 0 : DIRLOG d;
593 :
594 0 : char *p = strchr(s, ' ');
595 :
596 0 : if (p) {
597 0 : *p = 0;
598 0 : p++;
599 : }
600 :
601 0 : d.filename = s;
602 0 : d.runno = strtoul(p, &p, 0);
603 0 : d.size = strtod(p, &p);
604 :
605 0 : bool found = false;
606 0 : if (dirlist) {
607 0 : for (unsigned i = 0; i < dirlist->size(); i++)
608 0 : if ((*dirlist)[i].filename == d.filename) {
609 0 : found = true;
610 0 : break;
611 : }
612 : } else
613 0 : found = true;
614 :
615 0 : if (found)
616 0 : dlist->push_back(d);
617 0 : }
618 :
619 0 : fclose(fp);
620 :
621 0 : sort(dlist->begin(), dlist->end(), cmp_dirlog);
622 : }
623 :
624 0 : int save_list(const char *lazyname, const char *listname, const DIRLOGLIST *dlist) {
625 0 : std::string fname = list_filename(lazyname, listname);
626 0 : std::string tmpname = fname + ".tmp";
627 :
628 0 : FILE *fp = fopen(tmpname.c_str(), "w");
629 0 : if (!fp) {
630 0 : cm_msg(MERROR, "save_list", "Cannot write to \'%s\', errno %d (%s)",
631 : tmpname.c_str(),
632 0 : errno,
633 0 : strerror(errno));
634 0 : return !SUCCESS;
635 : }
636 :
637 0 : for (unsigned i = 0; i < dlist->size(); i++) {
638 0 : const char *s = (*dlist)[i].filename.c_str();
639 : const char *p;
640 0 : while ((p = strchr(s, DIR_SEPARATOR)))
641 0 : s = p + 1;
642 0 : fprintf(fp, "%s %d %12.0f\n",
643 : s,
644 0 : (*dlist)[i].runno,
645 0 : (*dlist)[i].size);
646 : }
647 :
648 0 : fclose(fp);
649 :
650 0 : int status = rename(tmpname.c_str(), fname.c_str());
651 0 : if (status) {
652 0 : cm_msg(MERROR, "save_list", "Cannot rename \'%s\' to \'%s\', errno %d (%s)",
653 : tmpname.c_str(),
654 : fname.c_str(),
655 0 : errno,
656 0 : strerror(errno));
657 0 : return !SUCCESS;
658 : }
659 :
660 0 : return SUCCESS;
661 0 : }
662 :
663 : /*------------------------------------------------------------------*/
664 0 : void convert_done_list(HNDLE hLch)
665 : /********************************************************************\
666 : Routine: convert_done_list
667 : Purpose: build a sorted internal /lazy/list list (pdo) tree.
668 : Input:
669 : HNDLE Key of the Lazy channel
670 : **pdo /lazy_xxx/list run listing
671 : Output:
672 : **pdo /lazy_xxx/list run listing
673 : Function value: number of elements
674 : \********************************************************************/
675 : {
676 0 : DIRLOGLIST dlist;
677 :
678 0 : build_log_list(lazy.backfmt, lazy.dir, &dlist);
679 :
680 : KEY key;
681 0 : int status = db_get_key(hDB, hLch, &key);
682 0 : assert(status == DB_SUCCESS);
683 :
684 : HNDLE hKey;
685 0 : status = db_find_key(hDB, hLch, "List", &hKey);
686 :
687 0 : if (status != DB_SUCCESS) {
688 0 : cm_msg(MERROR, "convert_done_list", "Cannot find \'/Lazy/%s/List\' db_find_key() status %d", key.name, status);
689 0 : cm_disconnect_experiment();
690 0 : exit(1);
691 : }
692 :
693 0 : INT *pdo = NULL;
694 0 : int n = build_done_list_odb(hLch, &pdo);
695 :
696 0 : DIRLOGLIST done;
697 :
698 0 : for (int i = 0; i < n; i++)
699 0 : for (unsigned j = 0; j < dlist.size(); j++)
700 0 : if (dlist[j].runno == pdo[i])
701 0 : done.push_back(dlist[j]);
702 :
703 0 : free(pdo);
704 :
705 0 : save_list(key.name, "donelist", &done);
706 :
707 0 : status = db_rename_key(hDB, hKey, "List.converted");
708 0 : assert(status == DB_SUCCESS);
709 :
710 0 : cm_msg(MINFO, "convert_done_list",
711 : "Done list converted from old ODB \'/Lazy/%s/List\' format to new file-based format. ODB \'List\' renamed to \'List.converted\'",
712 : key.name);
713 :
714 0 : cm_disconnect_experiment();
715 0 : exit(1);
716 0 : }
717 :
718 : /*------------------------------------------------------------------*/
719 0 : INT build_done_list(HNDLE hLch, const DIRLOGLIST *pdirlist, DIRLOGLIST *pdone)
720 : /********************************************************************\
721 : Routine: build_done_list
722 : Purpose: build a sorted internal /lazy/list list (pdo) tree.
723 : Input:
724 : HNDLE Key of the Lazy channel
725 : **pdo /lazy_xxx/list run listing
726 : Output:
727 : **pdo /lazy_xxx/list run listing
728 : Function value: number of elements
729 : \********************************************************************/
730 : {
731 : HNDLE hKey;
732 : KEY key;
733 0 : int status = db_get_key(hDB, hLch, &key);
734 0 : assert(status == DB_SUCCESS);
735 :
736 0 : if (db_find_key(hDB, hLch, "List", &hKey) == DB_SUCCESS) {
737 0 : cm_msg(MERROR, "build_done_list",
738 : "lazylogger cannot continue: found old-style done list in ODB \'/Lazy/%s/List\'. Please convert to new done list format using \'lazylogger -C\'",
739 : key.name);
740 0 : cm_disconnect_experiment();
741 0 : exit(1);
742 : }
743 :
744 0 : load_done_list(key.name, pdirlist, pdone);
745 :
746 0 : return pdone->size();
747 : }
748 :
749 : /*------------------------------------------------------------------*/
750 0 : INT save_done_list(HNDLE hLch, DIRLOGLIST *pdone)
751 : /********************************************************************\
752 : Routine: save_done_list
753 : Purpose: save a sorted internal /lazy/list list (pdo) tree.
754 : Input:
755 : HNDLE Key of the Lazy channel
756 : **pdo /lazy_xxx/list run listing
757 : Output:
758 : **pdo /lazy_xxx/list run listing
759 : Function value: number of elements
760 : \********************************************************************/
761 : {
762 : KEY key;
763 0 : int status = db_get_key(hDB, hLch, &key);
764 0 : assert(status == DB_SUCCESS);
765 0 : sort(pdone->begin(), pdone->end(), cmp_dirlog);
766 0 : save_list(key.name, "donelist", pdone);
767 0 : return SUCCESS;
768 : }
769 :
770 : /*------------------------------------------------------------------*/
771 0 : int find_next_file(const DIRLOGLIST *plog, const DIRLOGLIST *pdone)
772 : /********************************************************************\
773 : Routine: find_next_file
774 : Purpose: find next file to be backed up and return it's index in plog
775 : Input:
776 : *plog : disk file listing
777 : *pdone : list of files already backed up
778 : Output:
779 : Function value:
780 : index into plog
781 : -1 : no files
782 :
783 : \********************************************************************/
784 : {
785 0 : for (unsigned j = 0; j < plog->size(); j++) {
786 0 : bool found = false;
787 0 : for (unsigned i = 0; i < pdone->size(); i++) {
788 0 : if ((*plog)[j].filename == (*pdone)[i].filename)
789 0 : found = true;
790 : }
791 :
792 0 : if (!found)
793 0 : if ((*plog)[j].size > 0)
794 0 : return j;
795 : }
796 :
797 0 : return -1;
798 : }
799 :
800 : /*------------------------------------------------------------------*/
801 0 : INT lazy_select_purge(HNDLE hKey, INT channel, LAZY_INFO *pLall, const char *fmt, const char *dir, DIRLOG *f)
802 : /********************************************************************\
803 : Routine: lazy_select_purge
804 : Purpose: Search oldest run number which can be purged
805 : condition : oldest run# in (pdo AND present in plog)
806 : AND scan all the other channels based on the following
807 : conditions:
808 : "data dir" && "filename format" are the same &&
809 : the /list/run_number exists in all the above condition.
810 : Input:
811 : hKey : Current channel key
812 : channel : Current channel number
813 : *pLall : Pointer to all channels
814 : fmt : Format string
815 : dir : Directory string
816 : Output:
817 : fpufile : file to purge
818 : run : corresponding run# to be purged
819 : Function value:
820 : 0 success
821 : -1 run not found
822 : \********************************************************************/
823 : {
824 : int size;
825 : char ddir[256], ff[128], strmodulo[8];
826 :
827 : /* Scan donelist from first element (oldest)
828 : check if run exists in dirlog
829 : if yes return file and run number */
830 :
831 : while (1) {
832 : /* try to find the oldest matching run present in the list AND on disk */
833 : /* build current done list */
834 :
835 0 : DIRLOGLIST dirlists[MAX_LAZY_CHANNEL];
836 0 : DIRLOGLIST donelists[MAX_LAZY_CHANNEL];
837 :
838 : /* build matching dir and file format (ff) */
839 0 : for (int i = 0; i < MAX_LAZY_CHANNEL; i++) {
840 : /* Check if key present && key different than currrent
841 : and if modulo is off */
842 0 : if (((pLall + i)->hKey)) {
843 : /* extract dir and ff */
844 0 : size = sizeof(strmodulo);
845 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/Modulo.Position", strmodulo, &size, TID_STRING, TRUE);
846 0 : if (strmodulo[0]) {
847 : /* Modulo enabled, skip this channel */
848 0 : if (debug)
849 0 : printf("purge: skipping channel \'%s\' which uses modulo \'%s\'\n", lazyinfo[i].name, strmodulo);
850 0 : continue;
851 : }
852 :
853 0 : size = sizeof(ddir);
854 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/Data dir", ddir, &size, TID_STRING, TRUE);
855 0 : size = sizeof(ff);
856 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/filename format", ff, &size, TID_STRING, TRUE);
857 :
858 : // monkey about with trailing '/' characters
859 :
860 0 : int len = strlen(ddir);
861 0 : if (ddir[len - 1] != '/') {
862 0 : ddir[len] = '/';
863 0 : ddir[len + 1] = 0;
864 : }
865 :
866 : /* if same dir && same ff => mark lazy channel */
867 0 : if (strcmp(ddir, dir) != 0) {
868 0 : if (debug)
869 0 : printf("purge: skipping channel \'%s\' which uses different data dir \'%s\', we use \'%s\'\n",
870 0 : lazyinfo[i].name, ddir, dir);
871 0 : continue;
872 : }
873 :
874 0 : if (debug)
875 0 : printf("Loading file lists for channel \'%s\', data dir \'%s\', format \'%s\'\n", lazyinfo[i].name, ddir,
876 : ff);
877 :
878 : /* load file list and done list for matching channels */
879 0 : build_log_list(ff, ddir, &dirlists[i]);
880 0 : build_done_list(pLall[i].hKey, &dirlists[i], &donelists[i]);
881 : }
882 : } /* end of loop over channels */
883 :
884 : /* search for files to delete */
885 0 : for (unsigned k = 0; k < dirlists[channel].size(); k++) {
886 0 : bool can_delete = true;
887 :
888 0 : if (debug)
889 0 : printf("purge: consider file \'%s\'\n", dirlists[channel][k].filename.c_str());
890 :
891 0 : for (int i = 0; i < MAX_LAZY_CHANNEL; i++)
892 0 : if (((pLall + i)->hKey)) {
893 0 : bool in_dir_list = false;
894 0 : bool in_done_list = false;
895 :
896 0 : for (unsigned j = 0; j < dirlists[i].size(); j++)
897 0 : if (dirlists[i][j].filename == dirlists[channel][k].filename) {
898 0 : in_dir_list = true;
899 0 : break;
900 : }
901 :
902 0 : if (!in_dir_list) {
903 0 : if (debug)
904 0 : printf("channel \'%s\': file is not in dir list, ok to delete\n", lazyinfo[i].name);
905 0 : continue;
906 : }
907 :
908 0 : for (unsigned j = 0; j < donelists[i].size(); j++)
909 0 : if (donelists[i][j].filename == dirlists[channel][k].filename) {
910 0 : in_done_list = true;
911 0 : break;
912 : }
913 :
914 0 : if (!in_done_list) {
915 0 : if (debug)
916 0 : printf("channel \'%s\': file is in dirlist but not in done list, cannot delete\n",
917 0 : lazyinfo[i].name);
918 0 : can_delete = false;
919 0 : break;
920 : }
921 :
922 0 : if (debug)
923 0 : printf("channel \'%s\': file is in dirlist and in done list, ok to delete\n", lazyinfo[i].name);
924 : }
925 :
926 0 : if (can_delete) {
927 0 : if (debug)
928 0 : printf("purge: file \'%s\' is done by all channels\n", dirlists[channel][k].filename.c_str());
929 0 : *f = dirlists[channel][k];
930 0 : return SUCCESS;
931 : }
932 : }
933 :
934 : /* nothing to remove */
935 0 : return !SUCCESS;
936 0 : }
937 : }
938 :
939 : /*------------------------------------------------------------------*/
940 0 : void lazy_maintain_check(HNDLE hKey, LAZY_INFO *pLall)
941 : /********************************************************************\
942 : Routine: lazy_maintain_check
943 : Purpose: Check if the "maintain free space" of any of the other matching
944 : channels is != 0. matching correspond to the condition:
945 : "data dir" && "filename format"
946 : if found != 0 then set to 0 and inform
947 : Input:
948 : hKey : Current lazy channel key
949 : *pLall : Pointer to all channels
950 : \********************************************************************/
951 : {
952 : INT size;
953 : INT i, maintain;
954 : char dir[256], ff[128];
955 : char cdir[256], cff[128];
956 : char cmodulostr[8], modulostr[8];
957 :
958 : /* do test only if maintain has been touched */
959 0 : if (!maintain_touched)
960 0 : return;
961 0 : maintain_touched = FALSE;
962 :
963 : /* check is Maintain free is enabled */
964 0 : size = sizeof(maintain);
965 0 : db_get_value(hDB, hKey, "Settings/Maintain free space (%)", &maintain, &size, TID_INT, TRUE);
966 0 : if (maintain != 0) {
967 : /* scan other channels */
968 :
969 : /* get current specification */
970 0 : size = sizeof(cdir);
971 0 : db_get_value(hDB, hKey, "Settings/Data dir", cdir, &size, TID_STRING, TRUE);
972 0 : size = sizeof(cff);
973 0 : db_get_value(hDB, hKey, "Settings/filename format", cff, &size, TID_STRING, TRUE);
974 0 : size = sizeof(modulostr);
975 0 : db_get_value(hDB, hKey, "Settings/Modulo.Position", cmodulostr, &size, TID_STRING, TRUE);
976 :
977 : /* build matching dir and ff */
978 0 : for (i = 0; i < MAX_LAZY_CHANNEL; i++) {
979 0 : if (((pLall + i)->hKey) && (hKey != (pLall + i)->hKey)) { /* valid channel */
980 0 : size = sizeof(dir);
981 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/Data dir", dir, &size, TID_STRING, TRUE);
982 0 : size = sizeof(ff);
983 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/filename format", ff, &size, TID_STRING, TRUE);
984 0 : size = sizeof(modulostr);
985 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/Modulo.Position", modulostr, &size, TID_STRING, TRUE);
986 :
987 0 : if ((strcmp(dir, cdir) == 0) && (strcmp(ff, cff) == 0) && !cmodulostr[0] && !modulostr[0]) {
988 : /* check "maintain free space" */
989 0 : size = sizeof(maintain);
990 0 : db_get_value(hDB, (pLall + i)->hKey, "Settings/Maintain free space (%)",
991 : &maintain, &size, TID_INT, TRUE);
992 0 : if (maintain) {
993 : /* disable and inform */
994 0 : size = sizeof(maintain);
995 0 : maintain = 0;
996 0 : db_set_value(hDB, (pLall + i)->hKey, "Settings/Maintain free space (%)", &maintain, size, 1, TID_INT);
997 0 : cm_msg(MINFO, "lazy_maintain_check",
998 0 : "Maintain free space on channel %s has been disable", (pLall + i)->name);
999 : }
1000 : }
1001 : }
1002 : }
1003 : }
1004 : }
1005 :
1006 : /*------------------------------------------------------------------*/
1007 0 : void lazy_statistics_update(INT cploop_time)
1008 : /********************************************************************\
1009 : Routine: lazy_statistics_update
1010 : Purpose: update the /lazy/statistics
1011 : Input:
1012 : INT cploop_time : time of the last call
1013 : Output:
1014 : Function value:
1015 : 0 success
1016 : \********************************************************************/
1017 : {
1018 :
1019 0 : if (debug) {
1020 0 : printf("file.size:%f - ", lazyst.file_size);
1021 0 : printf("file.curr:%f - ", lazyst.cur_size);
1022 0 : printf("lastsz:%f - ", lastsz);
1023 0 : printf("nfiles:%i\n", lazyst.nfiles);
1024 : }
1025 : /* update rate [kb/s] statistics */
1026 0 : if (cploop_time == 0) // special function: set copy_rate to zero at end of copy
1027 0 : lazyst.copy_rate = 0.0;
1028 0 : if ((ss_millitime() - cploop_time) > 100)
1029 0 : lazyst.copy_rate = 1000.f * (lazyst.cur_size - lastsz) / (ss_millitime() - cploop_time);
1030 0 : if (lazyst.copy_rate < 0.0)
1031 0 : lazyst.copy_rate = 0.0;
1032 :
1033 : /* update % statistics */
1034 0 : if (lazyst.file_size != 0.0f)
1035 0 : lazyst.progress = (100.0f * (lazyst.cur_size / lazyst.file_size));
1036 : else
1037 0 : lazyst.progress = 0.0f;
1038 :
1039 : /* update backup % statistics */
1040 0 : if (lazy.capacity > 0.0f)
1041 0 : lazyst.bckfill = 100.0f * (lazyst.cur_dev_size / lazy.capacity);
1042 : else
1043 0 : lazyst.bckfill = 0.0f;
1044 :
1045 0 : lastsz = lazyst.cur_size;
1046 : /* udate ODB statistics */
1047 0 : db_send_changed_records();
1048 0 : }
1049 :
1050 : /*------------------------------------------------------------------*/
1051 0 : BOOL condition_test(char *string)
1052 : /********************************************************************\
1053 : Routine: condition_check
1054 : Purpose: return TRUE or FALSE depending if condition is satisfied
1055 : I expect a statement of the following form:
1056 : <key> <operator> <value>
1057 : with <key> : either link or key[index] or key(index)
1058 : <operator> : either: = < >
1059 : <value> : [+/-][digits]
1060 : Input: char * string to decode and test
1061 : Output:
1062 : Function value:
1063 : TRUE condition TRUE (carry on the copy)
1064 : FALSE condition FALSE (hold the copy)
1065 : \********************************************************************/
1066 : {
1067 : KEY key;
1068 : double value;
1069 : double lcond_value;
1070 : INT size, index, status;
1071 : char left[64], right[64];
1072 0 : char *p = NULL, *pp, *ppl, *pc, *lp;
1073 :
1074 0 : index = 0;
1075 0 : p = string;
1076 0 : if (p) {
1077 0 : while (isspace(*p))
1078 0 : p++;
1079 :
1080 0 : pc = strpbrk(p, "<=>");
1081 0 : if (pc) {
1082 0 : strncpy(left, p, pc - p);
1083 0 : lp = left + (pc - p - 1);
1084 0 : while (isspace(*lp))
1085 0 : lp--;
1086 0 : *(lp + 1) = '\0';
1087 0 : strncpy(right, pc + 1, (strlen(p) - strlen(left)));
1088 0 : right[strlen(p) - strlen(left) - 1] = '\0';
1089 : }
1090 :
1091 0 : if ((pp = strpbrk(left, "[(")) != NULL) {
1092 0 : if ((ppl = strpbrk(left, "])")) != NULL) {
1093 0 : *pp = '\0';
1094 0 : *ppl = '\0';
1095 0 : index = atoi(pp + 1);
1096 : }
1097 0 : *pp = '\0';
1098 : }
1099 :
1100 : /* convert value */
1101 0 : value = (double) (atoi(right));
1102 :
1103 0 : status = db_find_key(hDB, 0, left, &hKey);
1104 0 : if (status != DB_SUCCESS) {
1105 0 : cm_msg(MINFO, "condition_check", "Key %s not found", left);
1106 0 : return FALSE;
1107 : }
1108 0 : status = db_get_key(hDB, hKey, &key);
1109 0 : if ((status == DB_SUCCESS) && (key.type <= TID_DOUBLE)) {
1110 : /* get value of the condition */
1111 0 : size = sizeof(lcond_value);
1112 0 : db_get_data_index(hDB, hKey, &lcond_value, &size, index, key.type);
1113 0 : std::string s = db_sprintf(&lcond_value, key.item_size, 0, key.type);
1114 0 : lcond_value = std::stof(s);
1115 0 : }
1116 :
1117 : /* printf("string:%s\n condition: %s %f %c %f \n"
1118 : , string, left, lcond_value, *pc, value);
1119 : */
1120 : /*
1121 : if (pv == NULL)
1122 : return TRUE;
1123 : */
1124 : /* perform condition check */
1125 0 : if (((*pc == '>') && ((double) lcond_value > value)) || ((*pc == '=') && ((double) lcond_value == value)) ||
1126 0 : ((*pc == '<') && ((double) lcond_value < value)))
1127 0 : return TRUE;
1128 : else
1129 0 : return FALSE;
1130 : }
1131 : /* catch wrong argument in the condition as TRUE */
1132 0 : return TRUE;
1133 : }
1134 :
1135 : /*------------------------------------------------------------------*/
1136 0 : BOOL lazy_condition_check(void)
1137 : /********************************************************************\
1138 : Routine: lazy_condition_check
1139 : Purpose: Check if the copy should continue.
1140 : The condition can have the following setting:
1141 : ALWAYS, NEVER, WHILE_NO_ACQ_RUNNING, key<=>value
1142 : Input:
1143 : Output:
1144 : Function value:
1145 : BOOL : new copy condition
1146 : \********************************************************************/
1147 : {
1148 : /* Get condition */
1149 0 : if (equal_ustring(lazy.condition, "ALWAYS"))
1150 0 : return TRUE;
1151 0 : else if (equal_ustring(lazy.condition, "NEVER"))
1152 0 : return FALSE;
1153 0 : else if (equal_ustring(lazy.condition, "WHILE_ACQ_NOT_RUNNING")) {
1154 0 : if (run_state == STATE_RUNNING)
1155 0 : return FALSE;
1156 : else
1157 0 : return TRUE;
1158 : } else
1159 0 : return (condition_test(lazy.condition));
1160 : }
1161 :
1162 : /*------------------------------------------------------------------*/
1163 0 : INT lazy_copy(char *outfile, char *infile, int max_event_size)
1164 : /********************************************************************\
1165 : Routine: lazy_copy
1166 : Purpose: backup file to backup device
1167 : every 2 second will update the statistics and yield
1168 : if condition requires no copy, every 5 second will yield
1169 : Input:
1170 : char * outfile backup destination file
1171 : char * infile source file to be backed up
1172 : Output:
1173 : Function value:
1174 : 0 success
1175 : \********************************************************************/
1176 : {
1177 0 : void *plazy = NULL;
1178 : DWORD szlazy;
1179 0 : INT status, no_cpy_last_time = 0;
1180 : INT cpy_loop_time;
1181 : DWORD watchdog_timeout;
1182 : static INT last_error = 0;
1183 : //char *pext;
1184 0 : BOOL watchdog_flag, exit_request = FALSE;
1185 : char filename[256];
1186 :
1187 0 : if (debug)
1188 0 : printf("lazy_copy %s to %s\n", infile, outfile);
1189 :
1190 : /* init copy variables */
1191 0 : lazyst.cur_size = 0.0f;
1192 :
1193 : /* open any logging file (output) */
1194 0 : mstrlcpy(filename, outfile, sizeof(filename)); // ftp modifies filename
1195 0 : if ((status = md_file_wopen(dev_type, data_fmt, filename, &hDev)) != 1) {
1196 0 : if ((ss_time() - last_error) > 60) {
1197 0 : last_error = ss_time();
1198 0 : cm_msg(MTALK, "Lazy_copy", "cannot open %s, error %d", outfile, status);
1199 : }
1200 0 : return (FORCE_EXIT);
1201 : }
1202 :
1203 : /* New lazy copy if TAPE & append required force a mv to EOD */
1204 0 : if ((dev_type == LOG_TYPE_TAPE) && lazy.tapeAppend) {
1205 : /* Position Tape to end of Data */
1206 0 : cm_msg(MINFO, "Lazy", "Positioning Tape to EOD");
1207 :
1208 0 : cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
1209 0 : cm_set_watchdog_params(watchdog_flag, 300000); /* 5 min for tape rewind */
1210 0 : status = ss_tape_spool(hDev);
1211 0 : cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
1212 0 : if (status != SS_SUCCESS) {
1213 0 : cm_msg(MINFO, "Lazy", "Error while Positioning Tape to EOD (%d)", status);
1214 0 : ss_tape_close(hDev);
1215 0 : return (FORCE_EXIT);
1216 : }
1217 : }
1218 :
1219 : /* reset error message */
1220 0 : last_error = 0;
1221 :
1222 : /* open input data file */
1223 0 : if (md_file_ropen(infile, data_fmt, DONTOPENZIP, max_event_size) != MD_SUCCESS)
1224 0 : return (FORCE_EXIT);
1225 :
1226 : /* run shell command if available */
1227 0 : if (equal_ustring(lazy.type, "Tape")) {
1228 : /* get the block number. If -1 it probably means that the tape
1229 : is not ready. Wait for a while */
1230 0 : blockn = -1;
1231 0 : while (blockn < 0) {
1232 0 : blockn = ss_tape_get_blockn(hDev);
1233 0 : if (blockn >= 0)
1234 0 : break;
1235 0 : cm_msg(MINFO, "Lazy", "Tape is not ready");
1236 0 : cm_yield(3000);
1237 : }
1238 0 : if (lazy.commandBefore[0]) {
1239 : char cmd[256];
1240 0 : sprintf(cmd, "%s %s %s %d %s %i", lazy.commandBefore, infile, outfile, blockn, lazy.backlabel, lazyst.nfiles);
1241 0 : cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
1242 0 : ss_system(cmd);
1243 : }
1244 : }
1245 :
1246 : /* force a statistics update on the first loop */
1247 0 : cpy_loop_time = -2000;
1248 0 : if (dev_type == LOG_TYPE_TAPE) {
1249 : char str[256];
1250 0 : sprintf(str, "Starting lazy job on %s at block %d", lazyst.backfile, blockn);
1251 0 : if (msg_flag)
1252 0 : cm_msg(MTALK, "Lazy", "%s", str);
1253 0 : cm_msg1(MINFO, "lazy_copy", "lazy", "%s", str);
1254 : }
1255 :
1256 : /* infinite loop while copying */
1257 : while (1) {
1258 0 : if (copy_continue) {
1259 0 : if (md_physrec_get(data_fmt, &plazy, &szlazy) == MD_SUCCESS) {
1260 0 : status = md_log_write(hDev, data_fmt, dev_type, plazy, szlazy);
1261 0 : if (status != SS_SUCCESS) {
1262 : /* close source file */
1263 0 : md_file_rclose(dev_type);
1264 : /* close output data file */
1265 0 : md_file_wclose(hDev, dev_type, data_fmt, outfile);
1266 : /* szlazy is the requested block size. Why is it copied to cm_msg?
1267 : cm_msg(MERROR,"lazy_copy","Write error %i",szlazy); */
1268 0 : cm_msg(MERROR, "lazy_copy", "Write error ");
1269 0 : if (status == SS_NO_SPACE)
1270 0 : return status;
1271 0 : return (FORCE_EXIT);
1272 : }
1273 0 : lazyst.cur_size += (double) szlazy;
1274 0 : lazyst.cur_dev_size += (double) szlazy;
1275 0 : if ((ss_millitime() - cpy_loop_time) > 2000) {
1276 : /* update statistics */
1277 0 : lazy_statistics_update(cpy_loop_time);
1278 :
1279 : /* check conditions */
1280 0 : copy_continue = lazy_condition_check();
1281 :
1282 : /* update check loop */
1283 0 : cpy_loop_time = ss_millitime();
1284 :
1285 : /* yield quickly */
1286 0 : status = cm_yield(1);
1287 0 : if (status == RPC_SHUTDOWN || status == SS_ABORT || exit_request) {
1288 0 : cm_msg(MINFO, "Lazy", "Abort postponed until end of copy of %s %1.0lf[%%]",
1289 0 : infile, (double) lazyst.progress);
1290 0 : exit_request = TRUE;
1291 : }
1292 : }
1293 : } /* get physrec */
1294 : else
1295 0 : break;
1296 : } /* copy_continue */
1297 : else { /* !copy_continue */
1298 0 : status = cm_yield(1000);
1299 0 : if (status == RPC_SHUTDOWN || status == SS_ABORT)
1300 0 : return (FORCE_EXIT);
1301 0 : if ((ss_millitime() - no_cpy_last_time) > 5000) {
1302 0 : copy_continue = lazy_condition_check();
1303 0 : no_cpy_last_time = ss_millitime();
1304 : }
1305 : } /* !copy_continue */
1306 : } /* while forever */
1307 :
1308 : /* update for last the statistics */
1309 0 : lazy_statistics_update(0);
1310 :
1311 : /* close input log device */
1312 0 : md_file_rclose(dev_type);
1313 :
1314 : /* close output data file */
1315 0 : if (equal_ustring(lazy.type, "Tape")) {
1316 0 : blockn = ss_tape_get_blockn(hDev);
1317 : }
1318 0 : status = md_file_wclose(hDev, dev_type, data_fmt, outfile);
1319 0 : if (status != SS_SUCCESS) {
1320 0 : if (status == SS_NO_SPACE)
1321 0 : return status;
1322 0 : return (FORCE_EXIT);
1323 : }
1324 :
1325 : /* request exit */
1326 0 : if (exit_request)
1327 0 : return (EXIT_REQUEST);
1328 0 : return 0;
1329 : }
1330 :
1331 : //
1332 : //
1333 0 : int lazy_disk_copy_loop(const char *outfile, const char *infile, FILE *fpout, FILE *fpin) {
1334 : int status;
1335 0 : int no_cpy_last_time = 0;
1336 :
1337 : /* force a statistics update on the first loop */
1338 0 : int cpy_loop_time = -2000;
1339 :
1340 : /* infinite loop while copying */
1341 : while (1) {
1342 0 : if (copy_continue) {
1343 0 : const int kBufSize = 1 * 1024 * 1024;
1344 : char buf[kBufSize];
1345 0 : int rd = fread(buf, 1, kBufSize, fpin);
1346 0 : if (rd > 0) {
1347 0 : int wr = fwrite(buf, 1, rd, fpout);
1348 0 : if (wr != rd) {
1349 0 : cm_msg(MERROR, "Lazy_disk_copy", "Cannot write to \'%s\', errno %d (%s)", outfile, errno,
1350 0 : strerror(errno));
1351 : //if (status == SS_NO_SPACE)
1352 : // return status;
1353 0 : return TRY_LATER;
1354 : }
1355 :
1356 0 : lazyst.cur_size += (double) wr;
1357 0 : lazyst.cur_dev_size += (double) wr;
1358 0 : if ((ss_millitime() - cpy_loop_time) > 2000) {
1359 : /* update statistics */
1360 0 : lazy_statistics_update(cpy_loop_time);
1361 :
1362 : /* check conditions */
1363 0 : copy_continue = lazy_condition_check();
1364 :
1365 : /* update check loop */
1366 0 : cpy_loop_time = ss_millitime();
1367 :
1368 : /* yield quickly */
1369 0 : status = cm_yield(1);
1370 0 : if (status == RPC_SHUTDOWN || status == SS_ABORT) {
1371 0 : cm_msg(MINFO, "Lazy", "Copy aborted by cm_yield() status %d", status);
1372 0 : return FORCE_EXIT;
1373 : }
1374 : }
1375 0 : } else if (rd == 0) {
1376 : // end of input file
1377 0 : break;
1378 : } else {
1379 : // read error
1380 0 : cm_msg(MERROR, "Lazy_disk_copy", "Cannot read from \'%s\', errno %d (%s)", infile, errno, strerror(errno));
1381 0 : return FORCE_EXIT;
1382 : }
1383 : } /* copy_continue */
1384 : else { /* !copy_continue */
1385 0 : status = cm_yield(1000);
1386 0 : if (status == RPC_SHUTDOWN || status == SS_ABORT) {
1387 0 : return FORCE_EXIT;
1388 : }
1389 0 : if ((ss_millitime() - no_cpy_last_time) > 5000) {
1390 0 : copy_continue = lazy_condition_check();
1391 0 : no_cpy_last_time = ss_millitime();
1392 : }
1393 : } /* !copy_continue */
1394 0 : } /* while forever */
1395 :
1396 0 : return 0;
1397 : }
1398 :
1399 : #ifdef HAVE_CURL
1400 : //
1401 : // function to read the data file
1402 : INT cpy_sftp_loop_time = 0;
1403 :
1404 0 : static size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
1405 0 : FILE *f = (FILE *) stream;
1406 : size_t n;
1407 0 : if (ferror(f))
1408 0 : return CURL_READFUNC_ABORT;
1409 :
1410 0 : n = fread(ptr, size, nmemb, f) * size;
1411 0 : lastsz = n;
1412 0 : lazyst.cur_size += (double) lastsz;
1413 0 : lazyst.cur_dev_size += (double) lastsz;
1414 0 : if ((ss_millitime() - cpy_sftp_loop_time) > 2000) {
1415 0 : if (debug)
1416 0 : printf("readfunc (CURL) size:%ld nmemb:%ld n:%li total:%f\n", size, nmemb, n, lastsz);
1417 : // update statistics
1418 0 : lazy_statistics_update(cpy_sftp_loop_time);
1419 0 : cpy_sftp_loop_time = ss_millitime();
1420 0 : cm_yield(10);
1421 : }
1422 0 : return n;
1423 : }
1424 :
1425 : //
1426 : // global for the SFTP
1427 : long int port_number = 22;
1428 :
1429 : // get the remote file size in byte; -1 on error or if file not existent
1430 0 : static long int get_remote_file_size(const char *remote_file) {
1431 : CURLcode result;
1432 0 : long int remote_file_size_byte = -1;
1433 :
1434 0 : CURL *curlhandle = curl_easy_init();
1435 :
1436 : // print metainfos if in debug mode
1437 0 : if (debug) {
1438 0 : curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1);
1439 : }
1440 : // url/file to transfer
1441 0 : curl_easy_setopt(curlhandle, CURLOPT_URL, remote_file);
1442 : // set the port number to use for socket
1443 0 : curl_easy_setopt(curlhandle, CURLOPT_PORT, port_number);
1444 : // get user and password from protected file
1445 : // curl_easy_setopt(curlhandle, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1446 : // switch off the progress meter
1447 0 : curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
1448 : // don't transfer the file body
1449 0 : curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1);
1450 : // transfer the file header
1451 0 : curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1);
1452 : // get the modification time
1453 0 : curl_easy_setopt(curlhandle, CURLOPT_FILETIME, 1);
1454 :
1455 : // perform the transfer with all options
1456 0 : result = curl_easy_perform(curlhandle);
1457 0 : if (result == CURLE_OK) {
1458 : // get the file size from the header info
1459 :
1460 : #if LIBCURL_VERSION_NUM < 0x073700
1461 : result = curl_easy_getinfo(curlhandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &remote_file_size_byte);
1462 : #else
1463 0 : result = curl_easy_getinfo(curlhandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &remote_file_size_byte);
1464 : #endif
1465 0 : if (result) {
1466 0 : return -1;
1467 : }
1468 0 : if (debug) {
1469 0 : printf("[%s] Remote file size: %ld byte \n", __FUNCTION__, remote_file_size_byte);
1470 : }
1471 0 : } else if (result == CURLE_REMOTE_FILE_NOT_FOUND) {
1472 0 : if (debug) {
1473 0 : printf("[%s] Remote file %s not existent \n", __FUNCTION__, remote_file);
1474 : }
1475 0 : return -1;
1476 : }
1477 :
1478 0 : curl_easy_cleanup(curlhandle);
1479 :
1480 0 : return remote_file_size_byte;
1481 : }
1482 :
1483 : //
1484 : //
1485 0 : int lazy_sftp_copy_loop(const char *outfile, const char *infile, FILE *fpin) {
1486 : //
1487 : // Initialize curl
1488 0 : CURL *curlhandle = NULL;
1489 0 : curl_global_init(CURL_GLOBAL_ALL);
1490 0 : curlhandle = curl_easy_init();
1491 : CURLcode result;
1492 :
1493 0 : lastsz = 0;
1494 0 : cpy_sftp_loop_time = 0;
1495 : // set transfer mode to upload
1496 0 : curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
1497 : // define the upload url
1498 0 : curl_easy_setopt(curlhandle, CURLOPT_URL, outfile);
1499 : // set the port number to use for socket
1500 0 : curl_easy_setopt(curlhandle, CURLOPT_PORT, port_number);
1501 : // get user and password from protected netrc file
1502 : // could also be set with curl_easy_setopt(curlhandle, CURLOPT_USERPWD, "user:password") but this is even less save
1503 : // best way to do is generate a RSA-keypair (or similar) and don't set it here at all, this is not allowed for some dataservers though
1504 : //result = curl_easy_setopt(curlhandle, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1505 : // use a custom read function instead of the default fread()
1506 0 : result = curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
1507 : // define the file to read
1508 0 : curl_easy_setopt(curlhandle, CURLOPT_READDATA, fpin);
1509 : // define the file size to upload (2 GB limit for regular size)
1510 0 : if (lazyst.file_size < 2147483648)
1511 0 : result = curl_easy_setopt(curlhandle, CURLOPT_INFILESIZE, lazyst.file_size);
1512 : else
1513 0 : result = curl_easy_setopt(curlhandle, CURLOPT_INFILESIZE_LARGE, lazyst.file_size);
1514 :
1515 0 : result = curl_easy_perform(curlhandle);
1516 0 : if (result) {
1517 0 : cm_msg(MERROR, "SFTP_copy", "Failed to upload due to CURL errror %d", result);
1518 0 : printf("Failed to upload file '%s' with error code %d \n", infile, result);
1519 : } else {
1520 0 : printf("File '%s' successfully uploaded \n", infile);
1521 : }
1522 :
1523 0 : curl_easy_cleanup(curlhandle);
1524 0 : curl_global_cleanup();
1525 :
1526 0 : return result;
1527 : }
1528 :
1529 : //
1530 : // SFTP copy
1531 0 : int lazy_sftp_copy(const char *outfile, const char *infile) {
1532 :
1533 : DWORD watchdog_timeout;
1534 : BOOL watchdog_flag;
1535 :
1536 0 : if (debug)
1537 0 : printf("lazy_sftp_copy %s to %s\n", infile, outfile);
1538 :
1539 0 : double MiB = 1024 * 1024;
1540 : //double disk_size = ss_disk_size((char*)outfile);
1541 : //double disk_free = ss_disk_free((char*)outfile);
1542 : //printf("output disk size %.1f MiB, free %.1f MiB\n", disk_size/MiB, disk_free/MiB);
1543 :
1544 : /* init copy variables */
1545 0 : lazyst.cur_size = 0.0f;
1546 :
1547 : /* run shell command if available */
1548 0 : if (lazy.commandBefore[0]) {
1549 : char cmd[256];
1550 0 : sprintf(cmd, "%s %s %i", lazy.commandBefore, infile, lazyst.nfiles);
1551 0 : cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
1552 0 : ss_system(cmd);
1553 : }
1554 :
1555 0 : FILE *fpin = fopen(infile, "rb");
1556 0 : if (!fpin) {
1557 0 : cm_msg(MERROR, "Lazy_sftp_copy", "Cannot read from \'%s\', errno %d (%s)", infile, errno, strerror(errno));
1558 0 : return FORCE_EXIT;
1559 : }
1560 :
1561 0 : setbuf(fpin, NULL);
1562 :
1563 : {
1564 : char str[MAX_FILE_PATH];
1565 0 : sprintf(str, "Starting lazy_sftp_copy \'%s\' to \'%s\'", infile, outfile);
1566 0 : if (msg_flag)
1567 0 : cm_msg(MTALK, "Lazy", "%s", str);
1568 : // wrtie to file
1569 0 : cm_msg1(MINFO, "lazy_sftp_copy", "lazy", "%s", str);
1570 : }
1571 :
1572 0 : double cpy_start_time = ss_millitime();
1573 :
1574 0 : cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
1575 0 : cm_set_watchdog_params(watchdog_flag, 10 * 60 * 1000); /* increase timeout in case of delays writing output file */
1576 :
1577 0 : int copy_status = lazy_sftp_copy_loop(outfile, infile, fpin);
1578 :
1579 0 : int remote_size = get_remote_file_size(outfile);
1580 :
1581 : // Check for remote file size matching what we just sent.
1582 0 : if (lazyst.file_size != remote_size) {
1583 0 : printf(" File copied incomplete (%s)\n", outfile);
1584 0 : cm_msg(MERROR, "Lazy_SFTP_Copy", "File copied incomplete (%s)\n", outfile);
1585 0 : return TRY_LATER;
1586 : }
1587 :
1588 0 : if (debug)
1589 0 : printf("*********** remove File Size: %d\n", remote_size);
1590 :
1591 0 : cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
1592 :
1593 : /* update for last the statistics */
1594 0 : lazy_statistics_update(0);
1595 :
1596 : /* close input log device */
1597 0 : fclose(fpin);
1598 0 : fpin = NULL;
1599 :
1600 0 : if (copy_status) {
1601 0 : return copy_status;
1602 : }
1603 :
1604 0 : chmod(outfile, 0444);
1605 :
1606 0 : double t = (ss_millitime() - cpy_start_time) / 1000.0;
1607 : //double MiB = 1024*1024;
1608 0 : cm_msg(MINFO, "lazy_disk_copy", "Copy finished in %.1f sec, %.1f MiBytes at %.1f MiBytes/sec", t,
1609 0 : lazyst.cur_size / MiB, lazyst.cur_size / t / MiB);
1610 :
1611 0 : return 0;
1612 : }
1613 : #endif // HAVE_CURL
1614 :
1615 0 : INT lazy_disk_copy(const char *outfile, const char *infile)
1616 : /********************************************************************\
1617 : Routine: lazy_disk_copy
1618 : Purpose: backup file to backup device
1619 : every 2 second will update the statistics and yield
1620 : if condition requires no copy, every 5 second will yield
1621 : Input:
1622 : char * outfile backup destination file
1623 : char * infile source file to be backed up
1624 : Output:
1625 : Function value:
1626 : 0 success
1627 : \*********************************************************************/
1628 : {
1629 : int status;
1630 : DWORD watchdog_timeout;
1631 : BOOL watchdog_flag;
1632 :
1633 0 : if (debug)
1634 0 : printf("lazy_disk_copy %s to %s\n", infile, outfile);
1635 :
1636 0 : double MiB = 1024 * 1024;
1637 0 : double disk_size = ss_disk_size((char *) outfile);
1638 0 : double disk_free = ss_disk_free((char *) outfile);
1639 :
1640 0 : if (debug)
1641 0 : printf("output disk size %.1f MiB, free %.1f MiB\n", disk_size / MiB, disk_free / MiB);
1642 :
1643 : /* init copy variables */
1644 0 : lazyst.cur_size = 0.0f;
1645 :
1646 : /* run shell command if available */
1647 0 : if (lazy.commandBefore[0]) {
1648 : char cmd[256];
1649 0 : sprintf(cmd, "%s %s %i", lazy.commandBefore, infile, lazyst.nfiles);
1650 0 : cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
1651 0 : ss_system(cmd);
1652 : }
1653 :
1654 0 : FILE *fpin = fopen(infile, "rb");
1655 0 : if (!fpin) {
1656 0 : cm_msg(MERROR, "Lazy_disk_copy", "Cannot read from \'%s\', errno %d (%s)", infile, errno, strerror(errno));
1657 0 : return FORCE_EXIT;
1658 : }
1659 :
1660 0 : FILE *fptest = fopen(outfile, "rb");
1661 0 : if (fptest) {
1662 0 : fclose(fptest);
1663 0 : fptest = NULL;
1664 0 : cm_msg(MINFO, "Lazy_disk_copy", "Output file \'%s\' already exists, removing", outfile);
1665 0 : unlink(outfile);
1666 : //return FORCE_EXIT;
1667 : }
1668 :
1669 0 : FILE *fpout = fopen(outfile, "wb");
1670 0 : if (!fpout) {
1671 0 : cm_msg(MERROR, "Lazy_disk_copy", "Cannot write to \'%s\', errno %d (%s)", outfile, errno, strerror(errno));
1672 0 : fclose(fpin);
1673 0 : return TRY_LATER;
1674 : }
1675 :
1676 0 : setbuf(fpin, NULL);
1677 0 : setbuf(fpout, NULL);
1678 :
1679 : {
1680 : char str[MAX_FILE_PATH];
1681 0 : sprintf(str, "Starting lazy_disk_copy \'%s\' to \'%s\'", infile, outfile);
1682 0 : if (msg_flag)
1683 0 : cm_msg(MTALK, "Lazy", "%s", str);
1684 0 : cm_msg1(MINFO, "lazy_disk_copy", "lazy", "%s", str);
1685 : }
1686 :
1687 0 : double cpy_start_time = ss_millitime();
1688 :
1689 0 : cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
1690 0 : cm_set_watchdog_params(watchdog_flag, 10 * 60 * 1000); /* increase timeout in case of delays writing output file */
1691 :
1692 0 : int copy_status = lazy_disk_copy_loop(outfile, infile, fpout, fpin);
1693 :
1694 0 : cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
1695 :
1696 : /* update for last the statistics */
1697 0 : lazy_statistics_update(0);
1698 :
1699 : /* close input log device */
1700 0 : fclose(fpin);
1701 0 : fpin = NULL;
1702 :
1703 0 : status = fclose(fpout);
1704 0 : if (status != 0) {
1705 0 : cm_msg(MERROR, "Lazy_disk_copy", "Cannot close \'%s\', errno %d (%s)", outfile, errno, strerror(errno));
1706 : //if (status == SS_NO_SPACE)
1707 : // return status;
1708 0 : return TRY_LATER;
1709 : }
1710 :
1711 0 : if (copy_status) {
1712 0 : return copy_status;
1713 : }
1714 :
1715 0 : chmod(outfile, 0444);
1716 :
1717 0 : double t = (ss_millitime() - cpy_start_time) / 1000.0;
1718 : //double MiB = 1024*1024;
1719 0 : cm_msg(MINFO, "lazy_disk_copy", "Copy finished in %.1f sec, %.1f MiBytes at %.1f MiBytes/sec", t,
1720 0 : lazyst.cur_size / MiB, lazyst.cur_size / t / MiB);
1721 :
1722 0 : return 0;
1723 : }
1724 :
1725 : /*------------------------------------------------------------------*/
1726 :
1727 : #ifdef OS_LINUX // does not work under Windows because of missing popen
1728 :
1729 0 : INT lazy_script_copy(char *infile)
1730 : /********************************************************************\
1731 : Routine: lazy_script_copy
1732 : Purpose: call user script to backup file to backup device
1733 : Input:
1734 : char * infile source file to be backed up
1735 : Output:
1736 : Function value:
1737 : 0 success
1738 : \********************************************************************/
1739 : {
1740 : int status;
1741 : FILE *fin;
1742 0 : int cpy_loop_time = ss_millitime();
1743 : char cmd[256];
1744 :
1745 : /* init copy variables */
1746 0 : lazyst.cur_size = 0;
1747 :
1748 : /* run shell command if available */
1749 0 : if (lazy.commandBefore[0]) {
1750 : char cmd[256];
1751 0 : sprintf(cmd, "%s %s %i", lazy.commandBefore, infile, lazyst.nfiles);
1752 0 : cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
1753 0 : ss_system(cmd);
1754 : }
1755 :
1756 : /* create the command for the backup script */
1757 0 : sprintf(cmd, "%s %s 2>&1", lazy.path, infile);
1758 :
1759 : {
1760 : char str[100 + 256];
1761 0 : sprintf(str, "Starting lazy job \'%s\'", cmd);
1762 0 : if (msg_flag)
1763 0 : cm_msg(MTALK, "Lazy", "%s", str);
1764 0 : cm_msg1(MINFO, "lazy_script_copy", "lazy", "%s", str);
1765 : }
1766 :
1767 : /* start the backup script */
1768 0 : fin = popen(cmd, "r");
1769 :
1770 0 : if (fin == NULL) {
1771 0 : cm_msg(MTALK, "lazy_script_copy", "Cannot start \'%s\', errno %d (%s)", cmd, errno, strerror(errno));
1772 0 : return FORCE_EXIT;
1773 : }
1774 :
1775 : if (1) {
1776 0 : int desc = fileno(fin);
1777 0 : int flags = fcntl(desc, F_GETFL, 0);
1778 0 : fcntl(desc, F_SETFL, flags | O_NONBLOCK);
1779 : }
1780 :
1781 : /* infinite loop while copying */
1782 : while (1) {
1783 : char buf[1024];
1784 0 : int rd = read(fileno(fin), buf, sizeof(buf));
1785 0 : if (rd == 0) {
1786 : /* file closed - backup script completed */
1787 0 : break;
1788 0 : } else if (rd < 0) {
1789 : /* i/o error */
1790 :
1791 0 : if (errno == EAGAIN) {
1792 : /* this is the main loop while waiting for the backup script */
1793 0 : status = cm_yield(1000);
1794 0 : continue;
1795 : }
1796 :
1797 0 : cm_msg(MERROR, "lazy_script_copy", "Error reading output of the backup script, errno %d (%s)", errno,
1798 0 : strerror(errno));
1799 0 : break;
1800 : } else {
1801 : char *p;
1802 : /* backup script printed something, write it to log file */
1803 :
1804 : /* make sure text is NUL-terminated */
1805 0 : buf[rd] = 0;
1806 :
1807 : /* chop the output of the backup script into lines separated by '\n' */
1808 0 : p = buf;
1809 0 : while (p) {
1810 0 : char *q = strchr(p, '\n');
1811 0 : if (q) {
1812 0 : *q = 0; // replace '\n' with NUL
1813 0 : q++;
1814 0 : if (q[0] == 0) // check for end of line
1815 0 : q = NULL;
1816 : }
1817 0 : cm_msg(MINFO, "lazy_script_copy", "%s", p);
1818 0 : p = q;
1819 : }
1820 : }
1821 0 : }
1822 :
1823 : /* update for last the statistics */
1824 0 : lazy_statistics_update(cpy_loop_time);
1825 :
1826 : /* close input log device */
1827 0 : status = pclose(fin);
1828 :
1829 0 : if (status == -1) {
1830 0 : cm_msg(MERROR, "lazy_script_copy", "pclose() returned %d, errno %d (%s)", status, errno, strerror(errno));
1831 0 : return FORCE_EXIT;
1832 : }
1833 :
1834 0 : if (status != 0) {
1835 0 : cm_msg(MERROR, "lazy_script_copy", "Backup script finished with exit code %d, status 0x%x", (status >> 8),
1836 : status);
1837 0 : return SS_NO_SPACE;
1838 : }
1839 :
1840 0 : cm_msg(MINFO, "lazy_script_copy", "Backup script finished in %.1f sec with exit code %d",
1841 0 : (ss_millitime() - cpy_loop_time) / 1000.0, (status >> 8));
1842 :
1843 : /* request exit */
1844 0 : return 0;
1845 : }
1846 :
1847 : #endif // OS_LINUX
1848 :
1849 : /*------------------------------------------------------------------*/
1850 0 : BOOL lazy_file_exists(char *dir, char *file)
1851 : /********************************************************************\
1852 : Routine: lazy_file_exists
1853 : Purpose: check if file exists in dir by extracting its size
1854 : Input:
1855 : char * dir data directory
1856 : char * file file to be checked
1857 : Output:
1858 : Function value:
1859 : TRUE file found
1860 : FALSE file not found
1861 : \********************************************************************/
1862 : {
1863 : char *list;
1864 0 : char fullfile[MAX_FILE_PATH] = {'\0'};
1865 :
1866 0 : if (ss_file_find(dir, file, &list) == 1) {
1867 0 : strcat(fullfile, dir);
1868 0 : strcat(fullfile, DIR_SEPARATOR_STR);
1869 0 : strcat(fullfile, file);
1870 0 : if ((lazyst.file_size = (double) (ss_file_size(fullfile))) > 0) {
1871 0 : free(list);
1872 0 : return TRUE;
1873 : }
1874 : }
1875 0 : free(list);
1876 0 : return FALSE;
1877 : }
1878 :
1879 : /*------------------------------------------------------------------*/
1880 :
1881 0 : INT lazy_maintain_free_space(LAZY_INFO *pLch, LAZY_INFO *pLall) {
1882 : int status;
1883 :
1884 : /* update "maintain free space" */
1885 0 : lazy_maintain_check(pLch->hKey, pLall);
1886 :
1887 : /* check SPACE and purge if necessary = % (1:99) */
1888 0 : if (lazy.pupercent > 0) {
1889 :
1890 : // Compute initial disk space
1891 0 : double freepercent = 100. * ss_disk_free(lazy.dir) / ss_disk_size(lazy.dir);
1892 :
1893 : // Check for Disk full first
1894 0 : if (freepercent < 5.0) {
1895 0 : std::string str;
1896 0 : str += "Disk ";
1897 0 : str += lazy.dir;
1898 0 : str += "is almost full, free space: ";
1899 : char buf[256];
1900 0 : sprintf(buf, "%.1f%%", freepercent);
1901 0 : str += buf;
1902 0 : al_trigger_alarm("Disk Full", str.c_str(), lazy.alarm, "Disk buffer full", AT_INTERNAL);
1903 0 : } else {
1904 : HNDLE hKey;
1905 0 : if (db_find_key(hDB, 0, "/Alarms/Alarms/Disk Full", &hKey) == DB_SUCCESS)
1906 0 : al_reset_alarm("Disk Full");
1907 : }
1908 :
1909 0 : if (debug)
1910 0 : printf("free space on %s: %.1f%%, lazy limit %d%%\n", lazy.dir, freepercent, lazy.pupercent);
1911 :
1912 : /* Lock other clients out of this following code as
1913 : it may access the other client info tree */
1914 :
1915 0 : status = ss_semaphore_wait_for(lazy_semaphore, 5000);
1916 0 : if (status != SS_SUCCESS) {
1917 : /* exit for now and come back later */
1918 0 : return NOTHING_TODO;
1919 : }
1920 :
1921 : /* check purging action */
1922 0 : while (freepercent <= (double) lazy.pupercent) {
1923 : // flag for single purge
1924 0 : BOOL donepurge = FALSE;
1925 : /* search file to purge : run in donelist AND run in dirlog */
1926 : /* synchronize donelist to dir log in case user has purged
1927 : some file by hand. Basically remove the run in the list if the
1928 : file is not anymore in the source dir. */
1929 0 : DIRLOG f;
1930 0 : if (lazy_select_purge(pLch->hKey, channel, pLall, lazy.backfmt, lazy.dir, &f) == SUCCESS) {
1931 : /* check if beyond keep file + 1 */
1932 : if (1 /*purun < (cur_acq_run - abs(lazy.staybehind) - 1)*/) {
1933 : DWORD rm_time;
1934 : /* remove file */
1935 0 : rm_time = ss_millitime();
1936 0 : std::string path = lazy.dir;
1937 0 : path += f.filename;
1938 0 : if (debug)
1939 0 : printf("file selected for removal %s [%s]\n", f.filename.c_str(), path.c_str());
1940 0 : status = lazy_file_remove(path.c_str());
1941 0 : rm_time = ss_millitime() - rm_time;
1942 0 : if (status != SS_SUCCESS) {
1943 0 : cm_msg(MERROR, "Lazy", "lazy_file_remove failed on file %s", path.c_str());
1944 : // break out if can't delete files
1945 0 : break;
1946 : } else {
1947 0 : status = lazy_log_update(REMOVE_FILE, f.runno, NULL, path.c_str(), rm_time);
1948 0 : donepurge = TRUE;
1949 : }
1950 0 : } // purun found
1951 :
1952 : // Re-compute free space
1953 0 : freepercent = 100. * ss_disk_free(lazy.dir) / ss_disk_size(lazy.dir);
1954 :
1955 0 : if (debug)
1956 0 : printf("free space on %s: %.1f%%, lazy limit %d%%\n", lazy.dir, freepercent, lazy.pupercent);
1957 :
1958 : } // select_purge
1959 :
1960 : // donepurge = FALSE => nothing else to do
1961 : // donepurge = TRUE => one purge done loop back once more
1962 0 : if (!donepurge)
1963 0 : break;
1964 0 : } // while
1965 :
1966 : /* Release the semaphore */
1967 0 : status = ss_semaphore_release(lazy_semaphore);
1968 :
1969 : } /* end of if pupercent > 0 */
1970 :
1971 0 : return SUCCESS;
1972 : }
1973 :
1974 : /*------------------------------------------------------------------*/
1975 0 : INT lazy_main(INT channel, LAZY_INFO *pLall, int max_event_size)
1976 : /********************************************************************\
1977 : Routine: lazy_main
1978 : Purpose: check if backup is necessary...
1979 : Input:
1980 : channel: Current channel number
1981 : *pLall : Pointer to all channels
1982 : Output:
1983 : Function value:
1984 : \********************************************************************/
1985 : {
1986 : DWORD cp_time;
1987 : INT size, status;
1988 : char str[MAX_FILE_PATH], inffile[MAX_FILE_PATH], outffile[MAX_FILE_PATH];
1989 0 : BOOL watchdog_flag, exit_request = FALSE;
1990 : DWORD watchdog_timeout;
1991 : LAZY_INFO *pLch;
1992 : static BOOL eot_reached = FALSE;
1993 : BOOL haveTape;
1994 :
1995 : /* current channel */
1996 0 : pLch = &pLall[channel];
1997 :
1998 0 : if (convert_flag) {
1999 0 : convert_done_list(pLch->hKey);
2000 0 : assert(!"NOT REACHED");
2001 : }
2002 :
2003 : /* extract Data format from the struct */
2004 0 : if (equal_ustring(lazy.format, "MIDAS"))
2005 0 : data_fmt = FORMAT_MIDAS;
2006 : else {
2007 0 : cm_msg(MERROR, "Lazy", "Unknown data format %s (MIDAS)", lazy.format);
2008 0 : return DB_NO_ACCESS;
2009 : }
2010 :
2011 : /* extract Device type from the struct */
2012 0 : if (equal_ustring(lazy.type, "DISK"))
2013 0 : dev_type = LOG_TYPE_DISK;
2014 0 : else if (equal_ustring(lazy.type, "TAPE"))
2015 0 : dev_type = LOG_TYPE_TAPE;
2016 0 : else if (equal_ustring(lazy.type, "FTP"))
2017 0 : dev_type = LOG_TYPE_FTP;
2018 0 : else if (equal_ustring(lazy.type, "SFTP"))
2019 0 : dev_type = LOG_TYPE_SFTP;
2020 0 : else if (equal_ustring(lazy.type, "SCRIPT"))
2021 0 : dev_type = LOG_TYPE_SCRIPT;
2022 : else {
2023 0 : cm_msg(MERROR, "Lazy", "Unknown device type %s (Disk, Tape, SFTP, FTP or SCRIPT)", lazy.type);
2024 0 : return DB_NO_ACCESS;
2025 : }
2026 :
2027 0 : if ((dev_type == LOG_TYPE_SCRIPT) || (dev_type == LOG_TYPE_DISK))
2028 0 : if (lazy.backlabel[0] == 0 || strcmp(lazy.backlabel, lazyinfo[channel].name) != 0) {
2029 0 : mstrlcpy(lazy.backlabel, lazyinfo[channel].name, sizeof(lazy.backlabel));
2030 0 : size = sizeof(lazy.backlabel);
2031 0 : db_set_value(hDB, pLch->hKey, "Settings/List label", lazy.backlabel, size, 1, TID_STRING);
2032 : }
2033 : /* make sure that we don't operate on the current DAQ file if so set to oldest */
2034 : //if (lazy.staybehind == 0) {
2035 : // cm_msg(MERROR, "Lazy", "Stay behind cannot be 0");
2036 : // return NOTHING_TODO;
2037 : //}
2038 :
2039 : /* Check if Tape is OK */
2040 : /* ... */
2041 :
2042 0 : haveTape = (lazy.backlabel[0] != '\0');
2043 :
2044 : /* check if space on device (not empty tape label) */
2045 0 : if (lazy.backlabel[0] == '\0') {
2046 0 : full_bck_flag = TRUE;
2047 : } else {
2048 0 : if (full_bck_flag) {
2049 0 : full_bck_flag = FALSE;
2050 0 : size = sizeof(lazyst);
2051 0 : memset(&lazyst, 0, size);
2052 0 : if (db_find_key(hDB, pLch->hKey, "Statistics", &hKeyst) == DB_SUCCESS) {
2053 0 : status = db_set_record(hDB, hKeyst, &lazyst, size, 0);
2054 : /* New session of lazy, apply append in case of Tape */
2055 : /* DISK for debugging */
2056 0 : if ((dev_type == LOG_TYPE_DISK) && lazy.tapeAppend) {
2057 : /* Position Tape to end of Data */
2058 0 : cm_msg(MINFO, "Lazy", "Positioning Tape to EOD");
2059 : }
2060 : } else
2061 0 : cm_msg(MERROR, "lazy_main", "did not find /Lazy/Lazy_%s/Statistics for zapping", pLch->name);
2062 : // INT al_reset_alarm(char *alarm_name)
2063 0 : if (dev_type == LOG_TYPE_TAPE)
2064 0 : al_reset_alarm("Tape");
2065 : }
2066 : }
2067 : /* check if data dir is none empty */
2068 0 : if (lazy.dir[0] == '\0') {
2069 0 : cm_msg(MINFO, "Lazy", "Please setup Data dir for input source path!");
2070 0 : return NOTHING_TODO;
2071 : }
2072 :
2073 0 : if (lazy.dir[0] != 0)
2074 0 : if (lazy.dir[strlen(lazy.dir) - 1] != DIR_SEPARATOR)
2075 0 : strcat(lazy.dir, DIR_SEPARATOR_STR);
2076 :
2077 : /* check if device path is set */
2078 0 : if (lazy.path[0] == '\0') {
2079 0 : cm_msg(MINFO, "Lazy", "Please setup backup device path too!");
2080 0 : return NOTHING_TODO;
2081 : }
2082 :
2083 0 : DIRLOGLIST dirlist;
2084 0 : build_log_list(lazy.backfmt, lazy.dir, &dirlist);
2085 :
2086 0 : save_list(pLch->name, "dirlist", &dirlist);
2087 :
2088 0 : DIRLOGLIST donelist;
2089 0 : build_done_list(pLch->hKey, &dirlist, &donelist);
2090 :
2091 0 : lazy_maintain_free_space(pLch, pLall);
2092 :
2093 : /* compare list : run NOT in donelist AND run in dirlog */
2094 0 : int tobe_backup = find_next_file(&dirlist, &donelist);
2095 :
2096 : //const DIRLOG* tobe_backup = cmp_log2donelist(&dirlist, &donelist);
2097 :
2098 : //if (debug)
2099 : //print_dirlog(&dirlist);
2100 :
2101 : //print_dirlog(&donelist);
2102 : //printf("tobe_backup: %p\n", tobe_backup);
2103 :
2104 0 : if (tobe_backup < 0)
2105 0 : return NOTHING_TODO;
2106 :
2107 0 : if (debug)
2108 0 : printf("selected for backup: %s, run %d\n", dirlist[tobe_backup].filename.c_str(), dirlist[tobe_backup].runno);
2109 :
2110 : /* Get current run number */
2111 : int cur_acq_run;
2112 0 : size = sizeof(cur_acq_run);
2113 0 : status = db_get_value(hDB, 0, "Runinfo/Run number", &cur_acq_run, &size, TID_INT, FALSE);
2114 0 : assert(status == SUCCESS);
2115 :
2116 0 : lazyst.cur_run = dirlist[tobe_backup].runno;
2117 :
2118 0 : int behind_files = dirlist.size() - tobe_backup;
2119 0 : int behind_runs = cur_acq_run - dirlist[tobe_backup].runno;
2120 :
2121 0 : bool nothing_todo_files = (behind_files <= lazy.staybehind);
2122 0 : bool nothing_todo_runs = (behind_runs < abs(lazy.staybehind));
2123 :
2124 0 : bool nothing_todo = false;
2125 :
2126 : /* "stay behind by so many runs" mode */
2127 0 : if (lazy.staybehind < 0)
2128 0 : nothing_todo = nothing_todo_runs;
2129 :
2130 : /* "stay behind by so many files" mode */
2131 0 : if (lazy.staybehind > 0)
2132 0 : nothing_todo = nothing_todo_files;
2133 :
2134 : /* "no stay behind" mode */
2135 0 : if (lazy.staybehind == 0) {
2136 0 : if (dirlist[tobe_backup].runno != cur_acq_run)
2137 0 : nothing_todo = false;
2138 0 : else if (behind_files > 1)
2139 0 : nothing_todo = false;
2140 : else {
2141 0 : nothing_todo = false;
2142 :
2143 : /* In case it is the current run make sure
2144 : 1) no transition is in progress
2145 : 2) the run start has not been aborted
2146 : 3) the run has been ended
2147 : */
2148 :
2149 : int flag;
2150 0 : size = sizeof(flag);
2151 0 : status = db_get_value(hDB, 0, "Runinfo/Transition in progress", &flag, &size, TID_INT, FALSE);
2152 0 : assert(status == SUCCESS);
2153 0 : if (flag) {
2154 0 : if (debug)
2155 0 : printf("transition in progress, cannot backup last file\n");
2156 0 : nothing_todo = true;
2157 : }
2158 :
2159 0 : size = sizeof(flag);
2160 0 : status = db_get_value(hDB, 0, "Runinfo/Start abort", &flag, &size, TID_INT, FALSE);
2161 0 : assert(status == SUCCESS);
2162 0 : if (flag) {
2163 0 : if (debug)
2164 0 : printf("run start aborted, cannot backup last file\n");
2165 0 : nothing_todo = true;
2166 : }
2167 :
2168 : int cur_state_run;
2169 0 : status = db_get_value(hDB, 0, "Runinfo/State", &cur_state_run, &size, TID_INT, FALSE);
2170 0 : assert(status == SUCCESS);
2171 0 : if ((cur_state_run != STATE_STOPPED)) {
2172 0 : if (debug)
2173 0 : printf("run still running, cannot backup last file\n");
2174 0 : nothing_todo = true;
2175 : }
2176 : }
2177 : }
2178 :
2179 0 : if (debug)
2180 0 : printf("behind: %d files, %d runs, staybehind: %d, nothing_todo: files: %d, runs: %d, lazylogger: %d\n",
2181 : behind_files, behind_runs, lazy.staybehind, nothing_todo_files, nothing_todo_runs, nothing_todo);
2182 :
2183 0 : if (nothing_todo) {
2184 0 : return NOTHING_TODO;
2185 : }
2186 :
2187 0 : if ((dev_type != LOG_TYPE_SCRIPT) && (dev_type != LOG_TYPE_DISK))
2188 0 : if (!haveTape) {
2189 0 : if (debug)
2190 0 : printf("haveTape: %d, nothing to do.\n", haveTape);
2191 0 : return NOTHING_TODO;
2192 : }
2193 :
2194 0 : mstrlcpy(lazyst.backfile, dirlist[tobe_backup].filename.c_str(), sizeof(lazyst.backfile));
2195 :
2196 0 : std::string xfile = lazy.dir;
2197 0 : xfile += dirlist[tobe_backup].filename;
2198 0 : mstrlcpy(inffile, xfile.c_str(), sizeof(inffile));
2199 :
2200 : /* Check again if the backup file is present in the logger dir */
2201 0 : if (lazy_file_exists(lazy.dir, lazyst.backfile)) {
2202 : /* compose the destination file name */
2203 0 : if ((dev_type == LOG_TYPE_DISK) || (dev_type == LOG_TYPE_SFTP)) {
2204 0 : if (lazy.path[0] != 0)
2205 0 : if (lazy.path[strlen(lazy.path) - 1] != DIR_SEPARATOR)
2206 0 : strcat(lazy.path, DIR_SEPARATOR_STR);
2207 0 : strcpy(outffile, lazy.path);
2208 0 : strcat(outffile, lazyst.backfile);
2209 0 : } else if (dev_type == LOG_TYPE_TAPE)
2210 0 : strcpy(outffile, lazy.path);
2211 0 : else if (dev_type == LOG_TYPE_FTP) {
2212 : /* Format for FTP
2213 : lazy.path=host,port,user,password,directory,filename[,umask]
2214 : expect filename in format such as "bck%08d.mid" */
2215 :
2216 : /*
2217 : if (lazy.path[0] != 0)
2218 : if (lazy.path[strlen(lazy.path)-1] != DIR_SEPARATOR)
2219 : strcat(lazy.path, DIR_SEPARATOR_STR);
2220 : */
2221 :
2222 0 : strcpy(str, lazy.path);
2223 : /* substitute "%d" for current run number */
2224 0 : if (strchr(str, '%'))
2225 0 : sprintf(outffile, str, lazyst.cur_run);
2226 : else
2227 0 : strcpy(outffile, str);
2228 :
2229 : /* substitute "#d" for current run number millenium */
2230 0 : mstrlcpy(str, outffile, sizeof(str));
2231 0 : if (strchr(str, '#')) {
2232 0 : *strchr(str, '#') = '%';
2233 0 : sprintf(outffile, str, lazyst.cur_run / 1000);
2234 : }
2235 : }
2236 :
2237 : /* check if space on backup device ONLY in the TAPE case */
2238 0 : if (((dev_type == LOG_TYPE_TAPE) && (lazy.capacity < (lazyst.cur_dev_size + lazyst.file_size))) || eot_reached) {
2239 : char pre_label[32];
2240 : /* save the last label for shell script */
2241 0 : strcpy(pre_label, lazy.backlabel);
2242 :
2243 : /* Reset EOT reached */
2244 0 : eot_reached = FALSE;
2245 :
2246 : /* not enough space => reset list label */
2247 0 : lazy.backlabel[0] = '\0';
2248 0 : size = sizeof(lazy.backlabel);
2249 0 : db_set_value(hDB, pLch->hKey, "Settings/List label", lazy.backlabel, size, 1, TID_STRING);
2250 0 : full_bck_flag = TRUE;
2251 0 : cm_msg(MINFO, "Lazy", "Not enough space for next copy on backup device!");
2252 :
2253 : /* rewind device if TAPE type */
2254 0 : if (dev_type == LOG_TYPE_TAPE) {
2255 : INT status, channel;
2256 : char str[256];
2257 0 : sprintf(str, "Tape %s is full with %d files", pre_label, lazyst.nfiles);
2258 0 : cm_msg(MINFO, "Lazy", "%s", str);
2259 :
2260 : /* Setup alarm */
2261 0 : lazy.alarm[0] = 0;
2262 0 : size = sizeof(lazy.alarm);
2263 0 : db_get_value(hDB, pLch->hKey, "Settings/Alarm Class", lazy.alarm, &size, TID_STRING, TRUE);
2264 :
2265 : /* trigger alarm if defined */
2266 0 : if (lazy.alarm[0])
2267 0 : al_trigger_alarm("Tape",
2268 : "Tape full, Please remove current tape and load new one!",
2269 : lazy.alarm, "Tape full", AT_INTERNAL);
2270 :
2271 : /* run shell command if available */
2272 0 : if (lazy.command[0]) {
2273 0 : std::string cmd;
2274 0 : cmd += lazy.command;
2275 0 : cmd += " ";
2276 0 : cmd += lazy.path;
2277 0 : cmd += " ";
2278 0 : cmd += pLch->name;
2279 0 : cmd += " ";
2280 0 : cmd += pre_label;
2281 0 : cm_msg(MINFO, "Lazy", "Exec post-rewind script:%s", cmd.c_str());
2282 0 : ss_system(cmd.c_str());
2283 0 : }
2284 :
2285 0 : cm_msg(MINFO, "Lazy", "backup device rewinding...");
2286 0 : cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
2287 0 : cm_set_watchdog_params(watchdog_flag, 300000); /* 5 min for tape rewind */
2288 0 : status = ss_tape_open(outffile, O_RDONLY, &channel);
2289 0 : if (channel < 0) {
2290 0 : cm_msg(MERROR, "Lazy", "Cannot rewind tape %s - %d - %d", outffile, channel, status);
2291 0 : return NOTHING_TODO;
2292 : }
2293 : //else
2294 : // cm_msg(MINFO,"Lazy", "After call ss_tape_open used to rewind tape %s - %d - %d", outffile, channel, status);
2295 0 : cm_msg(MINFO, "Lazy", "Calling ss_tape_unmount");
2296 0 : ss_tape_unmount(channel);
2297 0 : ss_tape_close(channel);
2298 0 : cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
2299 0 : return NOTHING_TODO;
2300 : } // 1
2301 : } // LOG_TYPE_TAPE
2302 :
2303 : // Postpone copy by "copy_delay" if the copy check happens right after the
2304 : // stop transition. This permit EOR external scripts to complete there operations
2305 : // prior to the lazycopy.
2306 : // Delay the copy in case:
2307 : // 0) all previous condition for copy is satisfied
2308 : // 1) Stopped transition has been detected,
2309 :
2310 0 : if (stop_transition) {
2311 0 : printf("in loop stop detected\n");
2312 0 : stop_transition = FALSE; // reset transition (trfunction())
2313 0 : delay_start = TRUE; // take notice of transition
2314 0 : lazy_time = ss_time(); // mark time for delay
2315 : }
2316 : // check if its time after a stop transition
2317 0 : if (delay_start && (ss_time() - lazy_time) < (DWORD) lazy.copy_delay) {
2318 0 : printf("During delay %d... (%d)\n", ss_time() - lazy_time, lazy.copy_delay);
2319 0 : return NOTHING_TODO;
2320 : } else {
2321 0 : delay_start = FALSE;
2322 : }
2323 :
2324 : /* Finally do the copy */
2325 0 : cp_time = ss_millitime();
2326 0 : status = 0;
2327 0 : if (dev_type == LOG_TYPE_SCRIPT) {
2328 : #ifdef OS_LINUX
2329 : //sprintf(lazy.backlabel, "%06d", 100 * (lazyst.cur_run / 100));
2330 0 : status = lazy_script_copy(inffile);
2331 : #else
2332 : assert(!"lazy_script_copy not supported under Windows");
2333 : #endif
2334 0 : } else if (dev_type == LOG_TYPE_SFTP) {
2335 : #ifdef HAVE_CURL
2336 : // copy CURL SFTP
2337 0 : status = lazy_sftp_copy(outffile, inffile);
2338 : #else
2339 : assert(!"SFTP copying requires CURL to be installed! Install CURL, re-run cmake, and re-compile!");
2340 : #endif
2341 0 : } else if (dev_type == LOG_TYPE_DISK) {
2342 : // copy block mode
2343 0 : status = lazy_disk_copy(outffile, inffile);
2344 : } else {
2345 : // copy event mode (old method)
2346 0 : status = lazy_copy(outffile, inffile, max_event_size);
2347 : }
2348 :
2349 0 : if ((status != 0) && (status != EXIT_REQUEST)) {
2350 0 : if (status == SS_NO_SPACE) {
2351 : /* Consider this case as EOT reached */
2352 0 : eot_reached = TRUE;
2353 0 : return status;
2354 0 : } else if (status == FORCE_EXIT)
2355 0 : return status;
2356 0 : cm_msg(MERROR, "Lazy", "copy failed -%s-%s-%i", lazy.path, lazyst.backfile, status);
2357 0 : if (status == TRY_LATER)
2358 0 : return status;
2359 0 : return FORCE_EXIT;
2360 : }
2361 0 : cp_time = ss_millitime() - cp_time;
2362 :
2363 : // copy done, update listings, logs, ODB
2364 0 : donelist.push_back(dirlist[tobe_backup]);
2365 0 : save_done_list(pLch->hKey, &donelist);
2366 0 : lazy_log_update(NEW_FILE, lazyst.cur_run, lazy.backlabel, lazyst.backfile, cp_time);
2367 0 : db_send_changed_records();
2368 : } /* file exists */
2369 : else {
2370 : // If file not present it may be due to a run abort.
2371 : // As the file is based on the "tobe_backup" run number
2372 : // which is evaluated every lazy check, if a run is missing
2373 : // it will be skiped properly.
2374 : // No message is needed in this case.
2375 : // cm_msg(MERROR, "Lazy", "lazy_file_exists file %s doesn't exists", lazyst.backfile);
2376 0 : return NOTHING_TODO;
2377 : }
2378 :
2379 0 : if (status == EXIT_REQUEST)
2380 0 : exit_request = TRUE;
2381 :
2382 : //-PAA code moved at the end of "file exists condition" (above)
2383 : // cp_time = ss_millitime() - cp_time;
2384 : // donelist.push_back(dirlist[tobe_backup]);
2385 : // save_done_list(pLch->hKey, &donelist);
2386 : // lazy_log_update(NEW_FILE, lazyst.cur_run, lazy.backlabel, lazyst.backfile, cp_time);
2387 :
2388 0 : if (msg_flag)
2389 0 : cm_msg(MTALK, "Lazy", " lazy job %s done!", lazyst.backfile);
2390 :
2391 : /* generate/update a <channel>_recover.odb file when everything is Ok
2392 : after each file copy */
2393 : {
2394 0 : std::string str;
2395 : /* leave "list label" as it is, as long as the _recover.odb is loaded before
2396 : the lazylogger is started with NO -z things should be fine */
2397 : /* save the recover with "List Label" empty */
2398 0 : if (lazy.dir[strlen(lazy.dir) - 1] != DIR_SEPARATOR) {
2399 0 : str += lazy.dir;
2400 0 : str += DIR_SEPARATOR;
2401 0 : str += pLch->name;
2402 0 : str += "_recover.odb";
2403 : } else {
2404 0 : str += lazy.dir;
2405 0 : str += pLch->name;
2406 0 : str += "_recover.odb";
2407 : }
2408 :
2409 0 : db_save(hDB, pLch->hKey, str.c_str(), TRUE);
2410 0 : }
2411 :
2412 0 : if (exit_request)
2413 0 : return (FORCE_EXIT);
2414 0 : return NOTHING_TODO;
2415 0 : }
2416 :
2417 : /*------------------------------------------------------------------*/
2418 :
2419 0 : static void watch_settings(HNDLE hDB, HNDLE hKey, HNDLE index, void *info) {
2420 : int status;
2421 0 : assert(info != NULL);
2422 0 : HNDLE hSet = *(HNDLE *) info;
2423 0 : int size = sizeof(lazy);
2424 0 : status = db_get_record1(hDB, hSet, &lazy, &size, 0, LAZY_SETTINGS_STRING);
2425 0 : if (status != DB_SUCCESS) {
2426 0 : cm_msg(MINFO, "watch_settings", "db_get_record(settings) status %d", status);
2427 0 : return;
2428 : }
2429 :
2430 : // printf("Settings updated\n");
2431 :
2432 0 : if (lazy.pupercent != 0)
2433 0 : maintain_touched = TRUE;
2434 : else
2435 0 : maintain_touched = FALSE;
2436 :
2437 : //printf("pup %d, touched %d\n", lazy.pupercent, maintain_touched);
2438 : }
2439 :
2440 : /*------------------------------------------------------------------*/
2441 0 : int main(int argc, char **argv) {
2442 : char channel_name[32];
2443 : char host_name[HOST_NAME_LENGTH];
2444 : char expt_name[HOST_NAME_LENGTH];
2445 : BOOL daemon;
2446 : INT i, msg, size, status, mainlast_time;
2447 0 : DWORD last_time_kb = 0;
2448 0 : setbuf(stdout, NULL);
2449 0 : setbuf(stderr, NULL);
2450 :
2451 : /* set default */
2452 0 : host_name[0] = 0;
2453 0 : expt_name[0] = 0;
2454 0 : channel_name[0] = 0;
2455 0 : BOOL zap_flag = FALSE;
2456 0 : msg_flag = FALSE;
2457 0 : debug = daemon = FALSE;
2458 :
2459 : /* set default */
2460 0 : cm_get_environment(host_name, sizeof(host_name), expt_name, sizeof(expt_name));
2461 :
2462 : /* get parameters */
2463 0 : for (i = 1; i < argc; i++) {
2464 0 : if (argv[i][0] == '-' && argv[i][1] == 'd')
2465 0 : debug = TRUE;
2466 0 : else if (argv[i][0] == '-' && argv[i][1] == 'n')
2467 0 : nodelete = TRUE;
2468 0 : else if (argv[i][0] == '-' && argv[i][1] == 'D')
2469 0 : daemon = TRUE;
2470 0 : else if (strncmp(argv[i], "-C", 2) == 0)
2471 0 : convert_flag = TRUE;
2472 0 : else if (strncmp(argv[i], "-z", 2) == 0)
2473 0 : zap_flag = TRUE;
2474 0 : else if (strncmp(argv[i], "-t", 2) == 0)
2475 0 : msg_flag = TRUE;
2476 0 : else if (argv[i][0] == '-') {
2477 0 : if (i + 1 >= argc || argv[i + 1][0] == '-')
2478 0 : goto usage;
2479 0 : if (strncmp(argv[i], "-e", 2) == 0)
2480 0 : strcpy(expt_name, argv[++i]);
2481 0 : else if (strncmp(argv[i], "-h", 2) == 0)
2482 0 : strcpy(host_name, argv[++i]);
2483 0 : else if (strncmp(argv[i], "-c", 2) == 0)
2484 0 : strcpy(channel_name, argv[++i]);
2485 : } else {
2486 0 : usage:
2487 0 : printf("Lazylogger: Multi channel background data copier\n");
2488 0 : printf("\n");
2489 0 : printf("Usage: lazylogger [-d] [-n] [-D] [-h <Hostname>] [-e <Experiment>] [-z] [-t] [-C] -c <channel name>\n");
2490 0 : printf("\n");
2491 0 : printf("Options:\n");
2492 0 : printf(" -c <channel name> - specify lazylogger channel name\n");
2493 0 : printf(" -C - convert old-format done list to new file-based format\n");
2494 0 : printf(" -d - enable debug printout\n");
2495 0 : printf(" -n - do not delete any files (for testing \"Maintain free space\")\n");
2496 0 : printf(" -D - start as a daemon\n");
2497 0 : printf(" -h - connect to experiment on another machine\n");
2498 0 : printf(" -e - connect to non-default experiment\n");
2499 0 : printf(" -z - clear /Lazy/channel/Statistics\n");
2500 0 : printf(" -t - permit lazy logger to TALK (see mlxspeaker)\n");
2501 0 : printf("\n");
2502 0 : printf("Quick man :\n");
2503 0 : printf("The Lazy/Settings tree is composed of the following parameters:\n");
2504 0 : printf("Maintain free space (%%)(0): purge source device to maintain free space on the source directory\n");
2505 0 : printf(" (0) : no purge \n");
2506 0 : printf("Stay behind (0) : If negative number : lazylog runs starting from the OLDEST\n");
2507 0 : printf(" run file sitting in the 'Dir data' to the current acquisition\n");
2508 0 : printf(" run minus the 'Stay behind number'\n");
2509 0 : printf(" If positive number : lazylog starts from the current\n");
2510 0 : printf(" acquisition run minus 'Stay behind number' \n");
2511 0 : printf(" Zero : no stay-behind - files are saved as soon as they are closed\n");
2512 0 : printf("Alarm Class : Specify the Class to be used in case of Tape Full condition\n");
2513 0 : printf("Running condition : active/deactive lazylogger under given condition i.e:\n");
2514 0 : printf(" 'ALWAYS' (default) : Independent of the ACQ state ...\n");
2515 0 : printf(" 'NEVER' : ...\n");
2516 0 : printf(" 'WHILE_ACQ_NOT_RUNNING': ...\n");
2517 0 : printf(" '/alias/max_rate < 200' (max_rate is a link)\n");
2518 0 : printf(" '/equipment/scaler/variables/scal[4] < 23.45'\n");
2519 0 : printf(" '/equipment/trigger/statistics/events per sec. < 400'\n");
2520 0 : printf("Data dir : MIDAS Data Directory (same as \"/Logger/Data Dir\")\n");
2521 0 : printf("Data format : Data format (MIDAS)\n");
2522 0 : printf("Filename format : Run format i.e. \"run%%05d.mid\", or \"*.mid.gz\" or \"*.mid.gz,*.xml\" \n");
2523 0 : printf("List label : Label of destination save_set.\n");
2524 0 : printf(" Prevent lazylogger to run if not given.\n");
2525 0 : printf(" Will be reset if maximum capacity reached.\n");
2526 0 : printf("Execute after rewind : Execute the command <cmd> after rewind complete\n");
2527 0 : printf(" : args passed are: 'device path' 'channel name' 'list label'\n");
2528 0 : printf(" : The actual command will look like: <cmd> /dev/nst0 Tape Data_2000\n");
2529 0 : printf("Backup type : Destination device type (Disk, Tape, Script, SFTP, FTP)\n");
2530 0 : printf("Path : Destination path (file.ext, /dev/nst0, ftp...)\n");
2531 0 : printf(" in case of SFTP type, the 'Path' entry should be:\n");
2532 0 : printf(" sftp://username@host/path\n");
2533 0 : printf(" in case of FTP type, the 'Path' entry should be:\n");
2534 0 : printf(" host, port, user, password, directory, run%%05d.mid\n");
2535 0 : printf("Capacity (Bytes) : Maximum capacity of the destination device.\n");
2536 0 : printf("modulo : Enable multiple lazy on same source. Ex: 3ch : 3.0, 3.1, 3.2\n");
2537 0 : printf("tapeAppend : Enable positioning of the TAPE to EOD before each lazy copy\n");
2538 0 : return 1;
2539 : }
2540 : }
2541 :
2542 : /* Handle SIGPIPE signals generated from errors on the pipe */
2543 : #ifdef SIGPIPE
2544 0 : signal(SIGPIPE, SIG_IGN);
2545 : #endif
2546 0 : if (daemon) {
2547 0 : printf("Becoming a daemon...\n");
2548 0 : ss_daemon_init(FALSE);
2549 : }
2550 :
2551 : /* connect to experiment */
2552 0 : status = cm_connect_experiment1(host_name, expt_name, "Lazy", 0, DEFAULT_ODB_SIZE, WATCHDOG_TIMEOUT);
2553 0 : if (status != CM_SUCCESS)
2554 0 : return 1;
2555 :
2556 : /* create a common semaphore for the independent lazylogger */
2557 0 : status = ss_semaphore_create("LAZY", &lazy_semaphore);
2558 :
2559 : /* check lazy status for multiple channels */
2560 0 : cm_get_experiment_database(&hDB, &hKey);
2561 0 : if (db_find_key(hDB, 0, "/Lazy", &hKey) == DB_SUCCESS) {
2562 : HNDLE hSubkey;
2563 : KEY key;
2564 0 : INT j = 0;
2565 0 : for (i = 0;; i++) {
2566 0 : db_enum_key(hDB, hKey, i, &hSubkey);
2567 0 : if (!hSubkey)
2568 0 : break;
2569 0 : db_get_key(hDB, hSubkey, &key);
2570 0 : if (key.type == TID_KEY) {
2571 : /* compose client name */
2572 0 : std::string strclient;
2573 0 : strclient += "Lazy_";
2574 0 : strclient += key.name;
2575 0 : if (cm_exist(strclient.c_str(), TRUE) == CM_SUCCESS)
2576 0 : lazyinfo[j].active = TRUE;
2577 : else
2578 0 : lazyinfo[j].active = FALSE;
2579 0 : strcpy(lazyinfo[j].name, key.name);
2580 :
2581 0 : lazyinfo[j].hKey = hSubkey;
2582 0 : j++;
2583 0 : }
2584 0 : }
2585 : } else {
2586 : /* create settings tree */
2587 0 : channel = 0;
2588 0 : if (channel_name[0] != 0)
2589 0 : mstrlcpy(lazyinfo[channel].name, channel_name, sizeof(lazyinfo[channel].name));
2590 0 : std::string str;
2591 0 : str += "/Lazy/";
2592 0 : str += lazyinfo[channel].name;
2593 0 : str += "/Settings";
2594 0 : db_create_record(hDB, 0, str.c_str(), LAZY_SETTINGS_STRING);
2595 0 : }
2596 :
2597 : { /* Selection of client */
2598 : INT i, j;
2599 : char str[32];
2600 :
2601 0 : if (lazyinfo[0].hKey) {
2602 0 : if (channel_name[0] == 0) {
2603 : /* command prompt */
2604 0 : printf(" Available Lazy channels to connect to:\n");
2605 0 : i = 0;
2606 0 : j = 1;
2607 0 : while (lazyinfo[i].hKey) {
2608 0 : if (!lazyinfo[i].active)
2609 0 : printf("%d) Lazy %s \n", j, lazyinfo[i].name);
2610 : else
2611 0 : printf(".) Lazy %s already active\n", lazyinfo[i].name);
2612 0 : j++;
2613 0 : i++;
2614 : }
2615 0 : printf("Enter client number or new lazy client name: ");
2616 0 : i = atoi(ss_gets(str, 32));
2617 0 : if ((i == 0) && ((strlen(str) == 0) || (strncmp(str, " ", 1) == 0))) {
2618 0 : cm_msg(MERROR, "Lazy", "Please specify a valid channel name (%s)", str);
2619 0 : cm_disconnect_experiment();
2620 0 : return 1;
2621 : }
2622 : } else {
2623 : /* Skip the command prompt for serving the -c option */
2624 : /*
2625 : scan if channel_name already exists
2626 : Yes : check if client is running
2627 : Yes : get out (goto error)
2628 : No : connect (extract index)
2629 : No : new channel (i=0)
2630 : */
2631 0 : i = 0;
2632 0 : j = -1;
2633 0 : while (lazyinfo[i].hKey) {
2634 0 : if (equal_ustring(channel_name, lazyinfo[i].name)) {
2635 : /* correct name => check active */
2636 0 : if (lazyinfo[i].active) {
2637 0 : cm_msg(MERROR, "Lazy", "Lazy channel "
2638 : "%s"
2639 : " already running!",
2640 0 : lazyinfo[i].name);
2641 0 : cm_disconnect_experiment();
2642 0 : return 1;
2643 : }
2644 0 : j = i;
2645 : }
2646 0 : i++;
2647 : }
2648 0 : if (j == -1) {
2649 : /* new entry */
2650 0 : i = 0;
2651 0 : mstrlcpy(str, channel_name, sizeof(str));
2652 : } else {
2653 : /* connect to */
2654 0 : i = j + 1;
2655 : }
2656 : }
2657 :
2658 0 : if (i == 0) { /* new entry */
2659 0 : for (j = 0; j < MAX_LAZY_CHANNEL; j++) {
2660 0 : if (lazyinfo[j].hKey == 0) {
2661 : /* compose client name */
2662 0 : std::string strclient;
2663 0 : strclient += "Lazy_";
2664 0 : strclient += str;
2665 0 : if (cm_exist(strclient.c_str(), TRUE) == CM_SUCCESS)
2666 0 : lazyinfo[j].active = TRUE;
2667 : else
2668 0 : lazyinfo[j].active = FALSE;
2669 0 : strcpy(lazyinfo[j].name, str);
2670 0 : lazyinfo[j].hKey = 0;
2671 0 : channel = j;
2672 0 : break;
2673 0 : }
2674 : }
2675 0 : } else if (!lazyinfo[i - 1].active)
2676 0 : channel = i - 1;
2677 : else
2678 0 : channel = -1;
2679 : }
2680 :
2681 0 : if (channel < 0) {
2682 0 : cm_disconnect_experiment();
2683 0 : return 1;
2684 : }
2685 :
2686 : { /* creation of the lazy channel */
2687 : char str[128];
2688 :
2689 0 : if (lazyinfo[channel].hKey == 0)
2690 0 : printf(" Creating Lazy channel %s\n", lazyinfo[channel].name);
2691 :
2692 : /* create/update settings */
2693 0 : sprintf(str, "/Lazy/%s/Settings", lazyinfo[channel].name);
2694 0 : db_create_record(hDB, 0, str, LAZY_SETTINGS_STRING);
2695 : /* create/update statistics */
2696 0 : sprintf(str, "/Lazy/%s/Statistics", lazyinfo[channel].name);
2697 0 : db_create_record(hDB, 0, str, LAZY_STATISTICS_STRING);
2698 0 : sprintf(str, "/Lazy/%s", lazyinfo[channel].name);
2699 0 : db_find_key(hDB, 0, str, &lazyinfo[channel].hKey);
2700 : }
2701 : }
2702 : /* disconnect from experiment */
2703 0 : cm_disconnect_experiment();
2704 :
2705 : { /* reconnect to experiment with proper name */
2706 0 : std::string str;
2707 0 : str += "Lazy_";
2708 0 : str += lazyinfo[channel].name;
2709 0 : status = cm_connect_experiment1(host_name, expt_name, str.c_str(), 0, DEFAULT_ODB_SIZE, WATCHDOG_TIMEOUT);
2710 0 : }
2711 0 : if (status != CM_SUCCESS) {
2712 0 : cm_disconnect_experiment();
2713 0 : return 1;
2714 : }
2715 :
2716 0 : cm_get_experiment_database(&hDB, &hKey);
2717 :
2718 0 : int max_event_size = DEFAULT_MAX_EVENT_SIZE;
2719 :
2720 0 : size = sizeof(max_event_size);
2721 0 : status = db_get_value(hDB, 0, "/Experiment/MAX_EVENT_SIZE", &max_event_size, &size, TID_DWORD, TRUE);
2722 :
2723 : /* Remove temporary Lazy entry */
2724 : {
2725 : HNDLE hPkey;
2726 :
2727 0 : status = db_find_key(hDB, 0, "Programs/Lazy", &hPkey);
2728 0 : if (status == DB_SUCCESS) {
2729 0 : status = db_delete_key(hDB, hPkey, FALSE);
2730 0 : if (status != DB_SUCCESS) {
2731 0 : cm_msg(MERROR, "Lazy", "Cannot delete /Programs/Lazy");
2732 : }
2733 : }
2734 : }
2735 :
2736 : /* turn on keepalive messages with increased timeout */
2737 0 : if (debug)
2738 0 : cm_set_watchdog_params(TRUE, 0);
2739 :
2740 : #ifdef HAVE_FTPLIB
2741 0 : if (debug)
2742 0 : ftp_debug((int (*)(const char *)) puts, (int (*)(const char *)) puts);
2743 : #endif
2744 :
2745 0 : printf("Lazy_%s starting... "
2746 : "!"
2747 : " to exit \n",
2748 0 : lazyinfo[channel].name);
2749 :
2750 0 : if (zap_flag) {
2751 : /* reset the statistics */
2752 0 : cm_msg(MINFO, "Lazy", "zapping %s/statistics content", lazyinfo[channel].name);
2753 0 : size = sizeof(lazyst);
2754 0 : memset(&lazyst, 0, size);
2755 0 : if (db_find_key(hDB, lazyinfo[channel].hKey, "Statistics", &hKeyst) == DB_SUCCESS)
2756 0 : status = db_set_record(hDB, hKeyst, &lazyst, size, 0);
2757 : else
2758 0 : cm_msg(MERROR, "Lazy", "did not find %s/Statistics for zapping", lazyinfo[channel].name);
2759 : }
2760 :
2761 : /* get value once & hot links the run state */
2762 0 : db_find_key(hDB, 0, "/runinfo/state", &hKey);
2763 0 : size = sizeof(run_state);
2764 0 : db_get_data(hDB, hKey, &run_state, &size, TID_INT);
2765 0 : status = db_open_record(hDB, hKey, &run_state, sizeof(run_state), MODE_READ, NULL, NULL); // watch a TID_INT
2766 0 : if (status != DB_SUCCESS) {
2767 0 : cm_msg(MERROR, "Lazy", "cannot open /runinfo/state record");
2768 : }
2769 : /* hot link for statistics in write mode */
2770 0 : size = sizeof(lazyst);
2771 0 : if (db_find_key(hDB, lazyinfo[channel].hKey, "Statistics", &hKey) == DB_SUCCESS) {
2772 0 : db_get_record1(hDB, hKey, &lazyst, &size, 0, LAZY_STATISTICS_STRING);
2773 : }
2774 0 : status = db_open_record1(hDB, hKey, &lazyst, sizeof(lazyst), MODE_WRITE, NULL, NULL, LAZY_STATISTICS_STRING);
2775 0 : if (status == DB_NO_ACCESS) {
2776 : /* record is probably still in exclusive access by dead FE, so reset it */
2777 0 : status = db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
2778 0 : if (status != DB_SUCCESS)
2779 0 : cm_msg(MERROR, "Lazy", "Cannot change access mode for %s/Statistics record, error %d", lazyinfo[channel].name,
2780 : status);
2781 : else
2782 0 : cm_msg(MINFO, "Lazy", "Recovered access mode for %s/Statistics record", lazyinfo[channel].name);
2783 0 : status = db_open_record1(hDB, hKey, &lazyst, sizeof(lazyst), MODE_WRITE, NULL, NULL, LAZY_STATISTICS_STRING);
2784 : }
2785 0 : if (status != DB_SUCCESS) {
2786 0 : cm_msg(MERROR, "Lazy", "cannot open %s/Statistics record", lazyinfo[channel].name);
2787 : }
2788 : /* get /settings once & hot link settings in read mode */
2789 0 : db_find_key(hDB, lazyinfo[channel].hKey, "Settings", &hKey);
2790 :
2791 0 : size = sizeof(lazy);
2792 0 : status = db_get_record1(hDB, hKey, &lazy, &size, 0, LAZY_SETTINGS_STRING);
2793 0 : if (status != DB_SUCCESS) {
2794 0 : cm_msg(MERROR, "Lazy", "cannot get %s/Settings record, db_get_record() status %d", lazyinfo[channel].name,
2795 : status);
2796 : }
2797 :
2798 0 : status = db_watch(hDB, hKey, watch_settings, &hKey);
2799 0 : if (status != DB_SUCCESS) {
2800 0 : cm_msg(MERROR, "Lazy", "cannot open %s/Settings record", lazyinfo[channel].name);
2801 : }
2802 :
2803 : /* set global key for that channel */
2804 0 : pcurrent_hKey = lazyinfo[channel].hKey;
2805 :
2806 : /* set Data dir from /logger if local is empty & /logger exists */
2807 0 : if ((lazy.dir[0] == '\0') && (db_find_key(hDB, 0, "/Logger/Data dir", &hKey) == DB_SUCCESS)) {
2808 0 : size = sizeof(lazy.dir);
2809 0 : db_get_data(hDB, hKey, lazy.dir, &size, TID_STRING);
2810 0 : db_set_value(hDB, lazyinfo[channel].hKey, "Settings/Data dir", lazy.dir, size, 1, TID_STRING);
2811 : }
2812 :
2813 : // Register for STOP transition
2814 0 : if (cm_register_transition(TR_STOP, lazy_trstop, 810) != CM_SUCCESS) {
2815 0 : printf("Failed to start local RPC server");
2816 0 : cm_disconnect_experiment();
2817 :
2818 : /* let user read message before window might close */
2819 0 : ss_sleep(5000);
2820 0 : return 1;
2821 : }
2822 :
2823 0 : mainlast_time = 0;
2824 :
2825 : /* initialize ss_getchar() */
2826 0 : ss_getchar(0);
2827 :
2828 0 : DWORD period = lazy.period * 1000;
2829 :
2830 0 : int ch = 0;
2831 :
2832 : do {
2833 0 : msg = cm_yield(2000);
2834 0 : if (period < 1)
2835 0 : period = 1;
2836 0 : if ((ss_millitime() - mainlast_time) > period) {
2837 0 : status = lazy_main(channel, &lazyinfo[0], max_event_size);
2838 0 : if (status == FORCE_EXIT) {
2839 0 : cm_msg(MERROR, "lazy", "Exit requested by program");
2840 0 : break;
2841 : }
2842 0 : mainlast_time = ss_millitime();
2843 0 : if (status == TRY_LATER) {
2844 0 : period *= 2;
2845 0 : DWORD max_period = 30 * 60 * 1000;
2846 0 : if (period > max_period)
2847 0 : period = max_period;
2848 0 : cm_msg(MINFO, "lazy", "Will try again after %d seconds", period);
2849 : } else {
2850 0 : period = lazy.period * 1000;
2851 : }
2852 : }
2853 :
2854 : /* check keyboard once every 100 ms */
2855 0 : if (ss_millitime() - last_time_kb > 100) {
2856 0 : last_time_kb = ss_millitime();
2857 :
2858 0 : ch = 0;
2859 0 : while (ss_kbhit()) {
2860 0 : ch = ss_getchar(0);
2861 0 : if (ch == -1)
2862 0 : ch = getchar();
2863 0 : if ((char) ch == '!')
2864 0 : break;
2865 : }
2866 : }
2867 0 : } while (msg != RPC_SHUTDOWN && msg != SS_ABORT && ch != '!');
2868 :
2869 0 : cm_disconnect_experiment();
2870 0 : return 1;
2871 : }
2872 :
2873 : /* emacs
2874 : * Local Variables:
2875 : * tab-width: 8
2876 : * c-basic-offset: 3
2877 : * indent-tabs-mode: nil
2878 : * End:
2879 : */
|