diff options
m--------- | grecs | 0 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/acl.c | 4 | ||||
-rw-r--r-- | src/inetd.c | 13 | ||||
-rw-r--r-- | src/pies.c | 337 | ||||
-rw-r--r-- | src/pies.h | 53 | ||||
-rw-r--r-- | src/progman.c | 139 |
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\"\ @@ -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); @@ -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); @@ -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 |