aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------grecs0
-rw-r--r--lib/Makefile.am2
-rw-r--r--src/Makefile.am10
-rw-r--r--src/acl.c4
-rw-r--r--src/inetd.c13
-rw-r--r--src/pies.c337
-rw-r--r--src/pies.h53
-rw-r--r--src/progman.c139
8 files changed, 458 insertions, 100 deletions
diff --git a/grecs b/grecs
-Subproject a52ab6c6c38e1dca047ada4d60249fb323942f0
+Subproject 5596f7cdcdc1983021185c5e0900d5fcba7f328
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2569bd1..5883021 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -25,5 +25,5 @@ libpies_a_SOURCES=\
libpies_a_LIBADD=$(LIBOBJS)
-INCLUDES = -I$(top_srcdir)/gnu -I../gnu
+AM_CPPFLAGS = -I$(top_srcdir)/gnu -I../gnu
diff --git a/src/Makefile.am b/src/Makefile.am
index 455b2c2..44e0a8d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,12 +54,6 @@ SUFFIXES=.opt .c .h
cmdline.h: cmdline.opt
-INCLUDES = \
- -I$(top_srcdir)/lib\
- -I$(top_srcdir)/gnu\
- -I$(top_builddir)/gnu\
- @GRECS_INCLUDES@
-
LDADD = \
../lib/libpies.a\
@GRECS_LDADD@\
@@ -69,6 +63,10 @@ LDADD = \
pkgstatedir=$(localstatedir)/pies
AM_CPPFLAGS=\
+ -I$(top_srcdir)/lib\
+ -I$(top_srcdir)/gnu\
+ -I$(top_builddir)/gnu\
+ @GRECS_INCLUDES@\
-DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)"\
-DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\
-DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\
diff --git a/src/acl.c b/src/acl.c
index dc459f5..eed2d78 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -482,12 +482,12 @@ struct grecs_keyword acl_keywords[] = {
/* TRANSLATORS: only words within angle brackets are translatable */
{ "allow", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"),
N_("Allow access"),
- grecs_type_string, NULL, 0,
+ grecs_type_string, GRECS_MULT, NULL, 0,
allow_cb },
/* TRANSLATORS: only words within angle brackets are translatable */
{ "deny", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"),
N_("Deny access"),
- grecs_type_string, NULL, 0,
+ grecs_type_string, GRECS_MULT, NULL, 0,
deny_cb },
{ NULL }
};
diff --git a/src/inetd.c b/src/inetd.c
index 1d7798d..febd84e 100644
--- a/src/inetd.c
+++ b/src/inetd.c
@@ -84,6 +84,7 @@ inetd_conf_file (const char *file)
size_t line_no = 0;
struct wordsplit ws;
char *dfl_address = NULL;
+ int wsflags;
fp = fopen (file, "r");
if (!fp)
@@ -94,6 +95,7 @@ inetd_conf_file (const char *file)
return 1;
}
+ wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_WS | WRDSF_SQUEEZE_DELIMS;
while (getline (&buf, &size, fp) >= 0)
{
char *p;
@@ -111,9 +113,6 @@ inetd_conf_file (const char *file)
struct inetd_builtin *builtin;
char *tag;
- if (line_no)
- wordsplit_free (&ws);
-
line_no++;
for (p = buf; *p && c_isblank (*p); p++)
;
@@ -121,14 +120,12 @@ inetd_conf_file (const char *file)
if (!p || *p == '\n' || *p == '#')
continue;
- if (wordsplit (p, &ws,
- WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_WS |
- WRDSF_SQUEEZE_DELIMS))
+ if (wordsplit (p, &ws, wsflags))
{
logmsg (LOG_ERR, "wordsplit: %s", strerror (errno));
continue;
}
-
+ wsflags |= WRDSF_REUSE;
if (ws.ws_wordc == 1)
{
size_t len = strlen (ws.ws_wordv[IFLD_SERVICE]);
@@ -308,7 +305,7 @@ inetd_conf_file (const char *file)
register_prog (comp);
}
- if (line_no)
+ if (wsflags & WRDSF_REUSE)
wordsplit_free (&ws);
free (dfl_address);
free (buf);
diff --git a/src/pies.c b/src/pies.c
index 85bd22d..ded1a10 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -26,6 +26,7 @@ int log_facility = LOG_USER;
char *log_tag;
struct pies_privs pies_privs;
int foreground;
+int init_process;
enum pies_command {
COM_START,
@@ -38,6 +39,8 @@ enum pies_command {
};
enum pies_command command;
+int initdefault; /* Default runlevel */
+int dfl_level;
char *statedir = DEFAULT_STATE_DIR;
char *instance;
char *pidfile;
@@ -219,24 +222,27 @@ struct grecs_keyword return_code_keywords[] = {
N_("arg: {disable | restart}"),
N_("Specifies action to take when a component finishes with this "
"return code."),
- grecs_type_string, NULL, offsetof (struct component, act_temp.act),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, act_temp.act),
_cb_action,
},
{"notify",
N_("arg: emails"),
N_("Notify this address when a component terminates."),
- grecs_type_string, NULL, offsetof (struct component, act_temp.addr)
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, act_temp.addr)
},
{"message",
NULL,
N_("Notification message text (with headers)."),
- grecs_type_string, NULL, offsetof (struct component, act_temp.message),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, act_temp.message),
NULL},
{"exec",
NULL,
N_("Execute this command."),
- grecs_type_string, NULL,
- offsetof (struct component, act_temp.command),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, act_temp.command),
NULL,
},
{NULL}
@@ -822,6 +828,7 @@ _cb_socket_type (enum grecs_callback_command cmd,
static struct tokendef modetab[] = {
{"exec", pies_comp_exec},
{"wait", pies_comp_exec},
+ {"once", pies_comp_once},
{"accept", pies_comp_accept},
{"inetd", pies_comp_inetd},
{"nostartaccept", pies_comp_inetd},
@@ -942,6 +949,53 @@ _cb_flags (enum grecs_callback_command cmd,
return 0;
}
+static const char valid_runlevels[] = "0123456Ss";
+
+static int
+_cb_initdefault (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr, grecs_value_t *value, void *cb_data)
+{
+ int *val = varptr;
+
+ if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
+ return 1;
+ if (strlen (value->v.string) != 1)
+ {
+ grecs_error (locus, 0, _("argument must be a single character"));
+ return 1;
+ }
+ if (!strchr (valid_runlevels, value->v.string[0]))
+ {
+ grecs_error (locus, 0, _("not a valid runlevel"));
+ return 1;
+ }
+ *val = toupper (value->v.string[0]);
+ return 0;
+}
+
+static int
+_cb_runlevels (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr, grecs_value_t *value, void *cb_data)
+{
+ char **sptr = varptr, *p;
+
+ if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
+ return 1;
+ for (p = value->v.string; *p; p++)
+ {
+ if (!strchr (valid_runlevels, *p))
+ {
+ grecs_error (locus, 0, _("not a valid runlevel: %c"));
+ return 1;
+ }
+ }
+ *sptr = grecs_strdup(value->v.string);
+ for (p = *sptr; *p; p++)
+ *p = toupper (*p);
+ return 0;
+}
struct grecs_keyword component_keywords[] = {
{"mode",
@@ -950,119 +1004,130 @@ struct grecs_keyword component_keywords[] = {
N_
("mode: {exec | wait | accept | inetd | nostartaccept | pass-fd | pass}"),
N_("Component execution mode."),
- grecs_type_string, NULL, offsetof (struct component, mode),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, mode),
_cb_mode,
},
{"program",
NULL,
N_("Full name of the program."),
- grecs_type_string, NULL,
- offsetof (struct component, program),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, program),
NULL,
},
{"command",
NULL,
N_("Command line."),
- grecs_type_string, NULL, 0,
+ grecs_type_string, GRECS_DFLT,
+ NULL, 0,
_cb_command,
},
{"prerequisites",
N_("list"),
N_("List of prerequisites."),
- grecs_type_string | GRECS_LIST, NULL, offsetof (struct component, prereq),
+ grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, prereq),
NULL,
},
{"dependents",
N_("list"),
N_("List of components for which this one is a prerequisite."),
- grecs_type_string | GRECS_LIST, NULL, offsetof (struct component, depend),
+ grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, depend),
NULL,
},
{"flags",
N_("list"),
N_("List of flags."),
- grecs_type_string | GRECS_LIST, NULL, offsetof (struct component, flags),
+ grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, flags),
_cb_flags },
+ {"runlevels",
+ N_("chars"),
+ N_("Runlevels to start that component in."),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, runlevels),
+ _cb_runlevels },
{"pass-fd-timeout",
NULL,
N_("Time to wait for pass-fd socket to become available."),
- grecs_type_uint, NULL,
- offsetof (struct component, pass_fd_timeout),
+ grecs_type_uint, GRECS_DFLT,
+ NULL, offsetof (struct component, pass_fd_timeout),
NULL,
},
{"max-instances",
NULL,
N_("Maximum number of running instances."),
- grecs_type_size, NULL,
- offsetof (struct component, max_instances),
+ grecs_type_size, GRECS_DFLT,
+ NULL, offsetof (struct component, max_instances),
NULL },
{"max-instances-message",
NULL,
N_("Text to send back if max-instances is reached (inetd-components only)."),
- grecs_type_string, NULL,
- offsetof (struct component, max_instances_message),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, max_instances_message),
NULL },
{"max-ip-connections",
NULL,
N_("Maximum number of simultaneous connections per IP address (inetd only)."),
- grecs_type_size, NULL,
- offsetof (struct component, max_ip_connections),
+ grecs_type_size, GRECS_DFLT,
+ NULL, offsetof (struct component, max_ip_connections),
NULL },
{"max-ip-connections-message",
NULL,
N_("Text to send back if max-ip-connections-message is reached (inetd only)."),
- grecs_type_string, NULL,
- offsetof (struct component, max_ip_connections_message),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, max_ip_connections_message),
NULL },
{"max-rate",
NULL,
N_("Maximum number of times an inetd component can be invoked in one minute."),
- grecs_type_size, NULL,
- offsetof (struct component, max_rate),
+ grecs_type_size, GRECS_DFLT,
+ NULL, offsetof (struct component, max_rate),
NULL },
{"socket",
N_("url: string"),
N_("Listen on the given url."),
- grecs_type_string, NULL,
- offsetof (struct component, socket_url),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, socket_url),
_cb_url,
},
{"socket-type",
/* TRANSLATORS: words after `type:' are keywords. */
N_("type: {stream | dgram | raw | rdm | seqpacket}"),
N_("Set socket type."),
- grecs_type_int, NULL,
- offsetof (struct component, socket_type),
+ grecs_type_int, GRECS_DFLT,
+ NULL, offsetof (struct component, socket_type),
_cb_socket_type },
{"pass-fd-socket",
N_("name"),
N_("Pass fd through this socket."),
- grecs_type_string, NULL,
- offsetof (struct component, pass_fd_socket),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, pass_fd_socket),
NULL,
},
{"acl",
N_("name: string"),
N_("Set ACL."),
- grecs_type_section, NULL, offsetof (struct component, acl),
+ grecs_type_section, GRECS_DFLT,
+ NULL, offsetof (struct component, acl),
acl_section_parser, NULL, acl_keywords},
{"access-denied-message",
NULL,
N_("Text to send back if access is denied (inetd-components only)."),
- grecs_type_string, NULL,
- offsetof (struct component, access_denied_message),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, access_denied_message),
NULL },
{"remove-file",
N_("file"),
N_("Remove file before starting the component."),
- grecs_type_string, NULL, offsetof (struct component, rmfile),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, rmfile),
NULL,
},
{"facility",
N_("arg"),
N_("Override default syslog facility for this component."),
- grecs_type_string, NULL, offsetof (struct component, facility),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, facility),
cb_syslog_facility,
},
{"stdout",
@@ -1070,7 +1135,8 @@ struct grecs_keyword component_keywords[] = {
N_("type: {file | syslog}> <channel: string"),
N_("Redirect program's standard output to the given file or "
"syslog priority."),
- grecs_type_string, NULL, offsetof (struct component, redir[RETR_OUT]),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, redir[RETR_OUT]),
_cb_redir,
},
{"stderr",
@@ -1078,67 +1144,77 @@ struct grecs_keyword component_keywords[] = {
N_("type: {file | syslog}> <channel: string"),
N_("Redirect program's standard error to the given file or "
"syslog priority."),
- grecs_type_string, NULL, offsetof (struct component, redir[RETR_ERR]),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, redir[RETR_ERR]),
_cb_redir,
},
{"user",
NULL,
N_("Run with this user privileges."),
- grecs_type_string, NULL, offsetof (struct component, privs.user),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, privs.user),
NULL,
},
{"group",
NULL,
N_("Retain supplementary group."),
- grecs_type_string | GRECS_LIST, NULL, offsetof (struct component,
- privs.groups),
+ grecs_type_string, GRECS_LIST,
+ NULL, offsetof (struct component, privs.groups),
NULL,
},
{"allgroups",
NULL,
N_("Retain all supplementary groups of which user is a member."),
- grecs_type_bool, NULL, offsetof (struct component, privs.allgroups),
+ grecs_type_bool, GRECS_DFLT,
+ NULL, offsetof (struct component, privs.allgroups),
NULL,
},
{"umask",
N_("arg: number"),
N_("Force this umask."),
- grecs_type_string, NULL, offsetof (struct component, umask),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, umask),
_cb_umask,
},
{"limits",
NULL,
N_("Set system limits"),
- grecs_type_string, NULL, offsetof (struct component, limits),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, limits),
_cb_limits,
},
{"env",
N_("arg: list"),
N_("Set program environment. Argument is a list of assignments "
"separated by white space."),
- grecs_type_string, NULL, offsetof (struct component, env),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, env),
_cb_env,
},
{"chdir",
N_("dir"),
N_("Change to this directory before executing the component."),
- grecs_type_string, NULL, offsetof (struct component, dir),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, dir),
NULL,
},
{"return-code",
N_("tag: exit-code-list"),
N_("Define what to do when the component finishes."),
- grecs_type_section, NULL, 0,
+ grecs_type_section, GRECS_DFLT,
+ NULL, 0,
return_code_section_parser, NULL, return_code_keywords},
{"service",
N_("name"),
N_("Service name for inetd component."),
- grecs_type_string, NULL, offsetof (struct component, service),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, service),
NULL },
{"tcpmux-master",
N_("tag"),
N_("Tag of master TCPMUX component."),
- grecs_type_string, NULL, offsetof (struct component, tcpmux),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof (struct component, tcpmux),
NULL },
{NULL}
};
@@ -1401,14 +1477,17 @@ static struct grecs_keyword syslog_kw[] = {
N_("Set syslog facility. Arg is one of the following: user, daemon, "
"auth, authpriv, mail, cron, local0 through local7 (case-insensitive), "
"or a facility number."),
- grecs_type_string, &log_facility, 0, cb_syslog_facility},
+ grecs_type_string, GRECS_DFLT,
+ &log_facility, 0, cb_syslog_facility},
{"tag", N_("string"), N_("Tag syslog messages with this string"),
- grecs_type_string, &log_tag},
+ grecs_type_string, GRECS_DFLT,
+ &log_tag},
#if 0
/* This is reserved for future use */
{
"print-priority", N_("arg"), N_("Prefix each message with its priority"),
- grecs_type_bool, &syslog_include_prio},
+ grecs_type_bool, GRECS_DFLT,
+ &syslog_include_prio},
#endif
{NULL},
};
@@ -1441,124 +1520,153 @@ struct grecs_keyword pies_keywords[] = {
{"component",
N_("tag: string"),
N_("Define a component"),
- grecs_type_section, NULL, 0,
+ grecs_type_section, GRECS_DFLT,
+ NULL, 0,
component_section_parser, NULL, component_keywords},
{"syslog",
NULL,
N_("Configure syslog logging"),
- grecs_type_section, NULL, 0, NULL, NULL, syslog_kw},
+ grecs_type_section, GRECS_DFLT,
+ NULL, 0, NULL, NULL, syslog_kw},
{"debug",
NULL,
N_("Set debug verbosity level."),
- grecs_type_uint, &debug_level, 0, NULL},
+ grecs_type_uint, GRECS_DFLT,
+ &debug_level, 0, NULL},
{"source-info",
NULL,
N_("Show source info with debugging messages."),
- grecs_type_bool, &source_info_option, 0, NULL},
+ grecs_type_bool, GRECS_DFLT,
+ &source_info_option, 0, NULL},
{"state-directory",
NULL,
N_("Full file name of the program state directory."),
- grecs_type_string, &statedir, 0, NULL},
+ grecs_type_string, GRECS_DFLT,
+ &statedir, 0, NULL},
{"pidfile",
NULL,
N_("Write PID to this file."),
- grecs_type_string, &pidfile, 0,
+ grecs_type_string, GRECS_DFLT,
+ &pidfile, 0,
NULL,
},
{"control-file",
NULL,
N_("Set location of the control file."),
- grecs_type_string, &ctlfile, 0,
+ grecs_type_string, GRECS_DFLT,
+ &ctlfile, 0,
NULL,
},
{"stat-file",
NULL,
N_("Set location of the statistics output file."),
- grecs_type_string, &statfile, 0,
+ grecs_type_string, GRECS_DFLT,
+ &statfile, 0,
NULL,
},
{"qotd-file",
NULL,
N_("Set location of the QOTD file."),
- grecs_type_string, &qotdfile, 0,
+ grecs_type_string, GRECS_DFLT,
+ &qotdfile, 0,
NULL },
{"user",
NULL,
N_("Run with this user privileges."),
- grecs_type_string, &pies_privs.user, 0,
+ grecs_type_string, GRECS_DFLT,
+ &pies_privs.user, 0,
NULL,
},
{"group",
NULL,
N_("Retain supplementary group."),
- grecs_type_string | GRECS_LIST, &pies_privs.groups, 0,
+ grecs_type_string, GRECS_LIST,
+ &pies_privs.groups, 0,
NULL,
},
{"allgroups",
NULL,
N_("Retain all supplementary groups of which user is a member."),
- grecs_type_bool, &pies_privs.allgroups, 0,
+ grecs_type_bool, GRECS_DFLT,
+ &pies_privs.allgroups, 0,
NULL,
},
{"umask",
N_("arg: number"),
N_("Force this umask."),
- grecs_type_string, &pies_umask, 0,
+ grecs_type_string, GRECS_DFLT,
+ &pies_umask, 0,
_cb_umask,
},
{"limits",
NULL,
N_("Set global system limits."),
- grecs_type_string, &pies_limits, 0, _cb_limits,
+ grecs_type_string, GRECS_DFLT,
+ &pies_limits, 0, _cb_limits,
+ },
+ {"initdefault",
+ N_("arg: char"),
+ N_("Default runlevel"),
+ grecs_type_string, GRECS_DFLT,
+ &initdefault, 0, _cb_initdefault,
},
{"shutdown-timeout",
"n",
N_("Wait <n> seconds for all components to shut down."),
- grecs_type_uint, &shutdown_timeout, 0,
+ grecs_type_uint, GRECS_DFLT,
+ &shutdown_timeout, 0,
NULL,
},
{"return-code",
N_("tag: exit-code-list"),
N_("Define what to do when the component finishes."),
- grecs_type_section, &default_component, 0,
+ grecs_type_section, GRECS_DFLT,
+ &default_component, 0,
return_code_section_parser, NULL, return_code_keywords},
{"acl",
N_("name: string"),
N_("Set global ACL."),
- grecs_type_section, &pies_acl, 0,
+ grecs_type_section, GRECS_DFLT,
+ &pies_acl, 0,
acl_section_parser, NULL, acl_keywords},
{"defacl",
N_("name: string"),
N_("Define an ACL."),
- grecs_type_section, NULL, 0,
+ grecs_type_section, GRECS_DFLT,
+ NULL, 0,
defacl_section_parser, NULL, acl_keywords},
{"include-inetd",
N_("file-or-dir: string"),
N_("Include inetd configuration file or directory"),
- grecs_type_string, NULL, 0,
+ grecs_type_string, GRECS_DFLT,
+ NULL, 0,
_cb_include_inetd },
{"include-meta1",
N_("file: string"),
N_("Include components from the specified MeTA1 configuration file."),
- grecs_type_string, NULL, 0,
+ grecs_type_string, GRECS_DFLT,
+ NULL, 0,
_cb_include_meta1,
},
{"meta1-queue-dir",
NULL,
N_("Set the name of MeTA1 queue directory (default /var/spool/meta1)."),
- grecs_type_string, &meta1_queue_dir, 0,
+ grecs_type_string, GRECS_DFLT,
+ &meta1_queue_dir, 0,
NULL,
},
{"mailer-program",
NULL,
N_("Full path to the mailer binary."),
- grecs_type_string, &mailer_program, 0,
+ grecs_type_string, GRECS_DFLT,
+ &mailer_program, 0,
NULL
},
{"mailer-command-line",
NULL,
N_("Mailer command line (without recipient addresses)."),
- grecs_type_string, &mailer_command_line, 0,
+ grecs_type_string, GRECS_DFLT,
+ &mailer_command_line, 0,
NULL
},
{NULL}
@@ -1705,6 +1813,7 @@ enum pies_status
pies_status_running
};
+//FIXME: If telinit?
enum pies_status
pies_check_status (pid_t *ppid)
{
@@ -1771,7 +1880,7 @@ int
request_restart_components (char **argv)
{
FILE *fp;
- pid_t pid = pidfile_read (1);
+ pid_t pid = pidfile_read (1);//FIXME: useless in init mode, init has pid == 1
if (pid == -1)
return 1;
@@ -1998,6 +2107,40 @@ set_state_file_names (const char *base)
qotdfile = mkfilename (statedir, base, ".qotd");
}
+static char *try_console[] = { NULL, "/dev/console", "/dev/tty0" };
+char *console_device;
+
+static void
+set_console_dev ()
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE (try_console); i++)
+ {
+ if (try_console[i])
+ {
+ int fd = open (try_console[i], O_RDONLY|O_NONBLOCK);
+
+ if (fd >= 0)
+ {
+ close (fd);
+ console_device = try_console[i];
+ return;
+ }
+ }
+ }
+ /* provide default */
+ console_device = "/dev/null";
+}
+
+static void
+inittrans ()
+{
+ if (progman_running_p ())
+ /* Noting to do if there are processes left in the previous runlevel */
+ return;
+
+}
+
int
main (int argc, char **argv)
{
@@ -2017,10 +2160,41 @@ main (int argc, char **argv)
set_quoting_style (NULL, shell_quoting_style);
+ init_process = getpid () == 1;
+
/* Set default logging */
diag_setup (DIAG_TO_SYSLOG | (stderr_closed_p () ? 0 : DIAG_TO_STDERR));
config_init ();
+ if (init_process)
+ {
+ for (index = 1; index < argc; index++)
+ {
+ if (!strcmp(argv[index], "single") || !strcmp(argv[index], "-s"))
+ dfl_level = 'S';
+#if 0
+ //FIXME
+ else if (!strcmp(argv[index], "-a") || !strcmp(argv[index], "auto"))
+ putenv("AUTOBOOT=YES");
+ else if (!strcmp(argv[index], "-b") ||
+ !strcmp(argv[index],"emergency"))
+ emerg_shell = 1;
+ else if (!strcmp(argv[index], "-z"))
+ {
+ /* Ignore -z xxx */
+ if (argv[index + 1])
+ index++;
+ }
+#endif
+ else if (strchr("0123456789sS", argv[index][0]) && !argv[index][1])
+ {
+ dfl_level = argv[index][0];
+ if (dfl_level == 's')
+ dfl_level = 'S';
+ }
+ }
+ }
+ else
parse_options (argc, argv, &index);
if (!instance)
@@ -2036,7 +2210,7 @@ main (int argc, char **argv)
set_conf_file_names (instance);
- if (!DEFAULT_PREPROCESSOR)
+ if (init_process || !DEFAULT_PREPROCESSOR)
grecs_preprocessor = NULL;
else
{
@@ -2130,6 +2304,12 @@ main (int argc, char **argv)
umask (pies_umask);
}
+ if (init_process)
+ {
+ foreground = 1;
+ set_console_dev ();
+ }
+ else
switch (pies_check_status (&pid))
{
case pies_status_ctr:
@@ -2164,6 +2344,7 @@ main (int argc, char **argv)
diag_setup (DIAG_TO_SYSLOG);
}
+ if (!init_process)
create_pidfile (pidfile);
if (argv[0][0] != '/')
@@ -2178,6 +2359,8 @@ main (int argc, char **argv)
do
{
+ if (init_process)
+ inittrans ();
if (!children_cleanup)
pies_pause ();
switch (action)
@@ -2208,7 +2391,7 @@ main (int argc, char **argv)
}
}
}
- while (action == ACTION_CONT);
+ while (init_process || action == ACTION_CONT);
progman_stop ();
remove_pidfile (pidfile);
diff --git a/src/pies.h b/src/pies.h
index 73b0583..9b3ae9d 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -122,6 +122,9 @@ struct pies_privs
enum pies_comp_mode
{
+ /*
+ ** Pies native component types.
+ */
/* Execute the component, no sockets are opened. This is the default
Pies mode. */
pies_comp_exec,
@@ -137,7 +140,47 @@ enum pies_comp_mode
/* Open a socket, start a component, and pass the socket fd to the
component via the UNIX domain socket. Corresponds to
`start_action = pass' in MeTA1. */
- pies_comp_pass_fd
+ pies_comp_pass_fd,
+
+ /*
+ ** Init-style components
+ */
+
+ /* Start the process when the specified runlevel is entered and wait
+ for its termination */
+ pies_comp_wait,
+ /* Execute the component once, when the specified runlevel is entered */
+ pies_comp_once,
+ /* Execute the component during system boot. Ignore runlevel settings. */
+ pies_comp_boot,
+ /* Execute the component during system boot and wait for it to terminate.
+ Ignore runlevel settings. */
+ pies_comp_bootwait,
+ /* Execute the component when the power goes down. */
+ pies_comp_powerfail,
+ /* Execute the component when the power goes down. Wait for it to
+ terminate. */
+ pies_comp_powerwait,
+ /* Execute the component when the power is restored. Wait for it to
+ terminate. */
+ pies_comp_powerokwait,
+ /* Execute the process when SIGINT is delivered, i.e. someone has
+ pressed the Ctrl+Alt+Del combination. */
+ pies_comp_ctrlaltdel,
+ /* Execute the component when a specified ondemand runlevel is called */
+ pies_comp_ondemand,
+ /* Execute the component on the system boot. */
+ pies_comp_sysinit,
+ /* Execute the component when running on the UPS and pies is informed that
+ the UPS battery is almost empty. */
+ pies_comp_powerfailnow,
+ /* Execute the component a signal from the keyboard handler arrives,
+ indicating that a special key combination was pressed on the console
+ keyboard. */
+ pies_comp_kbrequest,
+
+ /* Restart the component wherever it terminates */
+ pies_comp_respawn = pies_comp_exec,
};
#define CF_DISABLED 0x001 /* The componenet is disabled */
@@ -176,6 +219,9 @@ struct component
mode_t umask; /* Umask to install before starting */
limits_record_t limits; /* System limits */
+ /* For exec (init) components */
+ char *runlevels;
+
/* For inetd components */
size_t max_rate; /* Maximum number of invocations per minute */
size_t max_ip_connections; /* Max. number of connections per IP address */
@@ -225,7 +271,12 @@ extern char **mailer_argv;
extern size_t default_max_rate;
extern char *qotdfile;
+extern int init_process;
+extern char *console_device;
+extern int initdefault;
+
void register_prog (struct component *comp);
+int progman_running_p (void);
size_t progman_running_count (void);
void progman_start (void);
void progman_wake_sleeping (int);
diff --git a/src/progman.c b/src/progman.c
index c2b09c1..639c22f 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -15,6 +15,7 @@
along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
#include "pies.h"
+#include <termios.h>
enum prog_type
{
@@ -32,6 +33,7 @@ enum prog_status
status_sleeping, /* Component is sleeping. An attempt to start it will
be made at prog->v.p.timestamp + SLEEPTIME */
status_stopping, /* Component is being stopped */
+ status_finished, /* A "once" component has finished */
};
struct conn_class
@@ -61,6 +63,7 @@ struct prog
time_t timestamp; /* Time of last startup */
size_t failcount; /* Number of failed starts since timestamp */
enum prog_status status; /* Current component status */
+ char *runlevels;
/* If status == status_listener: */
size_t num_instances; /* Number of running instances */
/* If comp->type == pies_comp_inetd && status == status_enabled */
@@ -400,6 +403,17 @@ prog_rebuild_prerequisites (struct prog *prog)
prog->prereq[depc] = NULL;
}
+int
+progman_running_p ()
+{
+ struct prog *prog;
+
+ for (prog = proghead; prog; prog = prog->next)
+ if (prog->pid > 0)
+ return 1;
+ return 0;
+}
+
size_t
progman_running_count ()
{
@@ -1096,6 +1110,68 @@ progman_run_comp (struct component *comp, int fd,
prog_execute (prog);
}
+static int
+console_open (int mode)
+{
+ int i, fd;
+
+ for (i = 0; i < 5; i++)
+ {
+ fd = open (console_device, mode | O_NONBLOCK);
+ if (fd >= 0)
+ {
+ fcntl (fd, F_SETFL, mode);
+ return fd;
+ }
+ }
+ return -1;
+}
+
+static void
+console_stty ()
+{
+ struct termios tty;
+ int fd;
+
+ if ((fd = console_open (O_RDWR|O_NOCTTY)) < 0)
+ {
+ logmsg (LOG_CRIT, "can't open %s", console_device);
+ return;
+ }
+
+ tcgetattr (fd, &tty);
+
+ tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+ tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+ tty.c_cc[VINTR] = 3; /* ctrl('c') */
+ tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
+ tty.c_cc[VERASE] = 127;
+ tty.c_cc[VKILL] = 24; /* ctrl('x') */
+ tty.c_cc[VEOF] = 4; /* ctrl('d') */
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VSTART] = 17; /* ctrl('q') */
+ tty.c_cc[VSTOP] = 19; /* ctrl('s') */
+ tty.c_cc[VSUSP] = 26; /* ctrl('z') */
+
+ /*
+ * Set pre and post processing
+ */
+ tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+ tty.c_oflag = OPOST|ONLCR;
+ tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+ /*
+ * Now set the terminal line.
+ * We don't care about non-transmitted output data
+ * and non-read input data.
+ */
+ tcsetattr (fd, TCSANOW, &tty);
+ tcflush(fd, TCIOFLUSH);
+ close (fd);
+}
+
static void
prog_start (struct prog *prog)
{
@@ -1165,8 +1241,11 @@ prog_start (struct prog *prog)
return;
}
+ if (!init_process)
+ {
redir[RETR_OUT] = open_redirector (prog, RETR_OUT);
redir[RETR_ERR] = open_redirector (prog, RETR_ERR);
+ }
switch (pid = fork ())
{
@@ -1179,6 +1258,25 @@ prog_start (struct prog *prog)
{
case pies_comp_pass_fd:
case pies_comp_exec:
+ case pies_comp_once:
+ if (init_process)
+ {
+ int fd = console_open (O_RDWR|O_NOCTTY);
+ if (fd < 0)
+ {
+ logmsg (LOG_CRIT, "open(%s): %s",
+ console_device, strerror (errno));
+ fd = open("/dev/null", O_RDWR);
+ }
+ if (fd != 0)
+ dup2 (fd, 0);
+ if (fd != 1)
+ dup2 (fd, 1);
+ if (fd != 2)
+ dup2 (fd, 2);
+ }
+ else
+ {
if (redir[RETR_OUT] == -1)
{
close (1);
@@ -1188,6 +1286,7 @@ prog_start (struct prog *prog)
{
dup2 (redir[RETR_OUT], 1);
}
+ }
break;
case pies_comp_accept:
@@ -1201,6 +1300,8 @@ prog_start (struct prog *prog)
break;
}
+ if (!init_process)
+ {
if (redir[RETR_ERR] == -1)
{
if (!DIAG_OUTPUT (DIAG_TO_STDERR))
@@ -1213,6 +1314,7 @@ prog_start (struct prog *prog)
{
dup2 (redir[RETR_ERR], 2);
}
+ }
/* Close unneeded descripitors */
FD_ZERO (&fdset);
@@ -1244,7 +1346,8 @@ prog_start (struct prog *prog)
{
disable_socket (prog->v.p.socket);
}
- else if (prog->v.p.comp->mode != pies_comp_exec)
+ else if (prog->v.p.comp->mode != pies_comp_exec &&
+ prog->v.p.comp->mode != pies_comp_once)
close (prog->v.p.socket);
prog->pid = pid;
prog->v.p.status = status_enabled;
@@ -1657,6 +1760,14 @@ progman_recompute_alarm ()
+static int
+runlevel_match (struct prog *prog)
+{
+ if (!initdefault || !prog->v.p.comp->runlevels)
+ return 1;
+ return !!strchr (prog->v.p.comp->runlevels, initdefault);
+}
+
void
progman_start ()
{
@@ -1669,7