mirror of
https://github.com/troglobit/finit.git
synced 2026-10-06 07:43:43 +07:00
Merge pull request #445 from troglobit/space-in-argval
Space in argval Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -59,6 +59,8 @@ static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||
|
||||
static int stop(svc_t *svc, void *user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
@@ -72,6 +74,8 @@ static int stop(svc_t *svc, void *user_data)
|
||||
|
||||
static int start(svc_t *svc, void *user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
@@ -105,6 +109,8 @@ static int restart(svc_t *svc, void *user_data)
|
||||
|
||||
static int reload(svc_t *svc, void *user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
@@ -149,6 +155,8 @@ static int missing(char *job, char *id, void *user_data)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
(void)user_data;
|
||||
|
||||
if (!job)
|
||||
job = "";
|
||||
if (!id)
|
||||
@@ -228,6 +236,8 @@ struct wq emergency = { .cb = bypass_shutdown };
|
||||
|
||||
static void bypass_shutdown(void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
|
||||
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
||||
do_shutdown(halt);
|
||||
}
|
||||
@@ -332,6 +342,8 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
int sd, lvl;
|
||||
svc_t *svc;
|
||||
|
||||
(void)arg;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): api socket %d invalid.", __func__, w->fd);
|
||||
goto error;
|
||||
|
||||
@@ -88,6 +88,12 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
||||
}
|
||||
*val++ = 0;
|
||||
|
||||
/* unquote value, if quoted */
|
||||
if (unquote(&val, NULL)) {
|
||||
errx(1, "Syntax error, unterminated quote in %s/%s.%s=%s", path, ctrl, prop, val);
|
||||
return;
|
||||
}
|
||||
|
||||
/* disallow sneaky relative paths */
|
||||
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||
@@ -261,6 +267,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
(void)arg;
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): inotify socket %d invalid.", __func__, w->fd);
|
||||
return;
|
||||
|
||||
@@ -202,6 +202,9 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
||||
{
|
||||
const char *cond, *ptr;
|
||||
|
||||
(void)sb;
|
||||
(void)tflag;
|
||||
|
||||
if (ftw->level == 0)
|
||||
return 1;
|
||||
|
||||
@@ -390,6 +393,8 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
|
||||
{
|
||||
char *nm;
|
||||
|
||||
(void)sb;
|
||||
|
||||
if (ftw->level == 0)
|
||||
return 1;
|
||||
|
||||
|
||||
+38
-16
@@ -490,14 +490,16 @@ void conf_save_service(int type, char *cfg, char *file)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
||||
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
||||
* the conf_reset_env() function.
|
||||
/**
|
||||
* conf_parse_env - Parse a key=value line
|
||||
* @line: Line buffer without newline
|
||||
* @value: Whitespace trimmed value
|
||||
*
|
||||
* Returns:
|
||||
* %NULL on error, otherwise a whitespace trimmed key.
|
||||
*/
|
||||
static void parse_env(char *line)
|
||||
char *conf_parse_env(char *line, char **value)
|
||||
{
|
||||
struct env_entry *node;
|
||||
char *key, *val, *end;
|
||||
|
||||
/* skip any leading whitespace */
|
||||
@@ -519,7 +521,7 @@ static void parse_env(char *line)
|
||||
|
||||
val = strchr(key, '=');
|
||||
if (!val)
|
||||
return;
|
||||
return NULL;
|
||||
*val++ = 0;
|
||||
|
||||
/* strip leading whitespace from value */
|
||||
@@ -527,14 +529,8 @@ static void parse_env(char *line)
|
||||
val++;
|
||||
|
||||
/* unquote value, if quoted */
|
||||
if (val[0] == '"' || val[0] == '\'') {
|
||||
char q = val[0];
|
||||
|
||||
if (*end == q) {
|
||||
val = &val[1];
|
||||
*end = 0;
|
||||
}
|
||||
}
|
||||
unquote(&val, end);
|
||||
*value = val;
|
||||
|
||||
/* find end of key */
|
||||
end = key;
|
||||
@@ -561,18 +557,42 @@ static void parse_env(char *line)
|
||||
end++;
|
||||
if (*end != 0) {
|
||||
warnx("'%s=%s': not a valid identifier", key, val);
|
||||
return; /* invalid key */
|
||||
return NULL; /* invalid key */
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
||||
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
||||
* the conf_reset_env() function.
|
||||
*/
|
||||
static void parse_env(char *line)
|
||||
{
|
||||
struct env_entry *node;
|
||||
char *key, *val;
|
||||
|
||||
key = conf_parse_env(line, &val);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
dbg("Global env '%s'='%s'", key, val);
|
||||
setenv(key, val, 1);
|
||||
|
||||
node = malloc(sizeof(*node));
|
||||
if (!node) {
|
||||
nomem:
|
||||
err(1, "Out of memory cannot track env vars");
|
||||
return;
|
||||
}
|
||||
|
||||
node->name = strdup(key);
|
||||
if (!node->name) {
|
||||
free(node);
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
TAILQ_INSERT_HEAD(&env_list, node, link);
|
||||
}
|
||||
|
||||
@@ -1542,6 +1562,8 @@ static int conf_iwatch_read(int fd)
|
||||
|
||||
static void conf_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): iwatch socket %d invalid.", __func__, w->fd);
|
||||
return;
|
||||
|
||||
@@ -47,6 +47,7 @@ void conf_saverc (void);
|
||||
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
|
||||
void conf_save_service (int type, char *cfg, char *file);
|
||||
void conf_parse_cmdline (int argc, char *argv[]);
|
||||
char *conf_parse_env (char *line, char **val);
|
||||
int conf_parse_runlevels (char *runlevels);
|
||||
void conf_parse_cond (svc_t *svc, char *cond);
|
||||
|
||||
|
||||
+10
-1
@@ -77,7 +77,7 @@ void devmon_add_cond(const char *cond)
|
||||
struct dev_node *node;
|
||||
|
||||
if (!cond || strncmp(cond, "dev/", 4)) {
|
||||
dbg("no match");
|
||||
// dbg("no match %s", cond ?: "<NIL>");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -164,6 +164,8 @@ static void devmon_scandir(struct iwatch *iw, char *dir, int len)
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
(void)iw;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/*", dir);
|
||||
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||
if (rc && rc != GLOB_NOMATCH)
|
||||
@@ -207,6 +209,13 @@ static void devmon_cb(uev_t *w, void *arg, int events)
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
(void)arg;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in devmon watcher");
|
||||
return;
|
||||
}
|
||||
|
||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
|
||||
@@ -293,6 +293,8 @@ static size_t print_timestamp(char *buf, size_t len)
|
||||
sscanf(buf, "%f %f", &stamp, &dummy);
|
||||
return snprintf(buf, len, "[ %.6f ]", stamp);
|
||||
#else
|
||||
(void)buf;
|
||||
(void)len;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#define SYSLOG_NAMES
|
||||
#include <syslog.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "log.h"
|
||||
@@ -106,6 +109,73 @@ static const char *l2s(int prio)
|
||||
return "UNK";
|
||||
}
|
||||
|
||||
static int s2f(const char *str)
|
||||
{
|
||||
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||
if (string_match(facilitynames[i].c_name, str))
|
||||
return facilitynames[i].c_val;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int s2l(const char *str)
|
||||
{
|
||||
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||
if (string_match(prioritynames[i].c_name, str))
|
||||
return prioritynames[i].c_val;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse syslog facility.priority strings into their numerical values
|
||||
* using arrays defined in <syslog.h>. Note, the 'prio' argument may
|
||||
* be one of:
|
||||
*
|
||||
* - facility.level
|
||||
* - facility
|
||||
* - level
|
||||
*
|
||||
* It is up to the callee to assign defaults to 'facility' and 'level'
|
||||
* before calling this function. If There is any match the respective
|
||||
* facility or level will be assigned and this function returns OK.
|
||||
*/
|
||||
int log_parse(char *prio, int *facility, int *level)
|
||||
{
|
||||
char *fac = prio, *lvl;
|
||||
int f = -1;
|
||||
int l = -1;
|
||||
|
||||
if (!prio || !facility || !level)
|
||||
return -1;
|
||||
|
||||
lvl = strchr(prio, '.');
|
||||
if (lvl) {
|
||||
*lvl = 0;
|
||||
lvl++;
|
||||
}
|
||||
|
||||
if (lvl && *lvl)
|
||||
l = s2l(lvl);
|
||||
|
||||
f = s2f(fac);
|
||||
if (l < 0)
|
||||
l = s2l(fac);
|
||||
|
||||
if (l < 0 && f <= 0)
|
||||
return -1;
|
||||
|
||||
if (l <= LOG_DEBUG)
|
||||
*level = l;
|
||||
|
||||
if (f <= LOG_LOCAL7)
|
||||
*facility = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||
* and continue logging as a regular daemon.
|
||||
|
||||
@@ -78,6 +78,7 @@ void log_init (void);
|
||||
void log_exit (void);
|
||||
|
||||
void log_debug(void);
|
||||
int log_parse(char *prio, int *facility, int *level);
|
||||
|
||||
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
@@ -320,6 +320,8 @@ static int init_plugins(uev_ctx_t *ctx)
|
||||
plugin_t *p, *tmp;
|
||||
int fail = 0;
|
||||
|
||||
(void)ctx;
|
||||
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (plugin_io_init(p))
|
||||
fail++;
|
||||
|
||||
+95
-66
@@ -244,6 +244,9 @@ static void fallback_logger(char *ident, char *prio)
|
||||
int level = LOG_NOTICE;
|
||||
char buf[256];
|
||||
|
||||
strlcpy(buf, prio, sizeof(buf));
|
||||
log_parse(buf, &facility, &level);
|
||||
|
||||
prctl(PR_SET_NAME, "finitlog", 0, 0, 0);
|
||||
openlog(ident, LOG_NOWAIT | LOG_PID, facility);
|
||||
while ((fgets(buf, sizeof(buf), stdin)))
|
||||
@@ -327,6 +330,11 @@ static int lredirect(svc_t *svc)
|
||||
/* Default syslog identity name[:id] */
|
||||
tag = svc_ident(svc, buf, sizeof(buf));
|
||||
|
||||
if (svc->log.ident[0])
|
||||
tag = svc->log.ident;
|
||||
if (svc->log.prio[0])
|
||||
prio = svc->log.prio;
|
||||
|
||||
if (!have_sysklogd && !whichp(_PATH_LOGIT)) {
|
||||
logit(LOG_INFO, _PATH_LOGIT " missing, using syslog for %s instead", svc->name);
|
||||
fallback_logger(tag, prio);
|
||||
@@ -352,11 +360,6 @@ static int lredirect(svc_t *svc)
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (svc->log.ident[0])
|
||||
tag = svc->log.ident;
|
||||
if (svc->log.prio[0])
|
||||
prio = svc->log.prio;
|
||||
|
||||
if (have_sysklogd) {
|
||||
char pid[16];
|
||||
|
||||
@@ -425,11 +428,13 @@ static void source_env(svc_t *svc)
|
||||
|
||||
line = buf;
|
||||
while (fgets(line, LINE_SIZE, fp)) {
|
||||
char *key = chomp(line);
|
||||
wordexp_t we = { 0 };
|
||||
char *value, *end;
|
||||
char *key, *value;
|
||||
size_t i;
|
||||
|
||||
/* Trim newline */
|
||||
key = chomp(line);
|
||||
|
||||
/* skip any leading whitespace */
|
||||
while (isspace(*key))
|
||||
key++;
|
||||
@@ -438,64 +443,9 @@ static void source_env(svc_t *svc)
|
||||
if (*key == '#' || *key == ';')
|
||||
continue;
|
||||
|
||||
/* find end of line */
|
||||
end = key;
|
||||
while (*end)
|
||||
end++;
|
||||
|
||||
/* strip trailing whitespace */
|
||||
if (end > key) {
|
||||
end--;
|
||||
while (isspace(*end))
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
value = strchr(key, '=');
|
||||
if (!value)
|
||||
key = conf_parse_env(key, &value);
|
||||
if (!key)
|
||||
continue;
|
||||
*value++ = 0;
|
||||
|
||||
/* strip leading whitespace from value */
|
||||
while (isspace(*value))
|
||||
value++;
|
||||
|
||||
/* unquote value, if quoted */
|
||||
if (value[0] == '"' || value[0] == '\'') {
|
||||
char q = value[0];
|
||||
|
||||
if (*end == q) {
|
||||
value = &value[1];
|
||||
*end = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* find end of key */
|
||||
end = key;
|
||||
while (*end)
|
||||
end++;
|
||||
|
||||
/* strip trailing whitespace */
|
||||
if (end > key) {
|
||||
end--;
|
||||
while (isspace(*end))
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
/* strip any leading 'set ' */
|
||||
end = key;
|
||||
if (!strncmp(key, "set", 3))
|
||||
end += 3;
|
||||
|
||||
/* check key, no spaces allowed */
|
||||
while (*end && isspace(*end))
|
||||
end++;
|
||||
key = end;
|
||||
while (*end && !isspace(*end))
|
||||
end++;
|
||||
if (*end != 0) {
|
||||
warnx("'%s=%s': not a valid identifier", key, value);
|
||||
continue; /* invalid key */
|
||||
}
|
||||
|
||||
if (wordexp(value, &we, 0)) {
|
||||
setenv(key, value, 1);
|
||||
@@ -1190,6 +1140,83 @@ void service_runlevel(int newlevel)
|
||||
networking(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse run/task/service arguments with support for quoted strings, both
|
||||
* single and double quotes to allow arguments containing spaces.
|
||||
*
|
||||
* Returns next argument or NULL if end of line
|
||||
* Updates *line to point past the parsed argument
|
||||
*/
|
||||
static char *parse_args(char **line)
|
||||
{
|
||||
char *start, *end = NULL, *arg;
|
||||
char in_quote = 0;
|
||||
int has_colon = 0;
|
||||
|
||||
if (!line || !*line)
|
||||
return NULL;
|
||||
|
||||
/* Skip leading whitespace */
|
||||
while (**line && (**line == ' ' || **line == '\t'))
|
||||
(*line)++;
|
||||
|
||||
if (!**line)
|
||||
return NULL;
|
||||
|
||||
start = *line;
|
||||
|
||||
/* Parse the token */
|
||||
while (**line) {
|
||||
if (in_quote) {
|
||||
if (**line == in_quote) {
|
||||
/* End quote found */
|
||||
in_quote = 0;
|
||||
}
|
||||
} else {
|
||||
if (**line == '\'' || **line == '"') {
|
||||
/* Start quote */
|
||||
in_quote = **line;
|
||||
} else if (**line == ':') {
|
||||
/* Found colon - this might be key:value format */
|
||||
has_colon = 1;
|
||||
} else if (**line == ' ' || **line == '\t') {
|
||||
/* Whitespace - check if we're in key:value mode */
|
||||
if (has_colon) {
|
||||
/* Look ahead to see if there's a comma after whitespace */
|
||||
char *lookahead = *line;
|
||||
while (*lookahead && (*lookahead == ' ' || *lookahead == '\t'))
|
||||
lookahead++;
|
||||
if (*lookahead == ',') {
|
||||
/* Continue parsing - this space is part of the token */
|
||||
(*line)++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* End token at whitespace */
|
||||
end = *line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
(*line)++;
|
||||
}
|
||||
|
||||
/* Set end if we reached end of string */
|
||||
if (!end)
|
||||
end = *line;
|
||||
|
||||
/* Null terminate the argument */
|
||||
if (end > start) {
|
||||
arg = start;
|
||||
if (*end) {
|
||||
*end = '\0';
|
||||
*line = end + 1;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* log:/path/to/logfile,priority:facility.level,tag:ident
|
||||
*/
|
||||
@@ -1564,7 +1591,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
}
|
||||
}
|
||||
|
||||
cmd = strtok_r(line, " \t", &args);
|
||||
args = line;
|
||||
cmd = parse_args(&args);
|
||||
if (!cmd) {
|
||||
incomplete:
|
||||
errx(1, "Incomplete service '%s', cannot register", cfg);
|
||||
@@ -1644,7 +1672,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
break;
|
||||
|
||||
/* Check if valid command follows... */
|
||||
cmd = strtok_r(NULL, " ", &args);
|
||||
cmd = parse_args(&args);
|
||||
if (!cmd)
|
||||
goto incomplete;
|
||||
}
|
||||
@@ -2798,6 +2826,7 @@ void service_step_all(int types)
|
||||
|
||||
void service_worker(void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
service_step_all(SVC_TYPE_RESPAWN | SVC_TYPE_RUNTASK);
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@ static int status_cb(int pid, void *data)
|
||||
{
|
||||
int *has_proc = (int *)data;
|
||||
|
||||
(void)pid;
|
||||
*has_proc = 1;
|
||||
|
||||
return 1;
|
||||
@@ -425,6 +426,8 @@ void do_shutdown(shutop_t op)
|
||||
*/
|
||||
static void sighup_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -451,6 +454,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
||||
*/
|
||||
static void sigint_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)w;
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -467,6 +473,9 @@ static void sigint_cb(uev_t *w, void *arg, int events)
|
||||
*/
|
||||
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)w;
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -481,6 +490,8 @@ static void sigpwr_cb(uev_t *w, void *arg, int events)
|
||||
*/
|
||||
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -502,6 +513,9 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||
*/
|
||||
static void sigusr2_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)w;
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -522,6 +536,9 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
|
||||
*/
|
||||
static void sigterm_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
(void)w;
|
||||
(void)arg;
|
||||
|
||||
dbg("...");
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
@@ -545,6 +562,9 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
(void)w;
|
||||
(void)arg;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
errx(1, "Unrecoverable error in signal watcher");
|
||||
return;
|
||||
@@ -601,6 +621,9 @@ const char *sig_name(int signo)
|
||||
*/
|
||||
static void chld_handler(int sig, siginfo_t *info, void *ctx)
|
||||
{
|
||||
(void)sig;
|
||||
(void)info;
|
||||
(void)ctx;
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,9 @@ static int parse_mm(char *arg, int *major, int *minor)
|
||||
|
||||
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||
{
|
||||
(void)sb;
|
||||
(void)tflag;
|
||||
|
||||
if (ftw->level == 0)
|
||||
return 1;
|
||||
|
||||
|
||||
+21
@@ -165,6 +165,27 @@ static inline void hexdump(const char *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/* drop quotes from a string at point, if any */
|
||||
static inline int unquote(char **str, char *end)
|
||||
{
|
||||
char *ptr = *str;
|
||||
|
||||
/* unquote value, if quoted */
|
||||
if (ptr[0] == '"' || ptr[0] == '\'') {
|
||||
char q = ptr[0];
|
||||
|
||||
if (!end && !(end = strchr(&ptr[1], q)))
|
||||
return -1;
|
||||
|
||||
if (*end == q) {
|
||||
*str = &ptr[1];
|
||||
*end = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* FINIT_UTIL_H_ */
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user