git: fe06e383cc64 - main - daemon(8): Add option to write pidfile w/o supervising it

From: Michael Osipov <michaelo_at_FreeBSD.org>
Date: Thu, 13 Aug 2026 14:22:18 UTC
The branch main has been updated by michaelo:

URL: https://cgit.FreeBSD.org/src/commit/?id=fe06e383cc64fce8b604d21f8526b91fa6aecc39

commit fe06e383cc64fce8b604d21f8526b91fa6aecc39
Author:     Andre Albsmeier <mail@fbsd2.e4m.org>
AuthorDate: 2024-08-17 09:20:00 +0000
Commit:     Michael Osipov <michaelo@FreeBSD.org>
CommitDate: 2026-08-13 14:21:52 +0000

    daemon(8): Add option to write pidfile w/o supervising it
    
    Co-authored-by: Michael Osipov <michaelo@FreeBSD.org>
    PR:             280487
    Reviewed by:    kevans, michaelo
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D46313
---
 usr.sbin/daemon/daemon.8 | 19 ++++++++++++++++---
 usr.sbin/daemon/daemon.c | 27 +++++++++++++++++++++++----
 2 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/usr.sbin/daemon/daemon.8 b/usr.sbin/daemon/daemon.8
index ada1aa252265..8d86f7bac4a7 100644
--- a/usr.sbin/daemon/daemon.8
+++ b/usr.sbin/daemon/daemon.8
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 28, 2026
+.Dd August 13, 2026
 .Dt DAEMON 8
 .Os
 .Sh NAME
@@ -32,7 +32,7 @@
 .Nd run detached from the controlling terminal
 .Sh SYNOPSIS
 .Nm
-.Op Fl cfHrS
+.Op Fl cfHrSx
 .Op Fl p Ar child_pidfile
 .Op Fl P Ar supervisor_pidfile
 .Op Fl t Ar title
@@ -209,10 +209,23 @@ and
 .Ev SHELL
 are set accordingly.
 Requires adequate superuser privileges.
+.It Fl x , Fl -execute-only
+Do not supervise the child process when using
+.Fl p .
+This option is useful to run the given program as another user when
+.Xr su 1
+can't be used but a file holding the pid is needed.
+The
+.Ar child_pidfile
+will not be locked and the contents may be silently truncated by
+a concurrent daemon(8) invocation.
 .El
 .Pp
 If any of the options
-.Fl -child-pidfile ,
+.Fl -child-pidfile
+(without
+.Fl -execute-only
+),
 .Fl -output-mask ,
 .Fl -restart ,
 .Fl -restart-delay ,
diff --git a/usr.sbin/daemon/daemon.c b/usr.sbin/daemon/daemon.c
index 9158d6404b29..72a05c65592b 100644
--- a/usr.sbin/daemon/daemon.c
+++ b/usr.sbin/daemon/daemon.c
@@ -119,13 +119,14 @@ static int daemon_setup_kqueue(void);
 
 static int pidfile_truncate(struct pidfh *);
 
-static const char shortopts[] = "+cfHSp:P:ru:o:M:s:l:t:m:R:T:C:h";
+static const char shortopts[] = "+cfHSxp:P:ru:o:M:s:l:t:m:R:T:C:h";
 
 static const struct option longopts[] = {
 	{ "change-dir",         no_argument,            NULL,           'c' },
 	{ "close-fds",          no_argument,            NULL,           'f' },
 	{ "sighup",             no_argument,            NULL,           'H' },
 	{ "syslog",             no_argument,            NULL,           'S' },
+	{ "execute-only",       no_argument,            NULL,           'x' },
 	{ "output-file",        required_argument,      NULL,           'o' },
 	{ "output-file-mode",   required_argument,      NULL,           'M' },
 	{ "output-mask",        required_argument,      NULL,           'm' },
@@ -147,7 +148,7 @@ static _Noreturn void
 usage(int exitcode)
 {
 	(void)fprintf(stderr,
-	    "usage: daemon [-cfHrS] [-p child_pidfile] [-P supervisor_pidfile]\n"
+	    "usage: daemon [-cfHrSx] [-p child_pidfile] [-P supervisor_pidfile]\n"
 	    "              [-u user] [-o output_file] [-M output_file_mode] [-t title]\n"
 	    "              [-l syslog_facility] [-s syslog_priority]\n"
 	    "              [-T syslog_tag] [-m output_mask] [-R restart_delay_secs]\n"
@@ -159,6 +160,7 @@ usage(int exitcode)
 	    "  --close-fds          -f         Set stdin, stdout, stderr to /dev/null\n"
 	    "  --sighup             -H         Close and re-open output file on SIGHUP\n"
 	    "  --syslog             -S         Send output to syslog\n"
+	    "  --execute-only       -x         Do not supervise child process when using -p\n"
 	    "  --output-file        -o <file>  Append output of the child process to file\n"
 	    "  --output-file-mode   -M <mode>  Output file mode of the child process\n"
 	    "  --output-mask        -m <mask>  What to send to syslog/file\n"
@@ -185,6 +187,7 @@ main(int argc, char *argv[])
 	int ch = 0;
 	mode_t *set = NULL;
 	struct daemon_state state;
+	bool opt_x = false;
 
 	daemon_state_init(&state);
 
@@ -195,7 +198,7 @@ main(int argc, char *argv[])
 	/*
 	 * Supervision mode is enabled if one of the following options are used:
 	 * --output-file -o
-	 * --child-pidfile -p
+	 * --child-pidfile -p (if --execute-only -x is not given)
 	 * --supervisor-pidfile -P
 	 * --restart -r / --restart-delay -R
 	 * --syslog -S
@@ -262,9 +265,14 @@ main(int argc, char *argv[])
 			free(set);
 			set = NULL;
 			break;
+		case 'x':
+			opt_x = true;
+			break;
 		case 'p':
 			state.child_pidfile = optarg;
-			state.mode = MODE_SUPERVISE;
+			/*
+			 * Enable supervision later if no -x was given
+			 */
 			break;
 		case 'P':
 			state.parent_pidfile = optarg;
@@ -322,6 +330,17 @@ main(int argc, char *argv[])
 		usage(1);
 	}
 
+	/*
+	 * Enable supervision for -p if -x was not given
+	 */
+	if (state.child_pidfile != NULL) {
+		if (!opt_x) {
+			state.mode = MODE_SUPERVISE;
+		}
+	} else if (opt_x) {
+		errx(6, "-x is not allowed without -p");
+	}
+
 	if (!state.title) {
 		state.title = argv[0];
 	}