#include "amanda.h"
#include "util.h"
+#include <regex.h>
#include "arglist.h"
#include "clock.h"
-
-/*#define NET_READ_DEBUG*/
-
-#ifdef NET_READ_DEBUG
-#define netprintf(x) dbprintf(x)
-#else
-#define netprintf(x)
-#endif
+#include "sockaddr-util.h"
+#include "conffile.h"
+#include "base64.h"
static int make_socket(sa_family_t family);
-static int connect_port(struct sockaddr_storage *addrp, in_port_t port, char *proto,
- struct sockaddr_storage *svaddr, int nonblock);
-
-/*
- * Keep calling read() until we've read buflen's worth of data, or EOF,
- * or we get an error.
- *
- * Returns the number of bytes read, 0 on EOF, or negative on error.
- */
-ssize_t
-fullread(
- int fd,
- void * vbuf,
- size_t buflen)
-{
- ssize_t nread, tot = 0;
- char *buf = vbuf; /* cast to char so we can ++ it */
-
- while (buflen > 0) {
- nread = read(fd, buf, buflen);
- if (nread < 0) {
- if ((errno == EINTR) || (errno == EAGAIN))
- continue;
- return ((tot > 0) ? tot : -1);
- }
-
- if (nread == 0)
- break;
-
- tot += nread;
- buf += nread;
- buflen -= nread;
- }
- return (tot);
-}
-
-/*
- * Keep calling write() until we've written buflen's worth of data,
- * or we get an error.
- *
- * Returns the number of bytes written, or negative on error.
- */
-ssize_t
-fullwrite(
- int fd,
- const void *vbuf,
- size_t buflen)
-{
- ssize_t nwritten, tot = 0;
- const char *buf = vbuf; /* cast to char so we can ++ it */
-
- while (buflen > 0) {
- nwritten = write(fd, buf, buflen);
- if (nwritten < 0) {
- if ((errno == EINTR) || (errno == EAGAIN))
- continue;
- return ((tot > 0) ? tot : -1);
- }
- tot += nwritten;
- buf += nwritten;
- buflen -= nwritten;
- }
- return (tot);
-}
+static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
+ sockaddr_union *svaddr, int nonblock);
static int
make_socket(
int r;
#endif
+ g_debug("make_socket opening socket with family %d", family);
s = socket(family, SOCK_STREAM, 0);
if (s == -1) {
save_errno = errno;
- dbprintf(("%s: make_socket: socket() failed: %s\n",
- debug_prefix_time(NULL),
- strerror(save_errno)));
+ dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
errno = save_errno;
return -1;
}
r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (r < 0) {
save_errno = errno;
- dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n",
- debug_prefix_time(NULL),
- strerror(errno)));
+ dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
+ strerror(errno));
errno = save_errno;
}
#endif
(void *)&on, SIZEOF(on));
if (r == -1) {
save_errno = errno;
- dbprintf(("%s: make_socket: setsockopt() failed: %s\n",
- debug_prefix_time(NULL),
- strerror(save_errno)));
+ dbprintf(_("make_socket: setsockopt() failed: %s\n"),
+ strerror(save_errno));
aclose(s);
errno = save_errno;
return -1;
/* return -1 on failure */
int
connect_portrange(
- struct sockaddr_storage *addrp,
+ sockaddr_union *addrp,
in_port_t first_port,
in_port_t last_port,
char * proto,
- struct sockaddr_storage *svaddr,
+ sockaddr_union *svaddr,
int nonblock)
{
int s;
static in_port_t port_in_use[1024];
static int nb_port_in_use = 0;
int i;
+ int save_errno = EAGAIN;
assert(first_port <= last_port);
/* Try a port already used */
if(s > 0) {
return s;
}
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
}
}
port_in_use[nb_port_in_use++] = port;
return s;
}
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
}
- dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n",
- debug_prefix_time(NULL),
+ dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
first_port,
- last_port));
- errno = EAGAIN;
+ last_port);
+ errno = save_errno;
return -1;
}
/* return >0: this is the connected socket */
int
connect_port(
- struct sockaddr_storage *addrp,
+ sockaddr_union *addrp,
in_port_t port,
char * proto,
- struct sockaddr_storage *svaddr,
+ sockaddr_union *svaddr,
int nonblock)
{
int save_errno;
struct servent * servPort;
- socklen_t len;
- socklen_t socklen;
+ socklen_t_equiv len;
+ socklen_t_equiv socklen;
int s;
servPort = getservbyport((int)htons(port), proto);
if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
- dbprintf(("%s: connect_port: Skip port %d: Owned by %s.\n",
- debug_prefix_time(NULL), port, servPort->s_name));
+ dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
+ port, servPort->s_name);
+ errno = EBUSY;
return -1;
}
- if(servPort == NULL)
- dbprintf(("%s: connect_port: Try port %d: Available - \n",
- debug_prefix_time(NULL), port));
- else {
- dbprintf(("%s: connect_port: Try port %d: Owned by %s - \n",
- debug_prefix_time(NULL), port, servPort->s_name));
- }
+ if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;
- if ((s = make_socket(addrp->ss_family)) == -1) return -2;
-
- SS_SET_PORT(addrp, port);
+ SU_SET_PORT(addrp, port);
socklen = SS_LEN(addrp);
if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
save_errno = errno;
aclose(s);
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - %s\n"),
+ port, strerror(errno));
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
+ port, servPort->s_name, strerror(errno));
+ }
if (save_errno != EADDRINUSE) {
- dbprintf(("errno %d strerror %s\n",
- errno, strerror(errno)));
errno = save_errno;
return -2;
}
+
errno = save_errno;
return -1;
}
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
+ port, servPort->s_name);
+ }
/* find out what port was actually used */
len = sizeof(*addrp);
if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
save_errno = errno;
- dbprintf(("%s: connect_port: getsockname() failed: %s\n",
- debug_prefix_time(NULL),
- strerror(save_errno)));
+ dbprintf(_("connect_port: getsockname() failed: %s\n"),
+ strerror(save_errno));
aclose(s);
errno = save_errno;
return -1;
fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
save_errno = errno;
- dbprintf(("%s: connect_portrange: connect from %s failed: %s\n",
- debug_prefix_time(NULL),
+ dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
str_sockaddr(addrp),
- strerror(save_errno)));
- dbprintf(("%s: connect_portrange: connect to %s failed: %s\n",
- debug_prefix_time(NULL),
+ strerror(save_errno));
+ dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
str_sockaddr(svaddr),
- strerror(save_errno)));
+ strerror(save_errno));
aclose(s);
errno = save_errno;
if (save_errno == ECONNREFUSED ||
return -1;
}
- dbprintf(("%s: connected to %s\n",
- debug_prefix_time(NULL),
- str_sockaddr(svaddr)));
- dbprintf(("%s: our side is %s\n",
- debug_prefix_time(NULL),
- str_sockaddr(addrp)));
+ dbprintf(_("connected to %s\n"),
+ str_sockaddr(svaddr));
+ dbprintf(_("our side is %s\n"),
+ str_sockaddr(addrp));
return s;
}
int
bind_portrange(
int s,
- struct sockaddr_storage *addrp,
+ sockaddr_union *addrp,
in_port_t first_port,
in_port_t last_port,
char * proto)
{
in_port_t port;
in_port_t cnt;
- socklen_t socklen;
+ socklen_t_equiv socklen;
struct servent *servPort;
const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
+ int save_errno = EAGAIN;
assert(first_port <= last_port);
for (cnt = 0; cnt < num_ports; cnt++) {
servPort = getservbyport((int)htons(port), proto);
if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
- if (servPort == NULL) {
- dbprintf(("%s: bind_portrange2: Try port %d: Available - ",
- debug_prefix_time(NULL), port));
- } else {
- dbprintf(("%s: bind_portrange2: Try port %d: Owned by %s - ",
- debug_prefix_time(NULL), port, servPort->s_name));
- }
- SS_SET_PORT(addrp, port);
+ SU_SET_PORT(addrp, port);
socklen = SS_LEN(addrp);
if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
- dbprintf(("Success\n"));
+ if (servPort == NULL) {
+ dbprintf(_("bind_portrange2: Try port %d: Available - Success\n"), port);
+ } else {
+ dbprintf(_("bind_portrange2: Try port %d: Owned by %s - Success.\n"), port, servPort->s_name);
+ }
return 0;
}
- dbprintf(("%s\n", strerror(errno)));
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
+ if (servPort == NULL) {
+ dbprintf(_("bind_portrange2: Try port %d: Available - %s\n"),
+ port, strerror(errno));
+ } else {
+ dbprintf(_("bind_portrange2: Try port %d: Owned by %s - %s\n"),
+ port, servPort->s_name, strerror(errno));
+ }
} else {
- dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n",
- debug_prefix_time(NULL), port, servPort->s_name));
+ dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),
+ port, servPort->s_name);
}
if (++port > last_port)
port = first_port;
}
- dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n",
- debug_prefix_time(NULL),
+ dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),
first_port,
- last_port));
- errno = EAGAIN;
+ last_port);
+ errno = save_errno;
return -1;
}
/*
- * Construct a datestamp (YYYYMMDD) from a time_t.
+ * Writes out the entire iovec
*/
-char *
-construct_datestamp(
- time_t *t)
+ssize_t
+full_writev(
+ int fd,
+ struct iovec * iov,
+ int iovcnt)
{
- struct tm *tm;
- char datestamp[3 * NUM_STR_SIZE];
- time_t when;
+ ssize_t delta, n, total;
- if (t == NULL) {
- when = time((time_t *)NULL);
- } else {
- when = *t;
- }
- tm = localtime(&when);
- if (!tm)
- return stralloc("19000101");
-
- snprintf(datestamp, SIZEOF(datestamp),
- "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
- return stralloc(datestamp);
-}
+ assert(iov != NULL);
-/*
- * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
- */
-char *
-construct_timestamp(
- time_t *t)
-{
- struct tm *tm;
- char timestamp[6 * NUM_STR_SIZE];
- time_t when;
-
- if (t == NULL) {
- when = time((time_t *)NULL);
- } else {
- when = *t;
+ total = 0;
+ while (iovcnt > 0) {
+ /*
+ * Write the iovec
+ */
+ n = writev(fd, iov, iovcnt);
+ if (n < 0) {
+ if (errno != EINTR)
+ return (-1);
+ }
+ else if (n == 0) {
+ errno = EIO;
+ return (-1);
+ } else {
+ total += n;
+ /*
+ * Iterate through each iov. Figure out what we still need
+ * to write out.
+ */
+ for (; n > 0; iovcnt--, iov++) {
+ /* 'delta' is the bytes written from this iovec */
+ delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
+ /* subtract from the total num bytes written */
+ n -= delta;
+ assert(n >= 0);
+ /* subtract from this iovec */
+ iov->iov_len -= delta;
+ iov->iov_base = (char *)iov->iov_base + delta;
+ /* if this iovec isn't empty, run the writev again */
+ if (iov->iov_len > 0)
+ break;
+ }
+ }
}
- tm = localtime(&when);
- if (!tm)
- return stralloc("19000101000000");
-
- snprintf(timestamp, SIZEOF(timestamp),
- "%04d%02d%02d%02d%02d%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- return stralloc(timestamp);
+ return (total);
}
if ((str == NULL) || (*str == '\0')) {
ret = stralloc("\"\"");
- } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) {
+ } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
/*
* String does not need to be quoted since it contains
* neither whitespace, control or quote characters.
in++;
*(out++) = '\f';
continue;
+ } else if (*in >= '0' && *in <= '7') {
+ char c = 0;
+ int i = 0;
+
+ while (i < 3 && *in >= '0' && *in <= '7') {
+ c = (c << 3) + *(in++) - '0';
+ i++;
+ }
+ if (c)
+ *(out++) = c;
+ } else if (*in == '\0') {
+ /* trailing backslash -- ignore */
+ break;
}
}
*(out++) = *(in++);
return (ret);
}
-char *
-sanitize_string(
- const char *str)
+gchar **
+split_quoted_strings(
+ const gchar *string)
{
- char * s;
- char * ret;
-
- if ((str == NULL) || (*str == '\0')) {
- ret = stralloc("");
- } else {
- ret = stralloc(str);
- for (s = ret; *s != '\0'; s++) {
- if (iscntrl(*s))
- *s = '?';
+ char *local = g_strdup(string);
+ char *start = local;
+ char *p = local;
+ char **result;
+ GPtrArray *strs = g_ptr_array_new();
+ int iq = 0;
+
+ while (*p) {
+ if (!iq && *p == ' ') {
+ *p = '\0';
+ g_ptr_array_add(strs, unquote_string(start));
+ start = p+1;
+ } else if (*p == '\\') {
+ /* next character is taken literally; if it's a multicharacter
+ * escape (e.g., \171), that doesn't bother us here */
+ p++;
+ if (!*p) break;
+ } else if (*p == '\"') {
+ iq = ! iq;
}
+
+ p++;
}
- return (ret);
+ if (start != string)
+ g_ptr_array_add(strs, unquote_string(start));
+
+ /* now convert strs into a strv, by stealing its references to the underlying
+ * strings */
+ result = g_new0(char *, strs->len + 1);
+ memmove(result, strs->pdata, sizeof(char *) * strs->len);
+
+ g_ptr_array_free(strs, FALSE); /* FALSE => don't free strings */
+ g_free(local);
+
+ return result;
}
char *
-strquotedstr(void)
+strquotedstr(char **saveptr)
{
- char * tok = strtok(NULL, " ");
-
- if ((tok != NULL) && (tok[0] == '"')) {
- char * t;
- size_t len;
-
- len = strlen(tok);
- do {
- t = strtok(NULL, " ");
+ char * tok = strtok_r(NULL, " ", saveptr);
+ size_t len;
+ int in_quote;
+ int in_backslash;
+ char *p, *t;
+
+ if (!tok)
+ return tok;
+ len = strlen(tok);
+ in_quote = 0;
+ in_backslash = 0;
+ p = tok;
+ while (in_quote || in_backslash || *p != '\0') {
+ if (*p == '\0') {
+ /* append a new token */
+ t = strtok_r(NULL, " ", saveptr);
+ if (!t)
+ return NULL;
tok[len] = ' ';
len = strlen(tok);
- } while ((t != NULL) &&
- (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
+ }
+ if (!in_backslash) {
+ if (*p == '"')
+ in_quote = !in_quote;
+ else if (*p == '\\') {
+ in_backslash = 1;
+ }
+ } else {
+ in_backslash = 0;
+ }
+ p++;
}
return tok;
}
-ssize_t
-hexdump(
- const char *buffer,
- size_t len)
+char *
+sanitize_string(
+ const char *str)
{
- ssize_t rc = -1;
+ char * s;
+ char * ret;
- FILE *stream = popen("od -c -x -", "w");
-
- if (stream != NULL) {
- fflush(stdout);
- rc = (ssize_t)fwrite(buffer, len, 1, stream);
- if (ferror(stream))
- rc = -1;
- pclose(stream);
+ if ((str == NULL) || (*str == '\0')) {
+ ret = stralloc("");
+ } else {
+ ret = stralloc(str);
+ for (s = ret; *s != '\0'; s++) {
+ if (iscntrl((int)*s))
+ *s = '?';
+ }
}
- return rc;
+ return (ret);
}
/*
return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
}
-
-void
-dump_sockaddr(
- struct sockaddr_storage *sa)
-{
-#ifdef WORKING_IPV6
- char ipstr[INET6_ADDRSTRLEN];
-#else
- char ipstr[INET_ADDRSTRLEN];
-#endif
- int port;
-
- port = SS_GET_PORT(sa);
-#ifdef WORKING_IPV6
- if ( sa->ss_family == (sa_family_t)AF_INET6) {
- inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
- ipstr, sizeof(ipstr));
- dbprintf(("%s: (sockaddr_in6 *)%p = { %d, %d, %s }\n",
- debug_prefix_time(NULL), sa,
- ((struct sockaddr_in6 *)sa)->sin6_family,
- port,
- ipstr));
- } else
-#endif
- {
- inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
- sizeof(ipstr));
- dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n",
- debug_prefix_time(NULL), sa,
- ((struct sockaddr_in *)sa)->sin_family,
- port,
- ipstr));
- }
-}
-
-
-#ifdef WORKING_IPV6
-static char mystr_sockaddr[INET6_ADDRSTRLEN + 20];
-#else
-static char mystr_sockaddr[INET_ADDRSTRLEN + 20];
-#endif
-
-char *
-str_sockaddr(
- struct sockaddr_storage *sa)
-{
-#ifdef WORKING_IPV6
- char ipstr[INET6_ADDRSTRLEN];
-#else
- char ipstr[INET_ADDRSTRLEN];
-#endif
- int port;
-
- port = SS_GET_PORT(sa);
-#ifdef WORKING_IPV6
- if ( sa->ss_family == (sa_family_t)AF_INET6) {
- inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
- ipstr, sizeof(ipstr));
- } else
-#endif
- {
- inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
- sizeof(ipstr));
- }
- snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port);
- return mystr_sockaddr;
-}
-
-
-int
-cmp_sockaddr(
- struct sockaddr_storage *ss1,
- struct sockaddr_storage *ss2,
- int addr_only)
-{
- /* if addresses are v4mapped, "unmap" them */
-#ifdef WORKING_IPV6
-#ifdef IN6_IS_ADDR_V4MAPPED
- struct sockaddr_in ss1_v4;
- struct sockaddr_in ss2_v4;
-
- if (ss1->ss_family == AF_INET6 &&
- IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss1)->sin6_addr)) {
- memset(&ss1_v4, 0, sizeof(struct sockaddr_in));
- memcpy(&ss1_v4.sin_addr.s_addr,
- &(((struct sockaddr_in6 *)ss1)->sin6_addr.s6_addr[12]),
- sizeof(struct in_addr));
- ss1_v4.sin_family = AF_INET;
- SS_SET_PORT((struct sockaddr_storage *)&ss1_v4, SS_GET_PORT(ss1));
- ss1 = (struct sockaddr_storage *)&ss1_v4;
- }
-
- if (ss2->ss_family == AF_INET6 &&
- IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss2)->sin6_addr)) {
- memset(&ss2_v4, 0, sizeof(struct sockaddr_in));
- memcpy(&ss2_v4.sin_addr.s_addr,
- &(((struct sockaddr_in6 *)ss2)->sin6_addr.s6_addr[12]),
- sizeof(struct in_addr));
- ss2_v4.sin_family = AF_INET;
- SS_SET_PORT((struct sockaddr_storage *)&ss2_v4, SS_GET_PORT(ss2));
- ss2 = (struct sockaddr_storage *)&ss2_v4;
- }
-#endif
-#endif
-
- if (ss1->ss_family == ss2->ss_family) {
- if (addr_only) {
-#ifdef WORKING_IPV6
- if(ss1->ss_family == (sa_family_t)AF_INET6)
- return memcmp(
- &((struct sockaddr_in6 *)ss1)->sin6_addr,
- &((struct sockaddr_in6 *)ss2)->sin6_addr,
- sizeof(((struct sockaddr_in6 *)ss1)->sin6_addr));
- else
-#endif
- return memcmp(
- &((struct sockaddr_in *)ss1)->sin_addr,
- &((struct sockaddr_in *)ss2)->sin_addr,
- sizeof(((struct sockaddr_in *)ss1)->sin_addr));
- } else {
- return memcmp(ss1, ss2, SS_LEN(ss1));
- }
- } else {
- /* compare families to give a total order */
- if (ss1->ss_family < ss2->ss_family)
- return -1;
- else
- return 1;
- }
-}
-
-
int copy_file(
char *dst,
char *src,
{
int infd, outfd;
int save_errno;
- ssize_t nb;
+ size_t nb;
char buf[32768];
char *quoted;
if ((infd = open(src, O_RDONLY)) == -1) {
save_errno = errno;
quoted = quote_string(src);
- *errmsg = vstralloc("Can't open file ", quoted, " for reading: %s",
- strerror(save_errno), NULL);
+ *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
+ quoted, strerror(save_errno));
amfree(quoted);
return -1;
}
if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
save_errno = errno;
quoted = quote_string(dst);
- *errmsg = vstralloc("Can't open file ", quoted, " for writting: %s",
- strerror(save_errno), NULL);
+ *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
+ quoted, strerror(save_errno));
amfree(quoted);
close(infd);
return -1;
}
while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
- if(fullwrite(outfd,&buf,(size_t)nb) < nb) {
+ if(full_write(outfd,&buf,nb) < nb) {
save_errno = errno;
quoted = quote_string(dst);
- *errmsg = vstralloc("Error writing to \"", quoted, "\":",
- strerror(save_errno), NULL);
+ *errmsg = vstrallocf(_("Error writing to '%s': %s"),
+ quoted, strerror(save_errno));
amfree(quoted);
close(infd);
close(outfd);
}
}
- if (nb < 0) {
+ if (errno != 0) {
save_errno = errno;
quoted = quote_string(src);
- *errmsg = vstralloc("Error reading from \"", quoted, "\":",
- strerror(save_errno), NULL);
+ *errmsg = vstrallocf(_("Error reading from '%s': %s"),
+ quoted, strerror(save_errno));
amfree(quoted);
close(infd);
close(outfd);
close(outfd);
return 0;
}
-#ifndef HAVE_LIBREADLINE
+
+#ifndef HAVE_READLINE
/*
- * simple readline() replacements
+ * simple readline() replacements, used when we don't have readline
+ * support from the system.
*/
char *
readline(
const char *prompt)
{
- printf("%s", prompt);
+ g_printf("%s", prompt);
fflush(stdout);
fflush(stderr);
return agets(stdin);
add_history(
const char *line)
{
- (void)line; /* Quite unused parameter warning */
+ (void)line; /* Quiet unused parameter warning */
+}
+
+#endif
+
+/* Order of preference: readdir64(), readdir(). */
+#if HAVE_DECL_READDIR64
+# define USE_DIRENT64
+# define USE_READDIR64
+#elif HAVE_DECL_READDIR
+# define USE_READDIR
+#else
+# error No readdir() or readdir64() available!
+#endif
+
+char * portable_readdir(DIR* handle) {
+
+#ifdef USE_DIRENT64
+ struct dirent64 *entry_p;
+#else
+ struct dirent *entry_p;
+#endif
+
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ g_static_mutex_lock(&mutex);
+
+#ifdef USE_READDIR
+ entry_p = readdir(handle);
+#endif
+#ifdef USE_READDIR64
+ entry_p = readdir64(handle);
+#endif
+
+ g_static_mutex_unlock(&mutex);
+
+ if (entry_p == NULL)
+ return NULL;
+
+ /* FIXME: According to glibc documentation, d_name may not be
+ null-terminated in some cases on some very old platforms. Not
+ sure what to do about that case. */
+ return strdup(entry_p->d_name);
+}
+
+int search_directory(DIR * handle, const char * regex,
+ SearchDirectoryFunctor functor, gpointer user_data) {
+ int rval = 0;
+ regex_t compiled_regex;
+ gboolean done = FALSE;
+
+ if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
+ regfree(&compiled_regex);
+ return -1;
+ }
+
+ rewinddir(handle);
+
+ while (!done) {
+ char * read_name;
+ int result;
+ read_name = portable_readdir(handle);
+ if (read_name == NULL) {
+ regfree(&compiled_regex);
+ return rval;
+ }
+ result = regexec(&compiled_regex, read_name, 0, NULL, 0);
+ if (result == 0) {
+ rval ++;
+ done = !functor(read_name, user_data);
+ }
+ amfree(read_name);
+ }
+ regfree(&compiled_regex);
+ return rval;
+}
+
+char* find_regex_substring(const char* base_string, const regmatch_t match) {
+ char * rval;
+ int size;
+
+ size = match.rm_eo - match.rm_so;
+ rval = malloc(size+1);
+ memcpy(rval, base_string + match.rm_so, size);
+ rval[size] = '\0';
+
+ return rval;
+}
+
+int compare_possibly_null_strings(const char * a, const char * b) {
+ if (a == b) {
+ /* NULL or otherwise, they're the same. */
+ return 0;
+ } else if (a == NULL) {
+ /* b != NULL */
+ return -1;
+ } else if (b == NULL) {
+ /* a != NULL */
+ return 1;
+ } else {
+ /* a != NULL != b */
+ return strcmp(a, b);
+ }
+}
+
+int
+resolve_hostname(const char *hostname,
+ int socktype,
+ struct addrinfo **res,
+ char **canonname)
+{
+ struct addrinfo hints;
+ struct addrinfo *myres;
+ int flags = 0;
+ int result;
+
+ if (res) *res = NULL;
+ if (canonname) {
+ *canonname = NULL;
+ flags = AI_CANONNAME;
+ }
+
+#ifdef AI_ADDRCONFIG
+ flags |= AI_ADDRCONFIG;
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+#ifdef WORKING_IPV6
+ /* get any kind of addresss */
+ hints.ai_family = AF_UNSPEC;
+#else
+ /* even if getaddrinfo supports IPv6, don't let it return
+ * such an address */
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_flags = flags;
+ hints.ai_socktype = socktype;
+ result = getaddrinfo(hostname, NULL, &hints, &myres);
+ if (result != 0) {
+ return result;
+ }
+
+ if (canonname && myres && myres->ai_canonname) {
+ *canonname = stralloc(myres->ai_canonname);
+ }
+
+ if (res) {
+ *res = myres;
+ } else {
+ freeaddrinfo(myres);
+ }
+
+ return result;
+}
+
+char *
+_str_exit_status(
+ char *subject,
+ amwait_t status)
+{
+ if (WIFEXITED(status)) {
+ int exitstatus = WEXITSTATUS(status);
+ if (exitstatus == 0)
+ return vstrallocf(_("%s exited normally"), subject);
+ else
+ return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signal = WTERMSIG(status);
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status))
+ return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
+ subject, signal);
+ else
+#endif
+ return vstrallocf(_("%s exited after receiving signal %d"),
+ subject, signal);
+ }
+
+ if (WIFSTOPPED(status)) {
+ int signal = WSTOPSIG(status);
+ return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
+ subject, signal);
+ }
+
+#ifdef WIFCONTINUED
+ if (WIFCONTINUED(status)) {
+ return vstrallocf(_("%s was resumed"), subject);
+ }
+#endif
+
+ return vstrallocf(_("%s exited in unknown circumstances"), subject);
+}
+
+void
+check_running_as(running_as_flags who)
+{
+#ifdef CHECK_USERID
+ struct passwd *pw;
+ uid_t uid_me;
+ uid_t uid_target;
+ char *uname_me = NULL;
+ char *uname_target = NULL;
+ char *dumpuser;
+
+ uid_me = getuid();
+ if ((pw = getpwuid(uid_me)) == NULL) {
+ error(_("current userid %ld not found in password database"), (long)uid_me);
+ /* NOTREACHED */
+ }
+ uname_me = stralloc(pw->pw_name);
+
+#ifndef SINGLE_USERID
+ if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
+ error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
+ (long long int)geteuid(), (long long int)uid_me);
+ /* NOTREACHED */
+ }
+#endif
+
+ switch (who & RUNNING_AS_USER_MASK) {
+ case RUNNING_AS_ANY:
+ uid_target = uid_me;
+ uname_target = uname_me;
+ return;
+
+ case RUNNING_AS_ROOT:
+ uid_target = 0;
+ uname_target = "root";
+ break;
+
+ case RUNNING_AS_DUMPUSER_PREFERRED:
+ dumpuser = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(dumpuser)) != NULL &&
+ uid_me != pw->pw_uid) {
+ if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
+ uid_me == pw->pw_uid) {
+ /* uid == CLIENT_LOGIN: not ideal, but OK */
+ dbprintf(_("NOTE: running as '%s', which is the client"
+ " user, not the dumpuser ('%s'); forging"
+ " on anyway\n"),
+ CLIENT_LOGIN, dumpuser);
+ uid_target = uid_me; /* force success below */
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case RUNNING_AS_DUMPUSER:
+ uname_target = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up dumpuser \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
+
+ case RUNNING_AS_CLIENT_LOGIN:
+ uname_target = CLIENT_LOGIN;
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up client user \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
+
+ default:
+ error(_("Unknown check_running_as() call"));
+ /* NOTREACHED */
+ }
+
+ if (uid_me != uid_target) {
+ error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
+ /*NOTREACHED*/
+ }
+ amfree(uname_me);
+
+#else
+ /* Quiet unused variable warning */
+ (void)who;
+#endif
+}
+
+int
+set_root_privs(int need_root)
+{
+#ifndef SINGLE_USERID
+ if (need_root) {
+ if (seteuid(0) == -1) return 0;
+ /* (we don't switch the group back) */
+ } else {
+ if (geteuid() != 0) return 0;
+ if (seteuid(getuid()) == -1) return 0;
+ if (setegid(getgid()) == -1) return 0;
+ }
+#else
+ (void)need_root; /* Quiet unused variable warning */
+#endif
+ return 1;
}
+
+int
+become_root(void)
+{
+#ifndef SINGLE_USERID
+ // if euid !=0, it set only euid
+ if (setuid(0) == -1) return 0;
+ // will set ruid because euid == 0.
+ if (setuid(0) == -1) return 0;
#endif
+ return 1;
+}
+
+
+char *
+base64_decode_alloc_string(
+ char *in)
+{
+ char *out;
+ size_t in_len = strlen(in);
+ size_t out_len = 3 * (in_len / 4) + 3;
+
+ out = malloc(out_len);
+ if (!base64_decode(in, in_len, out, &out_len)) {
+ amfree(out);
+ return NULL;
+ }
+ out[out_len] = '\0';
+
+ return out;
+}
+
+
+/* A GHFunc (callback for g_hash_table_foreach) */
+void count_proplist(
+ gpointer key_p G_GNUC_UNUSED,
+ gpointer value_p,
+ gpointer user_data_p)
+{
+ property_t *value_s = value_p;
+ int *nb = user_data_p;
+ GSList *value;
+
+ for(value=value_s->values; value != NULL; value = value->next) {
+ (*nb)++;
+ }
+}
+
+/* A GHFunc (callback for g_hash_table_foreach) */
+void proplist_add_to_argv(
+ gpointer key_p,
+ gpointer value_p,
+ gpointer user_data_p)
+{
+ char *property_s = key_p;
+ property_t *value_s = value_p;
+ char ***argv = user_data_p;
+ GSList *value;
+ char *q, *w, *qprop;
+
+ q = stralloc(property_s);
+ /* convert to lower case */
+ for (w=q; *w != '\0'; w++) {
+ *w = tolower(*w);
+ if (*w == '_')
+ *w = '-';
+ }
+ qprop = stralloc2("--", q);
+ amfree(q);
+ for(value=value_s->values; value != NULL; value = value->next) {
+ **argv = stralloc(qprop);
+ (*argv)++;
+ **argv = stralloc((char *)value->data);
+ (*argv)++;
+ }
+ amfree(qprop);
+}
+
+
+/*
+ * Process parameters
+ */
+
+static char *pname = NULL;
+static char *ptype = NULL;
+static pcontext_t pcontext = CONTEXT_DEFAULT;
+
+void
+set_pname(char *p)
+{
+ pname = newstralloc(pname, p);
+}
+
+char *
+get_pname(void)
+{
+ if (!pname) pname = stralloc("unknown");
+ return pname;
+}
+
+void
+set_ptype(char *p)
+{
+ ptype = newstralloc(ptype, p);
+}
+
+char *
+get_ptype(void)
+{
+ if (!ptype) ptype = stralloc("unknown");
+ return ptype;
+}
+
+void
+set_pcontext(pcontext_t pc)
+{
+ pcontext = pc;
+}
+
+pcontext_t
+get_pcontext(void)
+{
+ return pcontext;
+}