PageRenderTime 76ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/3_2_0/server-src/find.c

#
C | 1290 lines | 1058 code | 138 blank | 94 comment | 324 complexity | 64fc95b2d0d0c12468e3abe02caeb1ba MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1991-1998 University of Maryland at College Park
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify, distribute, and sell this software and its
  7. * documentation for any purpose is hereby granted without fee, provided that
  8. * the above copyright notice appear in all copies and that both that
  9. * copyright notice and this permission notice appear in supporting
  10. * documentation, and that the name of U.M. not be used in advertising or
  11. * publicity pertaining to distribution of the software without specific,
  12. * written prior permission. U.M. makes no representations about the
  13. * suitability of this software for any purpose. It is provided "as is"
  14. * without express or implied warranty.
  15. *
  16. * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
  18. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  21. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. * Author: James da Silva, Systems Design and Analysis Group
  24. * Computer Science Department
  25. * University of Maryland at College Park
  26. */
  27. /*
  28. * $Id: find.c,v 1.33 2006/07/06 13:13:15 martinea Exp $
  29. *
  30. * controlling process for the Amanda backup system
  31. */
  32. #include "amanda.h"
  33. #include "match.h"
  34. #include "conffile.h"
  35. #include "tapefile.h"
  36. #include "logfile.h"
  37. #include "holding.h"
  38. #include "find.h"
  39. #include <regex.h>
  40. #include "cmdline.h"
  41. int find_match(char *host, char *disk);
  42. char *find_nicedate(char *datestamp);
  43. static int find_compare(const void *, const void *);
  44. static int parse_taper_datestamp_log(char *logline, char **datestamp, char **level);
  45. static gboolean logfile_has_tape(char * label, char * datestamp,
  46. char * logfile);
  47. static char *find_sort_order = NULL;
  48. find_result_t * find_dump(disklist_t* diskqp) {
  49. char *conf_logdir, *logfile = NULL;
  50. int tape, tape1, maxtape, logs;
  51. unsigned seq;
  52. tape_t *tp, *tp1;
  53. find_result_t *output_find = NULL;
  54. gboolean *tape_seen = NULL;
  55. conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
  56. maxtape = lookup_nb_tape();
  57. tape_seen = g_new0(gboolean, maxtape+1);
  58. for(tape = 1; tape <= maxtape; tape++) {
  59. if (tape_seen[tape] == 1)
  60. continue;
  61. tp = lookup_tapepos(tape);
  62. if(tp == NULL) continue;
  63. /* find all tape with the same datestamp */
  64. for (tape1 = tape; tape1 <= maxtape; tape1++) {
  65. tp1 = lookup_tapepos(tape1);
  66. if (tp1 == NULL) continue;
  67. if (strcmp(tp->datestamp, tp1->datestamp) != 0)
  68. continue;
  69. tape_seen[tape1] = 1;
  70. }
  71. /* search log files */
  72. logs = 0;
  73. /* new-style log.<date>.<seq> */
  74. for(seq = 0; 1; seq++) {
  75. char seq_str[NUM_STR_SIZE];
  76. g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
  77. logfile = newvstralloc(logfile,
  78. conf_logdir, "/log.", tp->datestamp, ".", seq_str, NULL);
  79. if(access(logfile, R_OK) != 0) break;
  80. if (search_logfile(&output_find, NULL, tp->datestamp,
  81. logfile, diskqp)) {
  82. logs ++;
  83. }
  84. }
  85. /* search old-style amflush log, if any */
  86. logfile = newvstralloc(logfile, conf_logdir, "/log.",
  87. tp->datestamp, ".amflush", NULL);
  88. if(access(logfile,R_OK) == 0) {
  89. if (search_logfile(&output_find, NULL, tp->datestamp,
  90. logfile, diskqp)) {
  91. logs ++;
  92. }
  93. }
  94. /* search old-style main log, if any */
  95. logfile = newvstralloc(logfile, conf_logdir, "/log.", tp->datestamp,
  96. NULL);
  97. if(access(logfile,R_OK) == 0) {
  98. if (search_logfile(&output_find, NULL, tp->datestamp,
  99. logfile, diskqp)) {
  100. logs ++;
  101. }
  102. }
  103. }
  104. g_free(tape_seen);
  105. amfree(logfile);
  106. amfree(conf_logdir);
  107. search_holding_disk(&output_find, diskqp);
  108. return(output_find);
  109. }
  110. char **
  111. find_log(void)
  112. {
  113. char *conf_logdir, *logfile = NULL;
  114. char *pathlogfile = NULL;
  115. int tape, maxtape, logs;
  116. unsigned seq;
  117. tape_t *tp;
  118. char **output_find_log = NULL;
  119. char **current_log;
  120. conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
  121. maxtape = lookup_nb_tape();
  122. output_find_log = alloc((maxtape*5+10) * SIZEOF(char *));
  123. current_log = output_find_log;
  124. for(tape = 1; tape <= maxtape; tape++) {
  125. tp = lookup_tapepos(tape);
  126. if(tp == NULL) continue;
  127. /* search log files */
  128. logs = 0;
  129. /* new-style log.<date>.<seq> */
  130. for(seq = 0; 1; seq++) {
  131. char seq_str[NUM_STR_SIZE];
  132. g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
  133. logfile = newvstralloc(logfile, "log.", tp->datestamp, ".", seq_str, NULL);
  134. pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
  135. if (access(pathlogfile, R_OK) != 0) break;
  136. if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
  137. if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
  138. *current_log = stralloc(logfile);
  139. current_log++;
  140. }
  141. logs++;
  142. break;
  143. }
  144. }
  145. /* search old-style amflush log, if any */
  146. logfile = newvstralloc(logfile, "log.", tp->datestamp, ".amflush", NULL);
  147. pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
  148. if (access(pathlogfile, R_OK) == 0) {
  149. if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
  150. if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
  151. *current_log = stralloc(logfile);
  152. current_log++;
  153. }
  154. logs++;
  155. }
  156. }
  157. /* search old-style main log, if any */
  158. logfile = newvstralloc(logfile, "log.", tp->datestamp, NULL);
  159. pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
  160. if (access(pathlogfile, R_OK) == 0) {
  161. if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
  162. if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
  163. *current_log = stralloc(logfile);
  164. current_log++;
  165. }
  166. logs++;
  167. }
  168. }
  169. if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
  170. g_fprintf(stderr, _("Warning: no log files found for tape %s written %s\n"),
  171. tp->label, find_nicedate(tp->datestamp));
  172. }
  173. amfree(logfile);
  174. amfree(pathlogfile);
  175. amfree(conf_logdir);
  176. *current_log = NULL;
  177. return(output_find_log);
  178. }
  179. void
  180. search_holding_disk(
  181. find_result_t **output_find,
  182. disklist_t * dynamic_disklist)
  183. {
  184. GSList *holding_file_list;
  185. GSList *e;
  186. char *holding_file;
  187. disk_t *dp;
  188. char *orig_name;
  189. holding_file_list = holding_get_files(NULL, 1);
  190. for(e = holding_file_list; e != NULL; e = e->next) {
  191. dumpfile_t file;
  192. holding_file = (char *)e->data;
  193. if (!holding_file_get_dumpfile(holding_file, &file))
  194. continue;
  195. if (file.dumplevel < 0 || file.dumplevel >= DUMP_LEVELS) {
  196. dumpfile_free_data(&file);
  197. continue;
  198. }
  199. dp = NULL;
  200. orig_name = g_strdup(file.name);
  201. for(;;) {
  202. char *s;
  203. if((dp = lookup_disk(file.name, file.disk)))
  204. break;
  205. if((s = strrchr(file.name,'.')) == NULL)
  206. break;
  207. *s = '\0';
  208. }
  209. strcpy(file.name, orig_name); /* restore munged string */
  210. g_free(orig_name);
  211. if ( dp == NULL ) {
  212. if (dynamic_disklist == NULL) {
  213. dumpfile_free_data(&file);
  214. continue;
  215. }
  216. dp = add_disk(dynamic_disklist, file.name, file.disk);
  217. enqueue_disk(dynamic_disklist, dp);
  218. }
  219. if(find_match(file.name,file.disk)) {
  220. find_result_t *new_output_find = g_new0(find_result_t, 1);
  221. new_output_find->next=*output_find;
  222. new_output_find->timestamp = stralloc(file.datestamp);
  223. new_output_find->write_timestamp = stralloc("00000000000000");
  224. new_output_find->hostname = stralloc(file.name);
  225. new_output_find->diskname = stralloc(file.disk);
  226. new_output_find->level=file.dumplevel;
  227. new_output_find->label=stralloc(holding_file);
  228. new_output_find->partnum = -1;
  229. new_output_find->totalparts = -1;
  230. new_output_find->filenum=0;
  231. if (file.is_partial) {
  232. new_output_find->status=stralloc("PARTIAL");
  233. new_output_find->dump_status=stralloc("PARTIAL");
  234. } else {
  235. new_output_find->status=stralloc("OK");
  236. new_output_find->dump_status=stralloc("OK");
  237. }
  238. new_output_find->message=stralloc("");
  239. new_output_find->kb = holding_file_size(holding_file, 1);
  240. new_output_find->orig_kb = file.orig_size;
  241. *output_find=new_output_find;
  242. }
  243. dumpfile_free_data(&file);
  244. }
  245. g_slist_free_full(holding_file_list);
  246. }
  247. static int
  248. find_compare(
  249. const void *i1,
  250. const void *j1)
  251. {
  252. int compare=0;
  253. find_result_t *i, *j;
  254. size_t nb_compare=strlen(find_sort_order);
  255. size_t k;
  256. for(k=0;k<nb_compare;k++) {
  257. char sort_key = find_sort_order[k];
  258. if (isupper((int)sort_key)) {
  259. /* swap */
  260. sort_key = tolower(sort_key);
  261. j = *(find_result_t **)i1;
  262. i = *(find_result_t **)j1;
  263. } else {
  264. i = *(find_result_t **)i1;
  265. j = *(find_result_t **)j1;
  266. }
  267. switch (sort_key) {
  268. case 'h' : compare=strcmp(i->hostname,j->hostname);
  269. break;
  270. case 'k' : compare=strcmp(i->diskname,j->diskname);
  271. break;
  272. case 'd' : compare=strcmp(i->timestamp,j->timestamp);
  273. break;
  274. case 'l' : compare=j->level - i->level;
  275. break;
  276. case 'f' : compare=(i->filenum == j->filenum) ? 0 :
  277. ((i->filenum < j->filenum) ? -1 : 1);
  278. break;
  279. case 'b' : compare=compare_possibly_null_strings(i->label,
  280. j->label);
  281. break;
  282. case 'w': compare=strcmp(i->write_timestamp, j->write_timestamp);
  283. break;
  284. case 'p' :
  285. compare=i->partnum - j->partnum;
  286. break;
  287. }
  288. if(compare != 0)
  289. return compare;
  290. }
  291. return 0;
  292. }
  293. void
  294. sort_find_result(
  295. char *sort_order,
  296. find_result_t **output_find)
  297. {
  298. find_result_t *output_find_result;
  299. find_result_t **array_find_result = NULL;
  300. size_t nb_result=0;
  301. size_t no_result;
  302. find_sort_order = sort_order;
  303. /* qsort core dump if nothing to sort */
  304. if(*output_find==NULL)
  305. return;
  306. /* How many result */
  307. for(output_find_result=*output_find;
  308. output_find_result;
  309. output_find_result=output_find_result->next) {
  310. nb_result++;
  311. }
  312. /* put the list in an array */
  313. array_find_result=alloc(nb_result * SIZEOF(find_result_t *));
  314. for(output_find_result=*output_find,no_result=0;
  315. output_find_result;
  316. output_find_result=output_find_result->next,no_result++) {
  317. array_find_result[no_result]=output_find_result;
  318. }
  319. /* sort the array */
  320. qsort(array_find_result,nb_result,SIZEOF(find_result_t *),
  321. find_compare);
  322. /* put the sorted result in the list */
  323. for(no_result=0;
  324. no_result<nb_result-1; no_result++) {
  325. array_find_result[no_result]->next = array_find_result[no_result+1];
  326. }
  327. array_find_result[nb_result-1]->next=NULL;
  328. *output_find=array_find_result[0];
  329. amfree(array_find_result);
  330. }
  331. void
  332. print_find_result(
  333. find_result_t *output_find)
  334. {
  335. find_result_t *output_find_result;
  336. int max_len_datestamp = 4;
  337. int max_len_hostname = 4;
  338. int max_len_diskname = 4;
  339. int max_len_level = 2;
  340. int max_len_label =12;
  341. int max_len_filenum = 4;
  342. int max_len_part = 4;
  343. int max_len_status = 6;
  344. size_t len;
  345. for(output_find_result=output_find;
  346. output_find_result;
  347. output_find_result=output_find_result->next) {
  348. char *qdiskname;
  349. char *s;
  350. len=strlen(find_nicedate(output_find_result->timestamp));
  351. if((int)len > max_len_datestamp)
  352. max_len_datestamp=(int)len;
  353. len=strlen(output_find_result->hostname);
  354. if((int)len > max_len_hostname)
  355. max_len_hostname = (int)len;
  356. qdiskname=quote_string(output_find_result->diskname);
  357. len=strlen(qdiskname);
  358. amfree(qdiskname);
  359. if((int)len > max_len_diskname)
  360. max_len_diskname = (int)len;
  361. if (output_find_result->label != NULL) {
  362. char *qlabel = quote_string(output_find_result->label);
  363. len=strlen(qlabel);
  364. amfree(qlabel);
  365. if((int)len > max_len_label)
  366. max_len_label = (int)len;
  367. }
  368. len=strlen(output_find_result->status) + 1 + strlen(output_find_result->dump_status);
  369. if((int)len > max_len_status)
  370. max_len_status = (int)len;
  371. s = g_strdup_printf("%d/%d", output_find_result->partnum,
  372. output_find_result->totalparts);
  373. len=strlen(s);
  374. if((int)len > max_len_part)
  375. max_len_part = (int)len;
  376. amfree(s);
  377. }
  378. /*
  379. * Since status is the rightmost field, we zap the maximum length
  380. * because it is not needed. The code is left in place in case
  381. * another column is added later.
  382. */
  383. max_len_status = 1;
  384. if(output_find==NULL) {
  385. g_printf(_("\nNo dump to list\n"));
  386. }
  387. else {
  388. g_printf(_("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s part%*s status\n"),
  389. max_len_datestamp-4,"",
  390. max_len_hostname-4 ,"",
  391. max_len_diskname-4 ,"",
  392. max_len_level-2 ,"",
  393. max_len_label-12 ,"",
  394. max_len_filenum-4 ,"",
  395. max_len_part-4 ,"");
  396. for(output_find_result=output_find;
  397. output_find_result;
  398. output_find_result=output_find_result->next) {
  399. char *qdiskname;
  400. char * formatted_label;
  401. char *s;
  402. char *status;
  403. qdiskname = quote_string(output_find_result->diskname);
  404. if (output_find_result->label == NULL)
  405. formatted_label = stralloc("");
  406. else
  407. formatted_label = quote_string(output_find_result->label);
  408. if (strcmp(output_find_result->status, "OK") != 0 ||
  409. strcmp(output_find_result->dump_status, "OK") != 0) {
  410. status = vstralloc(output_find_result->status, " ",
  411. output_find_result->dump_status, NULL);
  412. } else {
  413. status = stralloc(output_find_result->status);
  414. }
  415. /*@ignore@*/
  416. /* sec and kb are omitted here, for compatibility with the existing
  417. * output from 'amadmin' */
  418. s = g_strdup_printf("%d/%d", output_find_result->partnum,
  419. output_find_result->totalparts);
  420. g_printf("%-*s %-*s %-*s %*d %-*s %*lld %*s %s %s\n",
  421. max_len_datestamp,
  422. find_nicedate(output_find_result->timestamp),
  423. max_len_hostname, output_find_result->hostname,
  424. max_len_diskname, qdiskname,
  425. max_len_level, output_find_result->level,
  426. max_len_label, formatted_label,
  427. max_len_filenum, (long long)output_find_result->filenum,
  428. max_len_part, s,
  429. status,
  430. output_find_result->message
  431. );
  432. amfree(status);
  433. amfree(s);
  434. /*@end@*/
  435. amfree(qdiskname);
  436. amfree(formatted_label);
  437. }
  438. }
  439. }
  440. void
  441. free_find_result(
  442. find_result_t **output_find)
  443. {
  444. find_result_t *output_find_result, *prev;
  445. prev=NULL;
  446. for(output_find_result=*output_find;
  447. output_find_result;
  448. output_find_result=output_find_result->next) {
  449. amfree(prev);
  450. amfree(output_find_result->timestamp);
  451. amfree(output_find_result->write_timestamp);
  452. amfree(output_find_result->hostname);
  453. amfree(output_find_result->diskname);
  454. amfree(output_find_result->label);
  455. amfree(output_find_result->status);
  456. amfree(output_find_result->dump_status);
  457. amfree(output_find_result->message);
  458. prev = output_find_result;
  459. }
  460. amfree(prev);
  461. *output_find = NULL;
  462. }
  463. int
  464. find_match(
  465. char *host,
  466. char *disk)
  467. {
  468. disk_t *dp = lookup_disk(host,disk);
  469. return (dp && dp->todo);
  470. }
  471. char *
  472. find_nicedate(
  473. char *datestamp)
  474. {
  475. static char nice[20];
  476. int year, month, day;
  477. int hours, minutes, seconds;
  478. char date[9], atime[7];
  479. int numdate, numtime;
  480. strncpy(date, datestamp, 8);
  481. date[8] = '\0';
  482. numdate = atoi(date);
  483. year = numdate / 10000;
  484. month = (numdate / 100) % 100;
  485. day = numdate % 100;
  486. if(strlen(datestamp) <= 8) {
  487. g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d",
  488. year, month, day);
  489. }
  490. else {
  491. strncpy(atime, &(datestamp[8]), 6);
  492. atime[6] = '\0';
  493. numtime = atoi(atime);
  494. hours = numtime / 10000;
  495. minutes = (numtime / 100) % 100;
  496. seconds = numtime % 100;
  497. g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d %02d:%02d:%02d",
  498. year, month, day, hours, minutes, seconds);
  499. }
  500. return nice;
  501. }
  502. static int
  503. parse_taper_datestamp_log(
  504. char *logline,
  505. char **datestamp,
  506. char **label)
  507. {
  508. char *s;
  509. int ch;
  510. s = logline;
  511. ch = *s++;
  512. skip_whitespace(s, ch);
  513. if(ch == '\0') {
  514. return 0;
  515. }
  516. if(strncmp_const_skip(s - 1, "datestamp", s, ch) != 0) {
  517. return 0;
  518. }
  519. skip_whitespace(s, ch);
  520. if(ch == '\0') {
  521. return 0;
  522. }
  523. *datestamp = s - 1;
  524. skip_non_whitespace(s, ch);
  525. s[-1] = '\0';
  526. skip_whitespace(s, ch);
  527. if(ch == '\0') {
  528. return 0;
  529. }
  530. if(strncmp_const_skip(s - 1, "label", s, ch) != 0) {
  531. return 0;
  532. }
  533. skip_whitespace(s, ch);
  534. if(ch == '\0') {
  535. return 0;
  536. }
  537. *label = s - 1;
  538. skip_non_whitespace(s, ch);
  539. s[-1] = '\0';
  540. return 1;
  541. }
  542. /* Returns TRUE if the given logfile mentions the given tape. */
  543. static gboolean logfile_has_tape(char * label, char * datestamp,
  544. char * logfile) {
  545. FILE * logf;
  546. char * ck_datestamp, *ck_label;
  547. if((logf = fopen(logfile, "r")) == NULL) {
  548. error(_("could not open logfile %s: %s"), logfile, strerror(errno));
  549. /*NOTREACHED*/
  550. }
  551. while(get_logline(logf)) {
  552. if(curlog == L_START && curprog == P_TAPER) {
  553. if(parse_taper_datestamp_log(curstr,
  554. &ck_datestamp, &ck_label) == 0) {
  555. g_printf(_("strange log line \"start taper %s\" curstr='%s'\n"),
  556. logfile, curstr);
  557. } else if(strcmp(ck_datestamp, datestamp) == 0
  558. && strcmp(ck_label, label) == 0) {
  559. afclose(logf);
  560. return TRUE;
  561. }
  562. }
  563. }
  564. afclose(logf);
  565. return FALSE;
  566. }
  567. static gboolean
  568. volume_matches(
  569. const char *label1,
  570. const char *label2,
  571. const char *datestamp)
  572. {
  573. tape_t *tp;
  574. if (!label2)
  575. return TRUE;
  576. if (label1)
  577. return (strcmp(label1, label2) == 0);
  578. /* check in tapelist */
  579. if (!(tp = lookup_tapelabel(label2)))
  580. return FALSE;
  581. if (strcmp(tp->datestamp, datestamp) != 0)
  582. return FALSE;
  583. return TRUE;
  584. }
  585. /* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
  586. * dynamic_disklist */
  587. gboolean
  588. search_logfile(
  589. find_result_t **output_find,
  590. const char *label,
  591. const char *passed_datestamp,
  592. const char *logfile,
  593. disklist_t * dynamic_disklist)
  594. {
  595. FILE *logf;
  596. char *host, *host_undo;
  597. char *disk, *qdisk, *disk_undo;
  598. char *date, *date_undo;
  599. int partnum;
  600. int totalparts;
  601. int maxparts = -1;
  602. char *number;
  603. int fileno;
  604. char *current_label = stralloc("");
  605. char *rest;
  606. char *ck_label=NULL;
  607. int level = 0;
  608. off_t filenum;
  609. char *ck_datestamp, *datestamp;
  610. char *s;
  611. int ch;
  612. disk_t *dp;
  613. GHashTable* valid_label;
  614. GHashTable* part_by_dle;
  615. find_result_t *part_find;
  616. find_result_t *a_part_find;
  617. gboolean right_label = FALSE;
  618. gboolean found_something = FALSE;
  619. regex_t regex;
  620. int reg_result;
  621. regmatch_t pmatch[4];
  622. double sec;
  623. off_t kb;
  624. off_t orig_kb;
  625. int taper_part = 0;
  626. g_return_val_if_fail(output_find != NULL, 0);
  627. g_return_val_if_fail(logfile != NULL, 0);
  628. valid_label = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
  629. part_by_dle = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
  630. datestamp = g_strdup(passed_datestamp);
  631. if((logf = fopen(logfile, "r")) == NULL) {
  632. error(_("could not open logfile %s: %s"), logfile, strerror(errno));
  633. /*NOTREACHED*/
  634. }
  635. filenum = (off_t)0;
  636. while(get_logline(logf)) {
  637. if (curlog == L_START && curprog == P_TAPER) {
  638. if(parse_taper_datestamp_log(curstr, &ck_datestamp,
  639. &ck_label) == 0) {
  640. g_printf(_("strange log line in %s \"start taper %s\"\n"),
  641. logfile, curstr);
  642. continue;
  643. }
  644. if (datestamp != NULL) {
  645. if (strcmp(datestamp, ck_datestamp) != 0) {
  646. g_printf(_("Log file %s stamped %s, expecting %s!\n"),
  647. logfile, ck_datestamp, datestamp);
  648. break;
  649. }
  650. }
  651. right_label = volume_matches(label, ck_label, ck_datestamp);
  652. if (right_label && ck_label) {
  653. g_hash_table_insert(valid_label, g_strdup(ck_label),
  654. GINT_TO_POINTER(1));
  655. }
  656. if (label && datestamp && right_label) {
  657. found_something = TRUE;
  658. }
  659. amfree(current_label);
  660. current_label = g_strdup(ck_label);
  661. if (datestamp == NULL) {
  662. datestamp = g_strdup(ck_datestamp);
  663. }
  664. filenum = (off_t)0;
  665. }
  666. if (right_label &&
  667. (curlog == L_SUCCESS ||
  668. curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
  669. curprog == P_TAPER) {
  670. filenum++;
  671. } else if (right_label && curlog == L_PARTIAL && curprog == P_TAPER &&
  672. taper_part == 0) {
  673. filenum++;
  674. }
  675. partnum = -1;
  676. totalparts = -1;
  677. if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
  678. curlog == L_DONE || curlog == L_FAIL ||
  679. curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTIAL ||
  680. curlog == L_PARTPARTIAL ) {
  681. s = curstr;
  682. ch = *s++;
  683. skip_whitespace(s, ch);
  684. if(ch == '\0') {
  685. g_printf(_("strange log line in %s \"%s\"\n"),
  686. logfile, curstr);
  687. continue;
  688. }
  689. if (curlog == L_PART || curlog == L_PARTPARTIAL) {
  690. char * part_label = s - 1;
  691. taper_part++;
  692. skip_non_whitespace(s, ch);
  693. s[-1] = '\0';
  694. if (!g_hash_table_lookup(valid_label, part_label))
  695. continue;
  696. amfree(current_label);
  697. current_label = stralloc(part_label);
  698. skip_whitespace(s, ch);
  699. if(ch == '\0') {
  700. g_printf("strange log line in %s \"%s\"\n",
  701. logfile, curstr);
  702. continue;
  703. }
  704. number = s - 1;
  705. skip_non_whitespace(s, ch);
  706. s[-1] = '\0';
  707. fileno = atoi(number);
  708. filenum = fileno;
  709. if (filenum == 0)
  710. continue;
  711. skip_whitespace(s, ch);
  712. if(ch == '\0') {
  713. g_printf("strange log line in %s \"%s\"\n",
  714. logfile, curstr);
  715. continue;
  716. }
  717. } else {
  718. taper_part = 0;
  719. }
  720. host = s - 1;
  721. skip_non_whitespace(s, ch);
  722. host_undo = s - 1;
  723. *host_undo = '\0';
  724. skip_whitespace(s, ch);
  725. if(ch == '\0') {
  726. g_printf(_("strange log line in %s \"%s\"\n"),
  727. logfile, curstr);
  728. continue;
  729. }
  730. qdisk = s - 1;
  731. skip_quoted_string(s, ch);
  732. disk_undo = s - 1;
  733. *disk_undo = '\0';
  734. disk = unquote_string(qdisk);
  735. skip_whitespace(s, ch);
  736. if(ch == '\0') {
  737. g_printf(_("strange log line in %s \"%s\"\n"),
  738. logfile, curstr);
  739. continue;
  740. }
  741. date = s - 1;
  742. skip_non_whitespace(s, ch);
  743. date_undo = s - 1;
  744. *date_undo = '\0';
  745. if(strlen(date) < 3) { /* old log didn't have datestamp */
  746. level = atoi(date);
  747. date = stralloc(datestamp);
  748. partnum = 1;
  749. totalparts =1;
  750. } else {
  751. if (curprog == P_TAPER &&
  752. (curlog == L_CHUNK || curlog == L_PART ||
  753. curlog == L_PARTPARTIAL || curlog == L_PARTIAL ||
  754. curlog == L_DONE)) {
  755. skip_whitespace(s, ch);
  756. number = s - 1;
  757. skip_non_whitespace(s, ch);
  758. s[-1] = '\0';
  759. sscanf(number, "%d/%d", &partnum, &totalparts);
  760. if (partnum > maxparts)
  761. maxparts = partnum;
  762. if (totalparts > maxparts)
  763. maxparts = totalparts;
  764. }
  765. skip_whitespace(s, ch);
  766. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  767. g_printf(_("strange log line in %s \"%s\"\n"),
  768. logfile, curstr);
  769. continue;
  770. }
  771. skip_integer(s, ch);
  772. }
  773. skip_whitespace(s, ch);
  774. if(ch == '\0') {
  775. g_printf(_("strange log line in %s \"%s\"\n"),
  776. logfile, curstr);
  777. continue;
  778. }
  779. rest = s - 1;
  780. if((s = strchr(s, '\n')) != NULL) {
  781. *s = '\0';
  782. }
  783. /* extract sec, kb, kps, orig-kb from 'rest', if present. This isn't the stone age
  784. * anymore, so we'll just do it the easy way (a regex) */
  785. bzero(&regex, sizeof(regex));
  786. reg_result = regcomp(&regex,
  787. "\\[sec ([0-9.]+) kb ([0-9]+) kps [0-9.]+ orig-kb ([0-9]+)\\]", REG_EXTENDED);
  788. if (reg_result != 0) {
  789. error("Error compiling regular expression for parsing log lines");
  790. /* NOTREACHED */
  791. }
  792. /* an error here just means the line wasn't found -- not fatal. */
  793. reg_result = regexec(&regex, rest, sizeof(pmatch)/sizeof(*pmatch), pmatch, 0);
  794. if (reg_result == 0) {
  795. char *str;
  796. str = find_regex_substring(rest, pmatch[1]);
  797. sec = atof(str);
  798. amfree(str);
  799. str = find_regex_substring(rest, pmatch[2]);
  800. kb = OFF_T_ATOI(str);
  801. amfree(str);
  802. str = find_regex_substring(rest, pmatch[3]);
  803. orig_kb = OFF_T_ATOI(str);
  804. amfree(str);
  805. } else {
  806. regfree(&regex);
  807. bzero(&regex, sizeof(regex));
  808. /* the .* at the end of this captures the old {wr: .. } statistics */
  809. reg_result = regcomp(&regex,
  810. "\\[sec ([0-9.]+) kb ([0-9]+) kps [0-9.]+.*\\]", REG_EXTENDED);
  811. if (reg_result != 0) {
  812. error("Error compiling regular expression for parsing log lines");
  813. /* NOTREACHED */
  814. }
  815. /* an error here just means the line wasn't found -- not fatal. */
  816. reg_result = regexec(&regex, rest, sizeof(pmatch)/sizeof(*pmatch), pmatch, 0);
  817. if (reg_result == 0) {
  818. char *str;
  819. str = find_regex_substring(rest, pmatch[1]);
  820. sec = atof(str);
  821. amfree(str);
  822. str = find_regex_substring(rest, pmatch[2]);
  823. kb = OFF_T_ATOI(str);
  824. amfree(str);
  825. orig_kb = 0;
  826. } else {
  827. sec = 0;
  828. kb = 0;
  829. orig_kb = 0;
  830. }
  831. }
  832. if (strncmp(rest, "error ", 6) == 0) rest += 6;
  833. if (strncmp(rest, "config ", 7) == 0) rest += 7;
  834. regfree(&regex);
  835. dp = lookup_disk(host,disk);
  836. if ( dp == NULL ) {
  837. if (dynamic_disklist == NULL) {
  838. continue;
  839. }
  840. dp = add_disk(dynamic_disklist, host, disk);
  841. enqueue_disk(dynamic_disklist, dp);
  842. }
  843. if (find_match(host, disk)) {
  844. if(curprog == P_TAPER) {
  845. char *key = g_strdup_printf(
  846. "HOST:%s DISK:%s: DATE:%s LEVEL:%d",
  847. host, disk, date, level);
  848. find_result_t *new_output_find = g_new0(find_result_t, 1);
  849. part_find = g_hash_table_lookup(part_by_dle, key);
  850. new_output_find->timestamp = stralloc(date);
  851. new_output_find->write_timestamp = stralloc(datestamp);
  852. new_output_find->hostname=stralloc(host);
  853. new_output_find->diskname=stralloc(disk);
  854. new_output_find->level=level;
  855. new_output_find->partnum = partnum;
  856. new_output_find->totalparts = totalparts;
  857. new_output_find->label=stralloc(current_label);
  858. new_output_find->status=NULL;
  859. new_output_find->dump_status=NULL;
  860. new_output_find->message=stralloc("");
  861. new_output_find->filenum=filenum;
  862. new_output_find->sec=sec;
  863. new_output_find->kb=kb;
  864. new_output_find->orig_kb=orig_kb;
  865. new_output_find->next=NULL;
  866. if (curlog == L_SUCCESS) {
  867. new_output_find->status = stralloc("OK");
  868. new_output_find->dump_status = stralloc("OK");
  869. new_output_find->next = *output_find;
  870. new_output_find->partnum = 1; /* L_SUCCESS is pre-splitting */
  871. *output_find = new_output_find;
  872. found_something = TRUE;
  873. } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
  874. curlog == L_PARTIAL || curlog == L_FAIL) {
  875. /* result line */
  876. if (curlog == L_PARTIAL || curlog == L_FAIL) {
  877. /* set dump_status of each part */
  878. for (a_part_find = part_find;
  879. a_part_find;
  880. a_part_find = a_part_find->next) {
  881. amfree(a_part_find->dump_status);
  882. if (curlog == L_PARTIAL)
  883. a_part_find->dump_status = stralloc("PARTIAL");
  884. else {
  885. a_part_find->dump_status = stralloc("FAIL");
  886. amfree(a_part_find->message);
  887. a_part_find->message = stralloc(rest);
  888. }
  889. }
  890. } else {
  891. if (maxparts > -1) { /* format with part */
  892. /* must check if all part are there */
  893. int num_part = maxparts;
  894. for (a_part_find = part_find;
  895. a_part_find;
  896. a_part_find = a_part_find->next) {
  897. if (a_part_find->partnum == num_part &&
  898. strcmp(a_part_find->status, "OK") == 0)
  899. num_part--;
  900. }
  901. /* set dump_status of each part */
  902. for (a_part_find = part_find;
  903. a_part_find;
  904. a_part_find = a_part_find->next) {
  905. amfree(a_part_find->dump_status);
  906. if (num_part == 0) {
  907. a_part_find->dump_status =
  908. stralloc("OK");
  909. } else {
  910. a_part_find->dump_status =
  911. stralloc("FAIL");
  912. amfree(a_part_find->message);
  913. a_part_find->message =
  914. stralloc("Missing part");
  915. }
  916. }
  917. }
  918. }
  919. if (curlog == L_DONE) {
  920. for (a_part_find = part_find;
  921. a_part_find;
  922. a_part_find = a_part_find->next) {
  923. if (a_part_find->totalparts == -1) {
  924. a_part_find->totalparts = maxparts;
  925. }
  926. if (a_part_find->orig_kb == 0) {
  927. a_part_find->orig_kb = orig_kb;
  928. }
  929. }
  930. }
  931. if (part_find) { /* find last element */
  932. for (a_part_find = part_find;
  933. a_part_find->next != NULL;
  934. a_part_find=a_part_find->next) {
  935. }
  936. /* merge part_find to *output_find */
  937. a_part_find->next = *output_find;
  938. *output_find = part_find;
  939. part_find = NULL;
  940. maxparts = -1;
  941. found_something = TRUE;
  942. g_hash_table_remove(part_by_dle, key);
  943. }
  944. free_find_result(&new_output_find);
  945. } else { /* part line */
  946. if (curlog == L_PART || curlog == L_CHUNK) {
  947. new_output_find->status=stralloc("OK");
  948. new_output_find->dump_status=stralloc("OK");
  949. } else { /* PARTPARTIAL */
  950. new_output_find->status=stralloc("PARTIAL");
  951. new_output_find->dump_status=stralloc("PARTIAL");
  952. }
  953. /* Add to part_find list */
  954. if (part_find) {
  955. new_output_find->next = part_find;
  956. part_find = new_output_find;
  957. } else {
  958. new_output_find->next = NULL;
  959. part_find = new_output_find;
  960. }
  961. g_hash_table_insert(part_by_dle, g_strdup(key),
  962. part_find);
  963. found_something = TRUE;
  964. }
  965. amfree(key);
  966. }
  967. else if(curlog == L_FAIL) {
  968. /* print other failures too -- this is a hack to ensure that failures which
  969. * did not make it to tape are also listed in the output of 'amadmin x find';
  970. * users that do not want this information (e.g., Amanda::DB::Catalog) should
  971. * filter dumps with a NULL label. */
  972. find_result_t *new_output_find = g_new0(find_result_t, 1);
  973. new_output_find->next = *output_find;
  974. new_output_find->timestamp = stralloc(date);
  975. new_output_find->write_timestamp = g_strdup("00000000000000"); /* dump was not written.. */
  976. new_output_find->hostname=stralloc(host);
  977. new_output_find->diskname=stralloc(disk);
  978. new_output_find->level=level;
  979. new_output_find->label=NULL;
  980. new_output_find->partnum=partnum;
  981. new_output_find->totalparts=totalparts;
  982. new_output_find->filenum=0;
  983. new_output_find->sec=sec;
  984. new_output_find->kb=kb;
  985. new_output_find->kb=orig_kb;
  986. new_output_find->status=vstralloc(
  987. "FAILED (",
  988. program_str[(int)curprog],
  989. ") ",
  990. rest,
  991. NULL);
  992. new_output_find->dump_status=stralloc("");
  993. new_output_find->message=stralloc("");
  994. *output_find=new_output_find;
  995. found_something = TRUE;
  996. maxparts = -1;
  997. }
  998. }
  999. amfree(disk);
  1000. }
  1001. }
  1002. g_hash_table_destroy(valid_label);
  1003. afclose(logf);
  1004. amfree(datestamp);
  1005. amfree(current_label);
  1006. return found_something;
  1007. }
  1008. /*
  1009. * Return the set of dumps that match *all* of the given patterns (we consider
  1010. * an empty pattern to match .*, though). If 'ok' is true, will only match
  1011. * dumps with SUCCESS status.
  1012. *
  1013. * Returns a newly allocated list of results, where all strings are also newly
  1014. * allocated. Apparently some part of Amanda leaks under this condition.
  1015. */
  1016. find_result_t *
  1017. dumps_match(
  1018. find_result_t *output_find,
  1019. char *hostname,
  1020. char *diskname,
  1021. char *datestamp,
  1022. char *level,
  1023. int ok)
  1024. {
  1025. find_result_t *cur_result;
  1026. find_result_t *matches = NULL;
  1027. for(cur_result=output_find;
  1028. cur_result;
  1029. cur_result=cur_result->next) {
  1030. char level_str[NUM_STR_SIZE];
  1031. g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
  1032. if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) &&
  1033. (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) &&
  1034. (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) &&
  1035. (!level || *level== '\0' || match_level(level, level_str)) &&
  1036. (!ok || !strcmp(cur_result->status, "OK")) &&
  1037. (!ok || !strcmp(cur_result->dump_status, "OK"))){
  1038. find_result_t *curmatch = g_new0(find_result_t, 1);
  1039. memcpy(curmatch, cur_result, SIZEOF(find_result_t));
  1040. curmatch->timestamp = stralloc(cur_result->timestamp);
  1041. curmatch->write_timestamp = stralloc(cur_result->write_timestamp);
  1042. curmatch->hostname = stralloc(cur_result->hostname);
  1043. curmatch->diskname = stralloc(cur_result->diskname);
  1044. curmatch->level = cur_result->level;
  1045. curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
  1046. curmatch->filenum = cur_result->filenum;
  1047. curmatch->sec = cur_result->sec;
  1048. curmatch->kb = cur_result->kb;
  1049. curmatch->orig_kb = cur_result->orig_kb;
  1050. curmatch->status = stralloc(cur_result->status);
  1051. curmatch->dump_status = stralloc(cur_result->dump_status);
  1052. curmatch->message = stralloc(cur_result->message);
  1053. curmatch->partnum = cur_result->partnum;
  1054. curmatch->totalparts = cur_result->totalparts;
  1055. curmatch->next = matches;
  1056. matches = curmatch;
  1057. }
  1058. }
  1059. return(matches);
  1060. }
  1061. /*
  1062. * Return the set of dumps that match one or more of the given dumpspecs,
  1063. * If 'ok' is true, only dumps with a SUCCESS status will be matched.
  1064. *
  1065. * Returns a newly allocated list of results, where all strings are also newly
  1066. * allocated. Apparently some part of Amanda leaks under this condition.
  1067. */
  1068. find_result_t *
  1069. dumps_match_dumpspecs(
  1070. find_result_t *output_find,
  1071. GSList *dumpspecs,
  1072. int ok)
  1073. {
  1074. find_result_t *cur_result;
  1075. find_result_t *matches = NULL;
  1076. GSList *dumpspec;
  1077. dumpspec_t *ds;
  1078. for(cur_result=output_find;
  1079. cur_result;
  1080. cur_result=cur_result->next) {
  1081. char level_str[NUM_STR_SIZE];
  1082. char *zeropad_ts = NULL;
  1083. char *zeropad_w_ts = NULL;
  1084. g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
  1085. /* get the timestamp padded to full width */
  1086. if (strlen(cur_result->timestamp) < 14) {
  1087. zeropad_ts = g_new0(char, 15);
  1088. memset(zeropad_ts, '0', 14);
  1089. memcpy(zeropad_ts, cur_result->timestamp, strlen(cur_result->timestamp));
  1090. }
  1091. if (strlen(cur_result->write_timestamp) < 14) {
  1092. zeropad_w_ts = g_new0(char, 15);
  1093. memset(zeropad_w_ts, '0', 14);
  1094. memcpy(zeropad_w_ts, cur_result->write_timestamp, strlen(cur_result->write_timestamp));
  1095. }
  1096. for (dumpspec = dumpspecs; dumpspec; dumpspec = dumpspec->next) {
  1097. ds = (dumpspec_t *)dumpspec->data;
  1098. if((!ds->host || *ds->host == '\0' || match_host(ds->host, cur_result->hostname)) &&
  1099. (!ds->disk || *ds->disk == '\0' || match_disk(ds->disk, cur_result->diskname)) &&
  1100. (!ds->datestamp || *ds->datestamp== '\0'
  1101. || match_datestamp(ds->datestamp, cur_result->timestamp)
  1102. || (zeropad_ts && match_datestamp(ds->datestamp, zeropad_ts))) &&
  1103. (!ds->write_timestamp || *ds->write_timestamp== '\0'
  1104. || match_datestamp(ds->write_timestamp, cur_result->write_timestamp)
  1105. || (zeropad_w_ts && match_datestamp(ds->write_timestamp, zeropad_w_ts))) &&
  1106. (!ds->level || *ds->level== '\0' || match_level(ds->level, level_str)) &&
  1107. (!ok || !strcmp(cur_result->status, "OK")) &&
  1108. (!ok || !strcmp(cur_result->dump_status, "OK"))) {
  1109. find_result_t *curmatch = alloc(SIZEOF(find_result_t));
  1110. memcpy(curmatch, cur_result, SIZEOF(find_result_t));
  1111. curmatch->timestamp = stralloc(cur_result->timestamp);
  1112. curmatch->write_timestamp = stralloc(cur_result->write_timestamp);
  1113. curmatch->hostname = stralloc(cur_result->hostname);
  1114. curmatch->diskname = stralloc(cur_result->diskname);
  1115. curmatch->level = cur_result->level;
  1116. curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
  1117. curmatch->filenum = cur_result->filenum;
  1118. curmatch->status = stralloc(cur_result->status);
  1119. curmatch->dump_status = stralloc(cur_result->dump_status);
  1120. curmatch->message = stralloc(cur_result->message);
  1121. curmatch->partnum = cur_result->partnum;
  1122. curmatch->totalparts = cur_result->totalparts;
  1123. curmatch->next = matches;
  1124. matches = curmatch;
  1125. break;
  1126. }
  1127. }
  1128. amfree(zeropad_ts);
  1129. }
  1130. return(matches);
  1131. }
  1132. find_result_t *
  1133. dump_exist(
  1134. find_result_t *output_find,
  1135. char *hostname,
  1136. char *diskname,
  1137. char *datestamp,
  1138. int level)
  1139. {
  1140. find_result_t *output_find_result;
  1141. for(output_find_result=output_find;
  1142. output_find_result;
  1143. output_find_result=output_find_result->next) {
  1144. if( !strcmp(output_find_result->hostname, hostname) &&
  1145. !strcmp(output_find_result->diskname, diskname) &&
  1146. !strcmp(output_find_result->timestamp, datestamp) &&
  1147. output_find_result->level == level) {
  1148. return output_find_result;
  1149. }
  1150. }
  1151. return(NULL);
  1152. }