PageRenderTime 78ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

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

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