PageRenderTime 121ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 1ms

/amanda/tags/3_3_0_qa07/common-src/util.c

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