From owner-freebsd-bugs@FreeBSD.ORG Fri Nov 3 09:30:22 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8121F16A407 for ; Fri, 3 Nov 2006 09:30:22 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id DFFF143D5D for ; Fri, 3 Nov 2006 09:30:21 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id kA39ULUE060854 for ; Fri, 3 Nov 2006 09:30:21 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id kA39ULCi060853; Fri, 3 Nov 2006 09:30:21 GMT (envelope-from gnats) Resent-Date: Fri, 3 Nov 2006 09:30:21 GMT Resent-Message-Id: <200611030930.kA39ULCi060853@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Tomas Verbaitis Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 128BA16A47B for ; Fri, 3 Nov 2006 09:26:40 +0000 (UTC) (envelope-from tomasv@megalogika.stp.lt) Received: from megalogika.stp.lt (megalogika.stp.lt [193.219.52.197]) by mx1.FreeBSD.org (Postfix) with ESMTP id B89B243D7E for ; Fri, 3 Nov 2006 09:26:38 +0000 (GMT) (envelope-from tomasv@megalogika.stp.lt) Received: from pilvas.lan (pilvas.lan [192.169.1.86]) by megalogika.stp.lt (Postfix) with ESMTP id 1F3D91E0DF for ; Fri, 3 Nov 2006 11:26:31 +0200 (EET) Received: by pilvas.lan (Postfix, from userid 1001) id 66E9D4325; Fri, 3 Nov 2006 11:26:32 +0200 (EET) Message-Id: <20061103092632.66E9D4325@pilvas.lan> Date: Fri, 3 Nov 2006 11:26:32 +0200 (EET) From: Tomas Verbaitis To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: misc/105103: request to merge pidfile(3) and daemon(8) to 4-STABLE X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Tomas Verbaitis List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Nov 2006 09:30:22 -0000 >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@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 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 +.\" 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@FreeBSD.org . +.Pp +The code and manual page was written by +.An Pawel Jakub Dawidek Aq pjd@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 + * 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 +__FBSDID("$FreeBSD: src/lib/libutil/pidfile.c,v 1.3 2006/06/23 01:42:03 brian Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 +#include +__FBSDID("$FreeBSD: src/usr.sbin/daemon/daemon.c,v 1.4 2005/08/24 17:24:39 pjd Exp $"); + +#include #include +#include +#include #include #include #include @@ -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: