PageRenderTime 60ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

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