X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=bef87304e6ce20958297cc91391b1dc4ef65cf11;hb=2040ccf171404b709acb0ecf1d1f17b87c5d05f0;hp=dbdb69270de7a7db7163397ff5df9a2e08f4ef17;hpb=da92ca5eb506d513033e0c7a85daf25a7e1c9d0e;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index dbdb69270..bef87304e 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -280,6 +280,14 @@ int parse_uid(const char *s, uid_t* ret_uid) { if ((unsigned long) uid != ul) return -ERANGE; + /* Some libc APIs use (uid_t) -1 as special placeholder */ + if (uid == (uid_t) 0xFFFFFFFF) + return -ENXIO; + + /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ + if (uid == (uid_t) 0xFFFF) + return -ENXIO; + *ret_uid = uid; return 0; } @@ -1248,7 +1256,7 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre a = unhexchar(f[1]); b = unhexchar(f[2]); - if (a < 0 || b < 0) { + if (a < 0 || b < 0 || (a == 0 && b == 0)) { /* Invalid escape code, let's take it literal then */ *(t++) = '\\'; *(t++) = 'x'; @@ -1275,7 +1283,7 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre b = unoctchar(f[1]); c = unoctchar(f[2]); - if (a < 0 || b < 0 || c < 0) { + if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) { /* Invalid escape code, let's take it literal then */ *(t++) = '\\'; *(t++) = f[0]; @@ -1440,7 +1448,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { } int close_all_fds(const int except[], unsigned n_except) { - DIR *d; + _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r = 0; @@ -1495,7 +1503,6 @@ int close_all_fds(const int except[], unsigned n_except) { } } - closedir(d); return r; } @@ -1559,8 +1566,7 @@ int chvt(int vt) { int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { struct termios old_termios, new_termios; - char c; - char line[LINE_MAX]; + char c, line[LINE_MAX]; assert(f); assert(ret); @@ -1597,12 +1603,14 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { } } - if (t != (usec_t) -1) + if (t != (usec_t) -1) { if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) return -ETIMEDOUT; + } + errno = 0; if (!fgets(line, sizeof(line), f)) - return -EIO; + return errno ? -errno : -EIO; truncate_nl(line); @@ -1616,7 +1624,8 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { return 0; } -int ask(char *ret, const char *replies, const char *text, ...) { +int ask_char(char *ret, const char *replies, const char *text, ...) { + int r; assert(ret); assert(replies); @@ -1625,7 +1634,6 @@ int ask(char *ret, const char *replies, const char *text, ...) { for (;;) { va_list ap; char c; - int r; bool need_nl = true; if (on_tty()) @@ -1664,6 +1672,49 @@ int ask(char *ret, const char *replies, const char *text, ...) { } } +int ask_string(char **ret, const char *text, ...) { + assert(ret); + assert(text); + + for (;;) { + char line[LINE_MAX]; + va_list ap; + + if (on_tty()) + fputs(ANSI_HIGHLIGHT_ON, stdout); + + va_start(ap, text); + vprintf(text, ap); + va_end(ap); + + if (on_tty()) + fputs(ANSI_HIGHLIGHT_OFF, stdout); + + fflush(stdout); + + errno = 0; + if (!fgets(line, sizeof(line), stdin)) + return errno ? -errno : -EIO; + + if (!endswith(line, "\n")) + putchar('\n'); + else { + char *s; + + if (isempty(line)) + continue; + + truncate_nl(line); + s = strdup(line); + if (!s) + return -ENOMEM; + + *ret = s; + return 0; + } + } +} + int reset_terminal_fd(int fd, bool switch_to_text) { struct termios termios; int r = 0; @@ -3475,6 +3526,17 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) { } } +/* + * Return values: + * < 0 : wait_for_terminate() failed to get the state of the + * process, the process was terminated by a signal, or + * failed for an unknown reason. + * >=0 : The process terminated normally, and its exit code is + * returned. + * + * That is, success is indicated by a return value of zero, and an + * error is indicated by a non-zero value. + */ int wait_for_terminate_and_warn(const char *name, pid_t pid) { int r; siginfo_t status; @@ -3733,7 +3795,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { return endswith(de->d_name, suffix); } -void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) { +void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[], char *env[]) { pid_t executor_pid; int r; @@ -3764,6 +3826,14 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + if (!strv_isempty(env)) { + char **i; + + STRV_FOREACH(i, env) + putenv(*i); + } + + if (!d) { d = _d = opendir(directory); if (!d) { @@ -3788,7 +3858,8 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv if (!dirent_is_file(de)) continue; - if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) { + path = strjoin(directory, "/", de->d_name, NULL); + if (!path) { log_oom(); _exit(EXIT_FAILURE); } @@ -3957,6 +4028,21 @@ char* hostname_cleanup(char *s, bool lowercase) { return s; } +bool machine_name_is_valid(const char *s) { + + if (!hostname_is_valid(s)) + return false; + + /* Machine names should be useful hostnames, but also be + * useful in unit names, hence we enforce a stricter length + * limitation. */ + + if (strlen(s) > 64) + return false; + + return true; +} + int pipe_eof(int fd) { struct pollfd pollfd = { .fd = fd, @@ -5208,8 +5294,8 @@ int get_home_dir(char **_h) { assert(_h); /* Take the user specified one */ - e = getenv("HOME"); - if (e) { + e = secure_getenv("HOME"); + if (e && path_is_absolute(e)) { h = strdup(e); if (!h) return -ENOMEM; @@ -5316,13 +5402,14 @@ bool filename_is_safe(const char *p) { bool string_is_safe(const char *p) { const char *t; - assert(p); + if (!p) + return false; for (t = p; *t; t++) { if (*t > 0 && *t < ' ') return false; - if (strchr("\\\"\'", *t)) + if (strchr("\\\"\'\0x7f", *t)) return false; } @@ -5330,18 +5417,25 @@ bool string_is_safe(const char *p) { } /** - * Check if a string contains control characters. - * Spaces and tabs are not considered control characters. + * Check if a string contains control characters. If 'ok' is non-NULL + * it may be a string containing additional CCs to be considered OK. */ -bool string_has_cc(const char *p) { +bool string_has_cc(const char *p, const char *ok) { const char *t; assert(p); - for (t = p; *t; t++) - if (*t > 0 && *t < ' ' && *t != '\t') + for (t = p; *t; t++) { + if (ok && strchr(ok, *t)) + return false; + + if (*t > 0 && *t < ' ') return true; + if (*t == 127) + return true; + } + return false; } @@ -6714,3 +6808,18 @@ char *tempfn_random(const char *p) { return t; } + +/* make sure the hostname is not "localhost" */ +bool is_localhost(const char *hostname) { + assert(hostname); + + /* This tries to identify local hostnames described in RFC6761 + * plus the redhatism of .localdomain */ + + return streq(hostname, "localhost") || + streq(hostname, "localhost.") || + endswith(hostname, ".localhost") || + endswith(hostname, ".localhost.") || + endswith(hostname, ".localdomain") || + endswith(hostname, ".localdomain."); +}