aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-11-24 00:44:28 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-11-24 00:44:28 +0200
commit68796f86fe6abae13debf253c0e16b4bac9c1bca (patch)
tree5ab80057618ae33c10f44c9be1ee307e367747ff
parent2d3d121453b19003c6454e7c6b4ed98164e7d531 (diff)
downloadpies-68796f86fe6abae13debf253c0e16b4bac9c1bca.tar.gz
pies-68796f86fe6abae13debf253c0e16b4bac9c1bca.tar.bz2
Handle non-stream sockets. Pies can now replace inetd (- inetd.conf and built-in services).
* src/pies.c (component_keywords): New keywords: wait, socket-type. (component_verify): Add more checks. * src/pies.h (CF_WAIT): New define. (struct component): New member: socket_type. (struct pies_url): Rename proto to scheme. New members: proto, proto_s, port_s (register_listener): Remove proto. (register_socket): New proto. (create_socket): Change signature. (disable_socket, enable_socket): New protos. * src/progman.c (close_fds): New function. (open_redirector): Use close_fds. (prog_start): Use close_fds. Update call to create_socket. Disable socket if wait is set. (progman_accept): Support non-stream (and stream+wait) sockets. (component_fixup_depend): Update call to create_socket. Call register_socket. (run_command): Use close_fds. Re-enable socket if wait is set. * src/socket.c (create_socket): Take additional argument: socket_type. (register_socket): New function. (disable_socket, enable_socket): New functions. (pies_pause): Add missing break. * src/url.c (url_parse_host): Accept service name and numberic port number. (url_parse_proto): Rename to url_parse_scheme. All callers updated. (url_parse_scheme): Allow for optional protocol specification in scheme field (after a '+' sign). (pies_url_destroy): Free new fields.
-rw-r--r--src/pies.c72
-rw-r--r--src/pies.h17
-rw-r--r--src/progman.c126
-rw-r--r--src/socket.c32
-rw-r--r--src/url.c112
5 files changed, 278 insertions, 81 deletions
diff --git a/src/pies.c b/src/pies.c
index dbe4ca0..2bf127c 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -712,6 +712,36 @@ _cb_url (enum grecs_callback_command cmd,
return 0;
}
+static int
+_cb_socket_type (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr, grecs_value_t *value, void *cb_data)
+{
+ int t;
+
+ if (assert_scalar_stmt (locus, cmd)
+ || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
+ return 1;
+
+ if (strcmp (value->v.string, "stream") == 0)
+ t = SOCK_STREAM;
+ else if (strcmp (value->v.string, "dgram") == 0)
+ t = SOCK_DGRAM;
+ else if (strcmp (value->v.string, "rdm") == 0)
+ t = SOCK_RDM;
+ else if (strcmp (value->v.string, "seqpacket") == 0)
+ t = SOCK_SEQPACKET;
+ else if (strcmp (value->v.string, "raw") == 0)
+ t = SOCK_RAW;
+ else
+ {
+ grecs_error (locus, 0, _("bad socket type"));
+ return 0;
+ }
+ *(int*)varptr = t;
+ return 0;
+}
+
static struct tokendef modetab[] = {
{"exec", pies_comp_exec},
{"wait", pies_comp_exec},
@@ -791,6 +821,14 @@ _cb_disabled (enum grecs_callback_command cmd,
return _cb_bitmask (cmd, locus, varptr, value, CF_DISABLED);
}
+static int
+_cb_wait (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr, grecs_value_t *value, void *cb_data)
+{
+ return _cb_bitmask (cmd, locus, varptr, value, CF_WAIT);
+}
+
struct grecs_keyword component_keywords[] = {
{"mode",
/* TRANSLATORS: The words between '{' and '}' are keywords, do not
@@ -846,6 +884,13 @@ struct grecs_keyword component_keywords[] = {
offsetof (struct component, flags),
_cb_precious,
},
+ {"wait",
+ NULL,
+ N_("Wait for the server program to return."),
+ grecs_type_bool, NULL,
+ offsetof (struct component, flags),
+ _cb_wait,
+ },
{"max-instances",
NULL,
N_("Maximum number of running instances."),
@@ -859,6 +904,12 @@ struct grecs_keyword component_keywords[] = {
offsetof (struct component, socket_url),
_cb_url,
},
+ {"socket-type",
+ N_("type: stream | dgram | raw | rdm | seqpacket"),
+ N_("Set socket type."),
+ grecs_type_int, NULL,
+ offsetof (struct component, socket_type),
+ _cb_socket_type },
{"pass-fd-socket",
N_("name"),
N_("Pass fd through this socket."),
@@ -978,7 +1029,7 @@ make_full_name (const char *dir, const char *file)
}
static int
-component_verify (struct component *comp, grecs_locus_t * locus)
+component_verify (struct component *comp, grecs_locus_t *locus)
{
int header = 0;
int i;
@@ -1013,7 +1064,7 @@ component_verify (struct component *comp, grecs_locus_t * locus)
if (comp->dir)
{
char *p = make_full_name (comp->dir, comp->pass_fd_socket);
- //free (comp->pass_fd_socket);
+ /*free (comp->pass_fd_socket);*/
comp->pass_fd_socket = p;
}
else
@@ -1032,6 +1083,22 @@ component_verify (struct component *comp, grecs_locus_t * locus)
}
}
+ if (comp->mode == pies_comp_inetd)
+ {
+ if ((comp->flags & CF_WAIT) && comp->socket_type == SOCK_STREAM)
+ {
+ if (comp->max_instances)
+ COMPERR ("%s", _("max-instances ignored"));
+ else
+ comp->max_instances = 1;
+ }
+ }
+ else if (comp->flags & CF_WAIT)
+ {
+ COMPERR ("%s", _("wait is useless in this mode"));
+ comp->flags &= ~CF_WAIT;
+ }
+
if (comp->mode != pies_comp_exec
&& comp->redir[RETR_OUT].type != redir_null)
{
@@ -1071,6 +1138,7 @@ component_create (const char *name)
comp->facility = log_facility;
comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null;
comp->tag = xstrdup (name);
+ comp->socket_type = SOCK_STREAM;
}
return comp;
}
diff --git a/src/pies.h b/src/pies.h
index 02211a2..68a2ff5 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -137,7 +137,9 @@ enum pies_comp_mode
};
#define CF_DISABLED 0x01 /* The componenet is disabled */
-#define CF_PRECIOUS 0x02 /* The component is precious (cannot be disabled) */
+#define CF_PRECIOUS 0x02 /* The component is precious (should not
+ be disabled) */
+#define CF_WAIT 0x04
struct component
{
@@ -152,6 +154,7 @@ struct component
gl_list_t depend; /* Dependency targets */
int flags; /* CF_ bitmask */
size_t max_instances; /* Maximum number of running instances */
+ int socket_type; /* Socket type */
char *rmfile; /* Try to remove this file before starting */
struct pies_privs privs; /* UID/GIDS+groups to run under */
mode_t umask; /* Umask to install before starting */
@@ -229,9 +232,12 @@ struct grecs_keyword *find_component_keyword (const char *ident);
struct pies_url
{
char *string;
- char *proto;
+ char *scheme;
char *host;
+ char *port_s;
int port;
+ char *proto_s;
+ int proto;
char *path;
char *user;
char *passwd;
@@ -244,9 +250,12 @@ void pies_url_destroy (struct pies_url **purl);
const char * pies_url_get_arg (struct pies_url *url, const char *argname);
void pies_pause (void);
-int register_listener (int fd);
+int register_socket (int socktype, int fd);
int pass_fd (const char *socket, int fd, unsigned time_out);
-int create_socket (struct pies_url *url, const char *user, mode_t umask);
+int create_socket (struct pies_url *url, int socket_type,
+ const char *user, mode_t umask);
+int disable_socket (int fd);
+int enable_socket (int fd);
int parse_limits (limits_record_t *plrec, char *str, char **endp);
diff --git a/src/progman.c b/src/progman.c
index 3263172..85a5068 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -388,6 +388,19 @@ redirect_to_file (struct prog *master, int stream)
return fd;
}
+static void
+close_fds (fd_set *fdset)
+{
+ int i;
+
+ for (i = getmaxfd (); i >= 0; i--)
+ {
+ if (fdset && FD_ISSET (i, fdset))
+ continue;
+ close (i);
+ }
+}
+
int
open_redirector (struct prog *master, int stream)
{
@@ -398,6 +411,7 @@ open_redirector (struct prog *master, int stream)
pid_t pid;
int i, prio;
char *tag;
+ fd_set fdset;
switch (master->v.p.comp->redir[stream].type)
{
@@ -420,11 +434,9 @@ open_redirector (struct prog *master, int stream)
mf_proctitle_format ("%s redirector", tag);
free (tag);
- for (i = getmaxfd (); i >= 0; i--)
- {
- if (i != p[0])
- close (i);
- }
+ FD_ZERO (&fdset);
+ FD_SET (p[0], &fdset);
+ close_fds (&fdset);
diag_setup (0);
signal_setup (redir_exit);
@@ -605,7 +617,8 @@ prog_start (struct prog *prog)
pid_t pid;
time_t now;
int redir[2];
-
+ fd_set fdset;
+
if (prog->pid > 0 || !IS_COMPONENT (prog))
return;
@@ -658,6 +671,7 @@ prog_start (struct prog *prog)
case pies_comp_accept:
prog->v.p.socket = create_socket (prog->v.p.comp->socket_url,
+ prog->v.p.comp->socket_type,
prog->v.p.comp->privs.user,
prog->v.p.comp->umask);
if (prog->v.p.socket == -1)
@@ -771,14 +785,14 @@ prog_start (struct prog *prog)
dup2 (redir[RETR_ERR], 2);
}
- /* Close unneded descripitors */
- for (i = getmaxfd (); i > 2; i--)
- {
- if (prog->v.p.comp->mode == pies_comp_pass_fd
- && i == prog->v.p.socket)
- continue;
- close (i);
- }
+ /* Close unneeded descripitors */
+ FD_ZERO (&fdset);
+ FD_SET (0, &fdset);
+ FD_SET (1, &fdset);
+ FD_SET (2, &fdset);
+ if (prog->v.p.comp->mode == pies_comp_pass_fd)
+ FD_SET (prog->v.p.socket, &fdset);
+ close_fds (&fdset);
execvp (prog->v.p.comp->program ?
prog->v.p.comp->program : prog->v.p.comp->argv[0],
@@ -802,7 +816,11 @@ prog_start (struct prog *prog)
prog->v.p.comp->pass_fd_timeout : DEFAULT_PASS_FD_TIMEOUT);
/* FIXME: Error code */;
}
- if (prog->v.p.comp->mode != pies_comp_exec)
+ if (prog->v.p.comp->flags & CF_WAIT)
+ {
+ disable_socket (prog->v.p.socket);
+ }
+ else if (prog->v.p.comp->mode != pies_comp_exec)
close (prog->v.p.socket);
prog->pid = pid;
prog->v.p.status = status_enabled;
@@ -836,38 +854,29 @@ check_acl (pies_acl_t acl, struct sockaddr *s, int salen)
return 0;
}
-int
-progman_accept (int socket)
+static int
+_prog_accept (struct prog *p)
{
int fd;
- struct prog *p, *pinst;
+ struct prog *pinst;
union
{
struct sockaddr s_in;
struct sockaddr s_un;
} addr;
socklen_t addrlen = sizeof addr;
-
- fd = accept (socket, (struct sockaddr*) &addr, &addrlen);
+
+ fd = accept (p->v.p.socket, (struct sockaddr*) &addr, &addrlen);
if (fd == -1)
{
logmsg (LOG_ERR, _("accept failed: %s"), strerror (errno));
return 1;
}
- p = prog_lookup_by_socket (socket);
- if (!p)
- {
- logmsg (LOG_EMERG,
- _("INTERNAL ERROR: no matching prog for fd %d"), socket);
- close (fd);
- return 1;
- }
-
if (debug_level >= 1)
{
char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen);
- logmsg (LOG_DEBUG, "%s wants %s", s, p->tag);
+ logmsg (LOG_DEBUG, _("%s wants %s"), s, p->tag);
free (s);
}
@@ -901,6 +910,51 @@ progman_accept (int socket)
return 0;
}
+static int
+_prog_wait (struct prog *p)
+{
+ struct prog *pinst;
+
+ debug (1, (_("someone wants %s"), p->tag));
+
+ if (p->v.p.comp->max_instances
+ && p->v.p.num_instances >= p->v.p.comp->max_instances)
+ {
+ logmsg (LOG_ERR,
+ _("%s: too many instances running, dropping connection"),
+ p->tag);
+ return 1;
+ }
+
+ pinst = register_prog0 (p->v.p.comp, -1);
+ pinst->v.p.socket = p->v.p.socket;
+ pinst->v.p.listener = p;
+ prog_start (pinst);
+
+ pinst->v.p.socket = -1;
+
+ p->v.p.num_instances++;
+ return 0;
+}
+
+int
+progman_accept (int socket)
+{
+ struct prog *p = prog_lookup_by_socket (socket);
+ if (!p)
+ {
+ logmsg (LOG_EMERG,
+ _("INTERNAL ERROR: no matching prog for fd %d"), socket);
+ return 1;
+ }
+
+ if (p->v.p.comp->socket_type == SOCK_STREAM
+ && !(p->v.p.comp->flags & CF_WAIT))
+ return _prog_accept (p);
+
+ return _prog_wait (p);
+}
+
void
component_fixup_depend (struct component *comp)
@@ -1077,10 +1131,11 @@ progman_create_sockets ()
if (comp->mode == pies_comp_inetd)
{
int fd = create_socket (comp->socket_url,
+ comp->socket_type,
comp->privs.user, comp->umask);
if (fd == -1)
prog->v.p.status = status_disabled;
- else if (register_listener (fd))
+ else if (register_socket (comp->socket_type, fd))
{
close (fd);
prog->v.p.status = status_disabled;
@@ -1664,8 +1719,7 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
/* FIXME: see above */
- for (i = getmaxfd (); i >= 0; i--)
- close (i);
+ close_fds (NULL);
argv[0] = "/bin/sh";
argv[1] = "-c";
@@ -1707,9 +1761,13 @@ progman_cleanup (int expect_term)
print_status (prog->tag, pid, status, expect_term);
if (prog->v.p.comp->mode == pies_comp_inetd)
{
- prog->v.p.listener->v.p.num_instances--;
+ struct prog *listener = prog->v.p.listener;
+
+ listener->v.p.num_instances--;
prog_stop_redirectors (prog);
destroy_prog (&prog);
+ if (listener->v.p.comp->flags & CF_WAIT)
+ enable_socket (listener->v.p.socket);
}
else
{
diff --git a/src/socket.c b/src/socket.c
index 6f1bb87..8b25073 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -49,7 +49,8 @@ switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask)
}
int
-create_socket (struct pies_url *url, const char *user, mode_t umaskval)
+create_socket (struct pies_url *url, int socket_type,
+ const char *user, mode_t umaskval)
{
int rc;
int fd;
@@ -64,9 +65,9 @@ create_socket (struct pies_url *url, const char *user, mode_t umaskval)
gid_t gid = 0;
int switch_back;
- if (strcmp (url->proto, "unix") == 0
- || strcmp (url->proto, "file") == 0
- || strcmp (url->proto, "socket") == 0)
+ if (strcmp (url->scheme, "unix") == 0
+ || strcmp (url->scheme, "file") == 0
+ || strcmp (url->scheme, "socket") == 0)
{
struct stat st;
const char *group = NULL;
@@ -169,7 +170,7 @@ create_socket (struct pies_url *url, const char *user, mode_t umaskval)
}
}
}
- else if (strcmp (url->proto, "inet") == 0)
+ else if (strcmp (url->scheme, "inet") == 0)
{
const char *host = url->host;
short port = url->port;
@@ -209,7 +210,7 @@ create_socket (struct pies_url *url, const char *user, mode_t umaskval)
return -1;
}
- fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
+ fd = socket (addr.sa.sa_family, socket_type, url->proto);
if (fd == -1)
{
logmsg (LOG_ERR, _("%s: cannot create socket: %s"),
@@ -409,9 +410,9 @@ fd_set listenset;
int fd_max;
int
-register_listener (int fd)
+register_socket (int socktype, int fd)
{
- if (listen (fd, 8) == -1)
+ if (socktype == SOCK_STREAM && listen (fd, 8) == -1)
{
logmsg (LOG_ERR, "listen: %s", strerror (errno));
return 1;
@@ -422,6 +423,20 @@ register_listener (int fd)
return 0;
}
+int
+disable_socket (int fd)
+{
+ debug (2, (_("disabling fd %d"), fd));
+ FD_CLR (fd, &listenset);
+}
+
+int
+enable_socket (int fd)
+{
+ debug (2, (_("enabling fd %d"), fd));
+ FD_SET (fd, &listenset);
+}
+
void
pies_pause ()
{
@@ -437,6 +452,7 @@ pies_pause ()
if (FD_ISSET (i, &rdset))
progman_accept (i);
}
+ break;
}
else if (rc < 0)
{
diff --git a/src/url.c b/src/url.c
index 500aa0a..be74974 100644
--- a/src/url.c
+++ b/src/url.c
@@ -18,11 +18,12 @@
# include <config.h>
#endif
#include "pies.h"
+#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
-/* proto://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...]
+/* scheme://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...]
*/
static int
@@ -59,17 +60,17 @@ url_parse_args (struct pies_url *url, char **str)
static int
url_parse_path (struct pies_url *url, char **str)
{
- char *p;
-
- p = strchr (*str, ';');
- if (!p)
- p = *str + strlen (*str);
- if (alloc_string(&url->path, *str, p))
- return 1;
- *str = p;
- if (*p)
- ++ * str;
- return url_parse_args (url, str);
+ char *p;
+
+ p = strchr (*str, ';');
+ if (!p)
+ p = *str + strlen (*str);
+ if (alloc_string (&url->path, *str, p))
+ return 1;
+ *str = p;
+ if (*p)
+ ++*str;
+ return url_parse_args (url, str);
}
/* On input str points at the beginning of host part */
@@ -81,12 +82,29 @@ url_parse_host (struct pies_url *url, char **str)
if (s[len] == ':')
{
+ char *start = s + len + 1;
char *q;
- unsigned long n = strtoul (s + len + 1, &q, 10);
- if ((*q && !strchr("/;:", *q)) || n > USHRT_MAX)
+ unsigned long n = strtoul (start, &q, 10);
+ if (n > USHRT_MAX)
return 1;
- url->port = n;
- *str = q + strcspn(q, "/");
+ if ((*q && !strchr ("/;:", *q)))
+ {
+ char *proto = url->proto_s ? url->proto_s : "tcp";
+ size_t size = strcspn (start, "/;:");
+ struct servent *serv;
+
+ alloc_string_len (&url->port_s, start, size);
+ serv = getservbyname (url->port_s, proto);
+ if (!serv)
+ return 1;
+ url->port = ntohs (serv->s_port);
+ *str = start + size;
+ }
+ else
+ {
+ url->port = n;
+ *str = q;
+ }
}
else
*str = s + len;
@@ -106,22 +124,22 @@ url_parse_user (struct pies_url *url, char **str)
{
size_t len = strcspn (*str, ":;@/");
char *p = *str + len;
-
+
switch (*p)
{
case ';':
case ':':
len = strcspn (p + 1, "@/:");
- if (p[len+1] == '@')
+ if (p[len + 1] == '@')
{
- if (alloc_string_len(&url->passwd, p + 1, len))
+ if (alloc_string_len (&url->passwd, p + 1, len))
return 1;
if (alloc_string (&url->user, *str, p))
return 1;
*str = p + len + 2;
}
break;
-
+
case '@':
if (alloc_string (&url->user, *str, p))
return 1;
@@ -132,27 +150,53 @@ url_parse_user (struct pies_url *url, char **str)
}
static int
-url_parse_proto (struct pies_url *url, const char *str)
+url_parse_scheme (struct pies_url *url, const char *str)
{
+ size_t len;
char *p;
-
+
if (!str)
{
errno = EINVAL;
return 1;
}
-
- p = strchr (str, ':');
- if (!p)
+
+ len = strcspn (str, ":+");
+ if (!str[len])
{
errno = EINVAL;
return 1;
}
-
- alloc_string (&url->proto, str, p);
+ alloc_string_len (&url->scheme, str, len);
+
+ str += len;
+
+ if (*str == '+')
+ {
+ struct protoent *proto;
+
+ len = strcspn (++str, ":");
+ if (str[len] == 0)
+ {
+ errno = EINVAL;
+ return 1;
+ }
+ alloc_string_len (&url->proto_s, str, len);
+ str += len;
+ proto = getprotobyname (url->proto_s);
+ if (!proto)
+ {
+ errno = EINVAL;
+ return 1;
+ }
+ url->proto = proto->p_proto;
+ }
+ else
+ url->proto = 0;
+
/* Skip slashes */
- for (p++; *p == '/'; p++)
+ for (p = (char*) str + 1; *p == '/'; p++)
;
return url_parse_user (url, &p);
}
@@ -164,15 +208,17 @@ pies_url_destroy (struct pies_url **purl)
struct pies_url *url = *purl;
free (url->string);
- free (url->proto);
+ free (url->scheme);
free (url->host);
+ free (url->port_s);
+ free (url->proto_s);
free (url->path);
free (url->user);
free (url->passwd);
for (i = 0; i < url->argc; i++)
free (url->argv[i]);
free (url->argv);
- free(url);
+ free (url);
*purl = NULL;
}
@@ -181,12 +227,12 @@ pies_url_create (struct pies_url **purl, const char *str)
{
int rc;
struct pies_url *url;
-
+
url = malloc (sizeof (*url));
if (!url)
return 1;
- memset (url, 0, sizeof(*url));
- rc = url_parse_proto (url, str);
+ memset (url, 0, sizeof (*url));
+ rc = url_parse_scheme (url, str);
if (rc)
pies_url_destroy (&url);
else

Return to:

Send suggestions and report system problems to the System administrator.