+DIR *xopendirat(int fd, const char *name, int flags) {
+ int nfd;
+ DIR *d;
+
+ if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0)
+ return NULL;
+
+ if (!(d = fdopendir(nfd))) {
+ close_nointr_nofail(nfd);
+ return NULL;
+ }
+
+ return d;
+}
+
+int signal_from_string_try_harder(const char *s) {
+ int signo;
+ assert(s);
+
+ if ((signo = signal_from_string(s)) <= 0)
+ if (startswith(s, "SIG"))
+ return signal_from_string(s+3);
+
+ return signo;
+}
+
+void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
+
+ assert(f);
+ assert(name);
+ assert(t);
+
+ if (!dual_timestamp_is_set(t))
+ return;
+
+ fprintf(f, "%s=%llu %llu\n",
+ name,
+ (unsigned long long) t->realtime,
+ (unsigned long long) t->monotonic);
+}
+
+void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
+ unsigned long long a, b;
+
+ assert(value);
+ assert(t);
+
+ if (sscanf(value, "%lli %llu", &a, &b) != 2)
+ log_debug("Failed to parse finish timestamp value %s", value);
+ else {
+ t->realtime = a;
+ t->monotonic = b;
+ }
+}
+
+char *fstab_node_to_udev_node(const char *p) {
+ char *dn, *t, *u;
+ int r;
+
+ /* FIXME: to follow udev's logic 100% we need to leave valid
+ * UTF8 chars unescaped */
+
+ if (startswith(p, "LABEL=")) {
+
+ if (!(u = unquote(p+6, "\"\'")))
+ return NULL;
+
+ t = xescape(u, "/ ");
+ free(u);
+
+ if (!t)
+ return NULL;
+
+ r = asprintf(&dn, "/dev/disk/by-label/%s", t);
+ free(t);
+
+ if (r < 0)
+ return NULL;
+
+ return dn;
+ }
+
+ if (startswith(p, "UUID=")) {
+
+ if (!(u = unquote(p+5, "\"\'")))
+ return NULL;
+
+ t = xescape(u, "/ ");
+ free(u);
+
+ if (!t)
+ return NULL;
+
+ r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
+ free(t);
+
+ if (r < 0)
+ return NULL;
+
+ return dn;
+ }
+
+ return strdup(p);
+}
+
+void filter_environ(const char *prefix) {
+ int i, j;
+ assert(prefix);
+
+ if (!environ)
+ return;
+
+ for (i = 0, j = 0; environ[i]; i++) {
+
+ if (startswith(environ[i], prefix))
+ continue;
+
+ environ[j++] = environ[i];
+ }
+
+ environ[j] = NULL;
+}
+
+const char *default_term_for_tty(const char *tty) {
+ assert(tty);
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ if (startswith(tty, "tty") &&
+ tty[3] >= '0' && tty[3] <= '9')
+ return "TERM=linux";
+
+ /* FIXME: Proper handling of /dev/console would be cool */
+
+ return "TERM=vt100";
+}
+