LCOV - code coverage report
Current view: top level - progs - lazylogger.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 1347 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 35 0

            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              :  */
        

Generated by: LCOV version 2.0-1