PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

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

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