+cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
+ cpu_set_t *r;
+ unsigned n = 1024;
+
+ /* Allocates the cpuset in the right size */
+
+ for (;;) {
+ if (!(r = CPU_ALLOC(n)))
+ return NULL;
+
+ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
+ CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
+
+ if (ncpus)
+ *ncpus = n;
+
+ return r;
+ }
+
+ CPU_FREE(r);
+
+ if (errno != EINVAL)
+ return NULL;
+
+ n *= 2;
+ }
+}
+
+void status_vprintf(const char *format, va_list ap) {
+ char *s = NULL;
+ int fd = -1;
+
+ assert(format);
+
+ /* This independent of logging, as status messages are
+ * optional and go exclusively to the console. */
+
+ if (vasprintf(&s, format, ap) < 0)
+ goto finish;
+
+ if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
+ goto finish;
+
+ write(fd, s, strlen(s));
+
+finish:
+ free(s);
+
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+}
+
+void status_printf(const char *format, ...) {
+ va_list ap;
+
+ assert(format);
+
+ va_start(ap, format);
+ status_vprintf(format, ap);
+ va_end(ap);
+}
+
+void status_welcome(void) {
+
+#if defined(TARGET_FEDORA)
+ char *r;
+
+ if (read_one_line_file("/etc/system-release", &r) < 0)
+ return;
+
+ truncate_nl(r);
+
+ /* This tries to mimic the color magic the old Red Hat sysinit
+ * script did. */
+
+ if (startswith(r, "Red Hat"))
+ status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */
+ else if (startswith(r, "Fedora"))
+ status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */
+ else
+ status_printf("Welcome to %s!\n", r);
+
+ free(r);
+
+#elif defined(TARGET_SUSE)
+ char *r;
+
+ if (read_one_line_file("/etc/SuSE-release", &r) < 0)
+ return;
+
+ truncate_nl(r);
+
+ status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
+ free(r);
+#else
+#warning "You probably should add a welcome text logic here."
+#endif
+}
+
+char *replace_env(const char *format, char **env) {
+ enum {
+ WORD,
+ DOLLAR,
+ VARIABLE
+ } state = WORD;
+
+ const char *e, *word = format;
+ char *r = NULL, *k;
+
+ assert(format);
+
+ for (e = format; *e; e ++) {
+
+ switch (state) {
+
+ case WORD:
+ if (*e == '$')
+ state = DOLLAR;
+ break;
+
+ case DOLLAR:
+ if (*e == '(') {
+ if (!(k = strnappend(r, word, e-word-1)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e-1;
+ state = VARIABLE;
+
+ } else if (*e == '$') {
+ if (!(k = strnappend(r, word, e-word)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ state = WORD;
+ } else
+ state = WORD;
+ break;
+
+ case VARIABLE:
+ if (*e == ')') {
+ char *t;
+
+ if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
+ if (!(k = strappend(r, t)))
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ }
+
+ state = WORD;
+ }
+ break;
+ }
+ }
+
+ if (!(k = strnappend(r, word, e-word)))
+ goto fail;
+
+ free(r);
+ return k;
+
+fail:
+ free(r);
+ return NULL;
+}
+
+char **replace_env_argv(char **argv, char **env) {
+ char **r, **i;
+ unsigned k;
+
+ if (!(r = new(char*, strv_length(argv)+1)))
+ return NULL;
+
+ STRV_FOREACH(i, argv) {
+ if (!(r[k++] = replace_env(*i, env))) {
+ strv_free(r);
+ return NULL;
+ }
+ }
+
+ r[k] = NULL;
+ return r;
+}
+