PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

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