00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "midas.h"
00011 #include "msystem.h"
00012
00013 #ifdef HAVE_FTPLIB
00014 #include "ftplib.h"
00015 #endif
00016
00017 #include <mdsupport.h>
00018 #include <assert.h>
00019
00020 #include <vector>
00021 #include <string>
00022 #include <algorithm>
00023
00024 #define NOTHING_TODO 0
00025 #define FORCE_EXIT 1
00026 #define EXIT_REQUEST 2
00027 #define NEW_FILE 1
00028 #define REMOVE_FILE 2
00029 #define REMOVE_ENTRY 3
00030 #define MAX_LAZY_CHANNEL 100
00031 #define TRACE
00032 #define LOG_TYPE_SCRIPT (-1)
00033
00034 #define STRLCPY(dst, src) strlcpy((dst), (src), sizeof(dst))
00035
00036 BOOL debug = FALSE;
00037 BOOL nodelete = FALSE;
00038
00039 typedef struct {
00040 std::string filename;
00041 INT runno;
00042 double size;
00043 } DIRLOG;
00044
00045 typedef std::vector<DIRLOG> DIRLOGLIST;
00046
00047 bool cmp_dirlog1(const DIRLOG&a, const DIRLOG&b)
00048 {
00049 if (a.runno < b.runno)
00050 return true;
00051
00052 if (a.runno > b.runno)
00053 return false;
00054
00055 const char* sa = a.filename.c_str();
00056 const char* sb = b.filename.c_str();
00057
00058 while (1) {
00059 if (*sa == 0)
00060 return true;
00061
00062 if (*sb == 0)
00063 return false;
00064
00065
00066
00067 if (*sa < *sb)
00068 return true;
00069
00070 if (*sa > *sb)
00071 return false;
00072
00073
00074
00075 if (isdigit(*sa)) {
00076 int ia = strtoul(sa, (char**)&sa, 10);
00077 int ib = strtoul(sb, (char**)&sb, 10);
00078
00079
00080
00081 if (ia < ib)
00082 return true;
00083
00084 if (ia > ib)
00085 return false;
00086
00087
00088 continue;
00089 }
00090
00091 sa++;
00092 sb++;
00093 }
00094
00095 }
00096
00097 bool cmp_dirlog(const DIRLOG&a, const DIRLOG&b)
00098 {
00099 bool r = cmp_dirlog1(a,b);
00100
00101 return r;
00102 }
00103
00104 #ifndef MAX_FILE_PATH
00105 #define MAX_FILE_PATH 128 // must match value of 128 in LAZY_SETTINGS_STRING
00106 #endif
00107
00108 #define LAZY_SETTINGS_STRING "\
00109 Period = INT : 10\n\
00110 Maintain free space (%) = INT : 0\n\
00111 Stay behind = INT : 0\n\
00112 Alarm Class = STRING : [32]\n\
00113 Running condition = STRING : [128] ALWAYS\n\
00114 Data dir = STRING : [256] \n\
00115 Data format = STRING : [8] MIDAS\n\
00116 Filename format = STRING : [128] run%05d.mid\n\
00117 Backup type = STRING : [8] Tape\n\
00118 Execute after rewind = STRING : [64]\n\
00119 Path = STRING : [128] \n\
00120 Capacity (Bytes) = FLOAT : 5e9\n\
00121 List label= STRING : [128] \n\
00122 Execute before writing file = STRING : [64]\n\
00123 Execute after writing file = STRING : [64]\n\
00124 Modulo.Position = STRING : [8]\n\
00125 Tape Data Append = BOOL : y\n\
00126 "
00127 #define LAZY_STATISTICS_STRING "\
00128 Backup file = STRING : [128] none \n\
00129 File size (Bytes) = DOUBLE : 0.0\n\
00130 KBytes copied = DOUBLE : 0.0\n\
00131 Total Bytes copied = DOUBLE : 0.0\n\
00132 Copy progress (%) = DOUBLE : 0\n\
00133 Copy Rate (Bytes per s) = DOUBLE : 0\n\
00134 Backup status (%) = DOUBLE : 0\n\
00135 Number of Files = INT : 0\n\
00136 Current Lazy run = INT : 0\n\
00137 "
00138
00139 typedef struct {
00140 INT period;
00141 INT pupercent;
00142 INT staybehind;
00143
00144 char alarm[32];
00145 char condition[128];
00146 char dir[256];
00147 char format[8];
00148 char backfmt[MAX_FILE_PATH];
00149 char type[8];
00150 char command[64];
00151 char path[MAX_FILE_PATH];
00152 float capacity;
00153 char backlabel[MAX_FILE_PATH];
00154 char commandBefore[64];
00155 char commandAfter[64];
00156 char modulo[8];
00157 BOOL tapeAppend;
00158 } LAZY_SETTING;
00159 LAZY_SETTING lazy;
00160
00161 typedef struct {
00162 char backfile[MAX_FILE_PATH];
00163 double file_size;
00164 double cur_size;
00165 double cur_dev_size;
00166 double progress;
00167 double copy_rate;
00168 double bckfill;
00169 INT nfiles;
00170 INT cur_run;
00171 } LAZY_STATISTICS;
00172 LAZY_STATISTICS lazyst;
00173
00174
00175 typedef struct {
00176 HNDLE hKey;
00177 BOOL active;
00178 char name[32];
00179 } LAZY_INFO;
00180
00181 LAZY_INFO lazyinfo[MAX_LAZY_CHANNEL] = { {0, FALSE, "Tape"} };
00182
00183 INT channel = -1;
00184
00185
00186 INT lazy_semaphore;
00187 HNDLE hDB, hKey, pcurrent_hKey;
00188 double lastsz;
00189 HNDLE hKeyst;
00190 INT run_state, hDev;
00191 BOOL msg_flag;
00192 BOOL copy_continue = TRUE;
00193 INT data_fmt, dev_type;
00194 char lazylog[MAX_STRING_LENGTH];
00195 BOOL full_bck_flag = FALSE, maintain_touched = FALSE;
00196 INT blockn = 0;
00197
00198 #define WATCHDOG_TIMEOUT 60000
00199
00200
00201 INT moduloCheck(INT lModulo, INT lPosition, INT lrun);
00202 BOOL lazy_file_exists(char *dir, char *file);
00203 INT lazy_main(INT, LAZY_INFO *);
00204 INT lazy_copy(char *dev, char *file);
00205 INT lazy_load_params(HNDLE hDB, HNDLE hKey);
00206 INT build_log_list(const char *fmt, const char *dir, DIRLOGLIST *plog);
00207 INT build_done_list_odb(HNDLE, INT **);
00208 void lazy_settings_hotlink(HNDLE hDB, HNDLE hKey, void *info);
00209 void lazy_maintain_check(HNDLE hKey, LAZY_INFO * pLall);
00210
00211 void print_dirlog(const DIRLOGLIST* dirlog)
00212 {
00213 for (unsigned i=0; i<dirlog->size(); i++)
00214 printf("%d: %s, run %d, size %12.0f\n",
00215 i,
00216 (*dirlog)[i].filename.c_str(),
00217 (*dirlog)[i].runno,
00218 (*dirlog)[i].size);
00219 };
00220
00221
00222 INT lazy_run_extract(const char *name)
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 {
00235 #if 0
00236 char run_str[256];
00237 int j;
00238
00239 strlcpy(run_str, name, sizeof(run_str));
00240 if (strlen(run_str) < 2)
00241 return 0;
00242
00243 for (j = strlen(run_str) - 1; j >= 0 && !isdigit(run_str[j]); j--)
00244 run_str[j] = 0;
00245
00246 for (j = strlen(run_str) - 1; j >= 0 && isdigit(run_str[j]); j--);
00247
00248 return atoi(run_str + j + 1);
00249 #endif
00250
00251 while (*name && !isdigit(*name))
00252 name++;
00253
00254 if (*name == 0)
00255 return 0;
00256
00257 return atoi(name);
00258 }
00259
00260
00261 INT lazy_file_remove(const char *pufile)
00262 {
00263 INT fHandle, status;
00264
00265 if (nodelete) {
00266 printf("lazy_file_remove: running in nodelete mode (-n switch), will not remove \'%s\'\n", pufile);
00267 return !SS_SUCCESS;
00268 }
00269
00270
00271 fHandle = open(pufile, O_RDONLY, 0644);
00272 if (fHandle == -1)
00273 return SS_INVALID_NAME;
00274
00275 close(fHandle);
00276
00277 status = ss_file_remove((char*)pufile);
00278 if (status != 0)
00279 return SS_FILE_ERROR;
00280 return SS_SUCCESS;
00281 }
00282
00283
00284 INT lazy_log_update(INT action, INT run, const char *label, const char *file, DWORD perf_time)
00285 {
00286 char str[MAX_FILE_PATH];
00287 INT blocks;
00288
00289 strcpy(str, "no action");
00290
00291
00292 if (action == NEW_FILE) {
00293
00294 lazyst.nfiles++;
00295
00296 if (equal_ustring(lazy.type, "FTP"))
00297 sprintf(str, "%s: (cp:%.1fs) %s %1.3lfMB file COPIED",
00298 label, (double) perf_time / 1000., lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
00299 else if (equal_ustring(lazy.type, "Script")) {
00300 sprintf(str, "%s[%i] (cp:%.1fs) %s %1.3lfMB file NEW",
00301 label, lazyst.nfiles, (double) perf_time / 1000., lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
00302 } else if (equal_ustring(lazy.type, "Disk")) {
00303 if (lazy.path[0] != 0)
00304 if (lazy.path[strlen(lazy.path) - 1] != DIR_SEPARATOR)
00305 strcat(lazy.path, DIR_SEPARATOR_STR);
00306 sprintf(str, "%s[%i] (cp:%.1fs) %s%s %1.3lfMB file NEW",
00307 label, lazyst.nfiles, (double) perf_time / 1000.,
00308 lazy.path, lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0);
00309 } else if (equal_ustring(lazy.type, "Tape")) {
00310 blocks = (int) (lazyst.cur_dev_size / 32.0 / 1024.0) + lazyst.nfiles;
00311
00312 sprintf(str, "%s[%i] (cp:%.1fs) %s/%s %1.3lfMB file NEW (position at block %d)",
00313 label, lazyst.nfiles, (double) perf_time / 1000.,
00314 lazy.path, lazyst.backfile, lazyst.file_size / 1024.0 / 1024.0, blockn);
00315 if (lazy.commandAfter[0]) {
00316 char cmd[256];
00317 sprintf(cmd, "%s %s %i %s/%s %1.3lf %d", lazy.commandAfter,
00318 lazy.backlabel, lazyst.nfiles, lazy.path, lazyst.backfile,
00319 lazyst.file_size / 1024.0 / 1024.0, blockn);
00320 cm_msg(MINFO, "Lazy", "Exec post file write script:%s", cmd);
00321 ss_system(cmd);
00322 }
00323 }
00324 } else if (action == REMOVE_FILE)
00325 sprintf(str, "%i (rm:%dms) %s file REMOVED", run, perf_time, file);
00326
00327 else if (action == REMOVE_ENTRY)
00328 sprintf(str, "%s run#%i entry REMOVED", label, run);
00329
00330 #ifdef WRITE_MIDAS_LOG
00331 cm_msg(MINFO, "lazy_log_update", str);
00332 #endif
00333
00334 cm_msg1(MINFO, "lazy", "lazy_log_update", str);
00335
00336 return 0;
00337 }
00338
00339
00340 INT moduloCheck(INT lModulo, INT lPosition, INT lrun)
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 {
00353 if (lModulo) {
00354 if ((lrun % lModulo) == lPosition)
00355 return lrun;
00356 else
00357 return 0;
00358 } else
00359 return lrun;
00360 }
00361
00362
00363 INT build_log_list(const char *fmt, const char *xdir, DIRLOGLIST *dlist)
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 {
00376 char str[MAX_FILE_PATH];
00377 char dir[MAX_FILE_PATH];
00378 char *dot;
00379 int lModulo = 0, lPosition = 0;
00380
00381 strlcpy(dir, xdir, sizeof(dir));
00382
00383 while (fmt) {
00384
00385 STRLCPY(str, fmt);
00386
00387 fmt = strchr(fmt, ',');
00388 if (fmt)
00389 fmt++;
00390
00391 char*s = strchr(str, ',');
00392 if (s)
00393 *s = 0;
00394
00395 if (strchr(str, '%')) {
00396 *strchr(str, '%') = '*';
00397 if (strchr(str, '.'))
00398 strcpy((strchr(str, '*') + 1), strchr(str, '.'));
00399 }
00400
00401 char *list = NULL;
00402
00403
00404 int nfile = ss_file_find(dir, str, &list);
00405
00406
00407
00408
00409
00410
00411
00412 std::vector<std::string> flist;
00413 for (int j=0;j<nfile;j++)
00414 flist.push_back(list+j*MAX_STRING_LENGTH);
00415
00416 free(list);
00417
00418
00419 if (lazy.modulo[0]) {
00420
00421 dot = strchr(lazy.modulo, '.');
00422 if (dot) {
00423 *dot = '\0';
00424 lModulo = atoi(lazy.modulo);
00425 lPosition = atoi(dot + 1);
00426 *dot = '.';
00427 }
00428 }
00429
00430
00431 for (unsigned j = 0, l = 0; j < flist.size(); j++) {
00432 INT lrun;
00433
00434 lrun = lazy_run_extract((char*)flist[j].c_str());
00435
00436 lrun = moduloCheck(lModulo, lPosition, lrun);
00437
00438 if (lrun == 0)
00439 continue;
00440
00441 std::string s = dir;
00442 s += flist[j];
00443
00444 DIRLOG d;
00445 d.filename = flist[j];
00446 d.runno = lrun;
00447 d.size = ss_file_size((char*)s.c_str());
00448
00449 dlist->push_back(d);
00450
00451 l++;
00452 }
00453 }
00454
00455 sort(dlist->begin(), dlist->end(), cmp_dirlog);
00456
00457 return dlist->size();
00458 }
00459
00460
00461 INT build_done_list_odb(HNDLE hLch, INT ** pdo)
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472 {
00473 HNDLE hKey, hSubkey;
00474 KEY key;
00475 INT i, j, size, tot_nelement, nelement, temp;
00476
00477 if (db_find_key(hDB, hLch, "List", &hKey) != DB_SUCCESS) {
00478 return 0;
00479 }
00480
00481 tot_nelement = 0;
00482 for (i = 0;; i++) {
00483 db_enum_key(hDB, hKey, i, &hSubkey);
00484 if (!hSubkey)
00485 break;
00486 db_get_key(hDB, hSubkey, &key);
00487 nelement = key.num_values;
00488 *pdo = (INT*)realloc(*pdo, sizeof(INT)*(tot_nelement + nelement));
00489 size = nelement * sizeof(INT);
00490 db_get_data(hDB, hSubkey, (char *) (*pdo + tot_nelement), &size, TID_INT);
00491 tot_nelement += nelement;
00492 }
00493
00494 if (0) {
00495 printf("read pdo: %d\n", tot_nelement);
00496 for (i=0; i<tot_nelement; i++)
00497 printf("%d: %d\n", i, (*pdo)[i]);
00498 }
00499
00500
00501 for (i=0; i<tot_nelement; i++)
00502 if ((*pdo)[i] < 0) {
00503 int first = (*pdo)[i-1];
00504 int last = -(*pdo)[i];
00505 int nruns = last - first + 1;
00506 assert(nruns > 1);
00507
00508 *pdo = (INT*)realloc(*pdo, sizeof(INT)*(tot_nelement + nruns - 2));
00509 assert(*pdo != NULL);
00510
00511 memmove((*pdo) + i + nruns -1, (*pdo) + i + 1, sizeof(INT)*(tot_nelement - i - 1));
00512
00513 for (j=1; j<nruns; j++)
00514 (*pdo)[i+j-1] = first + j;
00515
00516 tot_nelement += nruns - 2;
00517 }
00518
00519 if (0) {
00520 printf("uncompressed pdo: %d\n", tot_nelement);
00521 for (i=0; i<tot_nelement; i++)
00522 printf("%d: %d\n", i, (*pdo)[i]);
00523 }
00524
00525
00526 for (j = 0; j < tot_nelement - 1; j++) {
00527 for (i = j + 1; i < tot_nelement; i++) {
00528 if (*(*pdo + j) > *(*pdo + i)) {
00529 memcpy(&temp, (*pdo + i), sizeof(INT));
00530 memcpy((*pdo + i), (*pdo + j), sizeof(INT));
00531 memcpy((*pdo + j), &temp, sizeof(INT));
00532 }
00533 }
00534 }
00535
00536 if (0) {
00537 printf("sorted pdo: %d\n", tot_nelement);
00538 for (i=0; i<tot_nelement; i++)
00539 printf(" %d\n", (*pdo)[i]);
00540 }
00541
00542 return tot_nelement;
00543 }
00544
00545 std::string list_filename(const char* lazyname, const char* listname)
00546 {
00547 char path[256];
00548 cm_get_path(path);
00549
00550 std::string s;
00551 s += path;
00552 s += ".Lazy_";
00553 s += lazyname;
00554 s += ".";
00555 s += listname;
00556 return s;
00557 }
00558
00559 void load_done_list(const char* lazyname, const DIRLOGLIST* dirlist, DIRLOGLIST* dlist)
00560 {
00561 FILE *fp = fopen(list_filename(lazyname, "donelist").c_str(), "r");
00562 if (!fp)
00563 return;
00564
00565 while (1) {
00566 char str[256];
00567 char* s = fgets(str, sizeof(str), fp);
00568 if (!s)
00569 break;
00570
00571 DIRLOG d;
00572
00573 char* p = strchr(s, ' ');
00574
00575 if (p) {
00576 *p = 0;
00577 p++;
00578 }
00579
00580 d.filename = s;
00581 d.runno = strtoul(p, &p, 0);
00582 d.size = strtod(p, &p);
00583
00584 bool found = false;
00585 if (dirlist) {
00586 for (unsigned i=0; i<dirlist->size(); i++)
00587 if ((*dirlist)[i].filename == d.filename) {
00588 found = true;
00589 break;
00590 }
00591 }
00592 else
00593 found = true;
00594
00595 if (found)
00596 dlist->push_back(d);
00597 }
00598
00599 fclose(fp);
00600
00601 sort(dlist->begin(), dlist->end(), cmp_dirlog);
00602 }
00603
00604 int save_list(const char* lazyname, const char* listname, const DIRLOGLIST* dlist)
00605 {
00606 std::string fname = list_filename(lazyname, listname);
00607 std::string tmpname = fname + ".tmp";
00608
00609 FILE *fp = fopen(tmpname.c_str(), "w");
00610 if (!fp) {
00611 cm_msg(MERROR, "save_list", "Cannot write to \'%s\', errno %d (%s)",
00612 tmpname.c_str(),
00613 errno,
00614 strerror(errno));
00615 return !SUCCESS;
00616 }
00617
00618 for (unsigned i=0; i<dlist->size(); i++) {
00619 const char* s = (*dlist)[i].filename.c_str();
00620 const char* p;
00621 while ((p = strchr(s, DIR_SEPARATOR)))
00622 s = p+1;
00623 fprintf(fp, "%s %d %12.0f\n",
00624 s,
00625 (*dlist)[i].runno,
00626 (*dlist)[i].size
00627 );
00628 }
00629
00630 fclose(fp);
00631
00632 int status = rename(tmpname.c_str(), fname.c_str());
00633 if (status) {
00634 cm_msg(MERROR, "save_list", "Cannot rename \'%s\' to \'%s\', errno %d (%s)",
00635 tmpname.c_str(),
00636 fname.c_str(),
00637 errno,
00638 strerror(errno));
00639 return !SUCCESS;
00640 }
00641
00642 return SUCCESS;
00643 }
00644
00645
00646 void convert_done_list(HNDLE hLch)
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 {
00658 DIRLOGLIST dlist;
00659 build_log_list(lazy.backfmt, lazy.dir, &dlist);
00660
00661 INT *pdo = NULL;
00662 int n = build_done_list_odb(hLch, &pdo);
00663
00664 DIRLOGLIST done;
00665
00666 for (int i=0; i<n; i++)
00667 for (unsigned j=0; j<dlist.size(); j++)
00668 if (dlist[j].runno == pdo[i])
00669 done.push_back(dlist[j]);
00670
00671 free(pdo);
00672
00673 KEY key;
00674 int status = db_get_key(hDB, hLch, &key);
00675 assert(status == DB_SUCCESS);
00676
00677 save_list(key.name, "donelist", &done);
00678 }
00679
00680
00681 INT build_done_list(HNDLE hLch, const DIRLOGLIST *pdirlist, DIRLOGLIST *pdone)
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 {
00693 KEY key;
00694 int status = db_get_key(hDB, hLch, &key);
00695 assert(status == DB_SUCCESS);
00696
00697 load_done_list(key.name, pdirlist, pdone);
00698
00699 if (pdone->size() == 0) {
00700 convert_done_list(hLch);
00701 load_done_list(key.name, pdirlist, pdone);
00702 }
00703
00704 return pdone->size();
00705 }
00706
00707
00708 INT save_done_list(HNDLE hLch, DIRLOGLIST *pdone)
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 {
00720 KEY key;
00721 int status = db_get_key(hDB, hLch, &key);
00722 assert(status == DB_SUCCESS);
00723 sort(pdone->begin(), pdone->end(), cmp_dirlog);
00724 save_list(key.name, "donelist", pdone);
00725 return SUCCESS;
00726 }
00727
00728
00729 int find_next_file(const DIRLOGLIST *plog, const DIRLOGLIST *pdone)
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 {
00743 for (unsigned j = 0; j < plog->size(); j++) {
00744 bool found = false;
00745 for (unsigned i = 0; i < pdone->size(); i++) {
00746 if ((*plog)[j].filename == (*pdone)[i].filename)
00747 found = true;
00748 }
00749
00750 if (!found)
00751 if ((*plog)[j].size > 0)
00752 return j;
00753 }
00754
00755 return -1;
00756 }
00757
00758
00759 INT lazy_select_purge(HNDLE hKey, INT channel, LAZY_INFO * pLall, const char* fmt, const char* dir, DIRLOG *f)
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 {
00782 int size;
00783 char ddir[256], ff[128], strmodulo[8];
00784
00785
00786
00787
00788
00789 while (1) {
00790
00791
00792
00793 DIRLOGLIST dirlists[MAX_LAZY_CHANNEL];
00794 DIRLOGLIST donelists[MAX_LAZY_CHANNEL];
00795
00796
00797 for (int i = 0; i < MAX_LAZY_CHANNEL; i++) {
00798
00799
00800 if (((pLall + i)->hKey)) {
00801
00802 size = sizeof(strmodulo);
00803 db_get_value(hDB, (pLall + i)->hKey, "Settings/Modulo.Position", strmodulo, &size, TID_STRING, TRUE);
00804 if (strmodulo[0]) {
00805
00806 if (debug)
00807 printf("purge: skipping channel \'%s\' which uses modulo \'%s\'\n", lazyinfo[i].name, strmodulo);
00808 continue;
00809 }
00810
00811 size = sizeof(ddir);
00812 db_get_value(hDB, (pLall + i)->hKey, "Settings/Data dir", ddir, &size, TID_STRING, TRUE);
00813 size = sizeof(ff);
00814 db_get_value(hDB, (pLall + i)->hKey, "Settings/filename format", ff, &size, TID_STRING, TRUE);
00815
00816
00817
00818 int len = strlen(ddir);
00819 if (ddir[len-1] != '/') {
00820 ddir[len] = '/';
00821 ddir[len+1] = 0;
00822 }
00823
00824
00825 if (strcmp(ddir, dir) != 0) {
00826 if (debug)
00827 printf("purge: skipping channel \'%s\' which uses different data dir \'%s\', we use \'%s\'\n", lazyinfo[i].name, ddir, dir);
00828 continue;
00829 }
00830
00831 if (debug)
00832 printf("Loading file lists for channel \'%s\', data dir \'%s\', format \'%s\'\n", lazyinfo[i].name, ddir, ff);
00833
00834
00835 build_log_list(ff, ddir, &dirlists[i]);
00836 build_done_list(pLall[i].hKey, &dirlists[i], &donelists[i]);
00837 }
00838 }
00839
00840
00841 for (unsigned k = 0; k < dirlists[channel].size(); k++) {
00842 bool can_delete = true;
00843
00844 if (debug)
00845 printf("purge: consider file \'%s\'\n", dirlists[channel][k].filename.c_str());
00846
00847 for (int i = 0; i < MAX_LAZY_CHANNEL; i++)
00848 if (((pLall + i)->hKey)) {
00849 bool in_dir_list = false;
00850 bool in_done_list = false;
00851
00852 for (unsigned j=0; j<dirlists[i].size(); j++)
00853 if (dirlists[i][j].filename == dirlists[channel][k].filename) {
00854 in_dir_list = true;
00855 break;
00856 }
00857
00858 if (!in_dir_list) {
00859 if (debug)
00860 printf("channel \'%s\': file is not in dir list, ok to delete\n", lazyinfo[i].name);
00861 continue;
00862 }
00863
00864 for (unsigned j=0; j<donelists[i].size(); j++)
00865 if (donelists[i][j].filename == dirlists[channel][k].filename) {
00866 in_done_list = true;
00867 break;
00868 }
00869
00870 if (!in_done_list) {
00871 if (debug)
00872 printf("channel \'%s\': file is in dirlist but not in done list, cannot delete\n", lazyinfo[i].name);
00873 can_delete = false;
00874 break;
00875 }
00876
00877 if (debug)
00878 printf("channel \'%s\': file is in dirlist and in done list, ok to delete\n", lazyinfo[i].name);
00879 }
00880
00881 if (can_delete) {
00882 if (debug)
00883 printf("purge: file \'%s\' is done by all channels\n", dirlists[channel][k].filename.c_str());
00884 *f = dirlists[channel][k];
00885 return SUCCESS;
00886 }
00887 }
00888
00889
00890 return !SUCCESS;
00891 }
00892 }
00893
00894
00895 void lazy_settings_hotlink(HNDLE hDB, HNDLE hKey, void *info)
00896 {
00897 INT size, maintain;
00898
00899
00900 size = sizeof(maintain);
00901 db_get_value(hDB, hKey, "Maintain free space (%)", &maintain, &size, TID_INT, TRUE);
00902 if (maintain != 0)
00903 maintain_touched = TRUE;
00904 else
00905 maintain_touched = FALSE;
00906 }
00907
00908
00909 void lazy_maintain_check(HNDLE hKey, LAZY_INFO * pLall)
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920 {
00921 INT size;
00922 INT i, maintain;
00923 char dir[256], ff[128];
00924 char cdir[256], cff[128];
00925 char cmodulostr[8], modulostr[8];
00926
00927
00928 if (!maintain_touched)
00929 return;
00930 maintain_touched = FALSE;
00931
00932
00933 size = sizeof(maintain);
00934 db_get_value(hDB, hKey, "Settings/Maintain free space (%)", &maintain, &size, TID_INT, TRUE);
00935 if (maintain != 0) {
00936
00937
00938
00939 size = sizeof(cdir);
00940 db_get_value(hDB, hKey, "Settings/Data dir", cdir, &size, TID_STRING, TRUE);
00941 size = sizeof(cff);
00942 db_get_value(hDB, hKey, "Settings/filename format", cff, &size, TID_STRING, TRUE);
00943 size = sizeof(modulostr);
00944 db_get_value(hDB, hKey, "Settings/Modulo.Position", cmodulostr, &size, TID_STRING, TRUE);
00945
00946
00947 for (i = 0; i < MAX_LAZY_CHANNEL; i++) {
00948 if (((pLall + i)->hKey) && (hKey != (pLall + i)->hKey)) {
00949 size = sizeof(dir);
00950 db_get_value(hDB, (pLall + i)->hKey, "Settings/Data dir", dir, &size, TID_STRING, TRUE);
00951 size = sizeof(ff);
00952 db_get_value(hDB, (pLall + i)->hKey, "Settings/filename format", ff, &size, TID_STRING, TRUE);
00953 size = sizeof(modulostr);
00954 db_get_value(hDB, (pLall + i)->hKey, "Settings/Modulo.Position", modulostr, &size, TID_STRING, TRUE);
00955
00956
00957 if ((strcmp(dir, cdir) == 0) && (strcmp(ff, cff) == 0) && !cmodulostr[0]
00958 && !modulostr[0]) {
00959
00960 size = sizeof(maintain);
00961 db_get_value(hDB, (pLall + i)->hKey, "Settings/Maintain free space (%)",
00962 &maintain, &size, TID_INT, TRUE);
00963 if (maintain) {
00964
00965 size = sizeof(maintain);
00966 maintain = 0;
00967 db_set_value(hDB, (pLall + i)->hKey, "Settings/Maintain free space (%)", &maintain, size, 1, TID_INT);
00968 cm_msg(MINFO, "lazy_maintain_check",
00969 "Maintain free space on channel %s has been disable", (pLall + i)->name);
00970 }
00971 }
00972 }
00973 }
00974 }
00975 }
00976
00977
00978 void lazy_statistics_update(INT cploop_time)
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988 {
00989
00990 if (cploop_time == 0)
00991 lazyst.copy_rate = 0.0;
00992 if ((ss_millitime() - cploop_time) > 100)
00993 lazyst.copy_rate = 1000.f * (lazyst.cur_size - lastsz) / (ss_millitime() - cploop_time);
00994 if (lazyst.copy_rate < 0.0)
00995 lazyst.copy_rate = 0.0;
00996
00997
00998 if (lazyst.file_size != 0.0f)
00999 lazyst.progress = (100.0f * (lazyst.cur_size / lazyst.file_size));
01000 else
01001 lazyst.progress = 0.0f;
01002
01003
01004 if (lazy.capacity > 0.0f)
01005 lazyst.bckfill = 100.0f * (lazyst.cur_dev_size / lazy.capacity);
01006 else
01007 lazyst.bckfill = 0.0f;
01008
01009 lastsz = lazyst.cur_size;
01010
01011 db_send_changed_records();
01012 }
01013
01014
01015 BOOL condition_test(char *string)
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 {
01031 KEY key;
01032 double value;
01033 double lcond_value;
01034 INT size, index, status;
01035 char str[128], left[64], right[64];
01036 char *p = NULL, *pp, *ppl, *pc, *lp;
01037
01038 index = 0;
01039 p = string;
01040 if (p) {
01041 while (isspace(*p))
01042 p++;
01043
01044 pc = strpbrk(p, "<=>");
01045 if (pc) {
01046 strncpy(left, p, pc - p);
01047 lp = left + (pc - p - 1);
01048 while (isspace(*lp))
01049 lp--;
01050 *(lp + 1) = '\0';
01051 strncpy(right, pc + 1, (strlen(p) - strlen(left)));
01052 right[strlen(p) - strlen(left) - 1] = '\0';
01053 }
01054
01055 if ((pp = strpbrk(left, "[(")) != NULL) {
01056 if ((ppl = strpbrk(left, "])")) != NULL) {
01057 *pp = '\0';
01058 *ppl = '\0';
01059 index = atoi(pp + 1);
01060 }
01061 *pp = '\0';
01062 }
01063
01064
01065 value = (double) (atoi(right));
01066
01067 status = db_find_key(hDB, 0, left, &hKey);
01068 if (status != DB_SUCCESS) {
01069 cm_msg(MINFO, "condition_check", "Key %s not found", left);
01070 return FALSE;
01071 }
01072 status = db_get_key(hDB, hKey, &key);
01073 if ((status == DB_SUCCESS) && (key.type <= TID_DOUBLE)) {
01074
01075 size = sizeof(lcond_value);
01076 db_get_data_index(hDB, hKey, &lcond_value, &size, index, key.type);
01077 db_sprintf(str, &lcond_value, key.item_size, 0, key.type);
01078 lcond_value = atof(str);
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089 if (((*pc == '>') && ((double) lcond_value > value)) ||
01090 ((*pc == '=') && ((double) lcond_value == value)) || ((*pc == '<') && ((double) lcond_value < value)))
01091 return TRUE;
01092 else
01093 return FALSE;
01094 }
01095
01096 return TRUE;
01097 }
01098
01099
01100 BOOL lazy_condition_check(void)
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111 {
01112
01113 if (equal_ustring(lazy.condition, "ALWAYS"))
01114 return TRUE;
01115 else if (equal_ustring(lazy.condition, "NEVER"))
01116 return FALSE;
01117 else if (equal_ustring(lazy.condition, "WHILE_ACQ_NOT_RUNNING")) {
01118 if (run_state == STATE_RUNNING)
01119 return FALSE;
01120 else
01121 return TRUE;
01122 } else
01123 return (condition_test(lazy.condition));
01124 }
01125
01126
01127 INT lazy_copy(char *outfile, char *infile)
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 {
01141 void *plazy = NULL;
01142 DWORD szlazy;
01143 INT status, no_cpy_last_time = 0;
01144 INT last_time, cpy_loop_time;
01145 DWORD watchdog_timeout;
01146 static INT last_error = 0;
01147
01148 BOOL watchdog_flag, exit_request = FALSE;
01149 char filename[256];
01150
01151
01152 lazyst.cur_size = 0.0f;
01153 last_time = 0;
01154
01155
01156 strlcpy(filename, outfile, sizeof(filename));
01157 if ((status = md_file_wopen(dev_type, data_fmt, filename, &hDev)) != 1) {
01158 if ((ss_time() - last_error) > 60) {
01159 last_error = ss_time();
01160 cm_msg(MTALK, "Lazy_copy", "cannot open %s, error %d", outfile, status);
01161 }
01162 return (FORCE_EXIT);
01163 }
01164
01165
01166 if ((dev_type == LOG_TYPE_TAPE) && lazy.tapeAppend) {
01167
01168 cm_msg(MINFO, "Lazy", "Positioning Tape to EOD");
01169
01170 cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
01171 cm_set_watchdog_params(watchdog_flag, 300000);
01172 status = ss_tape_spool(hDev);
01173 cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
01174 if (status != SS_SUCCESS) {
01175 cm_msg(MINFO, "Lazy", "Error while Positioning Tape to EOD (%d)", status);
01176 ss_tape_close(hDev);
01177 return (FORCE_EXIT);
01178 }
01179 }
01180
01181
01182 last_error = 0;
01183
01184
01185 if (md_file_ropen(infile, data_fmt) != MD_SUCCESS)
01186 return (FORCE_EXIT);
01187
01188
01189 if (equal_ustring(lazy.type, "Tape")) {
01190
01191
01192 blockn = -1;
01193 while (blockn < 0) {
01194 blockn = ss_tape_get_blockn(hDev);
01195 if (blockn >= 0)
01196 break;
01197 cm_msg(MINFO, "Lazy", "Tape is not ready");
01198 cm_yield(3000);
01199 }
01200 if (lazy.commandBefore[0]) {
01201 char cmd[256];
01202 sprintf(cmd, "%s %s %s %d %s %i", lazy.commandBefore, infile, outfile, blockn, lazy.backlabel, lazyst.nfiles);
01203 cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
01204 ss_system(cmd);
01205 }
01206 }
01207
01208
01209 cpy_loop_time = -2000;
01210 if (dev_type == LOG_TYPE_TAPE) {
01211 char str[MAX_FILE_PATH];
01212 sprintf(str, "Starting lazy job on %s at block %d", lazyst.backfile, blockn);
01213 if (msg_flag)
01214 cm_msg(MTALK, "Lazy", str);
01215 cm_msg(MINFO, "Lazy", str);
01216 cm_msg1(MINFO, "lazy_log_update", "lazy", str);
01217 }
01218
01219
01220 while (1) {
01221 if (copy_continue) {
01222 if (md_physrec_get(data_fmt, &plazy, &szlazy) == MD_SUCCESS) {
01223 status = md_log_write(hDev, data_fmt, dev_type, plazy, szlazy);
01224 if (status != SS_SUCCESS) {
01225
01226 md_file_rclose(dev_type);
01227
01228 md_file_wclose(hDev, dev_type, data_fmt, outfile);
01229
01230
01231 cm_msg(MERROR, "lazy_copy", "Write error ");
01232 if (status == SS_NO_SPACE)
01233 return status;
01234 return (FORCE_EXIT);
01235 }
01236 lazyst.cur_size += (double) szlazy;
01237 lazyst.cur_dev_size += (double) szlazy;
01238 if ((ss_millitime() - cpy_loop_time) > 2000) {
01239
01240 lazy_statistics_update(cpy_loop_time);
01241
01242
01243 copy_continue = lazy_condition_check();
01244
01245
01246 cpy_loop_time = ss_millitime();
01247
01248
01249 status = cm_yield(1);
01250 if (status == RPC_SHUTDOWN || status == SS_ABORT || exit_request) {
01251 cm_msg(MINFO, "Lazy", "Abort postponed until end of copy of %s %1.0lf[%%]",
01252 infile, (double) lazyst.progress);
01253 exit_request = TRUE;
01254 }
01255 }
01256 }
01257 else
01258 break;
01259 }
01260 else {
01261 status = cm_yield(1000);
01262 if (status == RPC_SHUTDOWN || status == SS_ABORT)
01263 return (FORCE_EXIT);
01264 if ((ss_millitime() - no_cpy_last_time) > 5000) {
01265 copy_continue = lazy_condition_check();
01266 no_cpy_last_time = ss_millitime();
01267 }
01268 }
01269 }
01270
01271
01272 lazy_statistics_update(0);
01273
01274
01275 md_file_rclose(dev_type);
01276
01277
01278 if (equal_ustring(lazy.type, "Tape")) {
01279 blockn = ss_tape_get_blockn(hDev);
01280 }
01281 status = md_file_wclose(hDev, dev_type, data_fmt, outfile);
01282 if (status != SS_SUCCESS) {
01283 if (status == SS_NO_SPACE)
01284 return status;
01285 return (FORCE_EXIT);
01286 }
01287
01288
01289 if (exit_request)
01290 return (EXIT_REQUEST);
01291 return 0;
01292
01293 }
01294
01295
01296
01297 #ifdef OS_LINUX // does not work under Windows because of missing popen
01298
01299 INT lazy_script_copy(char *infile)
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309 {
01310 int status;
01311 FILE *fin;
01312 int cpy_loop_time = ss_millitime();
01313 char cmd[256];
01314
01315
01316 lazyst.cur_size = 0;
01317
01318
01319 if (lazy.commandBefore[0]) {
01320 char cmd[256];
01321 sprintf(cmd, "%s %s %i", lazy.commandBefore, infile, lazyst.nfiles);
01322 cm_msg(MINFO, "Lazy", "Exec pre file write script:%s", cmd);
01323 ss_system(cmd);
01324 }
01325
01326
01327 sprintf(cmd, "%s %s 2>&1", lazy.path, infile);
01328
01329 {
01330 char str[MAX_FILE_PATH];
01331 sprintf(str, "Starting lazy job \'%s\'", cmd);
01332 if (msg_flag)
01333 cm_msg(MTALK, "Lazy", str);
01334 cm_msg(MINFO, "Lazy", str);
01335 cm_msg1(MINFO, "lazy_log_update", "lazy", str);
01336 }
01337
01338
01339 fin = popen(cmd, "r");
01340
01341 if (fin == NULL) {
01342 cm_msg(MTALK, "Lazy_copy", "cannot start %s, errno %d (%s)", cmd, errno, strerror(errno));
01343 return FORCE_EXIT;
01344 }
01345
01346 if (1) {
01347 int desc = fileno(fin);
01348 int flags = fcntl(desc, F_GETFL, 0);
01349 fcntl(desc, F_SETFL, flags | O_NONBLOCK);
01350 }
01351
01352
01353 while (1) {
01354 char buf[1024];
01355 int rd = read(fileno(fin), buf, sizeof(buf));
01356 if (rd == 0) {
01357
01358 break;
01359 } else if (rd < 0) {
01360
01361
01362 if (errno == EAGAIN) {
01363
01364 status = cm_yield(1000);
01365 continue;
01366 }
01367
01368 cm_msg(MERROR, "lazy_copy", "Error reading output of the backup script, errno %d (%s)", errno,
01369 strerror(errno));
01370 break;
01371 } else {
01372 char *p;
01373
01374
01375
01376 buf[rd] = 0;
01377
01378
01379 p = buf;
01380 while (p) {
01381 char *q = strchr(p, '\n');
01382 if (q) {
01383 *q = 0;
01384 q++;
01385 if (q[0] == 0)
01386 q = NULL;
01387 }
01388 cm_msg(MINFO, "lazy_copy", p);
01389 p = q;
01390 }
01391 }
01392 }
01393
01394
01395 lazy_statistics_update(cpy_loop_time);
01396
01397
01398 status = pclose(fin);
01399
01400 if (status != 0) {
01401 cm_msg(MERROR, "lazy_copy", "Backup script finished with exit code %d, status 0x%x", (status >> 8), status);
01402 return SS_NO_SPACE;
01403 }
01404
01405 cm_msg(MINFO, "lazy_copy", "Backup script finished in %.1f sec with exit code %d",
01406 (ss_millitime() - cpy_loop_time) / 1000.0, (status >> 8));
01407
01408
01409 return 0;
01410 }
01411
01412 #endif // OS_LINUX
01413
01414
01415 BOOL lazy_file_exists(char *dir, char *file)
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427 {
01428 char *list;
01429 char fullfile[MAX_FILE_PATH] = { '\0' };
01430
01431 if (ss_file_find(dir, file, &list) == 1) {
01432 strcat(fullfile, dir);
01433 strcat(fullfile, DIR_SEPARATOR_STR);
01434 strcat(fullfile, file);
01435 if ((lazyst.file_size = (double) (ss_file_size(fullfile))) > 0) {
01436 free(list);
01437 return TRUE;
01438 }
01439 }
01440 free(list);
01441 return FALSE;
01442 }
01443
01444
01445
01446 INT lazy_maintain_free_space(LAZY_INFO *pLch, LAZY_INFO *pLall)
01447 {
01448 int status;
01449
01450
01451 lazy_maintain_check(pLch->hKey, pLall);
01452
01453
01454 if (lazy.pupercent > 0) {
01455
01456
01457 double freepercent = 100. * ss_disk_free(lazy.dir) / ss_disk_size(lazy.dir);
01458
01459
01460 if (freepercent < 5.0) {
01461 char buf[256];
01462 sprintf(buf, "Disk %s is almost full, free space: %.1f%%", lazy.dir, freepercent);
01463 al_trigger_alarm("Disk Full", buf, lazy.alarm, "Disk buffer full", AT_INTERNAL);
01464 } else {
01465 HNDLE hKey;
01466 if (db_find_key(hDB, 0, "/Alarms/Alarms/Disk Full", &hKey) == DB_SUCCESS)
01467 al_reset_alarm("Disk Full");
01468 }
01469
01470 if (debug)
01471 printf("free space on %s: %.1f%%, lazy limit %d%%\n", lazy.dir, freepercent, lazy.pupercent);
01472
01473
01474
01475
01476 status = ss_semaphore_wait_for(lazy_semaphore, 5000);
01477 if (status != SS_SUCCESS) {
01478
01479 return NOTHING_TODO;
01480 }
01481
01482
01483 while (freepercent <= (double) lazy.pupercent) {
01484
01485 BOOL donepurge = FALSE;
01486
01487
01488
01489
01490 DIRLOG f;
01491 if (lazy_select_purge(pLch->hKey, channel, pLall, lazy.backfmt, lazy.dir, &f) == SUCCESS) {
01492
01493 if (1 ) {
01494 DWORD rm_time;
01495
01496 rm_time = ss_millitime();
01497 std::string path = lazy.dir;
01498 path += f.filename;
01499 if (debug)
01500 printf("file selected for removal %s [%s]\n", f.filename.c_str(), path.c_str());
01501 status = lazy_file_remove(path.c_str());
01502 rm_time = ss_millitime() - rm_time;
01503 if (status != SS_SUCCESS) {
01504 cm_msg(MERROR, "Lazy", "lazy_file_remove failed on file %s", path.c_str());
01505
01506 break;
01507 } else {
01508 status = lazy_log_update(REMOVE_FILE, f.runno, NULL, path.c_str(), rm_time);
01509 donepurge = TRUE;
01510 }
01511 }
01512
01513
01514 freepercent = 100. * ss_disk_free(lazy.dir) / ss_disk_size(lazy.dir);
01515
01516 if (debug)
01517 printf("free space on %s: %.1f%%, lazy limit %d%%\n", lazy.dir, freepercent, lazy.pupercent);
01518
01519 }
01520
01521
01522
01523 if (!donepurge)
01524 break;
01525 }
01526
01527
01528 status = ss_semaphore_release(lazy_semaphore);
01529
01530 }
01531
01532 return SUCCESS;
01533 }
01534
01535
01536
01537 INT lazy_main(INT channel, LAZY_INFO * pLall)
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547 {
01548 DWORD cp_time;
01549 INT size, status;
01550 char str[MAX_FILE_PATH], inffile[MAX_FILE_PATH], outffile[MAX_FILE_PATH];
01551 BOOL watchdog_flag, exit_request = FALSE;
01552 DWORD watchdog_timeout;
01553 LAZY_INFO *pLch;
01554 static BOOL eot_reached = FALSE;
01555 BOOL haveTape;
01556
01557
01558 pLch = &pLall[channel];
01559
01560
01561 if (equal_ustring(lazy.format, "MIDAS"))
01562 data_fmt = FORMAT_MIDAS;
01563 else {
01564 cm_msg(MERROR, "Lazy", "Unknown data format %s (MIDAS)", lazy.format);
01565 return DB_NO_ACCESS;
01566 }
01567
01568
01569 if (equal_ustring(lazy.type, "DISK"))
01570 dev_type = LOG_TYPE_DISK;
01571 else if (equal_ustring(lazy.type, "TAPE"))
01572 dev_type = LOG_TYPE_TAPE;
01573 else if (equal_ustring(lazy.type, "FTP"))
01574 dev_type = LOG_TYPE_FTP;
01575 else if (equal_ustring(lazy.type, "SCRIPT"))
01576 dev_type = LOG_TYPE_SCRIPT;
01577 else {
01578 cm_msg(MERROR, "Lazy", "Unknown device type %s (Disk, Tape, FTP or SCRIPT)", lazy.type);
01579 return DB_NO_ACCESS;
01580 }
01581
01582 if (dev_type == LOG_TYPE_SCRIPT)
01583 if (lazy.backlabel[0] == 0 || strcmp(lazy.backlabel, lazyinfo[channel].name) != 0) {
01584 strlcpy(lazy.backlabel, lazyinfo[channel].name, sizeof(lazy.backlabel));
01585 size = sizeof(lazy.backlabel);
01586 db_set_value(hDB, pLch->hKey, "Settings/List label", lazy.backlabel, size, 1, TID_STRING);
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598 haveTape = (lazy.backlabel[0] != '\0');
01599
01600
01601 if (lazy.backlabel[0] == '\0') {
01602 full_bck_flag = TRUE;
01603 } else {
01604 if (full_bck_flag) {
01605 full_bck_flag = FALSE;
01606 size = sizeof(lazyst);
01607 memset(&lazyst, 0, size);
01608 if (db_find_key(hDB, pLch->hKey, "Statistics", &hKeyst) == DB_SUCCESS) {
01609 status = db_set_record(hDB, hKeyst, &lazyst, size, 0);
01610
01611
01612 if ((dev_type == LOG_TYPE_DISK) && lazy.tapeAppend) {
01613
01614 cm_msg(MINFO, "Lazy", "Positioning Tape to EOD");
01615 }
01616 } else
01617 cm_msg(MERROR, "lazy_main", "did not find /Lazy/Lazy_%s/Statistics for zapping", pLch->name);
01618
01619 if (dev_type == LOG_TYPE_TAPE)
01620 al_reset_alarm("Tape");
01621 }
01622 }
01623
01624 if (lazy.dir[0] == '\0') {
01625 cm_msg(MINFO, "Lazy", "Please setup Data dir for input source path!");
01626 return NOTHING_TODO;
01627 }
01628
01629 if (lazy.dir[0] != 0)
01630 if (lazy.dir[strlen(lazy.dir)-1] != DIR_SEPARATOR)
01631 strcat(lazy.dir, DIR_SEPARATOR_STR);
01632
01633
01634 if (lazy.path[0] == '\0') {
01635 cm_msg(MINFO, "Lazy", "Please setup backup device path too!");
01636 return NOTHING_TODO;
01637 }
01638
01639 DIRLOGLIST dirlist;
01640 build_log_list(lazy.backfmt, lazy.dir, &dirlist);
01641
01642 save_list(pLch->name, "dirlist", &dirlist);
01643
01644 DIRLOGLIST donelist;
01645 build_done_list(pLch->hKey, &dirlist, &donelist);
01646
01647 lazy_maintain_free_space(pLch, pLall);
01648
01649
01650 int tobe_backup = find_next_file(&dirlist, &donelist);
01651
01652
01653
01654
01655
01656
01657
01658
01659 if (tobe_backup < 0)
01660 return NOTHING_TODO;
01661
01662 if (debug)
01663 printf("selected for backup: %s, run %d\n", dirlist[tobe_backup].filename.c_str(), dirlist[tobe_backup].runno);
01664
01665
01666 int cur_acq_run;
01667 size = sizeof(cur_acq_run);
01668 status = db_get_value(hDB, 0, "Runinfo/Run number", &cur_acq_run, &size, TID_INT, FALSE);
01669 assert(status == SUCCESS);
01670
01671 lazyst.cur_run = dirlist[tobe_backup].runno;
01672
01673 int behind_files = dirlist.size() - tobe_backup;
01674 int behind_runs = cur_acq_run - dirlist[tobe_backup].runno;
01675
01676 bool nothing_todo_files = (behind_files <= lazy.staybehind);
01677 bool nothing_todo_runs = (behind_runs < abs(lazy.staybehind));
01678
01679 bool nothing_todo = false;
01680
01681
01682 if (lazy.staybehind < 0)
01683 nothing_todo = nothing_todo_runs;
01684
01685
01686 if (lazy.staybehind > 0)
01687 nothing_todo = nothing_todo_files;
01688
01689
01690 if (lazy.staybehind == 0) {
01691 if (dirlist[tobe_backup].runno != cur_acq_run)
01692 nothing_todo = false;
01693 else if (behind_files > 1)
01694 nothing_todo = false;
01695 else {
01696 nothing_todo = false;
01697
01698
01699
01700
01701
01702
01703
01704 int flag;
01705 size = sizeof(flag);
01706 status = db_get_value(hDB, 0, "Runinfo/Transition in progress", &flag, &size, TID_INT, FALSE);
01707 assert(status == SUCCESS);
01708 if (flag) {
01709 if (debug)
01710 printf("transition in progress, cannot backup last file\n");
01711 nothing_todo = true;
01712 }
01713
01714 size = sizeof(flag);
01715 status = db_get_value(hDB, 0, "Runinfo/Start abort", &flag, &size, TID_INT, FALSE);
01716 assert(status == SUCCESS);
01717 if (flag) {
01718 if (debug)
01719 printf("run start aborted, cannot backup last file\n");
01720 nothing_todo = true;
01721 }
01722
01723 int cur_state_run;
01724 status = db_get_value(hDB, 0, "Runinfo/State", &cur_state_run, &size, TID_INT, FALSE);
01725 assert(status == SUCCESS);
01726 if ((cur_state_run != STATE_STOPPED)) {
01727 if (debug)
01728 printf("run still running, cannot backup last file\n");
01729 nothing_todo = true;
01730 }
01731 }
01732 }
01733
01734 if (debug)
01735 printf("behind: %d files, %d runs, staybehind: %d, nothing_todo: files: %d, runs: %d, lazylogger: %d\n", behind_files, behind_runs, lazy.staybehind, nothing_todo_files, nothing_todo_runs, nothing_todo);
01736
01737 if (nothing_todo) {
01738 return NOTHING_TODO;
01739 }
01740
01741 if (dev_type != LOG_TYPE_SCRIPT)
01742 if (!haveTape)
01743 return NOTHING_TODO;
01744
01745 strlcpy(lazyst.backfile, dirlist[tobe_backup].filename.c_str(), sizeof(lazyst.backfile));
01746
01747 std::string xfile = lazy.dir;
01748 xfile += dirlist[tobe_backup].filename;
01749 strlcpy(inffile, xfile.c_str(), sizeof(inffile));
01750
01751
01752 if (lazy_file_exists(lazy.dir, lazyst.backfile)) {
01753
01754 if (dev_type == LOG_TYPE_DISK) {
01755 if (lazy.path[0] != 0)
01756 if (lazy.path[strlen(lazy.path) - 1] != DIR_SEPARATOR)
01757 strcat(lazy.path, DIR_SEPARATOR_STR);
01758 strcpy(outffile, lazy.path);
01759 strcat(outffile, lazyst.backfile);
01760 } else if (dev_type == LOG_TYPE_TAPE)
01761 strcpy(outffile, lazy.path);
01762 else if (dev_type == LOG_TYPE_FTP) {
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774 strcpy(str, lazy.path);
01775
01776 if (strchr(str, '%'))
01777 sprintf(outffile, str, lazyst.cur_run);
01778 else
01779 strcpy(outffile, str);
01780
01781
01782 strlcpy(str, outffile, sizeof(str));
01783 if (strchr(str, '#')) {
01784 *strchr(str, '#') = '%';
01785 sprintf(outffile, str, lazyst.cur_run / 1000);
01786 }
01787 }
01788
01789
01790 if (((dev_type == LOG_TYPE_TAPE)
01791 && (lazy.capacity < (lazyst.cur_dev_size + lazyst.file_size)))
01792 || eot_reached) {
01793 char pre_label[32];
01794
01795 strcpy(pre_label, lazy.backlabel);
01796
01797
01798 eot_reached = FALSE;
01799
01800
01801 lazy.backlabel[0] = '\0';
01802 size = sizeof(lazy.backlabel);
01803 db_set_value(hDB, pLch->hKey, "Settings/List label", lazy.backlabel, size, 1, TID_STRING);
01804 full_bck_flag = TRUE;
01805 cm_msg(MINFO, "Lazy", "Not enough space for next copy on backup device!");
01806
01807
01808 if (dev_type == LOG_TYPE_TAPE) {
01809 INT status, channel;
01810 char str[128];
01811
01812 sprintf(str, "Tape %s is full with %d files", pre_label, lazyst.nfiles);
01813 cm_msg(MINFO, "Lazy", str);
01814
01815
01816 lazy.alarm[0] = 0;
01817 size = sizeof(lazy.alarm);
01818 db_get_value(hDB, pLch->hKey, "Settings/Alarm Class", lazy.alarm, &size, TID_STRING, TRUE);
01819
01820
01821 if (lazy.alarm[0])
01822 al_trigger_alarm("Tape",
01823 "Tape full, Please remove current tape and load new one!",
01824 lazy.alarm, "Tape full", AT_INTERNAL);
01825
01826
01827 if (lazy.command[0]) {
01828 char cmd[256];
01829 sprintf(cmd, "%s %s %s %s", lazy.command, lazy.path, pLch->name, pre_label);
01830 cm_msg(MINFO, "Lazy", "Exec post-rewind script:%s", cmd);
01831 ss_system(cmd);
01832 }
01833
01834 cm_msg(MINFO, "Lazy", "backup device rewinding...");
01835 cm_get_watchdog_params(&watchdog_flag, &watchdog_timeout);
01836 cm_set_watchdog_params(watchdog_flag, 300000);
01837 status = ss_tape_open(outffile, O_RDONLY, &channel);
01838 if (channel < 0) {
01839 cm_msg(MERROR, "Lazy", "Cannot rewind tape %s - %d - %d", outffile, channel, status);
01840 return NOTHING_TODO;
01841 }
01842
01843
01844 cm_msg(MINFO, "Lazy", "Calling ss_tape_unmount");
01845 ss_tape_unmount(channel);
01846 ss_tape_close(channel);
01847 cm_set_watchdog_params(watchdog_flag, watchdog_timeout);
01848 return NOTHING_TODO;
01849 }
01850 }
01851
01852
01853 cp_time = ss_millitime();
01854 status = 0;
01855 if (dev_type == LOG_TYPE_SCRIPT) {
01856 #ifdef OS_LINUX
01857
01858 status = lazy_script_copy(inffile);
01859 #else
01860 assert(!"lazy_script_copy not supported under Windows");
01861 #endif
01862 } else {
01863 status = lazy_copy(outffile, inffile);
01864 }
01865
01866 if ((status != 0) && (status != EXIT_REQUEST)) {
01867 if (status == SS_NO_SPACE) {
01868
01869 eot_reached = TRUE;
01870 return status;
01871 } else if (status == FORCE_EXIT)
01872 return status;
01873 cm_msg(MERROR, "Lazy", "copy failed -%s-%s-%i", lazy.path, lazyst.backfile, status);
01874 return FORCE_EXIT;
01875 }
01876 }
01877 else {
01878
01879
01880
01881
01882
01883
01884 return NOTHING_TODO;
01885 }
01886
01887 if (status == EXIT_REQUEST)
01888 exit_request = TRUE;
01889
01890 cp_time = ss_millitime() - cp_time;
01891
01892 donelist.push_back(dirlist[tobe_backup]);
01893
01894 save_done_list(pLch->hKey, &donelist);
01895
01896 lazy_log_update(NEW_FILE, lazyst.cur_run, lazy.backlabel, lazyst.backfile, cp_time);
01897
01898 if (msg_flag)
01899 cm_msg(MTALK, "Lazy", " lazy job %s done!", lazyst.backfile);
01900
01901
01902
01903 {
01904 char str[128];
01905
01906
01907
01908 if (lazy.dir[strlen(lazy.dir) - 1] != DIR_SEPARATOR)
01909 sprintf(str, "%s%c%s_recover.odb", lazy.dir, DIR_SEPARATOR, pLch->name);
01910 else
01911 sprintf(str, "%s%s_recover.odb", lazy.dir, pLch->name);
01912
01913 db_save(hDB, pLch->hKey, str, TRUE);
01914 }
01915
01916 if (exit_request)
01917 return (FORCE_EXIT);
01918 return NOTHING_TODO;
01919 }
01920
01921
01922 int main(int argc, char **argv)
01923 {
01924 char channel_name[32];
01925 char host_name[HOST_NAME_LENGTH];
01926 char expt_name[HOST_NAME_LENGTH];
01927 BOOL daemon;
01928 INT i, msg, ch, size, status, mainlast_time;
01929
01930 setbuf(stdout, NULL);
01931 setbuf(stderr, NULL);
01932
01933
01934 host_name[0] = 0;
01935 expt_name[0] = 0;
01936 channel_name[0] = 0;
01937 BOOL zap_flag = FALSE;
01938 msg_flag = FALSE;
01939 debug = daemon = FALSE;
01940
01941
01942 cm_get_environment(host_name, sizeof(host_name), expt_name, sizeof(expt_name));
01943
01944
01945 for (i = 1; i < argc; i++) {
01946 if (argv[i][0] == '-' && argv[i][1] == 'd')
01947 debug = TRUE;
01948 else if (argv[i][0] == '-' && argv[i][1] == 'n')
01949 nodelete = TRUE;
01950 else if (argv[i][0] == '-' && argv[i][1] == 'D')
01951 daemon = TRUE;
01952 else if (strncmp(argv[i], "-z", 2) == 0)
01953 zap_flag = TRUE;
01954 else if (strncmp(argv[i], "-t", 2) == 0)
01955 msg_flag = TRUE;
01956 else if (argv[i][0] == '-') {
01957 if (i + 1 >= argc || argv[i + 1][0] == '-')
01958 goto usage;
01959 if (strncmp(argv[i], "-e", 2) == 0)
01960 strcpy(expt_name, argv[++i]);
01961 else if (strncmp(argv[i], "-h", 2) == 0)
01962 strcpy(host_name, argv[++i]);
01963 else if (strncmp(argv[i], "-c", 2) == 0)
01964 strcpy(channel_name, argv[++i]);
01965 } else {
01966 usage:
01967 printf("Lazylogger: Multi channel background data copier\n");
01968 printf("\n");
01969 printf("Usage: lazylogger [-d] [-n] [-D] [-h <Hostname>] [-e <Experiment>] [-z] [-t] -c <channel name>\n");
01970 printf("\n");
01971 printf("Options:\n");
01972 printf(" -d - enable debug printout\n");
01973 printf(" -n - do not delete any files (for testing \"Maintain free space\")\n");
01974 printf(" -D - start as a daemon\n");
01975 printf(" -h - connect to experiment on another machine\n");
01976 printf(" -e - connect to non-default experiment\n");
01977 printf(" -z - clear /Lazy/channel/Statistics\n");
01978 printf(" -t - permit lazy logger to TALK (see mlxspeaker)\n");
01979 printf("\n");
01980 printf("Quick man :\n");
01981 printf("The Lazy/Settings tree is composed of the following parameters:\n");
01982 printf("Maintain free space (%%)(0): purge source device to maintain free space on the source directory\n");
01983 printf(" (0) : no purge \n");
01984 printf("Stay behind (0) : If negative number : lazylog runs starting from the OLDEST\n");
01985 printf(" run file sitting in the 'Dir data' to the current acquisition\n");
01986 printf(" run minus the 'Stay behind number'\n");
01987 printf(" If positive number : lazylog starts from the current\n");
01988 printf(" acquisition run minus 'Stay behind number' \n");
01989 printf(" Zero : no stay-behind - files are saved as soon as they are closed\n");
01990 printf("Alarm Class : Specify the Class to be used in case of Tape Full condition\n");
01991 printf("Running condition : active/deactive lazylogger under given condition i.e:\n");
01992 printf(" 'ALWAYS' (default) : Independent of the ACQ state ...\n");
01993 printf(" 'NEVER' : ...\n");
01994 printf(" 'WHILE_ACQ_NOT_RUNNING': ...\n");
01995 printf(" '/alias/max_rate < 200' (max_rate is a link)\n");
01996 printf(" '/equipment/scaler/variables/scal[4] < 23.45'\n");
01997 printf(" '/equipment/trigger/statistics/events per sec. < 400'\n");
01998 printf("Data dir : MIDAS Data Directory (same as \"/Logger/Data Dir\")\n");
01999 printf("Data format : Data format (MIDAS)\n");
02000 printf("Filename format : Run format i.e. \"run%%05d.mid\", or \"*.mid.gz\" or \"*.mid.gz,*.xml\" \n");
02001 printf("List label : Label of destination save_set.\n");
02002 printf(" Prevent lazylogger to run if not given.\n");
02003 printf(" Will be reset if maximum capacity reached.\n");
02004 printf("Execute after rewind : Execute the command <cmd> after rewind complete\n");
02005 printf(" : args passed are: 'device path' 'channel name' 'list label'\n");
02006 printf(" : The actual command will look like: <cmd> /dev/nst0 Tape Data_2000\n");
02007 printf("Backup type : Destination device type (Disk, Tape, Script, FTP)\n");
02008 printf("Path : Destination path (file.ext, /dev/nst0, ftp...)\n");
02009 printf(" in case of FTP type, the 'Path' entry should be:\n");
02010 printf(" host, port, user, password, directory, run%%05d.mid\n");
02011 printf("Capacity (Bytes) : Maximum capacity of the destination device.\n");
02012 printf("modulo : Enable multiple lazy on same source. Ex: 3ch : 3.0, 3.1, 3.2\n");
02013 printf("tapeAppend : Enable positioning of the TAPE to EOD before each lazy copy\n");
02014 return 1;
02015 }
02016 }
02017
02018
02019 #ifdef SIGPIPE
02020 signal(SIGPIPE, SIG_IGN);
02021 #endif
02022 if (daemon) {
02023 printf("Becoming a daemon...\n");
02024 ss_daemon_init(FALSE);
02025 }
02026
02027
02028 status = cm_connect_experiment1(host_name, expt_name, "Lazy", 0, DEFAULT_ODB_SIZE, WATCHDOG_TIMEOUT);
02029 if (status != CM_SUCCESS)
02030 return 1;
02031
02032
02033 status = ss_semaphore_create("LAZY", &lazy_semaphore);
02034
02035
02036 cm_get_experiment_database(&hDB, &hKey);
02037 if (db_find_key(hDB, 0, "/Lazy", &hKey) == DB_SUCCESS) {
02038 HNDLE hSubkey;
02039 KEY key;
02040 char strclient[32];
02041 INT j = 0;
02042 for (i = 0;; i++) {
02043 db_enum_key(hDB, hKey, i, &hSubkey);
02044 if (!hSubkey)
02045 break;
02046 db_get_key(hDB, hSubkey, &key);
02047 if (key.type == TID_KEY) {
02048
02049 sprintf(strclient, "Lazy_%s", key.name);
02050 if (cm_exist(strclient, TRUE) == CM_SUCCESS)
02051 lazyinfo[j].active = TRUE;
02052 else
02053 lazyinfo[j].active = FALSE;
02054 strcpy(lazyinfo[j].name, key.name);
02055
02056 lazyinfo[j].hKey = hSubkey;
02057 j++;
02058 }
02059 }
02060 } else {
02061
02062 char str[32];
02063 channel = 0;
02064 if (channel_name[0] != 0)
02065 strlcpy(lazyinfo[channel].name, channel_name, sizeof(lazyinfo[channel].name));
02066 sprintf(str, "/Lazy/%s/Settings", lazyinfo[channel].name);
02067 db_create_record(hDB, 0, str, LAZY_SETTINGS_STRING);
02068 }
02069
02070 {
02071 INT i, j;
02072 char str[32];
02073
02074 if (lazyinfo[0].hKey) {
02075 if (channel_name[0] == 0) {
02076
02077 printf(" Available Lazy channels to connect to:\n");
02078 i = 0;
02079 j = 1;
02080 while (lazyinfo[i].hKey) {
02081 if (!lazyinfo[i].active)
02082 printf("%d) Lazy %s \n", j, lazyinfo[i].name);
02083 else
02084 printf(".) Lazy %s already active\n", lazyinfo[i].name);
02085 j++;
02086 i++;
02087 }
02088 printf("Enter client number or new lazy client name: ");
02089 i = atoi(ss_gets(str, 32));
02090 if ((i == 0) && ((strlen(str) == 0) || (strncmp(str, " ", 1) == 0))) {
02091 cm_msg(MERROR, "Lazy", "Please specify a valid channel name (%s)", str);
02092 goto error;
02093 }
02094 } else {
02095
02096
02097
02098
02099
02100
02101
02102
02103 i = 0;
02104 j = -1;
02105 while (lazyinfo[i].hKey) {
02106 if (equal_ustring(channel_name, lazyinfo[i].name)) {
02107
02108 if (lazyinfo[i].active) {
02109 cm_msg(MERROR, "Lazy", "Lazy channel " "%s" " already running!", lazyinfo[i].name);
02110 goto error;
02111 }
02112 j = i;
02113 }
02114 i++;
02115 }
02116 if (j == -1) {
02117
02118 i = 0;
02119 sprintf(str, "%s", channel_name);
02120 } else {
02121
02122 i = j + 1;
02123 }
02124 }
02125
02126 if (i == 0) {
02127 char strclient[32];
02128 for (j = 0; j < MAX_LAZY_CHANNEL; j++) {
02129 if (lazyinfo[j].hKey == 0) {
02130
02131 sprintf(strclient, "Lazy_%s", str);
02132 if (cm_exist(strclient, TRUE) == CM_SUCCESS)
02133 lazyinfo[j].active = TRUE;
02134 else
02135 lazyinfo[j].active = FALSE;
02136 strcpy(lazyinfo[j].name, str);
02137 lazyinfo[j].hKey = 0;
02138 channel = j;
02139 break;
02140 }
02141 }
02142 } else if (!lazyinfo[i - 1].active)
02143 channel = i - 1;
02144 else
02145 channel = -1;
02146 }
02147
02148 if (channel < 0) goto error;
02149
02150 {
02151 char str[128];
02152
02153 if (lazyinfo[channel].hKey == 0)
02154 printf(" Creating Lazy channel %s\n", lazyinfo[channel].name);
02155
02156
02157 sprintf(str, "/Lazy/%s/Settings", lazyinfo[channel].name);
02158 db_create_record(hDB, 0, str, LAZY_SETTINGS_STRING);
02159
02160 sprintf(str, "/Lazy/%s/Statistics", lazyinfo[channel].name);
02161 db_create_record(hDB, 0, str, LAZY_STATISTICS_STRING);
02162 sprintf(str, "/Lazy/%s", lazyinfo[channel].name);
02163 db_find_key(hDB, 0, str, &lazyinfo[channel].hKey);
02164 }
02165 }
02166
02167 cm_disconnect_experiment();
02168
02169 {
02170 char str[32];
02171 sprintf(str, "Lazy_%s", lazyinfo[channel].name);
02172 status = cm_connect_experiment1(host_name, expt_name, str, 0, DEFAULT_ODB_SIZE, WATCHDOG_TIMEOUT);
02173 }
02174 if (status != CM_SUCCESS)
02175 goto error;
02176
02177 cm_get_experiment_database(&hDB, &hKey);
02178
02179
02180 {
02181 HNDLE hPkey;
02182
02183 status = db_find_key(hDB, 0, "Programs/Lazy", &hPkey);
02184 if (status == DB_SUCCESS) {
02185 status = db_delete_key(hDB, hPkey, FALSE);
02186 if (status != DB_SUCCESS) {
02187 cm_msg(MERROR, "Lazy", "Cannot delete /Programs/Lazy");
02188 }
02189 }
02190 }
02191
02192
02193 if (debug)
02194 cm_set_watchdog_params(TRUE, 0);
02195
02196 #ifdef HAVE_FTPLIB
02197 if (debug)
02198 ftp_debug((int (*)(char *)) puts, (int (*)(char *)) puts);
02199 #endif
02200
02201 printf("Lazy_%s starting... " "!" " to exit \n", lazyinfo[channel].name);
02202
02203 if (zap_flag) {
02204
02205 cm_msg(MINFO, "Lazy", "zapping %s/statistics content", lazyinfo[channel].name);
02206 size = sizeof(lazyst);
02207 memset(&lazyst, 0, size);
02208 if (db_find_key(hDB, lazyinfo[channel].hKey, "Statistics", &hKeyst) == DB_SUCCESS)
02209 status = db_set_record(hDB, hKeyst, &lazyst, size, 0);
02210 else
02211 cm_msg(MERROR, "Lazy", "did not find %s/Statistics for zapping", lazyinfo[channel].name);
02212 }
02213
02214
02215 db_find_key(hDB, 0, "/runinfo/state", &hKey);
02216 size = sizeof(run_state);
02217 db_get_data(hDB, hKey, &run_state, &size, TID_INT);
02218 status = db_open_record(hDB, hKey, &run_state, sizeof(run_state), MODE_READ, NULL, NULL);
02219 if (status != DB_SUCCESS) {
02220 cm_msg(MERROR, "Lazy", "cannot open /runinfo/state record");
02221 }
02222
02223 size = sizeof(lazyst);
02224 if (db_find_key(hDB, lazyinfo[channel].hKey, "Statistics", &hKey) == DB_SUCCESS)
02225 db_get_record(hDB, hKey, &lazyst, &size, 0);
02226 status = db_open_record(hDB, hKey, &lazyst, sizeof(lazyst), MODE_WRITE, NULL, NULL);
02227 if (status != DB_SUCCESS) {
02228 cm_msg(MERROR, "Lazy", "cannot open %s/Statistics record", lazyinfo[channel].name);
02229 }
02230
02231 db_find_key(hDB, lazyinfo[channel].hKey, "Settings", &hKey);
02232 size = sizeof(lazy);
02233 status = db_open_record(hDB, hKey, &lazy, sizeof(lazy)
02234 , MODE_READ, lazy_settings_hotlink, NULL);
02235 if (status != DB_SUCCESS) {
02236 cm_msg(MERROR, "Lazy", "cannot open %s/Settings record", lazyinfo[channel].name);
02237 }
02238
02239
02240 pcurrent_hKey = lazyinfo[channel].hKey;
02241
02242
02243 if ((lazy.dir[0] == '\0') && (db_find_key(hDB, 0, "/Logger/Data dir", &hKey) == DB_SUCCESS)) {
02244 size = sizeof(lazy.dir);
02245 db_get_data(hDB, hKey, lazy.dir, &size, TID_STRING);
02246 db_set_value(hDB, lazyinfo[channel].hKey, "Settings/Data dir", lazy.dir, size, 1, TID_STRING);
02247 }
02248
02249 mainlast_time = 0;
02250
02251
02252 ss_getchar(0);
02253
02254 do {
02255 msg = cm_yield(2000);
02256 DWORD period = lazy.period*1000;
02257 if (period < 1)
02258 period = 1;
02259 if ((ss_millitime() - mainlast_time) > period) {
02260 status = lazy_main(channel, &lazyinfo[0]);
02261 if (status == FORCE_EXIT) {
02262 cm_msg(MERROR, "lazy", "Exit requested by program");
02263 break;
02264 }
02265 mainlast_time = ss_millitime();
02266 }
02267 ch = 0;
02268 while (ss_kbhit()) {
02269 ch = ss_getchar(0);
02270 if (ch == -1)
02271 ch = getchar();
02272 if ((char) ch == '!')
02273 break;
02274 }
02275 } while (msg != RPC_SHUTDOWN && msg != SS_ABORT && ch != '!');
02276
02277 error:
02278 cm_disconnect_experiment();
02279 return 1;
02280 }