service: add options RestartPreventExitStatus and SuccessExitStatus

In some cases, like wrong configuration, restarting after error
does not help, so administrator can specify statuses by RestartPreventExitStatus
which will not cause restart of a service.

Sometimes you have non-standart exit status, so this can be specified
by SuccessfulExitStatus.
This commit is contained in:
Lukas Nykryn
2012-08-14 14:46:03 +02:00
committed by Lennart Poettering
parent d98cc1f29f
commit 96342de68d
18 changed files with 154 additions and 16 deletions
+70
View File
@@ -32,6 +32,8 @@
#include "log.h"
#include "utf8.h"
#include "path-util.h"
#include "set.h"
#include "exit-status.h"
int config_item_table_lookup(
void *table,
@@ -933,3 +935,71 @@ int config_parse_level(
*o = (*o & LOG_FACMASK) | x;
return 0;
}
int config_parse_set_status(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char *w;
size_t l;
char *state;
int r;
ExitStatusSet *status_set = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
FOREACH_WORD(w, l, rvalue, state) {
int val;
char *temp = strndup(w, l);
if (!temp)
return log_oom();
r = safe_atoi(temp, &val);
if (r < 0) {
val = signal_from_string_try_harder(temp);
free(temp);
if (val > 0) {
if (!status_set->signal) {
status_set->signal = set_new(trivial_hash_func, trivial_compare_func);
if (!status_set->signal)
return log_oom();
}
r = set_put(status_set->signal, INT_TO_PTR(val));
if (r < 0) {
log_error("[%s:%u] Unable to store: %s", filename, line, w);
return r;
}
} else {
log_error("[%s:%u] Failed to parse value: %s", filename, line, w);
return r;
}
} else {
free(temp);
if(val < 0 || val > 255)
log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
else {
if (!status_set->code) {
status_set->code = set_new(trivial_hash_func, trivial_compare_func);
if (!status_set->code)
return log_oom();
}
r = set_put(status_set->code, INT_TO_PTR(val));
if (r < 0) {
log_error("[%s:%u] Unable to store: %s", filename, line, w);
return r;
}
}
}
}
return 0;
}
+1
View File
@@ -105,6 +105,7 @@ int config_parse_nsec(const char *filename, unsigned line, const char *section,
int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_set_status(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function( \
+11 -5
View File
@@ -23,6 +23,8 @@
#include <sys/wait.h>
#include "exit-status.h"
#include "set.h"
#include "macro.h"
const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
@@ -158,10 +160,12 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
}
bool is_clean_exit(int code, int status) {
bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
if (code == CLD_EXITED)
return status == 0;
return status == 0 ||
(success_status &&
set_contains(success_status->code, INT_TO_PTR(status)));
/* If a daemon does not implement handlers for some of the
* signals that's not considered an unclean shutdown */
@@ -170,14 +174,16 @@ bool is_clean_exit(int code, int status) {
status == SIGHUP ||
status == SIGINT ||
status == SIGTERM ||
status == SIGPIPE;
status == SIGPIPE ||
(success_status &&
set_contains(success_status->signal, INT_TO_PTR(status)));
return false;
}
bool is_clean_exit_lsb(int code, int status) {
bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) {
if (is_clean_exit(code, status))
if (is_clean_exit(code, status, success_status))
return true;
return
+8 -3
View File
@@ -22,7 +22,7 @@
***/
#include <stdbool.h>
#include "set.h"
typedef enum ExitStatus {
/* EXIT_SUCCESS defined by libc */
/* EXIT_FAILURE defined by libc */
@@ -77,7 +77,12 @@ typedef enum ExitStatusLevel {
EXIT_STATUS_FULL = EXIT_STATUS_LSB
} ExitStatusLevel;
typedef struct ExitStatusSet {
Set *code;
Set *signal;
} ExitStatusSet;
const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level);
bool is_clean_exit(int code, int status);
bool is_clean_exit_lsb(int code, int status);
bool is_clean_exit(int code, int status, ExitStatusSet *success_status);
bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status);
+15
View File
@@ -378,6 +378,21 @@ void* hashmap_get(Hashmap *h, const void *key) {
return e->value;
}
bool hashmap_contains(Hashmap *h, const void *key) {
unsigned hash;
struct hashmap_entry *e;
if (!h)
return false;
hash = h->hash_func(key) % NBUCKETS;
if (!(e = hash_scan(h, hash, key)))
return false;
return true;
}
void* hashmap_remove(Hashmap *h, const void *key) {
struct hashmap_entry *e;
unsigned hash;
+1
View File
@@ -53,6 +53,7 @@ int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t
int hashmap_put(Hashmap *h, const void *key, void *value);
int hashmap_replace(Hashmap *h, const void *key, void *value);
void* hashmap_get(Hashmap *h, const void *key);
bool hashmap_contains(Hashmap *h, const void *key);
void* hashmap_remove(Hashmap *h, const void *key);
void* hashmap_remove_value(Hashmap *h, const void *key, void *value);
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
+4
View File
@@ -57,6 +57,10 @@ void *set_get(Set *s, void *value) {
return hashmap_get(MAKE_HASHMAP(s), value);
}
bool set_contains(Set *s, void *value) {
return hashmap_contains(MAKE_HASHMAP(s), value);
}
void *set_remove(Set *s, void *value) {
return hashmap_remove(MAKE_HASHMAP(s), value);
}
+1
View File
@@ -40,6 +40,7 @@ int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_
int set_put(Set *s, void *value);
int set_replace(Set *s, void *value);
void *set_get(Set *s, void *value);
bool set_contains(Set *s, void *value);
void *set_remove(Set *s, void *value);
int set_remove_and_put(Set *s, void *old_value, void *new_value);
+1 -1
View File
@@ -4357,7 +4357,7 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
}
if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
if (!is_clean_exit(si.si_code, si.si_status)) {
if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
if (si.si_code == CLD_EXITED)
log_error("%s exited with exit status %i.", path, si.si_status);
else