misc/105103: request to merge pidfile(3) and daemon(8) to 4-STABLE
Tomas Verbaitis
tomasv at megalogika.lt
Fri Nov 3 09:30:22 UTC 2006
>Number: 105103
>Category: misc
>Synopsis: request to merge pidfile(3) and daemon(8) to 4-STABLE
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Fri Nov 03 09:30:21 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator: Tomas Verbaitis
>Release: FreeBSD 4.11-STABLE i386
>Organization:
Megalogika Ltd., http://megalogika.lt
>Environment:
System: FreeBSD stroike.lan 4.11-STABLE FreeBSD 4.11-STABLE #2: Wed Oct 4 14:05:39 GMT 2006
tomasv at stroike.lan:/usr/obj/usr/src/sys/STROIKE i386
>Description:
In order to use www/tomcat55 and other Apache Tomcat ports on 4-STABLE
daemon(8) functionality to write daemonized process' PID to file
(-p option) is needed.
>How-To-Repeat:
Install www/tomcat55 on 4-STABLE
Try to launch Tomcat using provided rc script
Or just try daemon -p 1020 ls -l
>Fix:
Provided is a patch which merges required functionality to 4-STABLE
diff -u -ruN /usr/src/sys/sys/errno.h /usr/local/src/FreeBSD/sys/sys/errno.h
--- /usr/src/sys/sys/errno.h Wed Jan 12 18:34:54 2005
+++ /usr/local/src/FreeBSD/sys/sys/errno.h Thu Nov 2 19:05:42 2006
@@ -168,7 +168,8 @@
#define ECANCELED 85 /* Operation canceled */
#define EILSEQ 86 /* Illegal byte sequence */
#define ENOATTR 87 /* Attribute not found */
-#define ELAST 87 /* Must be equal largest errno */
+#define EDOOFUS 88 /* Programming error */
+#define ELAST 88 /* Must be equal largest errno */
#endif /* _POSIX_SOURCE */
diff -u -ruN /usr/src/sys/sys/types.h /usr/local/src/FreeBSD/sys/sys/types.h
--- /usr/src/sys/sys/types.h Sat Apr 21 17:53:06 2001
+++ /usr/local/src/FreeBSD/sys/sys/types.h Thu Nov 2 19:05:42 2006
@@ -108,6 +108,7 @@
typedef u_int32_t dev_t; /* device number */
#define udev_t dev_t
+typedef __uint32_t __dev_t; /* device number or struct cdev */
#ifndef _POSIX_SOURCE
/*
diff -u -ruN /usr/src/lib/libutil/Makefile /usr/local/src/FreeBSD/lib/libutil/Makefile
--- /usr/src/lib/libutil/Makefile Wed Apr 25 13:04:42 2001
+++ /usr/local/src/FreeBSD/lib/libutil/Makefile Wed Oct 18 15:03:57 2006
@@ -9,13 +9,13 @@
SRCS= login.c login_tty.c logout.c logwtmp.c pty.c \
login_cap.c login_class.c login_auth.c login_times.c login_ok.c \
login_crypt.c _secure_path.c uucplock.c property.c auth.c \
- realhostname.c fparseln.c stub.c
+ realhostname.c fparseln.c stub.c pidfile.c
INCS= libutil.h login_cap.h
MAN+= login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
login_cap.3 login_class.3 login_times.3 login_ok.3 \
_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
- realhostname_sa.3 trimdomain.3 fparseln.3
+ realhostname_sa.3 trimdomain.3 fparseln.3 pidfile.3
MAN+= login.conf.5 auth.conf.5
MLINKS+= property.3 properties_read.3 property.3 properties_free.3
MLINKS+= property.3 property_find.3
@@ -38,5 +38,9 @@
MLINKS+=login_auth.3 auth_checknologin.3 login_auth.3 auth_cat.3
MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \
uucplock.3 uu_unlock.3 uucplock.3 uu_lockerr.3
+MLINKS+=pidfile.3 pidfile_open.3 \
+ pidfile.3 pidfile_write.3 \
+ pidfile.3 pidfile_close.3 \
+ pidfile.3 pidfile_remove.3
.include <bsd.lib.mk>
diff -u -ruN /usr/src/lib/libutil/libutil.h /usr/local/src/FreeBSD/lib/libutil/libutil.h
--- /usr/src/lib/libutil/libutil.h Wed Nov 22 05:49:49 2000
+++ /usr/local/src/FreeBSD/lib/libutil/libutil.h Wed Oct 18 15:06:30 2006
@@ -41,6 +41,16 @@
char *value;
} *properties;
+#ifdef _SYS_PARAM_H_
+/* for pidfile.c */
+struct pidfh {
+ int pf_fd;
+ char pf_path[MAXPATHLEN + 1];
+ __dev_t pf_dev;
+ ino_t pf_ino;
+};
+#endif
+
/* Avoid pulling in all the include files for no need */
struct termios;
struct winsize;
@@ -73,6 +83,14 @@
#ifdef _STDIO_H_ /* avoid adding new includes */
char *fparseln __P((FILE *, size_t *, size_t *, const char[3], int));
#endif
+
+#ifdef _SYS_PARAM_H_
+struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);
+int pidfile_write(struct pidfh *pfh);
+int pidfile_close(struct pidfh *pfh);
+int pidfile_remove(struct pidfh *pfh);
+#endif
+
__END_DECLS
#define UU_LOCK_INUSE (1)
diff -u -ruN /usr/src/lib/libutil/pidfile.3 /usr/local/src/FreeBSD/lib/libutil/pidfile.3
--- /usr/src/lib/libutil/pidfile.3 Thu Jan 1 02:00:00 1970
+++ /usr/local/src/FreeBSD/lib/libutil/pidfile.3 Wed Oct 18 15:01:24 2006
@@ -0,0 +1,249 @@
+.\" Copyright (c) 2005 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libutil/pidfile.3,v 1.5 2006/03/04 15:20:28 keramida Exp $
+.\"
+.Dd August 22, 2005
+.Dt PIDFILE 3
+.Os
+.Sh NAME
+.Nm pidfile_open ,
+.Nm pidfile_write ,
+.Nm pidfile_close ,
+.Nm pidfile_remove
+.Nd "library for PID files handling"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/param.h
+.In libutil.h
+.Ft "struct pidfh *"
+.Fn pidfile_open "const char *path" "mode_t mode" "pid_t *pidptr"
+.Ft int
+.Fn pidfile_write "struct pidfh *pfh"
+.Ft int
+.Fn pidfile_close "struct pidfh *pfh"
+.Ft int
+.Fn pidfile_remove "struct pidfh *pfh"
+.Sh DESCRIPTION
+The
+.Nm pidfile
+family of functions allows daemons to handle PID files.
+It uses
+.Xr flock 2
+to lock a pidfile and detect already running daemons.
+.Pp
+The
+.Fn pidfile_open
+function opens (or creates) a file specified by the
+.Fa path
+argument and locks it with the
+.Xr flock 2
+system call.
+If a file can not be locked, a PID of an already running daemon is returned in
+the
+.Fa pidptr
+argument (if it is not
+.Dv NULL ) .
+The function does not write process' PID into the file here, so it can be
+used before
+.Fn fork Ns ing
+and exit with a proper error message when needed.
+If the
+.Fa path
+argument is
+.Dv NULL ,
+.Pa /var/run/ Ns Ao Va progname Ac Ns Pa .pid
+file will be used.
+.Pp
+The
+.Fn pidfile_write
+function writes process' PID into a previously opened file.
+.Pp
+The
+.Fn pidfile_close
+function closes a pidfile.
+It should be used after daemon
+.Fn fork Ns s
+to start a child process.
+.Pp
+The
+.Fn pidfile_remove
+function closes and removes a pidfile.
+.Sh RETURN VALUES
+The
+.Fn pidfile_open
+function returns a valid pointer to a
+.Vt pidfh
+structure on success, or
+.Dv NULL
+if an error occurs.
+If an error occurs,
+.Va errno
+will be set.
+.Rv -std pidfile_write pidfile_close pidfile_remove
+.Sh EXAMPLES
+The following example shows in which order these functions should be used.
+Note that it is safe to pass
+.Dv NULL
+to
+.Fn pidfile_write ,
+.Fn pidfile_remove
+and
+.Fn pidfile_close
+functions.
+.Bd -literal
+struct pidfh *pfh;
+pid_t otherpid, childpid;
+
+pfh = pidfile_open("/var/run/daemon.pid", 0600, &otherpid);
+if (pfh == NULL) {
+ if (errno == EEXIST) {
+ errx(EXIT_FAILURE, "Daemon already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ /* If we cannot create pidfile from other reasons, only warn. */
+ warn("Cannot open or create pidfile");
+}
+
+if (daemon(0, 0) == -1) {
+ warn("Cannot daemonize");
+ pidfile_remove(pfh);
+ exit(EXIT_FAILURE);
+}
+
+pidfile_write(pfh);
+
+for (;;) {
+ /* Do work. */
+ childpid = fork();
+ switch (childpid) {
+ case -1:
+ syslog(LOG_ERR, "Cannot fork(): %s.", strerror(errno));
+ break;
+ case 0:
+ pidfile_close(pfh);
+ /* Do child work. */
+ break;
+ default:
+ syslog(LOG_INFO, "Child %jd started.", (intmax_t)childpid);
+ break;
+ }
+}
+
+pidfile_remove(pfh);
+exit(EXIT_SUCCESS);
+.Ed
+.Sh ERRORS
+The
+.Fn pidfile_open
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EEXIST
+Some process already holds the lock on the given pidfile, meaning that a
+daemon is already running.
+.It Bq Er ENAMETOOLONG
+Specified pidfile's name is too long.
+.It Bq Er EINVAL
+Some process already holds the lock on the given pidfile, but PID read
+from there is invalid.
+.El
+.Pp
+The
+.Fn pidfile_open
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr fstat 2 ,
+.Xr open 2 ,
+and
+.Xr read 2
+calls.
+.Pp
+The
+.Fn pidfile_write
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EDOOFUS
+Improper function use.
+Probably called before
+.Fn pidfile_open .
+.El
+.Pp
+The
+.Fn pidfile_write
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr fstat 2 ,
+.Xr ftruncate 2 ,
+and
+.Xr write 2
+calls.
+.Pp
+The
+.Fn pidfile_close
+function may fail and set
+.Va errno
+for any errors specified for the
+.Xr close 2
+and
+.Xr fstat 2
+calls.
+.Pp
+The
+.Fn pidfile_remove
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EDOOFUS
+Improper function use.
+Probably called not from the process which made
+.Fn pidfile_write .
+.El
+.Pp
+The
+.Fn pidfile_remove
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr close 2 ,
+.Xr flock 2 ,
+.Xr fstat 2 ,
+.Xr write 2 ,
+and
+.Xr unlink 2
+calls.
+.Sh SEE ALSO
+.Xr flock 2 ,
+.Xr open 2 ,
+.Xr daemon 3
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm pidfile
+functionality is based on ideas from
+.An John-Mark Gurney Aq jmg at FreeBSD.org .
+.Pp
+The code and manual page was written by
+.An Pawel Jakub Dawidek Aq pjd at FreeBSD.org .
diff -u -ruN /usr/src/lib/libutil/pidfile.c /usr/local/src/FreeBSD/lib/libutil/pidfile.c
--- /usr/src/lib/libutil/pidfile.c Thu Jan 1 02:00:00 1970
+++ /usr/local/src/FreeBSD/lib/libutil/pidfile.c Wed Oct 18 15:01:24 2006
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 2005 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libutil/pidfile.c,v 1.3 2006/06/23 01:42:03 brian Exp $");
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+
+static int _pidfile_remove(struct pidfh *pfh, int freeit);
+
+static int
+pidfile_verify(struct pidfh *pfh)
+{
+ struct stat sb;
+
+ if (pfh == NULL || pfh->pf_fd == -1)
+ return (EDOOFUS);
+ /*
+ * Check remembered descriptor.
+ */
+ if (fstat(pfh->pf_fd, &sb) == -1)
+ return (errno);
+ if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
+ return (EDOOFUS);
+ return (0);
+}
+
+static int
+pidfile_read(const char *path, pid_t *pidptr)
+{
+ char buf[16], *endptr;
+ int error, fd, i;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return (errno);
+
+ i = read(fd, buf, sizeof(buf) - 1);
+ error = errno; /* Remember errno in case close() wants to change it. */
+ close(fd);
+ if (i == -1)
+ return (error);
+ buf[i] = '\0';
+
+ *pidptr = strtol(buf, &endptr, 10);
+ if (endptr != &buf[i])
+ return (EINVAL);
+
+ return (0);
+}
+
+struct pidfh *
+pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
+{
+ struct pidfh *pfh;
+ struct stat sb;
+ int error, fd;
+
+ pfh = malloc(sizeof(*pfh));
+ if (pfh == NULL)
+ return (NULL);
+
+ if (path == NULL) {
+ snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid",
+ getprogname());
+ } else {
+ strlcpy(pfh->pf_path, path, sizeof(pfh->pf_path));
+ }
+ if (strlen(pfh->pf_path) == sizeof(pfh->pf_path) - 1) {
+ free(pfh);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+
+ /*
+ * Open the PID file and obtain exclusive lock.
+ * We truncate PID file here only to remove old PID immediatelly,
+ * PID file will be truncated again in pidfile_write(), so
+ * pidfile_write() can be called multiple times.
+ */
+ fd = open(pfh->pf_path,
+ O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, mode);
+ if (fd == -1) {
+ if (errno == EWOULDBLOCK && pidptr != NULL) {
+ errno = pidfile_read(pfh->pf_path, pidptr);
+ if (errno == 0)
+ errno = EEXIST;
+ }
+ free(pfh);
+ return (NULL);
+ }
+ /*
+ * Remember file information, so in pidfile_write() we are sure we write
+ * to the proper descriptor.
+ */
+ if (fstat(fd, &sb) == -1) {
+ error = errno;
+ unlink(pfh->pf_path);
+ close(fd);
+ free(pfh);
+ errno = error;
+ return (NULL);
+ }
+
+ pfh->pf_fd = fd;
+ pfh->pf_dev = sb.st_dev;
+ pfh->pf_ino = sb.st_ino;
+
+ return (pfh);
+}
+
+int
+pidfile_write(struct pidfh *pfh)
+{
+ char pidstr[16];
+ int error, fd;
+
+ /*
+ * Check remembered descriptor, so we don't overwrite some other
+ * file if pidfile was closed and descriptor reused.
+ */
+ errno = pidfile_verify(pfh);
+ if (errno != 0) {
+ /*
+ * Don't close descriptor, because we are not sure if it's ours.
+ */
+ return (-1);
+ }
+ fd = pfh->pf_fd;
+
+ /*
+ * Truncate PID file, so multiple calls of pidfile_write() are allowed.
+ */
+ if (ftruncate(fd, 0) == -1) {
+ error = errno;
+ _pidfile_remove(pfh, 0);
+ errno = error;
+ return (-1);
+ }
+
+ snprintf(pidstr, sizeof(pidstr), "%u", getpid());
+ if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
+ error = errno;
+ _pidfile_remove(pfh, 0);
+ errno = error;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pidfile_close(struct pidfh *pfh)
+{
+ int error;
+
+ error = pidfile_verify(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ if (close(pfh->pf_fd) == -1)
+ error = errno;
+ free(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+_pidfile_remove(struct pidfh *pfh, int freeit)
+{
+ int error;
+
+ error = pidfile_verify(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ if (unlink(pfh->pf_path) == -1)
+ error = errno;
+ if (flock(pfh->pf_fd, LOCK_UN) == -1) {
+ if (error == 0)
+ error = errno;
+ }
+ if (close(pfh->pf_fd) == -1) {
+ if (error == 0)
+ error = errno;
+ }
+ if (freeit)
+ free(pfh);
+ else
+ pfh->pf_fd = -1;
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pidfile_remove(struct pidfh *pfh)
+{
+
+ return (_pidfile_remove(pfh, 1));
+}
diff -u -ruN /usr/src/usr.sbin/daemon/Makefile /usr/local/src/FreeBSD/usr.sbin/daemon/Makefile
--- /usr/src/usr.sbin/daemon/Makefile Wed Aug 28 20:25:54 2002
+++ /usr/local/src/FreeBSD/usr.sbin/daemon/Makefile Wed Oct 18 15:14:40 2006
@@ -1,7 +1,11 @@
-# $FreeBSD: src/usr.sbin/daemon/Makefile,v 1.1.2.1 2002/08/28 17:25:54 sheldonh Exp $
+# $FreeBSD: src/usr.sbin/daemon/Makefile,v 1.3 2005/08/24 17:24:39 pjd Exp $
PROG= daemon
-WARNS?= 2
MAN= daemon.8
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+WARNS?= 2
.include <bsd.prog.mk>
diff -u -ruN /usr/src/usr.sbin/daemon/daemon.8 /usr/local/src/FreeBSD/usr.sbin/daemon/daemon.8
--- /usr/src/usr.sbin/daemon/daemon.8 Wed Feb 5 05:30:32 2003
+++ /usr/local/src/FreeBSD/usr.sbin/daemon/daemon.8 Wed Oct 18 15:14:40 2006
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: src/usr.sbin/daemon/daemon.8,v 1.2.2.2 2003/02/05 03:30:32 trhodes Exp $
+.\" $FreeBSD: src/usr.sbin/daemon/daemon.8,v 1.7 2005/08/24 17:24:39 pjd Exp $
.\"
.Dd August 30, 2001
.Dt DAEMON 8
@@ -35,6 +35,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl cf
+.Op Fl p Ar pidfile
.Ar command arguments ...
.Sh DESCRIPTION
The
@@ -50,13 +51,27 @@
.It Fl f
Redirect standard input, standard output and standard error to
.Pa /dev/null .
+.It Fl p Ar file
+Write the ID of the created process into the
+.Ar file
+using
+.Xr pidfile 3
+functionality.
+Note, that the file will be created shortly before the process is
+actually executed, and will remain after the process exits (although
+it will be removed if the execution fails).
.El
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
The
.Nm
utility exits 1 if an error is returned by the
.Xr daemon 3
-library routine, otherwise 0.
+library routine, 2 if the
+.Ar pidfile
+is requested, but cannot be opened, 3 if process is already running (pidfile
+exists and is locked),
+otherwise 0.
+.Sh DIAGNOSTICS
If the command cannot be executed, an error message is displayed on
standard error unless the
.Fl f
@@ -64,6 +79,7 @@
.Sh SEE ALSO
.Xr daemon 3 ,
.Xr exec 3 ,
+.Xr pidfile 3 ,
.Xr termios 4 ,
.Xr tty 4
.Sh HISTORY
diff -u -ruN /usr/src/usr.sbin/daemon/daemon.c /usr/local/src/FreeBSD/usr.sbin/daemon/daemon.c
--- /usr/src/usr.sbin/daemon/daemon.c Wed Aug 28 20:25:54 2002
+++ /usr/local/src/FreeBSD/usr.sbin/daemon/daemon.c Wed Oct 18 15:14:40 2006
@@ -26,12 +26,16 @@
* SUCH DAMAGE.
*
* From BSDI: daemon.c,v 1.2 1996/08/15 01:11:09 jch Exp
- * $FreeBSD: src/usr.sbin/daemon/daemon.c,v 1.1.2.1 2002/08/28 17:25:54 sheldonh Exp $
*/
-#include <sys/types.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/daemon/daemon.c,v 1.4 2005/08/24 17:24:39 pjd Exp $");
+
+#include <sys/param.h>
#include <err.h>
+#include <errno.h>
+#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -41,10 +45,14 @@
int
main(int argc, char *argv[])
{
- int ch, nochdir, noclose;
+ struct pidfh *pfh;
+ int ch, nochdir, noclose, errcode;
+ const char *pidfile;
+ pid_t otherpid;
nochdir = noclose = 1;
- while ((ch = getopt(argc, argv, "-cf")) != -1) {
+ pidfile = NULL;
+ while ((ch = getopt(argc, argv, "-cfp:")) != -1) {
switch (ch) {
case 'c':
nochdir = 0;
@@ -52,7 +60,9 @@
case 'f':
noclose = 0;
break;
- case '?':
+ case 'p':
+ pidfile = optarg;
+ break;
default:
usage();
}
@@ -62,17 +72,46 @@
if (argc == 0)
usage();
+ /*
+ * Try to open the pidfile before calling daemon(3),
+ * to be able to report the error intelligently
+ */
+ if (pidfile) {
+ pfh = pidfile_open(pidfile, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST) {
+ errx(3, "process already running, pid: %d",
+ otherpid);
+ }
+ err(2, "pidfile ``%s''", pidfile);
+ }
+ }
+
if (daemon(nochdir, noclose) == -1)
err(1, NULL);
+
+ /* Now that we are the child, write out the pid */
+ if (pidfile)
+ pidfile_write(pfh);
+
execvp(argv[0], argv);
+ /*
+ * execvp() failed -- unlink pidfile if any, and
+ * report the error
+ */
+ errcode = errno; /* Preserve errcode -- unlink may reset it */
+ if (pidfile)
+ pidfile_remove(pfh);
+
/* The child is now running, so the exit status doesn't matter. */
- err(1, "%s", argv[0]);
+ errc(1, errcode, "%s", argv[0]);
}
static void
usage(void)
{
- (void)fprintf(stderr, "usage: daemon [-cf] command arguments ...\n");
+ (void)fprintf(stderr,
+ "usage: daemon [-cf] [-p pidfile] command arguments ...\n");
exit(1);
}
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list