PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/trunk/client-src/client_util.c

#
C | 1899 lines | 1843 code | 24 blank | 32 comment | 44 complexity | e1e78c27a1d2f66cf137053e31deb771 MD5 | raw file

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

Large files files are truncated, but you can click here to view the full file