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;
}
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';
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];
}
int close_all_fds(const int except[], unsigned n_except) {
- DIR *d;
+ _cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
}
}
- closedir(d);
return r;
}
static const char table[] =
"cifs\0"
"smbfs\0"
+ "sshfs\0"
"ncpfs\0"
"ncp\0"
"nfs\0"
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);
}
}
- 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);
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);
for (;;) {
va_list ap;
char c;
- int r;
bool need_nl = true;
if (on_tty())
}
}
+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;
}
}
+/*
+ * 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;
bool tty_is_vc(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
-
return vtnr_from_tty(tty) >= 0;
}
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;
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) {
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);
}
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,
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;
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;
}
}
/**
- * 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;
}
assert(mode);
assert(_f);
- if (!path_strv_canonicalize_absolute_uniq(search, root))
+ if (!path_strv_resolve_uniq(search, root))
return -ENOMEM;
STRV_FOREACH(i, search) {
_cleanup_free_ char *p = NULL;
FILE *f;
- p = strjoin(*i, "/", path, NULL);
+ if (root)
+ p = strjoin(root, *i, "/", path, NULL);
+ else
+ p = strjoin(*i, "/", path, NULL);
if (!p)
return -ENOMEM;
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.");
+}