commit: 00f9110aaef088dfb282d0775449f273000c189c
parent 1523b277a5e4a7fc9fa8e10dbce03f6275de141f
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Mon, 15 Apr 2024 06:11:14 +0200
cmd/nohup: new
Diffstat:
6 files changed, 176 insertions(+), 4 deletions(-)
diff --git a/cmd/env.1 b/cmd/env.1
@@ -43,7 +43,9 @@ is invoked, the exit status of
.Nm
shall be the exit status of
.Ar command ;
-Otherwise, the env utility shall exit with one of the following values:
+Otherwise, the
+.Nm
+utility shall exit with one of the following values:
.Bl -tag -width Ds
.It 0
.Nm
diff --git a/cmd/nohup.1 b/cmd/nohup.1
@@ -0,0 +1,56 @@
+.\" utils-std: Collection of commonly available Unix tools
+.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+.\" SPDX-License-Identifier: MPL-2.0
+.Dd 2024-04-15
+.Dt NOHUP 1
+.Os
+.Sh NAME
+.Nm nohup
+.Nd run command with hangups ignored
+.Sh SYNOPSIS
+.Nm
+.Ar command
+.Op Ar arguments ...
+.Sh DESCRIPTION
+.Nm
+runs
+.Ar command
+with SIGHUP ignored, allowing to keep
+.Ar command
+running even after the terminal hanged up.
+.Pp
+If stdout is TTY, it's output is saved to
+.Pa ./nohup.out
+or if it fails to open it for writing, to
+.Pa ~/nohup.out .
+If stderr is also a TTY, it's output is also saved to
+.Pa nohup.out .
+.Sh EXIT STATUS
+If
+.Ar command
+is invoked, the exit status of
+.Nm
+shall be the exit status of
+.Ar command ;
+Otherwise, the
+.Nm
+utility shall exit with one of the following values:
+.Bl -tag -width Ds
+.It 126
+.Ar command
+was found but couldn't be invoked.
+.It 127
+.Ar command
+wasn't found or an error occured within the
+.Nm
+utility.
+.El
+.Sh SEE ALSO
+.Xr tmux 1
+.Sh STANDARDS
+.Nm
+should be compliant with the
+.St -p1003.1-2008
+specification.
+.Sh AUTHORS
+.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/nohup.c b/cmd/nohup.c
@@ -0,0 +1,114 @@
+// utils-std: Collection of commonly available Unix tools
+// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h> // open
+#include <limits.h> // PATH_MAX
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h> // fprintf
+#include <stdlib.h> // getenv
+#include <string.h> // strerror
+#include <sys/stat.h> // S_IRUSR, S_IWUSR
+#include <unistd.h> // isatty
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: nohup command [args ...]\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int nohup_fd = -1;
+
+ if(argc <= 1)
+ {
+ usage();
+ return 127;
+ }
+
+ if(signal(SIGHUP, SIG_IGN) == SIG_ERR)
+ {
+ fprintf(stderr, "nohup: Failed to set SIGHUP as ignored: %s\n", strerror(errno));
+ return 127;
+ }
+
+ assert(errno == 0);
+ if(isatty(1))
+ {
+ assert(errno == 0);
+ nohup_fd = open("nohup.out", O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
+ if(nohup_fd < 0)
+ {
+ fprintf(stderr,
+ "nohup: Warning: Failed opening ./nohup.out (%s), fallbacking to ~/nohup.out\n",
+ strerror(errno));
+
+ char *home = getenv("HOME");
+ if(!home)
+ {
+ fprintf(
+ stderr,
+ "nohup: $HOME is undefined, can't fallback writing from ./nohup.out to ~/nohup.out\n");
+ return 127;
+ }
+
+ char home_nohup[PATH_MAX];
+ if(snprintf(home_nohup, sizeof(home_nohup), "%s/nohup.out", home) < 0)
+ {
+ fprintf(
+ stderr, "nohup: Failed concatenating $HOME and '/nohup.out': %s\n", strerror(errno));
+ return 127;
+ }
+
+ nohup_fd = open(home_nohup, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
+ if(nohup_fd < 0)
+ {
+ fprintf(stderr, "nohup: Error: Failed opening ~/nohup.out: %s\n", strerror(errno));
+ return 127;
+ }
+ }
+
+ if(dup2(nohup_fd, 1) < 0)
+ {
+ fprintf(
+ stderr, "nohup: Error: Failed assigning 'nohup.out' to stdout: %s\n", strerror(errno));
+ return 127;
+ }
+
+ if(isatty(2))
+ {
+ assert(errno == 0);
+ if(dup2(1, 2))
+ {
+ fprintf(stderr, "nohup: Error: Failed assigning stdout to stderr: %s\n", strerror(errno));
+ return 127;
+ }
+ }
+ else
+ errno = 0; // isatty sets errno on returning false
+ }
+ else
+ errno = 0; // isatty sets errno on returning false
+
+ argc -= 1;
+ argv += 1;
+
+ assert(argv[0]);
+ assert(errno == 0);
+ /* flawfinder: ignore. No restrictions on commands is intended */
+ if(execvp(argv[0], argv) < 0)
+ {
+ fprintf(stderr, "nohup: execvp(\"%s\", ...): %s\n", argv[0], strerror(errno));
+
+ return (errno == ENOENT) ? 127 : 126;
+ }
+
+ assert(false);
+}
diff --git a/coreutils.txt b/coreutils.txt
@@ -50,7 +50,7 @@ mktemp: Todo
mv: Todo
nice: Maybe
nl: No, use sed
-nohup: Maybe
+nohup: Done
nproc: ?
numfmt: Maybe, consider humanize(1)
od: Todo
diff --git a/lsb_commands.txt b/lsb_commands.txt
@@ -88,7 +88,7 @@ mv: Todo
newgrp: out of scope
nice: Maybe
nl: No, use sed
-nohup: Maybe
+nohup: Done
od: Todo
passwd: out of scope
paste: Todo
diff --git a/posix_utilities.txt b/posix_utilities.txt
@@ -88,7 +88,7 @@ newgrp
nice
nl
nm: no, toolchain
-nohup
+nohup: done
od
paste
patch: no