PageRenderTime 63ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/trunk/common-src/util.c

#
C | 1694 lines | 1346 code | 183 blank | 165 comment | 344 complexity | 59a10a5d0e81faf5e6f40ccae399fc10 MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1999 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: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $
  28. */
  29. #include "amanda.h"
  30. #include "util.h"
  31. #include "match.h"
  32. #include <regex.h>
  33. #include "clock.h"
  34. #include "sockaddr-util.h"
  35. #include "conffile.h"
  36. #include "base64.h"
  37. #include "stream.h"
  38. #include "pipespawn.h"
  39. #include <glib.h>
  40. #include <string.h>
  41. static int make_socket(sa_family_t family);
  42. static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
  43. sockaddr_union *svaddr, int nonblock);
  44. static int
  45. make_socket(
  46. sa_family_t family)
  47. {
  48. int s;
  49. int save_errno;
  50. #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
  51. int on=1;
  52. int r;
  53. #endif
  54. g_debug("make_socket opening socket with family %d", family);
  55. s = socket(family, SOCK_STREAM, 0);
  56. if (s == -1) {
  57. save_errno = errno;
  58. dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
  59. errno = save_errno;
  60. return -1;
  61. }
  62. if (s < 0 || s >= (int)FD_SETSIZE) {
  63. aclose(s);
  64. errno = EMFILE; /* out of range */
  65. return -1;
  66. }
  67. #ifdef USE_REUSEADDR
  68. r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  69. if (r < 0) {
  70. save_errno = errno;
  71. dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
  72. strerror(errno));
  73. errno = save_errno;
  74. }
  75. #endif
  76. #ifdef SO_KEEPALIVE
  77. r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
  78. (void *)&on, sizeof(on));
  79. if (r == -1) {
  80. save_errno = errno;
  81. dbprintf(_("make_socket: setsockopt() failed: %s\n"),
  82. strerror(save_errno));
  83. aclose(s);
  84. errno = save_errno;
  85. return -1;
  86. }
  87. #endif
  88. return s;
  89. }
  90. GQuark am_util_error_quark(void)
  91. {
  92. return g_quark_from_static_string("am-util-error-quark");
  93. }
  94. /* addrp is my address */
  95. /* svaddr is the address of the remote machine */
  96. /* return socket on success */
  97. /* return -1 on failure */
  98. int
  99. connect_portrange(
  100. sockaddr_union *addrp,
  101. in_port_t first_port,
  102. in_port_t last_port,
  103. char * proto,
  104. sockaddr_union *svaddr,
  105. int nonblock)
  106. {
  107. int s;
  108. in_port_t port;
  109. static in_port_t port_in_use[1024];
  110. static int nb_port_in_use = 0;
  111. int i;
  112. int save_errno = EAGAIN;
  113. assert(first_port <= last_port);
  114. /* Try a port already used */
  115. for(i=0; i < nb_port_in_use; i++) {
  116. port = port_in_use[i];
  117. if(port >= first_port && port <= last_port) {
  118. s = connect_port(addrp, port, proto, svaddr, nonblock);
  119. if(s == -2) return -1;
  120. if(s > 0) {
  121. return s;
  122. }
  123. if (errno != EAGAIN && errno != EBUSY)
  124. save_errno = errno;
  125. }
  126. }
  127. /* Try a port in the range */
  128. for (port = first_port; port <= last_port; port++) {
  129. s = connect_port(addrp, port, proto, svaddr, nonblock);
  130. if(s == -2) return -1;
  131. if(s > 0) {
  132. port_in_use[nb_port_in_use++] = port;
  133. return s;
  134. }
  135. if (errno != EAGAIN && errno != EBUSY)
  136. save_errno = errno;
  137. }
  138. dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
  139. first_port,
  140. last_port);
  141. errno = save_errno;
  142. return -1;
  143. }
  144. /* addrp is my address */
  145. /* svaddr is the address of the remote machine */
  146. /* return -2: Don't try again */
  147. /* return -1: Try with another port */
  148. /* return >0: this is the connected socket */
  149. int
  150. connect_port(
  151. sockaddr_union *addrp,
  152. in_port_t port,
  153. char * proto,
  154. sockaddr_union *svaddr,
  155. int nonblock)
  156. {
  157. int save_errno;
  158. struct servent * servPort;
  159. socklen_t_equiv len;
  160. socklen_t_equiv socklen;
  161. int s;
  162. servPort = getservbyport((int)htons(port), proto);
  163. if (servPort != NULL && !strstr(servPort->s_name, AMANDA_SERVICE_NAME)) {
  164. dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
  165. port, servPort->s_name);
  166. errno = EBUSY;
  167. return -1;
  168. }
  169. if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;
  170. SU_SET_PORT(addrp, port);
  171. socklen = SS_LEN(addrp);
  172. if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
  173. save_errno = errno;
  174. aclose(s);
  175. if(servPort == NULL) {
  176. dbprintf(_("connect_port: Try port %d: available - %s\n"),
  177. port, strerror(errno));
  178. } else {
  179. dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
  180. port, servPort->s_name, strerror(errno));
  181. }
  182. if (save_errno != EADDRINUSE) {
  183. errno = save_errno;
  184. return -2;
  185. }
  186. errno = save_errno;
  187. return -1;
  188. }
  189. if(servPort == NULL) {
  190. dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
  191. } else {
  192. dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
  193. port, servPort->s_name);
  194. }
  195. /* find out what port was actually used */
  196. len = sizeof(*addrp);
  197. if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
  198. save_errno = errno;
  199. dbprintf(_("connect_port: getsockname() failed: %s\n"),
  200. strerror(save_errno));
  201. aclose(s);
  202. errno = save_errno;
  203. return -1;
  204. }
  205. if (nonblock)
  206. fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
  207. if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
  208. save_errno = errno;
  209. dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
  210. str_sockaddr(addrp),
  211. strerror(save_errno));
  212. dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
  213. str_sockaddr(svaddr),
  214. strerror(save_errno));
  215. aclose(s);
  216. errno = save_errno;
  217. if (save_errno == ECONNREFUSED ||
  218. save_errno == EHOSTUNREACH ||
  219. save_errno == ENETUNREACH ||
  220. save_errno == ETIMEDOUT) {
  221. return -2 ;
  222. }
  223. return -1;
  224. }
  225. dbprintf(_("connected to %s\n"),
  226. str_sockaddr(svaddr));
  227. dbprintf(_("our side is %s\n"),
  228. str_sockaddr(addrp));
  229. return s;
  230. }
  231. /*
  232. * Bind to a port in the given range. Takes a begin,end pair of port numbers.
  233. *
  234. * Returns negative on error (EGAIN if all ports are in use). Returns 0
  235. * on success.
  236. */
  237. int
  238. bind_portrange(
  239. int s,
  240. sockaddr_union *addrp,
  241. in_port_t first_port,
  242. in_port_t last_port,
  243. char * proto)
  244. {
  245. in_port_t port;
  246. in_port_t cnt;
  247. socklen_t_equiv socklen;
  248. struct servent *servPort;
  249. const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
  250. int save_errno = EAGAIN;
  251. assert(first_port <= last_port);
  252. /*
  253. * We pick a different starting port based on our pid and the current
  254. * time to avoid always picking the same reserved port twice.
  255. */
  256. port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
  257. /*
  258. * Scan through the range, trying all available ports that are either
  259. * not taken in /etc/services or registered for *amanda*. Wrap around
  260. * if we don't happen to start at the beginning.
  261. */
  262. for (cnt = 0; cnt < num_ports; cnt++) {
  263. servPort = getservbyport((int)htons(port), proto);
  264. if ((servPort == NULL) || strstr(servPort->s_name, AMANDA_SERVICE_NAME)) {
  265. SU_SET_PORT(addrp, port);
  266. socklen = SS_LEN(addrp);
  267. if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
  268. if (servPort == NULL) {
  269. g_debug(_("bind_portrange2: Try port %d: Available - Success"), port);
  270. } else {
  271. g_debug(_("bind_portrange2: Try port %d: Owned by %s - Success."), port, servPort->s_name);
  272. }
  273. return 0;
  274. }
  275. if (errno != EAGAIN && errno != EBUSY)
  276. save_errno = errno;
  277. if (servPort == NULL) {
  278. g_debug(_("bind_portrange2: Try port %d: Available - %s"),
  279. port, strerror(errno));
  280. } else {
  281. g_debug(_("bind_portrange2: Try port %d: Owned by %s - %s"),
  282. port, servPort->s_name, strerror(errno));
  283. }
  284. } else {
  285. g_debug(_("bind_portrange2: Skip port %d: Owned by %s."),
  286. port, servPort->s_name);
  287. }
  288. if (++port > last_port)
  289. port = first_port;
  290. }
  291. g_debug(_("bind_portrange: all ports between %d and %d busy"),
  292. first_port,
  293. last_port);
  294. errno = save_errno;
  295. return -1;
  296. }
  297. int
  298. interruptible_accept(
  299. int sock,
  300. struct sockaddr *addr,
  301. socklen_t *addrlen,
  302. gboolean (*prolong)(gpointer data),
  303. gpointer prolong_data)
  304. {
  305. SELECT_ARG_TYPE readset;
  306. struct timeval tv;
  307. int nfound;
  308. if (sock < 0 || sock >= FD_SETSIZE) {
  309. g_debug("interruptible_accept: bad socket %d", sock);
  310. return EBADF;
  311. }
  312. memset(&readset, 0, sizeof(readset));
  313. while (1) {
  314. if (!prolong(prolong_data)) {
  315. errno = 0;
  316. return -1;
  317. }
  318. FD_ZERO(&readset);
  319. FD_SET(sock, &readset);
  320. /* try accepting for 1s */
  321. memset(&tv, 0, sizeof(tv));
  322. tv.tv_sec = 1;
  323. nfound = select(sock+1, &readset, NULL, NULL, &tv);
  324. if (nfound < 0) {
  325. return -1;
  326. } else if (nfound == 0) {
  327. continue;
  328. } else if (!FD_ISSET(sock, &readset)) {
  329. g_debug("interruptible_accept: select malfunction");
  330. errno = EBADF;
  331. return -1;
  332. } else {
  333. int rv = accept(sock, addr, addrlen);
  334. if (rv < 0 && errno == EAGAIN)
  335. continue;
  336. return rv;
  337. }
  338. }
  339. }
  340. /*
  341. * Writes out the entire iovec
  342. */
  343. ssize_t
  344. full_writev(
  345. int fd,
  346. struct iovec * iov,
  347. int iovcnt)
  348. {
  349. ssize_t delta, n, total;
  350. assert(iov != NULL);
  351. total = 0;
  352. while (iovcnt > 0) {
  353. /*
  354. * Write the iovec
  355. */
  356. n = writev(fd, iov, iovcnt);
  357. if (n < 0) {
  358. if (errno != EINTR)
  359. return (-1);
  360. }
  361. else if (n == 0) {
  362. errno = EIO;
  363. return (-1);
  364. } else {
  365. total += n;
  366. /*
  367. * Iterate through each iov. Figure out what we still need
  368. * to write out.
  369. */
  370. for (; n > 0; iovcnt--, iov++) {
  371. /* 'delta' is the bytes written from this iovec */
  372. delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
  373. /* subtract from the total num bytes written */
  374. n -= delta;
  375. assert(n >= 0);
  376. /* subtract from this iovec */
  377. iov->iov_len -= delta;
  378. iov->iov_base = (char *)iov->iov_base + delta;
  379. /* if this iovec isn't empty, run the writev again */
  380. if (iov->iov_len > 0)
  381. break;
  382. }
  383. }
  384. }
  385. return (total);
  386. }
  387. /*
  388. * For backward compatibility we are trying for minimal quoting. Unless ALWAYS
  389. * is true, we only quote a string if it contains whitespace or is misquoted...
  390. */
  391. char *
  392. quote_string_maybe(
  393. const char *str,
  394. gboolean always)
  395. {
  396. char * s;
  397. char * ret;
  398. if ((str == NULL) || (*str == '\0')) {
  399. ret = g_strdup("\"\"");
  400. } else {
  401. const char *r;
  402. for (r = str; *r; r++) {
  403. if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
  404. *r <= ' ' || *r == 0x7F )
  405. always = 1;
  406. }
  407. if (!always) {
  408. /*
  409. * String does not need to be quoted since it contains
  410. * neither whitespace, control or quote characters.
  411. */
  412. ret = g_strdup(str);
  413. } else {
  414. /*
  415. * Allocate maximum possible string length.
  416. * (a string of all quotes plus room for leading ", trailing " and
  417. * NULL)
  418. */
  419. ret = s = g_malloc((strlen(str) * 2) + 2 + 1);
  420. *(s++) = '"';
  421. while (*str != '\0') {
  422. if (*str == '\t') {
  423. *(s++) = '\\';
  424. *(s++) = 't';
  425. str++;
  426. continue;
  427. } else if (*str == '\n') {
  428. *(s++) = '\\';
  429. *(s++) = 'n';
  430. str++;
  431. continue;
  432. } else if (*str == '\r') {
  433. *(s++) = '\\';
  434. *(s++) = 'r';
  435. str++;
  436. continue;
  437. } else if (*str == '\f') {
  438. *(s++) = '\\';
  439. *(s++) = 'f';
  440. str++;
  441. continue;
  442. } else if (*str == '\\') {
  443. *(s++) = '\\';
  444. *(s++) = '\\';
  445. str++;
  446. continue;
  447. }
  448. if (*str == '"')
  449. *(s++) = '\\';
  450. *(s++) = *(str++);
  451. }
  452. *(s++) = '"';
  453. *s = '\0';
  454. }
  455. }
  456. return (ret);
  457. }
  458. int
  459. len_quote_string_maybe(
  460. const char *str,
  461. gboolean always)
  462. {
  463. int ret;
  464. if ((str == NULL) || (*str == '\0')) {
  465. ret = 0;
  466. } else {
  467. const char *r;
  468. for (r = str; *r; r++) {
  469. if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
  470. *r <= ' ' || *r == 0x7F )
  471. always = 1;
  472. }
  473. if (!always) {
  474. /*
  475. * String does not need to be quoted since it contains
  476. * neither whitespace, control or quote characters.
  477. */
  478. ret = strlen(str);
  479. } else {
  480. /*
  481. * Allocate maximum possible string length.
  482. * (a string of all quotes plus room for leading ", trailing " and
  483. * NULL)
  484. */
  485. ret = 1;
  486. while (*str != '\0') {
  487. if (*str == '\t') {
  488. ret++;
  489. ret++;
  490. str++;
  491. continue;
  492. } else if (*str == '\n') {
  493. ret++;
  494. ret++;
  495. str++;
  496. continue;
  497. } else if (*str == '\r') {
  498. ret++;
  499. ret++;
  500. str++;
  501. continue;
  502. } else if (*str == '\f') {
  503. ret++;
  504. ret++;
  505. str++;
  506. continue;
  507. } else if (*str == '\\') {
  508. ret++;
  509. ret++;
  510. str++;
  511. continue;
  512. }
  513. if (*str == '"')
  514. ret++;
  515. ret++;
  516. str++;
  517. }
  518. ret++;
  519. }
  520. }
  521. return (ret);
  522. }
  523. char *
  524. unquote_string(
  525. const char *str)
  526. {
  527. char * ret;
  528. if ((str == NULL) || (*str == '\0')) {
  529. ret = g_strdup("");
  530. } else {
  531. char * in;
  532. char * out;
  533. ret = in = out = g_strdup(str);
  534. while (*in != '\0') {
  535. if (*in == '"') {
  536. in++;
  537. continue;
  538. }
  539. if (*in == '\\') {
  540. in++;
  541. if (*in == 'n') {
  542. in++;
  543. *(out++) = '\n';
  544. continue;
  545. } else if (*in == 't') {
  546. in++;
  547. *(out++) = '\t';
  548. continue;
  549. } else if (*in == 'r') {
  550. in++;
  551. *(out++) = '\r';
  552. continue;
  553. } else if (*in == 'f') {
  554. in++;
  555. *(out++) = '\f';
  556. continue;
  557. } else if (*in >= '0' && *in <= '7') {
  558. char c = 0;
  559. int i = 0;
  560. while (i < 3 && *in >= '0' && *in <= '7') {
  561. c = (c << 3) + *(in++) - '0';
  562. i++;
  563. }
  564. if (c)
  565. *(out++) = c;
  566. } else if (*in == '\0') {
  567. /* trailing backslash -- ignore */
  568. break;
  569. }
  570. }
  571. *(out++) = *(in++);
  572. }
  573. *out = '\0';
  574. }
  575. return (ret);
  576. }
  577. gchar **
  578. split_quoted_strings(
  579. const gchar *string)
  580. {
  581. char *local;
  582. char *start;
  583. char *p;
  584. char **result;
  585. GPtrArray *strs;
  586. int iq = 0;
  587. if (!string)
  588. return NULL;
  589. p = start = local = g_strdup(string);
  590. strs = g_ptr_array_new();
  591. while (*p) {
  592. if (!iq && *p == ' ') {
  593. *p = '\0';
  594. g_ptr_array_add(strs, unquote_string(start));
  595. start = p+1;
  596. } else if (*p == '\\') {
  597. /* next character is taken literally; if it's a multicharacter
  598. * escape (e.g., \171), that doesn't bother us here */
  599. p++;
  600. if (!*p) break;
  601. } else if (*p == '\"') {
  602. iq = ! iq;
  603. }
  604. p++;
  605. }
  606. if (start != string)
  607. g_ptr_array_add(strs, unquote_string(start));
  608. /* now convert strs into a strv, by stealing its references to the underlying
  609. * strings */
  610. result = g_new0(char *, strs->len + 1);
  611. memmove(result, strs->pdata, sizeof(char *) * strs->len);
  612. g_ptr_array_free(strs, TRUE); /* TRUE => free pdata, strings are not freed */
  613. g_free(local);
  614. return result;
  615. }
  616. char *
  617. strquotedstr(char **saveptr)
  618. {
  619. char * tok = strtok_r(NULL, " ", saveptr);
  620. size_t len;
  621. int in_quote;
  622. int in_backslash;
  623. char *p, *t;
  624. if (!tok)
  625. return tok;
  626. len = strlen(tok);
  627. in_quote = 0;
  628. in_backslash = 0;
  629. p = tok;
  630. while (in_quote || in_backslash || *p != '\0') {
  631. if (*p == '\0') {
  632. /* append a new token */
  633. t = strtok_r(NULL, " ", saveptr);
  634. if (!t)
  635. return NULL;
  636. tok[len] = ' ';
  637. len = strlen(tok);
  638. }
  639. if (!in_backslash) {
  640. if (*p == '"')
  641. in_quote = !in_quote;
  642. else if (*p == '\\') {
  643. in_backslash = 1;
  644. }
  645. } else {
  646. in_backslash = 0;
  647. }
  648. p++;
  649. }
  650. return tok;
  651. }
  652. char *
  653. sanitize_string(
  654. const char *str)
  655. {
  656. char * s;
  657. char * ret;
  658. if ((str == NULL) || (*str == '\0')) {
  659. ret = g_strdup("");
  660. } else {
  661. ret = g_strdup(str);
  662. for (s = ret; *s != '\0'; s++) {
  663. if (iscntrl((int)*s))
  664. *s = '?';
  665. }
  666. }
  667. return (ret);
  668. }
  669. char *hexencode_string(const char *str)
  670. {
  671. size_t orig_len, new_len, i;
  672. GString *s;
  673. gchar *ret;
  674. if (!str) {
  675. s = g_string_sized_new(0);
  676. goto cleanup;
  677. }
  678. new_len = orig_len = strlen(str);
  679. for (i = 0; i < orig_len; i++) {
  680. if (!g_ascii_isalnum(str[i])) {
  681. new_len += 2;
  682. }
  683. }
  684. s = g_string_sized_new(new_len);
  685. for (i = 0; i < orig_len; i++) {
  686. if (g_ascii_isalnum(str[i])) {
  687. g_string_append_c(s, str[i]);
  688. } else {
  689. g_string_append_printf(s, "%%%02hhx", str[i]);
  690. }
  691. }
  692. cleanup:
  693. ret = s->str;
  694. g_string_free(s, FALSE);
  695. return ret;
  696. }
  697. char *hexdecode_string(const char *str, GError **err)
  698. {
  699. size_t orig_len, new_len, i;
  700. GString *s;
  701. gchar *ret;
  702. if (!str) {
  703. s = g_string_sized_new(0);
  704. goto cleanup;
  705. }
  706. new_len = orig_len = strlen(str);
  707. for (i = 0; i < orig_len; i++) {
  708. if (str[i] == '%') {
  709. new_len -= 2;
  710. }
  711. }
  712. s = g_string_sized_new(new_len);
  713. for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) {
  714. if (str[i] == '%') {
  715. gchar tmp = 0;
  716. size_t j;
  717. for (j = 1; j < 3; j++) {
  718. tmp <<= 4;
  719. if (str[i+j] >= '0' && str[i+j] <= '9') {
  720. tmp += str[i+j] - '0';
  721. } else if (str[i+j] >= 'a' && str[i+j] <= 'f') {
  722. tmp += str[i+j] - 'a' + 10;
  723. } else if (str[i+j] >= 'A' && str[i+j] <= 'F') {
  724. tmp += str[i+j] - 'A' + 10;
  725. } else {
  726. /* error */
  727. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  728. "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j);
  729. g_string_truncate(s, 0);
  730. goto cleanup;
  731. }
  732. }
  733. if (!tmp) {
  734. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  735. "Encoded NULL at starting offset %zd", i);
  736. g_string_truncate(s, 0);
  737. goto cleanup;
  738. }
  739. g_string_append_c(s, tmp);
  740. i += 2;
  741. } else {
  742. g_string_append_c(s, str[i]);
  743. }
  744. }
  745. for ( /*nothing*/; i < orig_len; i++) {
  746. if (str[i] == '%') {
  747. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  748. "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1);
  749. g_string_truncate(s, 0);
  750. goto cleanup;
  751. } else {
  752. g_string_append_c(s, str[i]);
  753. }
  754. }
  755. cleanup:
  756. ret = s->str;
  757. g_string_free(s, FALSE);
  758. return ret;
  759. }
  760. /* Helper for parse_braced_component; this will turn a single element array
  761. * matching /^\d+\.\.\d+$/ into a sequence of numbered array elements. */
  762. static GPtrArray *
  763. expand_braced_sequence(GPtrArray *arr)
  764. {
  765. char *elt, *p;
  766. char *l, *r;
  767. int ldigits, rdigits, ndigits;
  768. guint64 start, end;
  769. gboolean leading_zero;
  770. /* check whether the element matches the pattern */
  771. /* expand last element of the array only */
  772. elt = g_ptr_array_index(arr, arr->len-1);
  773. ldigits = 0;
  774. for (l = p = elt; *p && g_ascii_isdigit(*p); p++)
  775. ldigits++;
  776. if (ldigits == 0)
  777. return arr;
  778. if (*(p++) != '.')
  779. return arr;
  780. if (*(p++) != '.')
  781. return arr;
  782. rdigits = 0;
  783. for (r = p; *p && g_ascii_isdigit(*p); p++)
  784. rdigits++;
  785. if (rdigits == 0)
  786. return arr;
  787. if (*p)
  788. return arr;
  789. /* we have a match, so extract start and end */
  790. start = g_ascii_strtoull(l, NULL, 10);
  791. end = g_ascii_strtoull(r, NULL, 10);
  792. leading_zero = *l == '0';
  793. ndigits = MAX(ldigits, rdigits);
  794. if (start > end)
  795. return arr;
  796. /* sanity check.. */
  797. if (end - start > 100000)
  798. return arr;
  799. /* remove last from the array */
  800. g_ptr_array_remove_index(arr, arr->len - 1);
  801. /* Add new elements */
  802. while (start <= end) {
  803. if (leading_zero) {
  804. g_ptr_array_add(arr, g_strdup_printf("%0*ju",
  805. ndigits, (uintmax_t)start));
  806. } else {
  807. g_ptr_array_add(arr, g_strdup_printf("%ju", (uintmax_t)start));
  808. }
  809. start++;
  810. }
  811. return arr;
  812. }
  813. /* Helper for expand_braced_alternates; returns a list of un-escaped strings
  814. * for the first "component" of str, where a component is a plain string or a
  815. * brace-enclosed set of alternatives. str is pointing to the first character
  816. * of the next component on return. */
  817. static GPtrArray *
  818. parse_braced_component(char **str)
  819. {
  820. GPtrArray *result = g_ptr_array_new();
  821. if (**str == '{') {
  822. char *p = (*str)+1;
  823. char *local = g_malloc(strlen(*str)+1);
  824. char *current = local;
  825. char *c = current;
  826. while (1) {
  827. if (*p == '\0' || *p == '{') {
  828. /* unterminated { .. } or extra '{' */
  829. amfree(local);
  830. g_ptr_array_free(result, TRUE);
  831. return NULL;
  832. }
  833. if (*p == '}' || *p == ',') {
  834. *c = '\0';
  835. g_ptr_array_add(result, g_strdup(current));
  836. result = expand_braced_sequence(result);
  837. current = ++c;
  838. if (*p == '}')
  839. break;
  840. else
  841. p++;
  842. }
  843. if (*p == '\\') {
  844. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  845. p++;
  846. }
  847. *(c++) = *(p++);
  848. }
  849. amfree(local);
  850. if (*p)
  851. *str = p+1;
  852. else
  853. *str = p;
  854. } else {
  855. /* no braces -- just un-escape a plain string */
  856. char *local = g_malloc(strlen(*str)+1);
  857. char *r = local;
  858. char *p = *str;
  859. while (*p && *p != '{') {
  860. if (*p == '\\') {
  861. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  862. p++;
  863. }
  864. *(r++) = *(p++);
  865. }
  866. *r = '\0';
  867. g_ptr_array_add(result, local);
  868. *str = p;
  869. }
  870. return result;
  871. }
  872. GPtrArray *
  873. expand_braced_alternates(
  874. char * source)
  875. {
  876. GPtrArray *rval = g_ptr_array_new();
  877. g_ptr_array_add(rval, g_strdup(""));
  878. while (*source) {
  879. GPtrArray *new_components;
  880. GPtrArray *new_rval;
  881. guint i, j;
  882. new_components = parse_braced_component(&source);
  883. if (!new_components) {
  884. /* parse error */
  885. g_ptr_array_free(rval, TRUE);
  886. return NULL;
  887. }
  888. new_rval = g_ptr_array_new();
  889. /* do a cartesian join of rval and new_components */
  890. for (i = 0; i < rval->len; i++) {
  891. for (j = 0; j < new_components->len; j++) {
  892. g_ptr_array_add(new_rval, g_strconcat(
  893. g_ptr_array_index(rval, i),
  894. g_ptr_array_index(new_components, j),
  895. NULL));
  896. }
  897. }
  898. g_ptr_array_free(rval, TRUE);
  899. g_ptr_array_free(new_components, TRUE);
  900. rval = new_rval;
  901. }
  902. return rval;
  903. }
  904. char *
  905. collapse_braced_alternates(
  906. GPtrArray *source)
  907. {
  908. GString *result = NULL;
  909. guint i;
  910. result = g_string_new("{");
  911. for (i = 0; i < source->len; i ++) {
  912. const char *str = g_ptr_array_index(source, i);
  913. char *qstr = NULL;
  914. if (strchr(str, ',') || strchr(str, '\\') ||
  915. strchr(str, '{') || strchr(str, '}')) {
  916. const char *s;
  917. char *d;
  918. s = str;
  919. qstr = d = g_malloc(strlen(str)*2+1);
  920. while (*s) {
  921. if (*s == ',' || *s == '\\' || *s == '{' || *s == '}')
  922. *(d++) = '\\';
  923. *(d++) = *(s++);
  924. }
  925. *(d++) = '\0';
  926. }
  927. g_string_append_printf(result, "%s%s", qstr? qstr : str,
  928. (i < source->len-1)? "," : "");
  929. if (qstr)
  930. g_free(qstr);
  931. }
  932. g_string_append(result, "}");
  933. return g_string_free(result, FALSE);
  934. }
  935. /*
  936. Return 0 if the following characters are present
  937. * ( ) < > [ ] , ; : ! $ \ / "
  938. else returns 1
  939. */
  940. int
  941. validate_mailto(
  942. const char *mailto)
  943. {
  944. return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
  945. }
  946. int copy_file(
  947. char *dst,
  948. char *src,
  949. char **errmsg)
  950. {
  951. int infd, outfd;
  952. int save_errno;
  953. size_t nb;
  954. char buf[32768];
  955. char *quoted;
  956. if ((infd = open(src, O_RDONLY)) == -1) {
  957. save_errno = errno;
  958. quoted = quote_string(src);
  959. *errmsg = g_strdup_printf(_("Can't open file '%s' for reading: %s"),
  960. quoted, strerror(save_errno));
  961. amfree(quoted);
  962. return -1;
  963. }
  964. if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
  965. save_errno = errno;
  966. quoted = quote_string(dst);
  967. *errmsg = g_strdup_printf(_("Can't open file '%s' for writting: %s"),
  968. quoted, strerror(save_errno));
  969. amfree(quoted);
  970. close(infd);
  971. return -1;
  972. }
  973. while((nb=read(infd, &buf, sizeof(buf))) > 0) {
  974. if(full_write(outfd,&buf,nb) < nb) {
  975. save_errno = errno;
  976. quoted = quote_string(dst);
  977. *errmsg = g_strdup_printf(_("Error writing to '%s': %s"),
  978. quoted, strerror(save_errno));
  979. amfree(quoted);
  980. close(infd);
  981. close(outfd);
  982. return -1;
  983. }
  984. }
  985. if (errno != 0) {
  986. save_errno = errno;
  987. quoted = quote_string(src);
  988. *errmsg = g_strdup_printf(_("Error reading from '%s': %s"),
  989. quoted, strerror(save_errno));
  990. amfree(quoted);
  991. close(infd);
  992. close(outfd);
  993. return -1;
  994. }
  995. close(infd);
  996. close(outfd);
  997. return 0;
  998. }
  999. #ifndef HAVE_LIBREADLINE
  1000. /*
  1001. * simple readline() replacements, used when we don't have readline
  1002. * support from the system.
  1003. */
  1004. char *
  1005. readline(
  1006. const char *prompt)
  1007. {
  1008. g_printf("%s", prompt);
  1009. fflush(stdout);
  1010. fflush(stderr);
  1011. return agets(stdin);
  1012. }
  1013. void
  1014. add_history(
  1015. const char *line)
  1016. {
  1017. (void)line; /* Quiet unused parameter warning */
  1018. }
  1019. #endif
  1020. /* Order of preference: readdir64(), readdir(). */
  1021. #if HAVE_DECL_READDIR64
  1022. # define USE_DIRENT64
  1023. # define USE_READDIR64
  1024. #elif HAVE_DECL_READDIR
  1025. # define USE_READDIR
  1026. #else
  1027. # error No readdir() or readdir64() available!
  1028. #endif
  1029. char * portable_readdir(DIR* handle) {
  1030. #ifdef USE_DIRENT64
  1031. struct dirent64 *entry_p;
  1032. #else
  1033. struct dirent *entry_p;
  1034. #endif
  1035. static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  1036. g_static_mutex_lock(&mutex);
  1037. #ifdef USE_READDIR
  1038. entry_p = readdir(handle);
  1039. #endif
  1040. #ifdef USE_READDIR64
  1041. entry_p = readdir64(handle);
  1042. #endif
  1043. g_static_mutex_unlock(&mutex);
  1044. if (entry_p == NULL)
  1045. return NULL;
  1046. /* FIXME: According to glibc documentation, d_name may not be
  1047. null-terminated in some cases on some very old platforms. Not
  1048. sure what to do about that case. */
  1049. return strdup(entry_p->d_name);
  1050. }
  1051. int search_directory(DIR * handle, const char * regex,
  1052. SearchDirectoryFunctor functor, gpointer user_data) {
  1053. int rval = 0;
  1054. regex_t compiled_regex;
  1055. gboolean done = FALSE;
  1056. if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
  1057. regfree(&compiled_regex);
  1058. return -1;
  1059. }
  1060. rewinddir(handle);
  1061. while (!done) {
  1062. char * read_name;
  1063. int result;
  1064. read_name = portable_readdir(handle);
  1065. if (read_name == NULL) {
  1066. regfree(&compiled_regex);
  1067. return rval;
  1068. }
  1069. result = regexec(&compiled_regex, read_name, 0, NULL, 0);
  1070. if (result == 0) {
  1071. rval ++;
  1072. done = !functor(read_name, user_data);
  1073. }
  1074. amfree(read_name);
  1075. }
  1076. regfree(&compiled_regex);
  1077. return rval;
  1078. }
  1079. char* find_regex_substring(const char* base_string, const regmatch_t match) {
  1080. char * rval;
  1081. int size;
  1082. size = match.rm_eo - match.rm_so;
  1083. rval = malloc(size+1);
  1084. memcpy(rval, base_string + match.rm_so, size);
  1085. rval[size] = '\0';
  1086. return rval;
  1087. }
  1088. int compare_possibly_null_strings(const char * a, const char * b) {
  1089. if (a == b) {
  1090. /* NULL or otherwise, they're the same. */
  1091. return 0;
  1092. } else if (a == NULL) {
  1093. /* b != NULL */
  1094. return -1;
  1095. } else if (b == NULL) {
  1096. /* a != NULL */
  1097. return 1;
  1098. } else {
  1099. /* a != NULL != b */
  1100. return strcmp(a, b);
  1101. }
  1102. }
  1103. int
  1104. resolve_hostname(const char *hostname,
  1105. int socktype,
  1106. struct addrinfo **res,
  1107. char **canonname)
  1108. {
  1109. struct addrinfo hints;
  1110. struct addrinfo *myres;
  1111. int flags = 0;
  1112. int result;
  1113. if (res) *res = NULL;
  1114. if (canonname) {
  1115. *canonname = NULL;
  1116. flags = AI_CANONNAME;
  1117. }
  1118. #ifdef AI_ADDRCONFIG
  1119. flags |= AI_ADDRCONFIG;
  1120. #endif
  1121. memset(&hints, 0, sizeof(hints));
  1122. #ifdef WORKING_IPV6
  1123. /* get any kind of addresss */
  1124. hints.ai_family = AF_UNSPEC;
  1125. #else
  1126. /* even if getaddrinfo supports IPv6, don't let it return
  1127. * such an address */
  1128. hints.ai_family = AF_INET;
  1129. #endif
  1130. hints.ai_flags = flags;
  1131. hints.ai_socktype = socktype;
  1132. result = getaddrinfo(hostname, NULL, &hints, &myres);
  1133. if (result != 0) {
  1134. return result;
  1135. }
  1136. if (canonname && myres && myres->ai_canonname) {
  1137. *canonname = g_strdup(myres->ai_canonname);
  1138. }
  1139. if (res) {
  1140. *res = myres;
  1141. } else {
  1142. freeaddrinfo(myres);
  1143. }
  1144. return result;
  1145. }
  1146. char *
  1147. _str_exit_status(
  1148. char *subject,
  1149. amwait_t status)
  1150. {
  1151. if (WIFEXITED(status)) {
  1152. int exitstatus = WEXITSTATUS(status);
  1153. if (exitstatus == 0)
  1154. return g_strdup_printf(_("%s exited normally"), subject);
  1155. else
  1156. return g_strdup_printf(_("%s exited with status %d"), subject, exitstatus);
  1157. }
  1158. if (WIFSIGNALED(status)) {
  1159. int signal = WTERMSIG(status);
  1160. #ifdef WCOREDUMP
  1161. if (WCOREDUMP(status))
  1162. return g_strdup_printf(_("%s exited after receiving signal %d (core dumped)"),
  1163. subject, signal);
  1164. else
  1165. #endif
  1166. return g_strdup_printf(_("%s exited after receiving signal %d"),
  1167. subject, signal);
  1168. }
  1169. if (WIFSTOPPED(status)) {
  1170. int signal = WSTOPSIG(status);
  1171. return g_strdup_printf(_("%s stopped temporarily after receiving signal %d"),
  1172. subject, signal);
  1173. }
  1174. #ifdef WIFCONTINUED
  1175. if (WIFCONTINUED(status)) {
  1176. return g_strdup_printf(_("%s was resumed"), subject);
  1177. }
  1178. #endif
  1179. return g_strdup_printf(_("%s exited in unknown circumstances"), subject);
  1180. }
  1181. void
  1182. check_running_as(running_as_flags who)
  1183. {
  1184. #ifdef CHECK_USERID
  1185. struct passwd *pw;
  1186. uid_t uid_me;
  1187. uid_t uid_target;
  1188. char *uname_me = NULL;
  1189. char *uname_target = NULL;
  1190. char *dumpuser;
  1191. uid_me = getuid();
  1192. if ((pw = getpwuid(uid_me)) == NULL) {
  1193. error(_("current userid %ld not found in password database"), (long)uid_me);
  1194. /* NOTREACHED */
  1195. }
  1196. uname_me = g_strdup(pw->pw_name);
  1197. #ifndef SINGLE_USERID
  1198. if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
  1199. error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
  1200. (long long int)geteuid(), (long long int)uid_me);
  1201. /* NOTREACHED */
  1202. }
  1203. #endif
  1204. switch (who & RUNNING_AS_USER_MASK) {
  1205. case RUNNING_AS_ANY:
  1206. uid_target = uid_me;
  1207. uname_target = uname_me;
  1208. amfree(uname_me);
  1209. return;
  1210. case RUNNING_AS_ROOT:
  1211. uid_target = 0;
  1212. uname_target = "root";
  1213. break;
  1214. case RUNNING_AS_DUMPUSER_PREFERRED:
  1215. dumpuser = getconf_str(CNF_DUMPUSER);
  1216. if ((pw = getpwnam(dumpuser)) != NULL &&
  1217. uid_me != pw->pw_uid) {
  1218. if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
  1219. uid_me == pw->pw_uid) {
  1220. /* uid == CLIENT_LOGIN: not ideal, but OK */
  1221. dbprintf(_("NOTE: running as '%s', which is the client"
  1222. " user, not the dumpuser ('%s'); forging"
  1223. " on anyway\n"),
  1224. CLIENT_LOGIN, dumpuser);
  1225. uid_target = uid_me; /* force success below */
  1226. break;
  1227. }
  1228. }
  1229. /* FALLTHROUGH */
  1230. case RUNNING_AS_DUMPUSER:
  1231. uname_target = getconf_str(CNF_DUMPUSER);
  1232. if ((pw = getpwnam(uname_target)) == NULL) {
  1233. error(_("cannot look up dumpuser \"%s\""), uname_target);
  1234. /*NOTREACHED*/
  1235. }
  1236. uid_target = pw->pw_uid;
  1237. break;
  1238. case RUNNING_AS_CLIENT_LOGIN:
  1239. uname_target = CLIENT_LOGIN;
  1240. if ((pw = getpwnam(uname_target)) == NULL) {
  1241. error(_("cannot look up client user \"%s\""), uname_target);
  1242. /*NOTREACHED*/
  1243. }
  1244. uid_target = pw->pw_uid;
  1245. break;
  1246. default:
  1247. error(_("Unknown check_running_as() call"));
  1248. /* NOTREACHED */
  1249. }
  1250. if (uid_me != uid_target) {
  1251. error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
  1252. /*NOTREACHED*/
  1253. }
  1254. amfree(uname_me);
  1255. #else
  1256. /* Quiet unused variable warning */
  1257. (void)who;
  1258. #endif
  1259. }
  1260. int
  1261. set_root_privs(int need_root)
  1262. {
  1263. #ifndef SINGLE_USERID
  1264. static gboolean first_call = TRUE;
  1265. static uid_t unpriv = 1;
  1266. if (first_call) {
  1267. /* save the original real userid (that of our invoker) */
  1268. unpriv = getuid();
  1269. /* and set all of our userids (including, importantly, the saved
  1270. * userid) to 0 */
  1271. setuid(0);
  1272. /* don't need to do this next time */
  1273. first_call = FALSE;
  1274. }
  1275. if (need_root == 1) {
  1276. if (geteuid() == 0) return 1; /* already done */
  1277. if (seteuid(0) == -1) return 0;
  1278. /* (we don't switch the group back) */
  1279. } else if (need_root == -1) {
  1280. /* make sure the euid is 0 so that we can set the uid */
  1281. if (geteuid() != 0) {
  1282. if (seteuid(0) == -1) return 0;
  1283. }
  1284. /* now set the uid to the unprivileged userid */
  1285. if (setuid(unpriv) == -1) return 0;
  1286. } else {
  1287. if (geteuid() != 0) return 1; /* already done */
  1288. /* set the *effective* userid only */
  1289. if (seteuid(unpriv) == -1) return 0;
  1290. if (setegid(getgid()) == -1) return 0;
  1291. }
  1292. #else
  1293. (void)need_root; /* Quiet unused variable warning */
  1294. #endif
  1295. return 1;
  1296. }
  1297. int
  1298. become_root(void)
  1299. {
  1300. #ifndef SINGLE_USERID
  1301. /* first, set the effective userid to 0 */
  1302. if (seteuid(0) == -1) return 0;
  1303. /* then, set all of the userids to 0 */
  1304. if (setuid(0) == -1) return 0;
  1305. #endif
  1306. return 1;
  1307. }
  1308. char *
  1309. base64_decode_alloc_string(
  1310. char *in)
  1311. {
  1312. char *out;
  1313. size_t in_len = strlen(in);
  1314. size_t out_len = 3 * (in_len / 4) + 3;
  1315. out = malloc(out_len);
  1316. if (!base64_decode(in, in_len, out, &out_len)) {
  1317. amfree(out);
  1318. return NULL;
  1319. }
  1320. out[out_len] = '\0';
  1321. return out;
  1322. }
  1323. /* A GHFunc (callback for g_hash_table_foreach),
  1324. * Store a property and it's value in an ARGV.
  1325. *
  1326. * @param key_p: (char *) property name.
  1327. * @param value_p: (GSList *) property values list.
  1328. * @param user_data_p: (char ***) pointer to ARGV.
  1329. */
  1330. static void
  1331. proplist_add_to_argv(
  1332. gpointer key_p,
  1333. gpointer value_p,
  1334. gpointer user_data_p)
  1335. {
  1336. char *property_s = key_p;
  1337. property_t *value_s = value_p;
  1338. GPtrArray *argv_ptr = user_data_p;
  1339. GSList *value;
  1340. char *q, *w, *qprop;
  1341. q = g_strdup(property_s);
  1342. /* convert to lower case */
  1343. for (w=q; *w != '\0'; w++) {
  1344. *w = tolower(*w);
  1345. if (*w == '_')
  1346. *w = '-';
  1347. }
  1348. qprop = g_strconcat("--", q, NULL);
  1349. amfree(q);
  1350. for(value=value_s->values; value != NULL; value = value->next) {
  1351. g_ptr_array_add(argv_ptr, g_strdup(qprop));
  1352. g_ptr_array_add(argv_ptr, g_strdup((char *)value->data));
  1353. }
  1354. amfree(qprop);
  1355. }
  1356. void
  1357. property_add_to_argv(
  1358. GPtrArray *argv_ptr,
  1359. GHashTable *proplist)
  1360. {
  1361. g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr);
  1362. }
  1363. /*
  1364. * Process parameters
  1365. */
  1366. static char *pname = NULL;
  1367. static char *ptype = NULL;
  1368. static pcontext_t pcontext = CONTEXT_DEFAULT;
  1369. void
  1370. set_pname(char *p)
  1371. {
  1372. g_free(pname);
  1373. pname = g_strdup(p);
  1374. }
  1375. char *
  1376. get_pname(void)
  1377. {
  1378. if (!pname) pname = g_strdup("unknown");
  1379. return pname;
  1380. }
  1381. void
  1382. set_ptype(char *p)
  1383. {
  1384. g_free(ptype);
  1385. ptype = g_strdup(p);
  1386. }
  1387. char *
  1388. get_ptype(void)
  1389. {
  1390. if (!ptype) ptype = g_strdup("unknown");
  1391. return ptype;
  1392. }
  1393. void
  1394. set_pcontext(pcontext_t pc)
  1395. {
  1396. pcontext = pc;
  1397. }
  1398. pcontext_t
  1399. get_pcontext(void)
  1400. {
  1401. return pcontext;
  1402. }
  1403. #ifdef __OpenBSD__
  1404. void
  1405. openbsd_fd_inform(void)
  1406. {
  1407. int i;
  1408. for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) {
  1409. /* a simple fcntl() will cause the library to "look" at this file
  1410. * descriptor, which is good enough */
  1411. (void)fcntl(i, F_GETFL);
  1412. }
  1413. }
  1414. #endif
  1415. void
  1416. debug_executing(
  1417. GPtrArray *argv_ptr)
  1418. {
  1419. char *cmdline;
  1420. GString *strbuf;
  1421. gsize i, len = argv_ptr->len - 1;
  1422. /*
  1423. * This is ugly, but we have no choice: we cannot count on the caller to
  1424. * supply a NULL-terminated GPtrArray (he'll have other problems than this
  1425. * function, anyway), so we have to display all but the last argument - and
  1426. * therefore need to peek into the array directly to knows its length.
  1427. *
  1428. * To make things even funnier, we have to quote all arguments _except_ the
  1429. * command name (ie, the first one).
  1430. */
  1431. strbuf = g_string_new((char *)g_ptr_array_index(argv_ptr, 0));
  1432. for (i = 1; i < len; i++) {
  1433. cmdline = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i));
  1434. g_string_append_printf(strbuf, " %s", cmdline);
  1435. g_free(cmdline);
  1436. }
  1437. cmdline = g_string_free(strbuf, FALSE);
  1438. g_debug("Executing: %s\n", cmdline);
  1439. g_free(cmdline);
  1440. }
  1441. char *
  1442. get_first_line(
  1443. GPtrArray *argv_ptr)
  1444. {
  1445. char *output_string = NULL;
  1446. int inpipe[2], outpipe[2], errpipe[2];
  1447. int pid;
  1448. FILE *out, *err;
  1449. assert(argv_ptr != NULL);
  1450. assert(argv_ptr->pdata != NULL);
  1451. assert(argv_ptr->len >= 1);
  1452. if (pipe(inpipe) == -1) {
  1453. error(_("error [open pipe: %s]"), strerror(errno));
  1454. /*NOTREACHED*/
  1455. }
  1456. if (pipe(outpipe) == -1) {
  1457. error(_("error [open pipe: %s]"), strerror(errno));
  1458. /*NOTREACHED*/
  1459. }
  1460. if (pipe(errpipe) == -1) {
  1461. error(_("error [open pipe: %s]"), strerror(errno));
  1462. /*NOTREACHED*/
  1463. }
  1464. fflush(stdout);
  1465. switch(pid = fork()) {
  1466. case -1:
  1467. error(_("error [fork: %s]"), strerror(errno));
  1468. /*NOTREACHED*/
  1469. default: /* parent process */
  1470. aclose(inpipe[0]);
  1471. aclose(outpipe[1]);
  1472. aclose(errpipe[1]);
  1473. break;
  1474. case 0: /* child process */
  1475. aclose(inpipe[1]);
  1476. aclose(outpipe[0]);
  1477. aclose(errpipe[0]);
  1478. dup2(inpipe[0], 0);
  1479. dup2(outpipe[1], 1);
  1480. dup2(errpipe[1], 2);
  1481. debug_executing(argv_ptr);
  1482. g_fprintf(stdout, "unknown\n");
  1483. execv((char *)*argv_ptr->pdata, (char **)argv_ptr->pdata);
  1484. error(_("error [exec %s: %s]"), (char *)*argv_ptr->pdata, strerror(errno));
  1485. }
  1486. aclose(inpipe[1]);
  1487. out = fdopen(outpipe[0],"r");
  1488. err = fdopen(errpipe[0],"r");
  1489. output_string = agets(out);
  1490. if (!output_string)
  1491. output_string = agets(err);
  1492. fclose(out);
  1493. fclose(err);
  1494. waitpid(pid, NULL, 0);
  1495. return output_string;
  1496. }