| /* upstart |
| * |
| * parse_job.c - job definition parsing |
| * |
| * Copyright © 2009 Canonical Ltd. |
| * Author: Scott James Remnant <scott@netsplit.com>. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2, as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif /* HAVE_CONFIG_H */ |
| |
| |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| |
| #include <errno.h> |
| #include <limits.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <nih/macros.h> |
| #include <nih/alloc.h> |
| #include <nih/string.h> |
| #include <nih/list.h> |
| #include <nih/signal.h> |
| #include <nih/config.h> |
| #include <nih/logging.h> |
| #include <nih/error.h> |
| |
| #include "process.h" |
| #include "job_class.h" |
| #include "event.h" |
| #include "parse_job.h" |
| #include "errors.h" |
| |
| |
| /* Prototypes for static functions */ |
| static int parse_exec (Process *process, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int parse_script (Process *process, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int parse_process (JobClass *class, ProcessType process, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static EventOperator *parse_on (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result, malloc)); |
| static int parse_on_operator (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno, |
| NihList *stack, EventOperator **root) |
| __attribute__ ((warn_unused_result)); |
| static int parse_on_paren (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno, |
| NihList *stack, EventOperator **root, |
| size_t *paren) |
| __attribute__ ((warn_unused_result)); |
| static int parse_on_operand (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno, |
| NihList *stack, EventOperator **root) |
| __attribute__ ((warn_unused_result)); |
| static int parse_on_collect (JobClass *class, |
| NihList *stack, EventOperator **root) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_instance (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_description (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_author (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_version (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_env (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_export (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_start (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_stop (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_emits (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_exec (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_script (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_pre_start (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_post_start (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_pre_stop (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_post_stop (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_expect (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_task (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_kill (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_respawn (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_normal (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_console (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| static int stanza_umask (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_nice (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_oom (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_limit (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_chroot (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| static int stanza_chdir (JobClass *class, NihConfigStanza *stanza, |
| const char *file, size_t len, |
| size_t *pos, size_t *lineno) |
| __attribute__ ((warn_unused_result)); |
| |
| |
| /** |
| * stanzas: |
| * |
| * This is the table of known job definition stanzas and the functions |
| * that handle parsing them. |
| **/ |
| static NihConfigStanza stanzas[] = { |
| { "instance", (NihConfigHandler)stanza_instance }, |
| { "description", (NihConfigHandler)stanza_description }, |
| { "author", (NihConfigHandler)stanza_author }, |
| { "version", (NihConfigHandler)stanza_version }, |
| { "env", (NihConfigHandler)stanza_env }, |
| { "export", (NihConfigHandler)stanza_export }, |
| { "start", (NihConfigHandler)stanza_start }, |
| { "stop", (NihConfigHandler)stanza_stop }, |
| { "emits", (NihConfigHandler)stanza_emits }, |
| { "exec", (NihConfigHandler)stanza_exec }, |
| { "script", (NihConfigHandler)stanza_script }, |
| { "pre-start", (NihConfigHandler)stanza_pre_start }, |
| { "post-start", (NihConfigHandler)stanza_post_start }, |
| { "pre-stop", (NihConfigHandler)stanza_pre_stop }, |
| { "post-stop", (NihConfigHandler)stanza_post_stop }, |
| { "expect", (NihConfigHandler)stanza_expect }, |
| { "task", (NihConfigHandler)stanza_task }, |
| { "kill", (NihConfigHandler)stanza_kill }, |
| { "respawn", (NihConfigHandler)stanza_respawn }, |
| { "normal", (NihConfigHandler)stanza_normal }, |
| { "console", (NihConfigHandler)stanza_console }, |
| { "umask", (NihConfigHandler)stanza_umask }, |
| { "nice", (NihConfigHandler)stanza_nice }, |
| { "oom", (NihConfigHandler)stanza_oom }, |
| { "limit", (NihConfigHandler)stanza_limit }, |
| { "chroot", (NihConfigHandler)stanza_chroot }, |
| { "chdir", (NihConfigHandler)stanza_chdir }, |
| |
| NIH_CONFIG_LAST |
| }; |
| |
| |
| /** |
| * parse_job: |
| * @parent: parent object for new job, |
| * @name: name of new job, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * This function is used to parse a job definition from @file, for a job |
| * named @name. A sequence of stanzas is expected, defining the parameters |
| * of the job. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned job. When all parents |
| * of the returned job are freed, the returned job will also be |
| * freed. |
| * |
| * Returns: new JobClass structure on success, NULL on raised error. |
| **/ |
| JobClass * |
| parse_job (const void *parent, |
| const char *name, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| JobClass *class; |
| |
| nih_assert (name != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| class = job_class_new (parent, name); |
| if (! class) |
| nih_return_system_error (NULL); |
| |
| if (nih_config_parse_file (file, len, pos, lineno, |
| stanzas, class) < 0) { |
| nih_free (class); |
| return NULL; |
| } |
| |
| return class; |
| } |
| |
| |
| /** |
| * parse_exec: |
| * @process: process being parsed. |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * This function is used to parse the arguments to a process's exec |
| * stanza from @file, the command and its arguments are expected to follow |
| * and will be the command run for the job. |
| * |
| * The Process for this to be parsed into should have already been |
| * allocated. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| parse_exec (Process *process, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (process != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (! nih_config_has_token (file, len, pos, lineno)) |
| nih_return_error (-1, NIH_CONFIG_EXPECTED_TOKEN, |
| _(NIH_CONFIG_EXPECTED_TOKEN_STR)); |
| |
| if (process->command) |
| nih_unref (process->command, process); |
| |
| process->script = FALSE; |
| process->command = nih_config_parse_command (process, file, len, |
| pos, lineno); |
| |
| if (! process->command) |
| return -1; |
| |
| return 0; |
| } |
| |
| /** |
| * parse_script: |
| * @process: process being parsed. |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * This function is used to parse a script block for a process's script |
| * stanza from @file. A block terminated with "end script" is expected to |
| * follow, and will be stored in the command for the job. |
| * |
| * The Process for this to be parsed into should have already been |
| * allocated. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| parse_script (Process *process, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (process != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (nih_config_skip_comment (file, len, pos, lineno) < 0) |
| return -1; |
| |
| if (process->command) |
| nih_unref (process->command, process); |
| |
| process->script = TRUE; |
| process->command = nih_config_parse_block (process, file, len, |
| pos, lineno, "script"); |
| |
| if (! process->command) |
| return -1; |
| |
| return 0; |
| } |
| |
| /** |
| * parse_process: |
| * @job: job class being parsed, |
| * @process: which process is being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * This function is used to allocate a Process for @process within @class, |
| * and expects either "exec" or "script" to follow, calling parse_exec() |
| * or parse_script() appropriately. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| parse_process (JobClass *class, |
| ProcessType process, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| /* Allocate a new Process structure if we need to */ |
| if (! class->process[process]) { |
| class->process[process] = process_new (class->process); |
| if (! class->process[process]) |
| nih_return_system_error (-1); |
| } |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno: 1); |
| |
| /* Parse the next argument to find out what type of process this is */ |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "exec")) { |
| ret = parse_exec (class->process[process], stanza, |
| file, len, &a_pos, &a_lineno); |
| } else if (! strcmp (arg, "script")) { |
| ret = parse_script (class->process[process], stanza, |
| file, len, &a_pos, &a_lineno); |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| |
| /** |
| * parse_on: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * This function is used to parse the arguments to an "on" stanza as an |
| * event expression. Names and arguments to events, intermixed with |
| * operators and grouped by parentheses are expected to follow and are |
| * allocated as a tree of EventOperator structures, the root of which is |
| * returned. |
| * |
| * Returns: EventOperator at root of expression tree on success, NULL |
| * on raised error. |
| **/ |
| static EventOperator * |
| parse_on (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| NihList stack; |
| EventOperator *root = NULL; |
| size_t on_pos, on_lineno, paren = 0; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| nih_list_init (&stack); |
| |
| on_pos = *pos; |
| on_lineno = (lineno ? *lineno : 1); |
| |
| /* Parse all of the tokens that we find following the configuration |
| * stanza; unlike other stanzas we happily parse multiple lines |
| * provided that we're inside parens, and we permit comments at the |
| * end of those lines. |
| */ |
| do { |
| nih_config_skip_whitespace (file, len, &on_pos, &on_lineno); |
| |
| do { |
| /* Update error position */ |
| *pos = on_pos; |
| if (lineno) |
| *lineno = on_lineno; |
| |
| /* Peek at the first character, since open and |
| * close parens aren't picked up by our normal |
| * tokeniser. |
| */ |
| if ((*pos < len) && strchr ("()", file[*pos])) { |
| if (parse_on_paren (class, stanza, file, len, |
| &on_pos, &on_lineno, |
| &stack, &root, |
| &paren) < 0) { |
| root = NULL; |
| goto finish; |
| } |
| |
| /* Otherwise it's either an operator or operand; |
| * parse it as an operator first, that function |
| * handles transfer to parse_on_operand() in the |
| * case of unrecognised token. |
| */ |
| } else if (parse_on_operator (class, stanza, file, len, |
| &on_pos, &on_lineno, |
| &stack, &root) < 0) { |
| root = NULL; |
| goto finish; |
| } |
| |
| } while (nih_config_has_token (file, len, |
| &on_pos, &on_lineno)); |
| |
| if (nih_config_skip_comment (file, len, |
| &on_pos, &on_lineno) < 0) |
| nih_assert_not_reached (); |
| } while ((on_pos < len) && paren); |
| |
| /* The final operator and operand should be still on the stack and |
| * need collecting; if not, take the stack pointer out before |
| * returning otherwise we'll try and access it. |
| */ |
| if (parse_on_collect (class, &stack, &root) < 0) { |
| nih_list_remove (&stack); |
| return NULL; |
| } |
| |
| /* If the stack isn't empty, then we've hit an open parenthesis and |
| * not found a matching close one. We've probably parsed the entire |
| * file by accident! |
| */ |
| if (! NIH_LIST_EMPTY (&stack)) { |
| nih_error_raise (PARSE_MISMATCHED_PARENS, |
| _(PARSE_MISMATCHED_PARENS_STR)); |
| root = NULL; |
| goto finish; |
| } |
| |
| |
| finish: |
| /* Remove the stack pointer from the list of items, otherwise we'll |
| * return it and we'll try and access it when freed. |
| */ |
| nih_list_remove (&stack); |
| |
| *pos = on_pos; |
| if (lineno) |
| *lineno = on_lineno; |
| |
| return root; |
| } |
| |
| /** |
| * parse_on_operator: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number, |
| * @stack: input operator stack, |
| * @root: output operator. |
| * |
| * This function parses a single token from the arguments of the "on" |
| * stanza. If the token is not a valid operator, this will call |
| * parse_on_operand() instead. |
| * |
| * Operators are pushed onto @stack after collecting any existing operators |
| * and operands on the stack, and placing them as the operator's left child. |
| * |
| * Returns: zero on success, negative value on raised error. |
| **/ |
| static int |
| parse_on_operator (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno, |
| NihList *stack, |
| EventOperator **root) |
| { |
| size_t a_pos, a_lineno; |
| nih_local char *arg = NULL; |
| EventOperatorType type; |
| EventOperator *oper; |
| NihListEntry *item; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| nih_assert (stack != NULL); |
| nih_assert (root != NULL); |
| |
| /* Get the next token to see whether it's an operator keyword that |
| * we recognise, don't dequote since this allows people to quote |
| * operators to turn them into ordinary operands. |
| */ |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| "()" NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| /* Compare token against known operators; if it isn't, then rewind |
| * back to the starting position and deal with it as an operand. |
| */ |
| if (! strcmp (arg, "and")) { |
| type = EVENT_AND; |
| } else if (! strcmp (arg, "or")) { |
| type = EVENT_OR; |
| } else { |
| return parse_on_operand (class, stanza, file, len, pos, lineno, |
| stack, root); |
| } |
| |
| /* Before we push the new operator onto the stack, we need to collect |
| * any existing operators and operands. |
| */ |
| if (parse_on_collect (class, stack, root) < 0) |
| return -1; |
| |
| /* Create the new operator, placing the existing root node as its |
| * left-hand child. |
| */ |
| oper = event_operator_new (class, type, NULL, NULL); |
| if (! oper) |
| nih_return_system_error (-1); |
| |
| nih_ref (*root, oper); |
| nih_unref (*root, class); |
| |
| nih_tree_add (&oper->node, &(*root)->node, NIH_TREE_LEFT); |
| *root = NULL; |
| |
| /* Push the new operator onto the stack */ |
| item = nih_list_entry_new (class); |
| if (! item) |
| nih_return_system_error (-1); |
| |
| item->data = oper; |
| nih_list_add_after (stack, &item->entry); |
| |
| ret = 0; |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * parse_on_paren: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number, |
| * @stack: input operator stack, |
| * @root: output operator, |
| * @paren: number of nested parentheses. |
| * |
| * This function deals with an open or close parenthesis in the arguments |
| * of the "on" stanza; it must only be called when the character at the |
| * current position is either. |
| * |
| * @paren is incremented for each open parenthesis, and decremented for |
| * each close one. This is a gross check for whether the parsing is |
| * currently within a grouping, and used by parse_on() to ignore newlines |
| * within them. |
| * |
| * An open parenthesis pushes a NULL operator onto the stack, this stops |
| * parse_on_collect() from collecting beyond it. |
| * |
| * A close parenthesis collects all operators on the stack up to the |
| * first (matching) marker, and removes the marker. |
| * |
| * Returns: zero on success, negative value on raised error. |
| **/ |
| static int |
| parse_on_paren (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno, |
| NihList *stack, |
| EventOperator **root, |
| size_t *paren) |
| { |
| NihListEntry *item; |
| EventOperator *oper; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| nih_assert (stack != NULL); |
| nih_assert (root != NULL); |
| nih_assert (paren != NULL); |
| |
| switch (file[*pos]) { |
| case '(': |
| (*paren)++; |
| |
| /* An open parenthesis may only occur if we're in a valid |
| * state for an operand; we must have no items on the stack, |
| * or an open parenthesis on the stack, or an operator |
| * on the stack; and must have nothing collected. |
| */ |
| item = (! NIH_LIST_EMPTY (stack) |
| ? (NihListEntry *)stack->next: NULL); |
| oper = (item ? (EventOperator *)item->data : NULL); |
| if (*root || (item && oper && (oper->type == EVENT_MATCH))) |
| nih_return_error (-1, PARSE_EXPECTED_OPERATOR, |
| _(PARSE_EXPECTED_OPERATOR_STR)); |
| |
| /* We push a NULL item onto the operator stack to denote |
| * the beginning of a parenthesis group, this prevents us |
| * popping past it later. |
| */ |
| item = nih_list_entry_new (class); |
| if (! item) |
| nih_return_system_error (-1); |
| |
| nih_list_add_after (stack, &item->entry); |
| break; |
| case ')': |
| (*paren)--; |
| |
| /* Collect up to the first open paren marker. */ |
| if (parse_on_collect (class, stack, root) < 0) |
| return -1; |
| |
| /* If we run out of stack, then we have mismatched parens. */ |
| if (NIH_LIST_EMPTY (stack)) |
| nih_return_error (-1, PARSE_MISMATCHED_PARENS, |
| _(PARSE_MISMATCHED_PARENS_STR)); |
| |
| /* The top item on the stack should be the open parenthesis |
| * marker, which we want to discard. |
| */ |
| nih_free (stack->next); |
| break; |
| default: |
| nih_assert_not_reached (); |
| } |
| |
| /* Skip over the paren and any following whitespace */ |
| (*pos)++; |
| nih_config_skip_whitespace (file, len, pos, lineno); |
| |
| return 0; |
| } |
| |
| /** |
| * parse_on_operand: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number, |
| * @stack: input operator stack, |
| * @root: output operator. |
| * |
| * This function parses a single operand to the "or" stanza. An operand |
| * is any token not considered an operator, such as the name of an event |
| * or arguments to that event. |
| * |
| * If the item on the top of @stack is an EVENT_MATCH operator, the operand |
| * is added to that operator's argument list; otherwise the operand is |
| * treated as the name of an event and a new EVENT_MATCH operator pushed |
| * onto the stack. |
| * |
| * Returns: zero on success, negative value on raised error. |
| **/ |
| static int |
| parse_on_operand (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno, |
| NihList *stack, |
| EventOperator **root) |
| { |
| EventOperator *oper; |
| NihListEntry *item; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| nih_assert (stack != NULL); |
| nih_assert (root != NULL); |
| |
| arg = nih_config_next_token (NULL, file, len, pos, lineno, |
| "()" NIH_CONFIG_CNLWS, TRUE); |
| if (! arg) |
| return -1; |
| |
| /* Look at the item on the top of the stack; if it is an |
| * EVENT_MATCH operator then the operand is an argument to that event; |
| * otherwise if the stack is empty, or the top item is an operator |
| * of some kind, then the operand begins a new EVENT_MATCH operator. |
| */ |
| item = (! NIH_LIST_EMPTY (stack) ? (NihListEntry *)stack->next: NULL); |
| oper = (item ? (EventOperator *)item->data : NULL); |
| if ((! item) || (! oper) || (oper->type != EVENT_MATCH)) { |
| /* Argument is the name of an event to be matched; create |
| * an EventOperator to match it and push it onto the stack. |
| * |
| * We get away with not popping anything here because we |
| * know that we can never end up with two events on the top |
| * of the stack. |
| */ |
| oper = event_operator_new (class, EVENT_MATCH, arg, NULL); |
| if (! oper) |
| nih_return_system_error (-1); |
| |
| item = nih_list_entry_new (class); |
| if (! item) |
| nih_return_system_error (-1); |
| |
| item->data = oper; |
| nih_list_add_after (stack, &item->entry); |
| } else { |
| char **e; |
| int pos = TRUE; |
| |
| /* Argument is an environment variable for the event on |
| * the top of the stack, so we append it there. |
| */ |
| if (! nih_str_array_addp (&oper->env, oper, NULL, arg)) |
| nih_return_system_error (-1); |
| |
| /* Sanity check the event's environment to ensure that no |
| * positional arguments follow name-based ones. |
| */ |
| for (e = oper->env; e && *e; e++) { |
| if (strchr (*e, '=')) { |
| pos = FALSE; |
| } else if (! pos) { |
| nih_error_raise (PARSE_EXPECTED_VARIABLE, |
| _(PARSE_EXPECTED_VARIABLE_STR)); |
| return -1; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * parse_on_collect: |
| * @class: job class being parsed, |
| * @stack: input operator stack, |
| * @root: output operator. |
| * |
| * This function collects the input operators from @stack, up until the |
| * beginning of the stack or a group within it (denoted by a stack item |
| * with NULL data), and places the collected operator tree in @root. |
| * |
| * @root may point to a NULL pointer, or to a previously collected |
| * operator; in which case it will become the right-hand child of the |
| * operator on the top of the stack. |
| * |
| * On return from this function, @root will always point to a non-NULL |
| * pointer since it is an error to fail to collect from the stack. |
| * |
| * Returns: zero on success, negative value on raised error. |
| **/ |
| static int |
| parse_on_collect (JobClass *class, |
| NihList *stack, |
| EventOperator **root) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stack != NULL); |
| nih_assert (root != NULL); |
| |
| NIH_LIST_FOREACH_SAFE (stack, iter) { |
| NihListEntry *item = (NihListEntry *)iter; |
| EventOperator *oper = (EventOperator *)item->data; |
| |
| /* Stop on the opening of a parenthesis group */ |
| if (! oper) |
| break; |
| |
| /* Remove the item from the stack */ |
| nih_free (item); |
| |
| /* Make the existing root node a child of the new operator; |
| * there must be one for operators, and must not be one for |
| * event matches. |
| */ |
| if ((oper->type != EVENT_MATCH) && (*root)) { |
| nih_ref (*root, oper); |
| nih_unref (*root, class); |
| |
| nih_tree_add (&oper->node, &(*root)->node, |
| NIH_TREE_RIGHT); |
| } else if (oper->type != EVENT_MATCH) { |
| nih_return_error (-1, PARSE_EXPECTED_EVENT, |
| _(PARSE_EXPECTED_EVENT_STR)); |
| } else if (*root) { |
| nih_return_error (-1, PARSE_EXPECTED_OPERATOR, |
| _(PARSE_EXPECTED_OPERATOR_STR)); |
| } |
| |
| /* Make the operator the new root */ |
| *root = oper; |
| } |
| |
| /* If we failed to collect any operands, an event was expected */ |
| if (! *root) |
| nih_return_error (-1, PARSE_EXPECTED_EVENT, |
| _(PARSE_EXPECTED_EVENT_STR)); |
| |
| return 0; |
| } |
| |
| |
| /** |
| * stanza_instance: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an instance stanza from @file, this has an argument specifying |
| * the instance name pattern which is stored in the class's instance member |
| * and expanded before use. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_instance (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->instance) |
| nih_unref (class->instance, class); |
| |
| class->instance = nih_config_next_arg (class, file, len, pos, lineno); |
| if (! class->instance) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| |
| /** |
| * stanza_description: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a description stanza from @file. This stanza expects a single |
| * argument giving a human-readable description of the job which is |
| * stored for later use. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_description (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->description) |
| nih_unref (class->description, class); |
| |
| class->description = nih_config_next_arg (class, file, |
| len, pos, lineno); |
| if (! class->description) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_author: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an author stanza from @file. This stanza expects a single |
| * argument giving a human-readable author name for the job which is |
| * stored for later use. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_author (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->author) |
| nih_unref (class->author, class); |
| |
| class->author = nih_config_next_arg (class, file, len, pos, lineno); |
| if (! class->author) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_version: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a version stanza from @file. This stanza expects a single |
| * argument giving a human-readable version number for the job which is |
| * stored for later use. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_version (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->version) |
| nih_unref (class->version, class); |
| |
| class->version = nih_config_next_arg (class, file, len, pos, lineno); |
| if (! class->version) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| |
| /** |
| * stanza_env: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an env stanza from @file, extracting a single argument of the form |
| * VAR=VALUE. These are stored in the env array, which is increased in |
| * size to accomodate the new value. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_env (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *env = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| env = nih_config_next_arg (NULL, file, len, pos, lineno); |
| if (! env) |
| return -1; |
| |
| if (! nih_str_array_addp (&class->env, class, NULL, env)) |
| nih_return_system_error (-1); |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_export: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an export stanza from @file, extracting one or more arguments |
| * containing environment variable names. These are stored in the export |
| * array, which is increased in size to accomodate the new values. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_export (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char **args = NULL; |
| char **arg; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (! nih_config_has_token (file, len, pos, lineno)) |
| nih_return_error (-1, NIH_CONFIG_EXPECTED_TOKEN, |
| _(NIH_CONFIG_EXPECTED_TOKEN_STR)); |
| |
| args = nih_config_parse_args (NULL, file, len, pos, lineno); |
| if (! args) |
| return -1; |
| |
| for (arg = args; *arg; arg++) |
| if (! nih_str_array_addp (&class->export, class, NULL, *arg)) |
| nih_return_system_error (-1); |
| |
| return 0; |
| } |
| |
| |
| /** |
| * stanza_start: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a start stanza from @file. This stanza expects a second "on" |
| * argument, followed by an event which is allocated as an EventInfo structure |
| * and stored in the start events list of the class. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_start (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "on")) { |
| if (class->start_on) |
| nih_unref (class->start_on, class); |
| |
| class->start_on = parse_on (class, stanza, file, len, |
| &a_pos, &a_lineno); |
| if (! class->start_on) |
| goto finish; |
| |
| ret = 0; |
| |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_stop: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a stop stanza from @file. This stanza expects a second "on" |
| * argument, followed by an event which is allocated as an EventInfo structure |
| * and stored in the stop events list of the class and copied to the instance |
| * later. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_stop (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "on")) { |
| if (class->stop_on) |
| nih_unref (class->stop_on, class); |
| |
| class->stop_on = parse_on (class, stanza, file, len, |
| &a_pos, &a_lineno); |
| if (! class->stop_on) |
| goto finish; |
| |
| ret = 0; |
| |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_emits: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an emits stanza from @file. This stanza expects one or more |
| * arguments giving the names of additional events that can be emitted |
| * by this job. These are stored in the emits array, which is increased |
| * in size to accomodate the new values. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_emits (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char **args = NULL; |
| char **arg; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (! nih_config_has_token (file, len, pos, lineno)) |
| nih_return_error (-1, NIH_CONFIG_EXPECTED_TOKEN, |
| _(NIH_CONFIG_EXPECTED_TOKEN_STR)); |
| |
| args = nih_config_parse_args (NULL, file, len, pos, lineno); |
| if (! args) |
| return -1; |
| |
| for (arg = args; *arg; arg++) |
| if (! nih_str_array_addp (&class->emits, class, NULL, *arg)) |
| nih_return_system_error (-1); |
| |
| return 0; |
| } |
| |
| |
| /** |
| * stanza_exec: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an exec stanza from @file by allocating the main job process and |
| * calling parse_exec() to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_exec (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (! class->process[PROCESS_MAIN]) { |
| class->process[PROCESS_MAIN] = process_new (class->process); |
| if (! class->process[PROCESS_MAIN]) |
| nih_return_system_error (-1); |
| } |
| |
| return parse_exec (class->process[PROCESS_MAIN], stanza, |
| file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_script: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a script stanza from @file by allocating the main job process and |
| * calling parse_script() to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_script (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (! class->process[PROCESS_MAIN]) { |
| class->process[PROCESS_MAIN] = process_new (class->process); |
| if (! class->process[PROCESS_MAIN]) |
| nih_return_system_error (-1); |
| } |
| |
| return parse_script (class->process[PROCESS_MAIN], stanza, |
| file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_pre_start: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a pre-start stanza from @file by calling parse_process() |
| * with PROCESS_PRE_START to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_pre_start (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| return parse_process (class, PROCESS_PRE_START, stanza, |
| file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_post_start: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a post-start stanza from @file by calling parse_process() |
| * with PROCESS_POST_START to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_post_start (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| return parse_process (class, PROCESS_POST_START, stanza, |
| file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_pre_stop: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a pre-stop stanza from @file by calling parse_process() |
| * with PROCESS_PRE_STOP to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_pre_stop (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| return parse_process (class, PROCESS_PRE_STOP, stanza, |
| file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_post_stop: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a post-stop stanza from @file by calling parse_process() |
| * with PROCESS_POST_STOP to parse it. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_post_stop (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| return parse_process (class, PROCESS_POST_STOP, stanza, |
| file, len, pos, lineno); |
| } |
| |
| |
| /** |
| * stanza_expect: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an expect stanza from @file. This stanza expects a single argument |
| * single argument giving one of the possible ExpectType enumerations which |
| * sets the class's expect member. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_expect (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "stop")) { |
| class->expect = EXPECT_STOP; |
| } else if (! strcmp (arg, "daemon")) { |
| class->expect = EXPECT_DAEMON; |
| } else if (! strcmp (arg, "fork")) { |
| class->expect = EXPECT_FORK; |
| } else if (! strcmp (arg, "none")) { |
| class->expect = EXPECT_NONE; |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_task: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a task stanza from @file. This sets the task flag for the class, and |
| * takes no further arguments. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_task (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| class->task = TRUE; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| |
| /** |
| * stanza_kill: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a kill stanza from @file, extracting a second-level stanza that |
| * states which value to set from its argument. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_kill (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "timeout")) { |
| nih_local char *timearg = NULL; |
| char *endptr; |
| |
| /* Update error position to the timeout value */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| timearg = nih_config_next_arg (NULL, file, len, |
| &a_pos, &a_lineno); |
| if (! timearg) |
| goto finish; |
| |
| errno = 0; |
| class->kill_timeout = strtol (timearg, &endptr, 10); |
| if (errno || *endptr || (class->kill_timeout < 0)) |
| nih_return_error (-1, PARSE_ILLEGAL_INTERVAL, |
| _(PARSE_ILLEGAL_INTERVAL_STR)); |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| |
| /** |
| * stanza_respawn: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a daemon stanza from @file. This either has no arguments, in |
| * which case it sets the respawn flag for the job, or it has the "limit" |
| * argument and sets the respawn rate limit. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_respawn (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| /* Deal with the no-argument form first */ |
| if (! nih_config_has_token (file, len, pos, lineno)) { |
| class->respawn = TRUE; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| |
| /* Take the next argument, a sub-stanza keyword. */ |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "limit")) { |
| nih_local char *limitarg = NULL; |
| char *endptr; |
| |
| /* Update error position to the limit value */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| /* Parse the limit value */ |
| limitarg = nih_config_next_arg (NULL, file, len, |
| &a_pos, &a_lineno); |
| if (! limitarg) |
| goto finish; |
| |
| if (strcmp (limitarg, "unlimited")) { |
| nih_local char *timearg = NULL; |
| |
| errno = 0; |
| class->respawn_limit = strtol (limitarg, &endptr, 10); |
| if (errno || *endptr || (class->respawn_limit < 0)) |
| nih_return_error (-1, PARSE_ILLEGAL_LIMIT, |
| _(PARSE_ILLEGAL_LIMIT_STR)); |
| |
| /* Update error position to the timeout value */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| /* Parse the timeout value */ |
| timearg = nih_config_next_arg (NULL, file, len, |
| &a_pos, &a_lineno); |
| if (! timearg) |
| goto finish; |
| |
| errno = 0; |
| class->respawn_interval = strtol (timearg, &endptr, 10); |
| if (errno || *endptr || (class->respawn_interval < 0)) |
| nih_return_error (-1, PARSE_ILLEGAL_INTERVAL, |
| _(PARSE_ILLEGAL_INTERVAL_STR)); |
| } else { |
| class->respawn_limit = 0; |
| class->respawn_interval = 0; |
| } |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_normal: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a normal stanza from @file. This stanza expects a single "exit" |
| * argument, followed by one or more arguments giving signal names or |
| * exit codes that the main process can return and be considered to have been |
| * stopped normally. |
| * |
| * Arguments are stored in the normalexit array, and the normalexit_len |
| * value updated. Signals are stored in the higher bytes. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_normal (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_token (NULL, file, len, &a_pos, &a_lineno, |
| NIH_CONFIG_CNLWS, FALSE); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "exit")) { |
| do { |
| unsigned long status; |
| nih_local char *exitarg = NULL; |
| char *endptr; |
| int *new_ne, signum; |
| |
| /* Update error position to the exit status */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| exitarg = nih_config_next_arg (NULL, file, len, |
| &a_pos, &a_lineno); |
| if (! exitarg) |
| goto finish; |
| |
| signum = nih_signal_from_name (exitarg); |
| if (signum < 0) { |
| errno = 0; |
| status = strtoul (exitarg, &endptr, 10); |
| if (errno || *endptr || (status > INT_MAX)) |
| nih_return_error (-1, PARSE_ILLEGAL_EXIT, |
| _(PARSE_ILLEGAL_EXIT_STR)); |
| } else { |
| status = signum << 8; |
| } |
| |
| new_ne = nih_realloc (class->normalexit, class, |
| sizeof (int) * (class->normalexit_len + 1)); |
| if (! new_ne) |
| nih_return_system_error (-1); |
| |
| class->normalexit = new_ne; |
| class->normalexit[class->normalexit_len++] = (int) status; |
| } while (nih_config_has_token (file, len, &a_pos, &a_lineno)); |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| |
| /** |
| * stanza_console: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a console stanza from @file, extracting a single argument that |
| * specifies where console output should be sent. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_console (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "none")) { |
| class->console = CONSOLE_NONE; |
| } else if (! strcmp (arg, "output")) { |
| class->console = CONSOLE_OUTPUT; |
| } else if (! strcmp (arg, "owner")) { |
| class->console = CONSOLE_OWNER; |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| |
| /** |
| * stanza_umask: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a umask stanza from @file, extracting a single argument containing |
| * a process file creation mask. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_umask (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| char *endptr; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| errno = 0; |
| class->umask = (mode_t)strtoul (arg, &endptr, 8); |
| if (errno || *endptr || (class->umask & ~0777)) |
| nih_return_error (-1, PARSE_ILLEGAL_UMASK, |
| _(PARSE_ILLEGAL_UMASK_STR)); |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_nice: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a nice stanza from @file, extracting a single argument containing |
| * a process priority. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_nice (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| char *endptr; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| errno = 0; |
| class->nice = (int)strtol (arg, &endptr, 10); |
| if (errno || *endptr || (class->nice < -20) || (class->nice > 19)) |
| nih_return_error (-1, PARSE_ILLEGAL_NICE, |
| _(PARSE_ILLEGAL_NICE_STR)); |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_oom: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse an oom stanza from @file, extracting a single argument containing |
| * a OOM killer adjustment (which may be "never" for the magic -17 value). |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_oom (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_local char *arg = NULL; |
| char *endptr; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "never")) { |
| class->oom_adj = -17; |
| } else { |
| errno = 0; |
| class->oom_adj = (int)strtol (arg, &endptr, 10); |
| if (errno || *endptr || (class->oom_adj < -17) || (class->oom_adj > 15)) |
| nih_return_error (-1, PARSE_ILLEGAL_OOM, |
| _(PARSE_ILLEGAL_OOM_STR)); |
| } |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_limit: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a limit stanza from @file, extracting a second-level stanza that |
| * states which limit to set from its two following arguments. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_limit (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| int resource; |
| nih_local char *arg = NULL, *softarg = NULL, *hardarg = NULL; |
| char *endptr; |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| a_pos = *pos; |
| a_lineno = (lineno ? *lineno : 1); |
| |
| arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! arg) |
| goto finish; |
| |
| if (! strcmp (arg, "as")) { |
| resource = RLIMIT_AS; |
| } else if (! strcmp (arg, "core")) { |
| resource = RLIMIT_CORE; |
| } else if (! strcmp (arg, "cpu")) { |
| resource = RLIMIT_CPU; |
| } else if (! strcmp (arg, "data")) { |
| resource = RLIMIT_DATA; |
| } else if (! strcmp (arg, "fsize")) { |
| resource = RLIMIT_FSIZE; |
| } else if (! strcmp (arg, "memlock")) { |
| resource = RLIMIT_MEMLOCK; |
| } else if (! strcmp (arg, "msgqueue")) { |
| resource = RLIMIT_MSGQUEUE; |
| } else if (! strcmp (arg, "nice")) { |
| resource = RLIMIT_NICE; |
| } else if (! strcmp (arg, "nofile")) { |
| resource = RLIMIT_NOFILE; |
| } else if (! strcmp (arg, "nproc")) { |
| resource = RLIMIT_NPROC; |
| } else if (! strcmp (arg, "rss")) { |
| resource = RLIMIT_RSS; |
| } else if (! strcmp (arg, "rtprio")) { |
| resource = RLIMIT_RTPRIO; |
| } else if (! strcmp (arg, "sigpending")) { |
| resource = RLIMIT_SIGPENDING; |
| } else if (! strcmp (arg, "stack")) { |
| resource = RLIMIT_STACK; |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| |
| if (! class->limits[resource]) { |
| class->limits[resource] = nih_new (class, struct rlimit); |
| if (! class->limits[resource]) |
| nih_return_system_error (-1); |
| } |
| |
| /* Update error position to the soft limit value */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| /* Parse the soft limit value */ |
| softarg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! softarg) |
| goto finish; |
| |
| if (strcmp (softarg, "unlimited")) { |
| errno = 0; |
| class->limits[resource]->rlim_cur = strtoul (softarg, &endptr, |
| 10); |
| if (errno || *endptr) |
| nih_return_error (-1, PARSE_ILLEGAL_LIMIT, |
| _(PARSE_ILLEGAL_LIMIT_STR)); |
| } else { |
| class->limits[resource]->rlim_cur = RLIM_INFINITY; |
| } |
| |
| /* Update error position to the hard limit value */ |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| /* Parse the hard limit value */ |
| hardarg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno); |
| if (! hardarg) |
| goto finish; |
| |
| if (strcmp (hardarg, "unlimited")) { |
| errno = 0; |
| class->limits[resource]->rlim_max = strtoul (hardarg, &endptr, |
| 10); |
| if (errno || *endptr) |
| nih_return_error (-1, PARSE_ILLEGAL_LIMIT, |
| _(PARSE_ILLEGAL_LIMIT_STR)); |
| } else { |
| class->limits[resource]->rlim_max = RLIM_INFINITY; |
| } |
| |
| ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| *lineno = a_lineno; |
| |
| return ret; |
| } |
| |
| /** |
| * stanza_chroot: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a chroot stanza from @file, extracting a single argument |
| * containing a directory name. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_chroot (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->chroot) |
| nih_unref (class->chroot, class); |
| |
| class->chroot = nih_config_next_arg (class, file, len, pos, lineno); |
| if (! class->chroot) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |
| |
| /** |
| * stanza_chdir: |
| * @class: job class being parsed, |
| * @stanza: stanza found, |
| * @file: file or string to parse, |
| * @len: length of @file, |
| * @pos: offset within @file, |
| * @lineno: line number. |
| * |
| * Parse a chdir stanza from @file, extracting a single argument |
| * containing a directory name. |
| * |
| * Returns: zero on success, negative value on error. |
| **/ |
| static int |
| stanza_chdir (JobClass *class, |
| NihConfigStanza *stanza, |
| const char *file, |
| size_t len, |
| size_t *pos, |
| size_t *lineno) |
| { |
| nih_assert (class != NULL); |
| nih_assert (stanza != NULL); |
| nih_assert (file != NULL); |
| nih_assert (pos != NULL); |
| |
| if (class->chdir) |
| nih_unref (class->chdir, class); |
| |
| class->chdir = nih_config_next_arg (class, file, len, pos, lineno); |
| if (! class->chdir) |
| return -1; |
| |
| return nih_config_skip_comment (file, len, pos, lineno); |
| } |