PageRenderTime 63ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/3_1_0_mac01/client-src/client_util.c

#
C | 1711 lines | 1658 code | 23 blank | 30 comment | 39 complexity | 696c83720506fb79b75e02888020edb1 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. * Authors: the Amanda Development Team. Its members are listed in a
  24. * file named AUTHORS, in the root directory of this distribution.
  25. */
  26. /*
  27. * $Id: client_util.c,v 1.34 2006/05/25 01:47:11 johnfranks Exp $
  28. *
  29. */
  30. #include "amanda.h"
  31. #include "conffile.h"
  32. #include "client_util.h"
  33. #include "getfsent.h"
  34. #include "util.h"
  35. #include "glib-util.h"
  36. #include "timestamp.h"
  37. #include "pipespawn.h"
  38. #include "amxml.h"
  39. #include "glob.h"
  40. #include "clock.h"
  41. #include "amandates.h"
  42. #define MAXMAXDUMPS 16
  43. static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
  44. static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
  45. static char *build_name(char *disk, char *exin, int verbose);
  46. static char *get_name(char *diskname, char *exin, time_t t, int n);
  47. char *
  48. fixup_relative(
  49. char * name,
  50. char * device)
  51. {
  52. char *newname;
  53. if(*name != '/') {
  54. char *dirname = amname_to_dirname(device);
  55. newname = vstralloc(dirname, "/", name , NULL);
  56. amfree(dirname);
  57. }
  58. else {
  59. newname = stralloc(name);
  60. }
  61. return newname;
  62. }
  63. static char *
  64. get_name(
  65. char * diskname,
  66. char * exin,
  67. time_t t,
  68. int n)
  69. {
  70. char number[NUM_STR_SIZE];
  71. char *filename;
  72. char *ts;
  73. ts = get_timestamp_from_time(t);
  74. if(n == 0)
  75. number[0] = '\0';
  76. else
  77. g_snprintf(number, SIZEOF(number), "%03d", n - 1);
  78. filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
  79. exin, NULL);
  80. amfree(ts);
  81. return filename;
  82. }
  83. static char *
  84. build_name(
  85. char * disk,
  86. char * exin,
  87. int verbose)
  88. {
  89. int n;
  90. int fd;
  91. char *filename = NULL;
  92. char *afilename = NULL;
  93. char *diskname;
  94. time_t curtime;
  95. char *dbgdir;
  96. char *e = NULL;
  97. DIR *d;
  98. struct dirent *entry;
  99. char *test_name;
  100. size_t match_len, d_name_len;
  101. char *quoted;
  102. time(&curtime);
  103. diskname = sanitise_filename(disk);
  104. dbgdir = stralloc2(AMANDA_TMPDIR, "/");
  105. if((d = opendir(AMANDA_TMPDIR)) == NULL) {
  106. error(_("open debug directory \"%s\": %s"),
  107. AMANDA_TMPDIR, strerror(errno));
  108. /*NOTREACHED*/
  109. }
  110. test_name = get_name(diskname, exin,
  111. curtime - (getconf_int(CNF_DEBUG_DAYS) * 24 * 60 * 60), 0);
  112. match_len = strlen(get_pname()) + strlen(diskname) + 2;
  113. while((entry = readdir(d)) != NULL) {
  114. if(is_dot_or_dotdot(entry->d_name)) {
  115. continue;
  116. }
  117. d_name_len = strlen(entry->d_name);
  118. if(strncmp(test_name, entry->d_name, match_len) != 0
  119. || d_name_len < match_len + 14 + 8
  120. || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
  121. continue; /* not one of our files */
  122. }
  123. if(strcmp(entry->d_name, test_name) < 0) {
  124. e = newvstralloc(e, dbgdir, entry->d_name, NULL);
  125. (void) unlink(e); /* get rid of old file */
  126. }
  127. }
  128. amfree(test_name);
  129. amfree(e);
  130. closedir(d);
  131. n=0;
  132. do {
  133. filename = get_name(diskname, exin, curtime, n);
  134. afilename = newvstralloc(afilename, dbgdir, filename, NULL);
  135. if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
  136. amfree(afilename);
  137. n++;
  138. }
  139. else {
  140. close(fd);
  141. }
  142. amfree(filename);
  143. } while(!afilename && n < 1000);
  144. if(afilename == NULL) {
  145. filename = get_name(diskname, exin, curtime, 0);
  146. afilename = newvstralloc(afilename, dbgdir, filename, NULL);
  147. quoted = quote_string(afilename);
  148. dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
  149. if(verbose) {
  150. g_printf(_("ERROR [cannot create %s (%s)]\n"),
  151. quoted, strerror(errno));
  152. }
  153. amfree(quoted);
  154. amfree(afilename);
  155. amfree(filename);
  156. }
  157. amfree(dbgdir);
  158. amfree(diskname);
  159. return afilename;
  160. }
  161. static int
  162. add_exclude(
  163. FILE * file_exclude,
  164. char * aexc,
  165. int verbose)
  166. {
  167. size_t l;
  168. char *quoted, *file;
  169. (void)verbose; /* Quiet unused parameter warning */
  170. l = strlen(aexc);
  171. if(aexc[l-1] == '\n') {
  172. aexc[l-1] = '\0';
  173. l--;
  174. }
  175. file = quoted = quote_string(aexc);
  176. if (*file == '"') {
  177. file[strlen(file) - 1] = '\0';
  178. file++;
  179. }
  180. g_fprintf(file_exclude, "%s\n", file);
  181. amfree(quoted);
  182. return 1;
  183. }
  184. static int
  185. add_include(
  186. char * disk,
  187. char * device,
  188. FILE * file_include,
  189. char * ainc,
  190. int verbose)
  191. {
  192. size_t l;
  193. int nb_exp=0;
  194. char *quoted, *file;
  195. (void)disk; /* Quiet unused parameter warning */
  196. (void)device; /* Quiet unused parameter warning */
  197. l = strlen(ainc);
  198. if(ainc[l-1] == '\n') {
  199. ainc[l-1] = '\0';
  200. l--;
  201. }
  202. if (strncmp(ainc, "./", 2) != 0) {
  203. quoted = quote_string(ainc);
  204. dbprintf(_("include must start with './' (%s)\n"), quoted);
  205. if(verbose) {
  206. g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
  207. }
  208. amfree(quoted);
  209. }
  210. else {
  211. char *incname = ainc+2;
  212. int set_root;
  213. set_root = set_root_privs(1);
  214. /* Take as is if not root && many '/' */
  215. if(!set_root && strchr(incname, '/')) {
  216. file = quoted = quote_string(ainc);
  217. if (*file == '"') {
  218. file[strlen(file) - 1] = '\0';
  219. file++;
  220. }
  221. g_fprintf(file_include, "%s\n", file);
  222. amfree(quoted);
  223. nb_exp++;
  224. }
  225. else {
  226. int nb;
  227. glob_t globbuf;
  228. char *cwd;
  229. globbuf.gl_offs = 0;
  230. cwd = g_get_current_dir();
  231. if (chdir(device) != 0) {
  232. error(_("Failed to chdir(%s): %s\n"), device, strerror(errno));
  233. }
  234. glob(incname, 0, NULL, &globbuf);
  235. if (chdir(cwd) != 0) {
  236. error(_("Failed to chdir(%s): %s\n"), cwd, strerror(errno));
  237. }
  238. if (set_root)
  239. set_root_privs(0);
  240. nb_exp = globbuf.gl_pathc;
  241. for (nb=0; nb < nb_exp; nb++) {
  242. file = stralloc2("./", globbuf.gl_pathv[nb]);
  243. quoted = quote_string(file);
  244. if (*file == '"') {
  245. file[strlen(file) - 1] = '\0';
  246. file++;
  247. }
  248. g_fprintf(file_include, "%s\n", file);
  249. amfree(quoted);
  250. amfree(file);
  251. }
  252. }
  253. }
  254. return nb_exp;
  255. }
  256. char *
  257. build_exclude(
  258. dle_t *dle,
  259. int verbose)
  260. {
  261. char *filename;
  262. FILE *file_exclude;
  263. FILE *exclude;
  264. char *aexc;
  265. sle_t *excl;
  266. int nb_exclude = 0;
  267. char *quoted;
  268. if (dle->exclude_file) nb_exclude += dle->exclude_file->nb_element;
  269. if (dle->exclude_list) nb_exclude += dle->exclude_list->nb_element;
  270. if (nb_exclude == 0) return NULL;
  271. if ((filename = build_name(dle->disk, "exclude", verbose)) != NULL) {
  272. if ((file_exclude = fopen(filename,"w")) != NULL) {
  273. if (dle->exclude_file) {
  274. for(excl = dle->exclude_file->first; excl != NULL;
  275. excl = excl->next) {
  276. add_exclude(file_exclude, excl->name,
  277. verbose && dle->exclude_optional == 0);
  278. }
  279. }
  280. if (dle->exclude_list) {
  281. for(excl = dle->exclude_list->first; excl != NULL;
  282. excl = excl->next) {
  283. char *exclname = fixup_relative(excl->name, dle->device);
  284. if((exclude = fopen(exclname, "r")) != NULL) {
  285. while ((aexc = agets(exclude)) != NULL) {
  286. if (aexc[0] == '\0') {
  287. amfree(aexc);
  288. continue;
  289. }
  290. add_exclude(file_exclude, aexc,
  291. verbose && dle->exclude_optional == 0);
  292. amfree(aexc);
  293. }
  294. fclose(exclude);
  295. }
  296. else {
  297. quoted = quote_string(exclname);
  298. dbprintf(_("Can't open exclude file %s (%s)\n"),
  299. quoted, strerror(errno));
  300. if(verbose && (dle->exclude_optional == 0 ||
  301. errno != ENOENT)) {
  302. g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
  303. quoted, strerror(errno));
  304. }
  305. amfree(quoted);
  306. }
  307. amfree(exclname);
  308. }
  309. }
  310. fclose(file_exclude);
  311. } else {
  312. quoted = quote_string(filename);
  313. dbprintf(_("Can't create exclude file %s (%s)\n"),
  314. quoted, strerror(errno));
  315. if (verbose) {
  316. g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
  317. quoted, strerror(errno));
  318. }
  319. amfree(quoted);
  320. }
  321. }
  322. return filename;
  323. }
  324. char *
  325. build_include(
  326. dle_t *dle,
  327. int verbose)
  328. {
  329. char *filename;
  330. FILE *file_include;
  331. FILE *include;
  332. char *ainc = NULL;
  333. sle_t *incl;
  334. int nb_include = 0;
  335. int nb_exp = 0;
  336. char *quoted;
  337. if (dle->include_file) nb_include += dle->include_file->nb_element;
  338. if (dle->include_list) nb_include += dle->include_list->nb_element;
  339. if (nb_include == 0) return NULL;
  340. if ((filename = build_name(dle->disk, "include", verbose)) != NULL) {
  341. if ((file_include = fopen(filename,"w")) != NULL) {
  342. if (dle->include_file) {
  343. for (incl = dle->include_file->first; incl != NULL;
  344. incl = incl->next) {
  345. nb_exp += add_include(dle->disk, dle->device, file_include,
  346. incl->name,
  347. verbose && dle->include_optional == 0);
  348. }
  349. }
  350. if (dle->include_list) {
  351. for (incl = dle->include_list->first; incl != NULL;
  352. incl = incl->next) {
  353. char *inclname = fixup_relative(incl->name, dle->device);
  354. if ((include = fopen(inclname, "r")) != NULL) {
  355. while ((ainc = agets(include)) != NULL) {
  356. if (ainc[0] == '\0') {
  357. amfree(ainc);
  358. continue;
  359. }
  360. nb_exp += add_include(dle->disk, dle->device,
  361. file_include, ainc,
  362. verbose && dle->include_optional == 0);
  363. amfree(ainc);
  364. }
  365. fclose(include);
  366. }
  367. else {
  368. quoted = quote_string(inclname);
  369. dbprintf(_("Can't open include file %s (%s)\n"),
  370. quoted, strerror(errno));
  371. if (verbose && (dle->include_optional == 0 ||
  372. errno != ENOENT)) {
  373. g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
  374. quoted, strerror(errno));
  375. }
  376. amfree(quoted);
  377. }
  378. amfree(inclname);
  379. }
  380. }
  381. fclose(file_include);
  382. } else {
  383. quoted = quote_string(filename);
  384. dbprintf(_("Can't create include file %s (%s)\n"),
  385. quoted, strerror(errno));
  386. if (verbose) {
  387. g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
  388. quoted, strerror(errno));
  389. }
  390. amfree(quoted);
  391. }
  392. }
  393. if (nb_exp == 0) {
  394. quoted = quote_string(dle->disk);
  395. dbprintf(_("No include for %s\n"), quoted);
  396. if (verbose && dle->include_optional == 0) {
  397. g_printf(_("ERROR [No include for %s]\n"), quoted);
  398. }
  399. amfree(quoted);
  400. }
  401. return filename;
  402. }
  403. void
  404. parse_options(
  405. char *str,
  406. dle_t *dle,
  407. am_feature_t *fs,
  408. int verbose)
  409. {
  410. char *exc;
  411. char *inc;
  412. char *p, *tok;
  413. char *quoted;
  414. p = stralloc(str);
  415. tok = strtok(p,";");
  416. while (tok != NULL) {
  417. if(am_has_feature(fs, fe_options_auth)
  418. && BSTRNCMP(tok,"auth=") == 0) {
  419. if (dle->auth != NULL) {
  420. quoted = quote_string(tok + 5);
  421. dbprintf(_("multiple auth option %s\n"), quoted);
  422. if(verbose) {
  423. g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
  424. }
  425. amfree(quoted);
  426. }
  427. dle->auth = stralloc(&tok[5]);
  428. }
  429. else if(am_has_feature(fs, fe_options_bsd_auth)
  430. && BSTRNCMP(tok, "bsd-auth") == 0) {
  431. if (dle->auth != NULL) {
  432. dbprintf(_("multiple auth option\n"));
  433. if (verbose) {
  434. g_printf(_("ERROR [multiple auth option]\n"));
  435. }
  436. }
  437. dle->auth = stralloc("bsd");
  438. }
  439. else if (BSTRNCMP(tok, "compress-fast") == 0) {
  440. if (dle->compress != COMP_NONE) {
  441. dbprintf(_("multiple compress option\n"));
  442. if (verbose) {
  443. g_printf(_("ERROR [multiple compress option]\n"));
  444. }
  445. }
  446. dle->compress = COMP_FAST;
  447. }
  448. else if (BSTRNCMP(tok, "compress-best") == 0) {
  449. if (dle->compress != COMP_NONE) {
  450. dbprintf(_("multiple compress option\n"));
  451. if (verbose) {
  452. g_printf(_("ERROR [multiple compress option]\n"));
  453. }
  454. }
  455. dle->compress = COMP_BEST;
  456. }
  457. else if (BSTRNCMP(tok, "srvcomp-fast") == 0) {
  458. if (dle->compress != COMP_NONE) {
  459. dbprintf(_("multiple compress option\n"));
  460. if (verbose) {
  461. g_printf(_("ERROR [multiple compress option]\n"));
  462. }
  463. }
  464. dle->compress = COMP_SERVER_FAST;
  465. }
  466. else if (BSTRNCMP(tok, "srvcomp-best") == 0) {
  467. if (dle->compress != COMP_NONE) {
  468. dbprintf(_("multiple compress option\n"));
  469. if (verbose) {
  470. g_printf(_("ERROR [multiple compress option]\n"));
  471. }
  472. }
  473. dle->compress = COMP_SERVER_BEST;
  474. }
  475. else if (BSTRNCMP(tok, "srvcomp-cust=") == 0) {
  476. if (dle->compress != COMP_NONE) {
  477. dbprintf(_("multiple compress option\n"));
  478. if (verbose) {
  479. g_printf(_("ERROR [multiple compress option]\n"));
  480. }
  481. }
  482. dle->compprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
  483. dle->compress = COMP_SERVER_CUST;
  484. }
  485. else if (BSTRNCMP(tok, "comp-cust=") == 0) {
  486. if (dle->compress != COMP_NONE) {
  487. dbprintf(_("multiple compress option\n"));
  488. if (verbose) {
  489. g_printf(_("ERROR [multiple compress option]\n"));
  490. }
  491. }
  492. dle->compprog = stralloc(tok + SIZEOF("comp-cust=") -1);
  493. dle->compress = COMP_CUST;
  494. /* parse encryption options */
  495. }
  496. else if (BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
  497. if (dle->encrypt != ENCRYPT_NONE) {
  498. dbprintf(_("multiple encrypt option\n"));
  499. if (verbose) {
  500. g_printf(_("ERROR [multiple encrypt option]\n"));
  501. }
  502. }
  503. dle->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
  504. dle->encrypt = ENCRYPT_SERV_CUST;
  505. }
  506. else if (BSTRNCMP(tok, "encrypt-cust=") == 0) {
  507. if (dle->encrypt != ENCRYPT_NONE) {
  508. dbprintf(_("multiple encrypt option\n"));
  509. if (verbose) {
  510. g_printf(_("ERROR [multiple encrypt option]\n"));
  511. }
  512. }
  513. dle->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
  514. dle->encrypt = ENCRYPT_CUST;
  515. }
  516. else if (BSTRNCMP(tok, "server-decrypt-option=") == 0) {
  517. dle->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
  518. }
  519. else if (BSTRNCMP(tok, "client-decrypt-option=") == 0) {
  520. dle->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
  521. }
  522. else if (BSTRNCMP(tok, "no-record") == 0) {
  523. if (dle->record != 1) {
  524. dbprintf(_("multiple no-record option\n"));
  525. if (verbose) {
  526. g_printf(_("ERROR [multiple no-record option]\n"));
  527. }
  528. }
  529. dle->record = 0;
  530. }
  531. else if (BSTRNCMP(tok, "index") == 0) {
  532. if (dle->create_index != 0) {
  533. dbprintf(_("multiple index option\n"));
  534. if (verbose) {
  535. g_printf(_("ERROR [multiple index option]\n"));
  536. }
  537. }
  538. dle->create_index = 1;
  539. }
  540. else if (BSTRNCMP(tok, "exclude-optional") == 0) {
  541. if (dle->exclude_optional != 0) {
  542. dbprintf(_("multiple exclude-optional option\n"));
  543. if (verbose) {
  544. g_printf(_("ERROR [multiple exclude-optional option]\n"));
  545. }
  546. }
  547. dle->exclude_optional = 1;
  548. }
  549. else if (strcmp(tok, "include-optional") == 0) {
  550. if (dle->include_optional != 0) {
  551. dbprintf(_("multiple include-optional option\n"));
  552. if (verbose) {
  553. g_printf(_("ERROR [multiple include-optional option]\n"));
  554. }
  555. }
  556. dle->include_optional = 1;
  557. }
  558. else if (BSTRNCMP(tok,"exclude-file=") == 0) {
  559. exc = unquote_string(&tok[13]);
  560. dle->exclude_file = append_sl(dle->exclude_file, exc);
  561. amfree(exc);
  562. }
  563. else if (BSTRNCMP(tok,"exclude-list=") == 0) {
  564. exc = unquote_string(&tok[13]);
  565. dle->exclude_list = append_sl(dle->exclude_list, exc);
  566. amfree(exc);
  567. }
  568. else if (BSTRNCMP(tok,"include-file=") == 0) {
  569. inc = unquote_string(&tok[13]);
  570. dle->include_file = append_sl(dle->include_file, inc);
  571. amfree(inc);
  572. }
  573. else if (BSTRNCMP(tok,"include-list=") == 0) {
  574. inc = unquote_string(&tok[13]);
  575. dle->include_list = append_sl(dle->include_list, inc);
  576. amfree(inc);
  577. }
  578. else if (BSTRNCMP(tok,"kencrypt") == 0) {
  579. dle->kencrypt = 1;
  580. }
  581. else if (strcmp(tok,"|") != 0) {
  582. quoted = quote_string(tok);
  583. dbprintf(_("unknown option %s\n"), quoted);
  584. if (verbose) {
  585. g_printf(_("ERROR [unknown option: %s]\n"), quoted);
  586. }
  587. amfree(quoted);
  588. }
  589. tok = strtok(NULL, ";");
  590. }
  591. amfree(p);
  592. }
  593. void
  594. application_property_add_to_argv(
  595. GPtrArray *argv_ptr,
  596. dle_t *dle,
  597. backup_support_option_t *bsu,
  598. am_feature_t *amfeatures)
  599. {
  600. sle_t *incl, *excl;
  601. if (bsu) {
  602. if (bsu->include_file && dle->include_file) {
  603. for (incl = dle->include_file->first; incl != NULL;
  604. incl = incl->next) {
  605. g_ptr_array_add(argv_ptr, stralloc("--include-file"));
  606. g_ptr_array_add(argv_ptr, stralloc(incl->name));
  607. }
  608. }
  609. if (bsu->include_list && dle->include_list) {
  610. for (incl = dle->include_list->first; incl != NULL;
  611. incl = incl->next) {
  612. g_ptr_array_add(argv_ptr, stralloc("--include-list"));
  613. g_ptr_array_add(argv_ptr, stralloc(incl->name));
  614. }
  615. }
  616. if (bsu->include_optional && dle->include_optional) {
  617. g_ptr_array_add(argv_ptr, stralloc("--include-optional"));
  618. g_ptr_array_add(argv_ptr, stralloc("yes"));
  619. }
  620. if (bsu->exclude_file && dle->exclude_file) {
  621. for (excl = dle->exclude_file->first; excl != NULL;
  622. excl = excl->next) {
  623. g_ptr_array_add(argv_ptr, stralloc("--exclude-file"));
  624. g_ptr_array_add(argv_ptr, stralloc(excl->name));
  625. }
  626. }
  627. if (bsu->exclude_list && dle->exclude_list) {
  628. for (excl = dle->exclude_list->first; excl != NULL;
  629. excl = excl->next) {
  630. g_ptr_array_add(argv_ptr, stralloc("--exclude-list"));
  631. g_ptr_array_add(argv_ptr, stralloc(excl->name));
  632. }
  633. }
  634. if (bsu->exclude_optional && dle->exclude_optional) {
  635. g_ptr_array_add(argv_ptr, stralloc("--exclude-optional"));
  636. g_ptr_array_add(argv_ptr, stralloc("yes"));
  637. }
  638. if (bsu->features && amfeatures) {
  639. char *feature_string = am_feature_to_string(amfeatures);
  640. g_ptr_array_add(argv_ptr, stralloc("--amfeatures"));
  641. g_ptr_array_add(argv_ptr, feature_string);
  642. }
  643. if (dle->data_path == DATA_PATH_DIRECTTCP &&
  644. bsu->data_path_set & DATA_PATH_DIRECTTCP) {
  645. GSList *directtcp;
  646. g_ptr_array_add(argv_ptr, stralloc("--data-path"));
  647. g_ptr_array_add(argv_ptr, stralloc("directtcp"));
  648. for (directtcp = dle->directtcp_list; directtcp != NULL;
  649. directtcp = directtcp->next) {
  650. g_ptr_array_add(argv_ptr, stralloc("--direct-tcp"));
  651. g_ptr_array_add(argv_ptr, stralloc(directtcp->data));
  652. break; /* XXX temporary; apps only support one ip:port pair */
  653. }
  654. }
  655. }
  656. g_hash_table_foreach(dle->application_property,
  657. &proplist_add_to_argv, argv_ptr);
  658. return;
  659. }
  660. backup_support_option_t *
  661. backup_support_option(
  662. char *program,
  663. g_option_t *g_options,
  664. char *disk,
  665. char *amdevice,
  666. GPtrArray **errarray)
  667. {
  668. pid_t supportpid;
  669. int supportin, supportout, supporterr;
  670. char *cmd;
  671. GPtrArray *argv_ptr = g_ptr_array_new();
  672. FILE *streamout;
  673. FILE *streamerr;
  674. char *line;
  675. int status;
  676. char *err = NULL;
  677. backup_support_option_t *bsu;
  678. *errarray = g_ptr_array_new();
  679. cmd = vstralloc(APPLICATION_DIR, "/", program, NULL);
  680. g_ptr_array_add(argv_ptr, stralloc(program));
  681. g_ptr_array_add(argv_ptr, stralloc("support"));
  682. if (g_options->config) {
  683. g_ptr_array_add(argv_ptr, stralloc("--config"));
  684. g_ptr_array_add(argv_ptr, stralloc(g_options->config));
  685. }
  686. if (g_options->hostname) {
  687. g_ptr_array_add(argv_ptr, stralloc("--host"));
  688. g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
  689. }
  690. if (disk) {
  691. g_ptr_array_add(argv_ptr, stralloc("--disk"));
  692. g_ptr_array_add(argv_ptr, stralloc(disk));
  693. }
  694. if (amdevice) {
  695. g_ptr_array_add(argv_ptr, stralloc("--device"));
  696. g_ptr_array_add(argv_ptr, stralloc(amdevice));
  697. }
  698. g_ptr_array_add(argv_ptr, NULL);
  699. supporterr = fileno(stderr);
  700. supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
  701. &supportin, &supportout, &supporterr,
  702. (char **)argv_ptr->pdata);
  703. aclose(supportin);
  704. bsu = g_new0(backup_support_option_t, 1);
  705. bsu->config = 1;
  706. bsu->host = 1;
  707. bsu->disk = 1;
  708. streamout = fdopen(supportout, "r");
  709. if (!streamout) {
  710. error(_("Error opening pipe to child: %s"), strerror(errno));
  711. /* NOTREACHED */
  712. }
  713. while((line = agets(streamout)) != NULL) {
  714. dbprintf(_("support line: %s\n"), line);
  715. if (strncmp(line,"CONFIG ", 7) == 0) {
  716. if (strcmp(line+7, "YES") == 0)
  717. bsu->config = 1;
  718. } else if (strncmp(line,"HOST ", 5) == 0) {
  719. if (strcmp(line+5, "YES") == 0)
  720. bsu->host = 1;
  721. } else if (strncmp(line,"DISK ", 5) == 0) {
  722. if (strcmp(line+5, "YES") == 0)
  723. bsu->disk = 1;
  724. } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
  725. if (strcmp(line+11, "YES") == 0)
  726. bsu->index_line = 1;
  727. } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
  728. if (strcmp(line+10, "YES") == 0)
  729. bsu->index_xml = 1;
  730. } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
  731. if (strcmp(line+13, "YES") == 0)
  732. bsu->message_line = 1;
  733. } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
  734. if (strcmp(line+12, "YES") == 0)
  735. bsu->message_xml = 1;
  736. } else if (strncmp(line,"RECORD ", 7) == 0) {
  737. if (strcmp(line+7, "YES") == 0)
  738. bsu->record = 1;
  739. } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
  740. if (strcmp(line+13, "YES") == 0)
  741. bsu->include_file = 1;
  742. } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
  743. if (strcmp(line+13, "YES") == 0)
  744. bsu->include_list = 1;
  745. } else if (strncmp(line,"INCLUDE-LIST-GLOB ", 17) == 0) {
  746. if (strcmp(line+17, "YES") == 0)
  747. bsu->include_list_glob = 1;
  748. } else if (strncmp(line,"INCLUDE-OPTIONAL ", 17) == 0) {
  749. if (strcmp(line+17, "YES") == 0)
  750. bsu->include_optional = 1;
  751. } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
  752. if (strcmp(line+13, "YES") == 0)
  753. bsu->exclude_file = 1;
  754. } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
  755. if (strcmp(line+13, "YES") == 0)
  756. bsu->exclude_list = 1;
  757. } else if (strncmp(line,"EXCLUDE-LIST-GLOB ", 17) == 0) {
  758. if (strcmp(line+17, "YES") == 0)
  759. bsu->exclude_list_glob = 1;
  760. } else if (strncmp(line,"EXCLUDE-OPTIONAL ", 17) == 0) {
  761. if (strcmp(line+17, "YES") == 0)
  762. bsu->exclude_optional = 1;
  763. } else if (strncmp(line,"COLLECTION ", 11) == 0) {
  764. if (strcmp(line+11, "YES") == 0)
  765. bsu->collection = 1;
  766. } else if (strncmp(line,"CALCSIZE ", 9) == 0) {
  767. if (strcmp(line+9, "YES") == 0)
  768. bsu->calcsize = 1;
  769. } else if (strncmp(line,"CLIENT-ESTIMATE ", 16) == 0) {
  770. if (strcmp(line+16, "YES") == 0)
  771. bsu->client_estimate = 1;
  772. } else if (strncmp(line,"MULTI-ESTIMATE ", 15) == 0) {
  773. if (strcmp(line+15, "YES") == 0)
  774. bsu->multi_estimate = 1;
  775. } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
  776. bsu->max_level = atoi(line+10);
  777. } else if (strncmp(line,"RECOVER-MODE ", 13) == 0) {
  778. if (strcasecmp(line+13, "SMB") == 0)
  779. bsu->smb_recover_mode = 1;
  780. } else if (strncmp(line,"DATA-PATH ", 10) == 0) {
  781. if (strcasecmp(line+10, "AMANDA") == 0)
  782. bsu->data_path_set |= DATA_PATH_AMANDA;
  783. else if (strcasecmp(line+10, "DIRECTTCP") == 0)
  784. bsu->data_path_set |= DATA_PATH_DIRECTTCP;
  785. } else if (strncmp(line,"RECOVER-PATH ", 13) == 0) {
  786. if (strcasecmp(line+13, "CWD") == 0)
  787. bsu->recover_path = RECOVER_PATH_CWD;
  788. else if (strcasecmp(line+13, "REMOTE") == 0)
  789. bsu->recover_path = RECOVER_PATH_REMOTE;
  790. } else if (strncmp(line,"AMFEATURES ", 11) == 0) {
  791. if (strcmp(line+11, "YES") == 0)
  792. bsu->features = 1;
  793. } else {
  794. dbprintf(_("Invalid support line: %s\n"), line);
  795. }
  796. amfree(line);
  797. }
  798. fclose(streamout);
  799. if (bsu->data_path_set == 0)
  800. bsu->data_path_set = DATA_PATH_AMANDA;
  801. streamerr = fdopen(supporterr, "r");
  802. if (!streamerr) {
  803. error(_("Error opening pipe to child: %s"), strerror(errno));
  804. /* NOTREACHED */
  805. }
  806. while((line = agets(streamerr)) != NULL) {
  807. if (strlen(line) > 0) {
  808. g_ptr_array_add(*errarray, line);
  809. dbprintf("Application '%s': %s\n", program, line);
  810. }
  811. amfree(bsu);
  812. }
  813. fclose(streamerr);
  814. if (waitpid(supportpid, &status, 0) < 0) {
  815. err = vstrallocf(_("waitpid failed: %s"), strerror(errno));
  816. } else if (!WIFEXITED(status)) {
  817. err = vstrallocf(_("exited with signal %d"), WTERMSIG(status));
  818. } else if (WEXITSTATUS(status) != 0) {
  819. err = vstrallocf(_("exited with status %d"), WEXITSTATUS(status));
  820. }
  821. if (err) {
  822. g_ptr_array_add(*errarray, err);
  823. dbprintf("Application '%s': %s\n", program, err);
  824. amfree(bsu);
  825. }
  826. g_ptr_array_free_full(argv_ptr);
  827. amfree(cmd);
  828. return bsu;
  829. }
  830. void
  831. run_client_script(
  832. script_t *script,
  833. execute_on_t execute_on,
  834. g_option_t *g_options,
  835. dle_t *dle)
  836. {
  837. pid_t scriptpid;
  838. int scriptin, scriptout, scripterr;
  839. char *cmd;
  840. GPtrArray *argv_ptr = g_ptr_array_new();
  841. FILE *streamout;
  842. FILE *streamerr;
  843. char *line;
  844. amwait_t wait_status;
  845. char *command = NULL;
  846. if ((script->execute_on & execute_on) == 0)
  847. return;
  848. if (script->execute_where != ES_CLIENT)
  849. return;
  850. cmd = vstralloc(APPLICATION_DIR, "/", script->plugin, NULL);
  851. g_ptr_array_add(argv_ptr, stralloc(script->plugin));
  852. switch (execute_on) {
  853. case EXECUTE_ON_PRE_DLE_AMCHECK:
  854. command = "PRE-DLE-AMCHECK";
  855. break;
  856. case EXECUTE_ON_PRE_HOST_AMCHECK:
  857. command = "PRE-HOST-AMCHECK";
  858. break;
  859. case EXECUTE_ON_POST_DLE_AMCHECK:
  860. command = "POST-DLE-AMCHECK";
  861. break;
  862. case EXECUTE_ON_POST_HOST_AMCHECK:
  863. command = "POST-HOST-AMCHECK";
  864. break;
  865. case EXECUTE_ON_PRE_DLE_ESTIMATE:
  866. command = "PRE-DLE-ESTIMATE";
  867. break;
  868. case EXECUTE_ON_PRE_HOST_ESTIMATE:
  869. command = "PRE-HOST-ESTIMATE";
  870. break;
  871. case EXECUTE_ON_POST_DLE_ESTIMATE:
  872. command = "POST-DLE-ESTIMATE";
  873. break;
  874. case EXECUTE_ON_POST_HOST_ESTIMATE:
  875. command = "POST-HOST-ESTIMATE";
  876. break;
  877. case EXECUTE_ON_PRE_DLE_BACKUP:
  878. command = "PRE-DLE-BACKUP";
  879. break;
  880. case EXECUTE_ON_PRE_HOST_BACKUP:
  881. command = "PRE-HOST-BACKUP";
  882. break;
  883. case EXECUTE_ON_POST_DLE_BACKUP:
  884. command = "POST-DLE-BACKUP";
  885. break;
  886. case EXECUTE_ON_POST_HOST_BACKUP:
  887. command = "POST-HOST-BACKUP";
  888. break;
  889. case EXECUTE_ON_PRE_RECOVER:
  890. command = "PRE-RECOVER";
  891. break;
  892. case EXECUTE_ON_POST_RECOVER:
  893. command = "POST-RECOVER";
  894. break;
  895. case EXECUTE_ON_PRE_LEVEL_RECOVER:
  896. command = "PRE-LEVEL-RECOVER";
  897. break;
  898. case EXECUTE_ON_POST_LEVEL_RECOVER:
  899. command = "POST-LEVEL-RECOVER";
  900. break;
  901. case EXECUTE_ON_INTER_LEVEL_RECOVER:
  902. command = "INTER-LEVEL-RECOVER";
  903. break;
  904. }
  905. g_ptr_array_add(argv_ptr, stralloc(command));
  906. g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
  907. g_ptr_array_add(argv_ptr, stralloc("client"));
  908. if (g_options->config) {
  909. g_ptr_array_add(argv_ptr, stralloc("--config"));
  910. g_ptr_array_add(argv_ptr, stralloc(g_options->config));
  911. }
  912. if (g_options->hostname) {
  913. g_ptr_array_add(argv_ptr, stralloc("--host"));
  914. g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
  915. }
  916. if (dle->disk) {
  917. g_ptr_array_add(argv_ptr, stralloc("--disk"));
  918. g_ptr_array_add(argv_ptr, stralloc(dle->disk));
  919. }
  920. if (dle->device) {
  921. g_ptr_array_add(argv_ptr, stralloc("--device"));
  922. g_ptr_array_add(argv_ptr, stralloc(dle->device));
  923. }
  924. if (dle->levellist) {
  925. levellist_t levellist;
  926. char number[NUM_STR_SIZE];
  927. for (levellist=dle->levellist; levellist; levellist=levellist->next) {
  928. level_t *alevel = (level_t *)levellist->data;
  929. g_ptr_array_add(argv_ptr, stralloc("--level"));
  930. g_snprintf(number, SIZEOF(number), "%d", alevel->level);
  931. g_ptr_array_add(argv_ptr, stralloc(number));
  932. }
  933. }
  934. property_add_to_argv(argv_ptr, script->property);
  935. g_ptr_array_add(argv_ptr, NULL);
  936. scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
  937. &scriptin, &scriptout, &scripterr,
  938. (char **)argv_ptr->pdata);
  939. close(scriptin);
  940. script->result = g_new0(client_script_result_t, 1);
  941. script->result->proplist =
  942. g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
  943. script->result->output = g_ptr_array_new();
  944. script->result->err = g_ptr_array_new();
  945. streamout = fdopen(scriptout, "r");
  946. if (streamout) {
  947. while((line = agets(streamout)) != NULL) {
  948. dbprintf("script: %s\n", line);
  949. if (BSTRNCMP(line, "PROPERTY ") == 0) {
  950. char *property_name, *property_value;
  951. property_name = line + 9;
  952. property_value = strchr(property_name,' ');
  953. if (property_value == NULL) {
  954. char *msg = g_strdup_printf(
  955. "ERROR %s: Bad output property: %s",
  956. script->plugin, line);
  957. g_ptr_array_add(script->result->output, msg);
  958. } else {
  959. property_t *property;
  960. *property_value++ = '\0';
  961. property_name = stralloc(property_name);
  962. property_value = stralloc(property_value);
  963. property = g_hash_table_lookup(script->result->proplist,
  964. property_name);
  965. if (!property) {
  966. property = g_new0(property_t, 1);
  967. g_hash_table_insert(script->result->proplist,
  968. property_name, property);
  969. }
  970. property->values = g_slist_append(property->values,
  971. property_value);
  972. }
  973. amfree(line);
  974. } else {
  975. g_ptr_array_add(script->result->output, line);
  976. }
  977. }
  978. }
  979. fclose(streamout);
  980. streamerr = fdopen(scripterr, "r");
  981. if (streamerr) {
  982. while((line = agets(streamerr)) != NULL) {
  983. g_ptr_array_add(script->result->err,
  984. g_strdup_printf(_("Script '%s' command '%s': %s"),
  985. script->plugin, command, line));
  986. amfree(line);
  987. }
  988. }
  989. waitpid(scriptpid, &wait_status, 0);
  990. if (WIFSIGNALED(wait_status)) {
  991. g_ptr_array_add(script->result->err,
  992. g_strdup_printf(_("Script '%s' command '%s' terminated with signal %d: see %s"),
  993. script->plugin, command,
  994. WTERMSIG(wait_status),
  995. dbfn()));
  996. } else if (WIFEXITED(wait_status)) {
  997. if (WEXITSTATUS(wait_status) != 0) {
  998. g_ptr_array_add(script->result->err,
  999. g_strdup_printf(_("Script '%s' command '%s' exited with status %d: see %s"),
  1000. script->plugin, command,
  1001. WEXITSTATUS(wait_status),
  1002. dbfn()));
  1003. } else {
  1004. /* Normal exit */
  1005. }
  1006. }
  1007. amfree(cmd);
  1008. g_ptr_array_free_full(argv_ptr);
  1009. }
  1010. void run_client_script_output(gpointer data, gpointer user_data);
  1011. void run_client_script_err_amcheck(gpointer data, gpointer user_data);
  1012. void run_client_script_err_estimate(gpointer data, gpointer user_data);
  1013. void run_client_script_err_backup(gpointer data, gpointer user_data);
  1014. void run_client_script_err_recover(gpointer data, gpointer user_data);
  1015. typedef struct script_output_s {
  1016. FILE *stream;
  1017. dle_t *dle;
  1018. } script_output_t;
  1019. void
  1020. run_client_script_output(
  1021. gpointer data,
  1022. gpointer user_data)
  1023. {
  1024. char *line = data;
  1025. script_output_t *so = user_data;
  1026. if (line && so->stream) {
  1027. g_fprintf(so->stream, "%s\n", line);
  1028. }
  1029. }
  1030. void
  1031. run_client_script_err_amcheck(
  1032. gpointer data,
  1033. gpointer user_data)
  1034. {
  1035. char *line = data;
  1036. script_output_t *so = user_data;
  1037. if (line && so->stream) {
  1038. g_fprintf(so->stream, "ERROR %s\n", line);
  1039. }
  1040. }
  1041. void
  1042. run_client_script_err_estimate(
  1043. gpointer data,
  1044. gpointer user_data)
  1045. {
  1046. char *line = data;
  1047. script_output_t *so = user_data;
  1048. if (line && so->stream) {
  1049. char *qdisk = quote_string(so->dle->disk);
  1050. g_fprintf(so->stream, "%s 0 WARNING \"%s\"\n", qdisk, line);
  1051. amfree(qdisk);
  1052. }
  1053. }
  1054. void
  1055. run_client_script_err_backup(
  1056. gpointer data,
  1057. gpointer user_data)
  1058. {
  1059. char *line = data;
  1060. script_output_t *so = user_data;
  1061. if (line && so->stream) {
  1062. g_fprintf(so->stream, "? %s\n", line);
  1063. }
  1064. }
  1065. void
  1066. run_client_script_err_recover(
  1067. gpointer data,
  1068. gpointer user_data)
  1069. {
  1070. char *line = data;
  1071. script_output_t *so = user_data;
  1072. if (line && so->stream) {
  1073. g_fprintf(so->stream, "%s\n", line);
  1074. }
  1075. }
  1076. void
  1077. run_client_scripts(
  1078. execute_on_t execute_on,
  1079. g_option_t *g_options,
  1080. dle_t *dle,
  1081. FILE *streamout)
  1082. {
  1083. GSList *scriptlist;
  1084. script_t *script;
  1085. GFunc client_script_err = NULL;
  1086. script_output_t so = { streamout, dle };
  1087. for (scriptlist = dle->scriptlist; scriptlist != NULL;
  1088. scriptlist = scriptlist->next) {
  1089. script = (script_t *)scriptlist->data;
  1090. run_client_script(script, execute_on, g_options, dle);
  1091. if (script->result && script->result->output) {
  1092. g_ptr_array_foreach(script->result->output,
  1093. run_client_script_output,
  1094. &so);
  1095. g_ptr_array_free(script->result->output, TRUE);
  1096. script->result->output = NULL;
  1097. }
  1098. if (script->result && script->result->err) {
  1099. switch (execute_on) {
  1100. case EXECUTE_ON_PRE_DLE_AMCHECK:
  1101. case EXECUTE_ON_PRE_HOST_AMCHECK:
  1102. case EXECUTE_ON_POST_DLE_AMCHECK:
  1103. case EXECUTE_ON_POST_HOST_AMCHECK:
  1104. client_script_err = run_client_script_err_amcheck;
  1105. break;
  1106. case EXECUTE_ON_PRE_DLE_ESTIMATE:
  1107. case EXECUTE_ON_PRE_HOST_ESTIMATE:
  1108. case EXECUTE_ON_POST_DLE_ESTIMATE:
  1109. case EXECUTE_ON_POST_HOST_ESTIMATE:
  1110. if (am_has_feature(g_options->features,
  1111. fe_sendsize_rep_warning)) {
  1112. client_script_err = run_client_script_err_estimate;
  1113. }
  1114. break;
  1115. case EXECUTE_ON_PRE_DLE_BACKUP:
  1116. case EXECUTE_ON_PRE_HOST_BACKUP:
  1117. case EXECUTE_ON_POST_DLE_BACKUP:
  1118. case EXECUTE_ON_POST_HOST_BACKUP:
  1119. client_script_err = run_client_script_err_backup;
  1120. break;
  1121. case EXECUTE_ON_PRE_RECOVER:
  1122. case EXECUTE_ON_POST_RECOVER:
  1123. case EXECUTE_ON_PRE_LEVEL_RECOVER:
  1124. case EXECUTE_ON_POST_LEVEL_RECOVER:
  1125. case EXECUTE_ON_INTER_LEVEL_RECOVER:
  1126. client_script_err = run_client_script_err_recover;
  1127. }
  1128. if (client_script_err != NULL) {
  1129. g_ptr_array_foreach(script->result->err,
  1130. client_script_err,
  1131. &so);
  1132. }
  1133. g_ptr_array_free(script->result->err, TRUE);
  1134. script->result->err = NULL;
  1135. }
  1136. }
  1137. }
  1138. void
  1139. run_calcsize(
  1140. char *config,
  1141. char *program,
  1142. char *disk,
  1143. char *dirname,
  1144. GSList *levels,
  1145. char *file_exclude,
  1146. char *file_include)
  1147. {
  1148. char *cmd, *cmdline;
  1149. char *command;
  1150. GPtrArray *argv_ptr = g_ptr_array_new();
  1151. char tmppath[PATH_MAX];
  1152. char number[NUM_STR_SIZE];
  1153. GSList *alevel;
  1154. guint level;
  1155. guint i;
  1156. char *match_expr;
  1157. int pipefd = -1, nullfd = -1;
  1158. pid_t calcpid;
  1159. times_t start_time;
  1160. FILE *dumpout = NULL;
  1161. int dumpsince;
  1162. char *errmsg = NULL;
  1163. off_t size = (off_t)1;
  1164. char *line = NULL;
  1165. amwait_t wait_status;
  1166. int len;
  1167. char *qdisk;
  1168. amandates_t *amdp;
  1169. char *amandates_file;
  1170. qdisk = quote_string(disk);
  1171. amandates_file = getconf_str(CNF_AMANDATES);
  1172. if(!start_amandates(amandates_file, 0)) {
  1173. char *errstr = strerror(errno);
  1174. char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr);
  1175. char *qerrmsg = quote_string(errmsg);
  1176. g_printf(_("ERROR %s\n"), qerrmsg);
  1177. amfree(qdisk);
  1178. amfree(errmsg);
  1179. amfree(qerrmsg);
  1180. return;
  1181. }
  1182. startclock();
  1183. cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL);
  1184. g_ptr_array_add(argv_ptr, stralloc("calcsize"));
  1185. if (config)
  1186. g_ptr_array_add(argv_ptr, stralloc(config));
  1187. else
  1188. g_ptr_array_add(argv_ptr, stralloc("NOCONFIG"));
  1189. g_ptr_array_add(argv_ptr, stralloc(program));
  1190. canonicalize_pathname(disk, tmppath);
  1191. g_ptr_array_add(argv_ptr, stralloc(tmppath));
  1192. canonicalize_pathname(dirname, tmppath);
  1193. g_ptr_array_add(argv_ptr, stralloc(tmppath));
  1194. if (file_exclude) {
  1195. g_ptr_array_add(argv_ptr, stralloc("-X"));
  1196. g_ptr_array_add(argv_ptr, stralloc(file_exclude));
  1197. }
  1198. if (file_include) {
  1199. g_ptr_array_add(argv_ptr, stralloc("-I"));
  1200. g_ptr_array_add(argv_ptr, stralloc(file_include));
  1201. }
  1202. for (alevel = levels; alevel != NULL; alevel = alevel->next) {
  1203. amdp = amandates_lookup(disk);
  1204. level = GPOINTER_TO_INT(alevel->data);
  1205. dbprintf("level: %d\n", level);
  1206. dumpsince = 0;
  1207. for (i=0; i < level; i++) {
  1208. if (dumpsince < amdp->dates[i])
  1209. dumpsince = amdp->dates[i];
  1210. }
  1211. g_snprintf(number, SIZEOF(number), "%d", level);
  1212. g_ptr_array_add(argv_ptr, stralloc(number));
  1213. g_snprintf(number, SIZEOF(number), "%d", dumpsince);
  1214. g_ptr_array_add(argv_ptr, stralloc(number));
  1215. }
  1216. g_ptr_array_add(argv_ptr, NULL);
  1217. command = (char *)g_ptr_array_index(argv_ptr, 0);
  1218. cmdline = stralloc(command);
  1219. for(i = 1; i < argv_ptr->len - 1; i++)
  1220. cmdline = vstrextend(&cmdline, " ",
  1221. (char *)g_ptr_array_index(argv_ptr,i), NULL);
  1222. dbprintf(_("running: \"%s\"\n"), cmdline);
  1223. amfree(cmdline);
  1224. start_time = curclock();
  1225. fflush(stderr); fflush(stdout);
  1226. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  1227. errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
  1228. strerror(errno));
  1229. dbprintf("%s\n", errmsg);
  1230. goto common_exit;
  1231. }
  1232. calcpid = pipespawnv(cmd, STDERR_PIPE, 0,
  1233. &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata);
  1234. amfree(cmd);
  1235. dumpout = fdopen(pipefd,"r");
  1236. if (!dumpout) {
  1237. error(_("Can't fdopen: %s"), strerror(errno));
  1238. /*NOTREACHED*/
  1239. }
  1240. match_expr = vstralloc(" %d SIZE %lld", NULL);
  1241. len = strlen(qdisk);
  1242. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  1243. long long size_ = (long long)0;
  1244. if (line[0] == '\0' || (int)strlen(line) <= len)
  1245. continue;
  1246. /* Don't use sscanf for qdisk because it can have a '%'. */
  1247. if (strncmp(line, qdisk, len) == 0 &&
  1248. sscanf(line+len, match_expr, &level, &size_) == 2) {
  1249. g_printf("%d %lld %d\n", level, size_, 1); /* write to sendsize */
  1250. dbprintf(_("estimate size for %s level %d: %lld KB\n"),
  1251. qdisk, level, size_);
  1252. }
  1253. size = (off_t)size_;
  1254. }
  1255. amfree(match_expr);
  1256. dbprintf(_("waiting for %s %s child (pid=%d)\n"),
  1257. command, qdisk, (int)calcpid);
  1258. waitpid(calcpid, &wait_status, 0);
  1259. if (WIFSIGNALED(wait_status)) {
  1260. errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  1261. "calcsize", WTERMSIG(wait_status),
  1262. dbfn());
  1263. } else if (WIFEXITED(wait_status)) {
  1264. if (WEXITSTATUS(wait_status) != 0) {
  1265. errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  1266. "calcsize", WEXITSTATUS(wait_status),
  1267. dbfn());
  1268. } else {
  1269. /* Normal exit */
  1270. }
  1271. } else {
  1272. errmsg = vstrallocf(_("%s got bad exit: see %s"),
  1273. "calcsize", dbfn());
  1274. }
  1275. dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
  1276. command, qdisk,
  1277. (int)calcpid, WEXITSTATUS(wait_status));
  1278. dbprintf(_(".....\n"));
  1279. dbprintf(_("estimate time for %s: %s\n"),
  1280. qdisk,
  1281. walltime_str(timessub(curclock(), start_time)));
  1282. common_exit:
  1283. if (errmsg && errmsg[0] != '\0') {
  1284. char *qerrmsg = quote_string(errmsg);
  1285. dbprintf(_("errmsg is %s\n"), errmsg);
  1286. g_printf("ERROR %s\n", qerrmsg);
  1287. amfree(qerrmsg);
  1288. }
  1289. amfree(qdisk);
  1290. amfree(errmsg);
  1291. g_ptr_array_free_full(argv_ptr);
  1292. amfree(cmd);
  1293. }
  1294. void
  1295. check_access(
  1296. char * filename,
  1297. int mode)
  1298. {
  1299. char *noun, *adjective;
  1300. char *quoted = quote_string(filename);
  1301. if(mode == F_OK)
  1302. noun = "find", adjective = "exists";
  1303. else if((mode & X_OK) == X_OK)
  1304. noun = "execute", adjective = "executable";
  1305. else if((mode & (W_OK|R_OK)) == (W_OK|R_OK))
  1306. noun = "read/write", adjective = "read/writable";
  1307. else
  1308. noun = "access", adjective = "accessible";
  1309. if(access(filename, mode) == -1)
  1310. g_printf(_("ERROR [can not %s %s: %s]\n"), noun, quoted, strerror(errno));
  1311. else
  1312. g_printf(_("OK %s %s\n"), quoted, adjective);
  1313. amfree(quoted);
  1314. }
  1315. void
  1316. check_file(
  1317. char * filename,
  1318. int mode)
  1319. {
  1320. struct stat stat_buf;
  1321. char *quoted;
  1322. if(!stat(filename, &stat_buf)) {
  1323. if(!S_ISREG(stat_buf.st_mode)) {
  1324. quoted = quote_string(filename);
  1325. g_printf(_("ERROR [%s is not a file]\n"), quoted);
  1326. amfree(quoted);
  1327. }
  1328. } else {
  1329. int save_errno = errno;
  1330. quoted = quote_string(filename);
  1331. g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
  1332. strerror(save_errno));
  1333. amfree(quoted);
  1334. }
  1335. if (getuid() == geteuid()) {
  1336. check_access(filename, mode);
  1337. }
  1338. }
  1339. void
  1340. check_dir(
  1341. char * dirname,
  1342. int mode)
  1343. {
  1344. struct stat stat_buf;
  1345. char *quoted;
  1346. char *dir;
  1347. if(!stat(dirname, &stat_buf)) {
  1348. if(!S_ISDIR(stat_buf.st_mode)) {
  1349. quoted = quote_string(dirname);
  1350. g_printf(_("ERROR [%s is not a directory]\n"), quoted);
  1351. amfree(quoted);
  1352. }
  1353. } else {
  1354. int save_errno = errno;
  1355. quoted = quote_string(dirname);
  1356. g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
  1357. strerror(save_errno));
  1358. amfree(quoted);
  1359. }
  1360. if (getuid() == geteuid()) {
  1361. dir = stralloc2(dirname, "/.");
  1362. check_access(dir, mode);
  1363. amfree(dir);
  1364. }
  1365. }
  1366. void
  1367. check_suid(
  1368. char * filename)
  1369. {
  1370. #ifndef SINGLE_USERID
  1371. struct stat stat_buf;
  1372. char *quoted = quote_string(filename);
  1373. if(!stat(filename, &stat_buf)) {
  1374. if(stat_buf.st_uid != 0 ) {
  1375. g_printf(_("ERROR [%s is not owned by root]\n"), quoted);
  1376. }
  1377. if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
  1378. g_printf(_("ERROR [%s is not SUID root]\n"), quoted);
  1379. }
  1380. }
  1381. else {
  1382. g_printf(_("ERROR [can not stat %s: %s]\n"), quoted, strerror(errno));
  1383. }
  1384. amfree(quoted);
  1385. #else
  1386. (void)filename; /* Quiet unused parameter warning */
  1387. #endif
  1388. }
  1389. /*
  1390. * Returns the value of the first integer in a string.
  1391. */
  1392. double
  1393. the_num(
  1394. char * str,
  1395. int pos)
  1396. {
  1397. char *num;
  1398. int ch;
  1399. double d;
  1400. do {
  1401. ch = *str++;
  1402. while(ch && !isdigit(ch)) ch = *str++;
  1403. if (pos == 1) break;
  1404. pos--;
  1405. while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
  1406. } while (ch);
  1407. num = str - 1;
  1408. while(isdigit(ch) || ch == '.') ch = *str++;
  1409. str[-1] = '\0';
  1410. d = atof(num);
  1411. str[-1] = (char)ch;
  1412. return d;
  1413. }
  1414. char *
  1415. config_errors_to_error_string(
  1416. GSList *errlist)
  1417. {
  1418. char *errmsg;
  1419. gboolean multiple_errors = FALSE;
  1420. if (errlist) {
  1421. errmsg = (char *)errlist->data;
  1422. if (errlist->next)
  1423. multiple_errors = TRUE;
  1424. } else {
  1425. errmsg = _("(no error message)");
  1426. }
  1427. return vstrallocf("ERROR %s%s", errmsg,
  1428. multiple_errors? _(" (additional errors not displayed)"):"");
  1429. }
  1430. void
  1431. add_type_table(
  1432. dmpline_t typ,
  1433. amregex_t **re_table,
  1434. amregex_t *orig_re_table,
  1435. GSList *normal_message,
  1436. GSList *ignore_message,
  1437. GSList *strange_message)
  1438. {
  1439. amregex_t *rp;
  1440. for(rp = orig_re_table; rp->regex != NULL; rp++) {
  1441. if (rp->typ == typ) {
  1442. int found = 0;
  1443. GSList *mes;
  1444. for (mes = normal_message; mes != NULL; mes = mes->next) {
  1445. if (strcmp(rp->regex, (char *)mes->data) == 0)
  1446. found = 1;
  1447. }
  1448. for (mes = ignore_message; mes != NULL; mes = mes->next) {
  1449. if (strcmp(rp->regex, (char *)mes->data) == 0)
  1450. found = 1;
  1451. }
  1452. for (mes = strange_message; mes != NULL; mes = mes->next) {
  1453. if (strcmp(rp->regex, (char *)mes->data) == 0)
  1454. found = 1;
  1455. }
  1456. if (found == 0) {
  1457. (*re_table)->regex = rp->regex;
  1458. (*re_table)->srcline = rp->srcline;
  1459. (*re_table)->scale = rp->scale;
  1460. (*re_table)->field = rp->field;
  1461. (*re_table)->typ = rp->typ;
  1462. (*re_table)++;
  1463. }
  1464. }
  1465. }
  1466. }
  1467. void
  1468. add_list_table(
  1469. dmpline_t typ,
  1470. amregex_t **re_table,
  1471. GSList *message)
  1472. {
  1473. GSList *mes;
  1474. for (mes = message; mes != NULL; mes = mes->next) {
  1475. (*re_table)->regex = (char *)mes->data;
  1476. (*re_table)->srcline = 0;
  1477. (*re_table)->scale = 0;
  1478. (*re_table)->field = 0;
  1479. (*re_table)->typ = typ;
  1480. (*re_table)++;
  1481. }
  1482. }
  1483. amregex_t *
  1484. build_re_table(
  1485. amregex_t *orig_re_table,
  1486. GSList *normal_message,
  1487. GSList *ignore_message,
  1488. GSList *strange_message)
  1489. {
  1490. int nb = 0;
  1491. amregex_t *rp;
  1492. amregex_t *re_table, *new_re_table;
  1493. for(rp = orig_re_table; rp->regex != NULL; rp++) {
  1494. nb++;
  1495. }
  1496. nb += g_slist_length(normal_message);
  1497. nb += g_slist_length(ignore_message);
  1498. nb += g_slist_length(strange_message);
  1499. nb ++;
  1500. re_table = new_re_table = malloc(nb * sizeof(amregex_t));
  1501. /* add SIZE from orig_re_table */
  1502. add_type_table(DMP_SIZE, &re_table, orig_re_table,
  1503. normal_message, ignore_message, strange_message);
  1504. /* add ignore_message */
  1505. add_list_table(DMP_IGNORE, &re_table, ignore_message);
  1506. /* add IGNORE from orig_re_table */
  1507. add_type_table(DMP_IGNORE, &re_table, orig_re_table,
  1508. normal_message, ignore_message, strange_message);
  1509. /* add normal_message */
  1510. add_list_table(DMP_NORMAL, &re_table, normal_message);
  1511. /* add NORMAL from orig_re_table */
  1512. add_type_table(DMP_NORMAL, &re_table, orig_re_table,
  1513. normal_message, ignore_message, strange_message);
  1514. /* add strange_message */
  1515. add_list_table(DMP_STRANGE, &re_table, strange_message);
  1516. /* add STRANGE from orig_re_table */
  1517. add_type_table(DMP_STRANGE, &re_table, orig_re_table,
  1518. normal_message, ignore_message, strange_message);
  1519. /* Add DMP_STRANGE with NULL regex, */
  1520. /* it is not copied by previous statement */
  1521. re_table->regex = NULL;
  1522. re_table->srcline = 0;
  1523. re_table->scale = 0;
  1524. re_table->field = 0;
  1525. re_table->typ = DMP_STRANGE;
  1526. return new_re_table;
  1527. }
  1528. typedef struct {
  1529. proplist_t result;
  1530. } merge_property_t;
  1531. static void
  1532. merge_property(
  1533. gpointer key_p,
  1534. gpointer value_p,
  1535. gpointer user_data_p)
  1536. {
  1537. char *property_s = key_p;
  1538. GSList *value_s = value_p;
  1539. merge_property_t *merge_p = user_data_p;
  1540. GSList *value = g_hash_table_lookup(merge_p->result, property_s);
  1541. if (value) { /* remove old value */
  1542. g_hash_table_remove(merge_p->result, key_p);
  1543. }
  1544. g_hash_table_insert(merge_p->result, key_p, value_s);
  1545. }
  1546. void
  1547. merge_properties(
  1548. proplist_t proplist1,
  1549. proplist_t proplist2)
  1550. {
  1551. merge_property_t merge_p = {proplist1};
  1552. if (proplist2 == NULL) {
  1553. return;
  1554. }
  1555. g_hash_table_foreach(proplist2,
  1556. &merge_property,
  1557. &merge_p);
  1558. }