From root@igarber.student.harvard.edu  Sun Mar  2 15:38:53 1997
Received: from who.cdrom.com (who.cdrom.com [204.216.27.3])
          by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id PAA10381
          for <FreeBSD-gnats-submit@freebsd.org>; Sun, 2 Mar 1997 15:38:53 -0800 (PST)
Received: from igarber.student.harvard.edu (igarber.student.harvard.edu [140.247.165.64])
          by who.cdrom.com (8.7.5/8.6.11) with ESMTP id PAA24753
          for <FreeBSD-gnats-submit@freebsd.org>; Sun, 2 Mar 1997 15:38:39 -0800 (PST)
Received: (from root@localhost)
	by igarber.student.harvard.edu (8.8.5/8.8.5) id SAA11614;
	Sun, 2 Mar 1997 18:31:54 GMT
Message-Id: <199703021831.SAA11614@igarber.student.harvard.edu>
Date: Sun, 2 Mar 1997 18:31:54 GMT
From: Charlie Root <root@igarber.student.harvard.edu>
Reply-To: mi@aldan.ziplink.net
To: FreeBSD-gnats-submit@freebsd.org
Subject: extending newsyslog(8)'s capabilities
X-Send-Pr-Version: 3.2

>Number:         2848
>Category:       misc
>Synopsis:       newsyslog will notify syslogd, not any other processes
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    jmg
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Mar  2 15:40:00 PST 1997
>Closed-Date:    Sat Sep 13 04:09:13 PDT 1997
>Last-Modified:  Sat Sep 13 04:10:51 PDT 1997
>Originator:     Mikhail Teterin
>Release:        FreeBSD 3.0-970209-SNAP i386
>Organization:
>Environment:

	newsyslog(8) as we know it

>Description:

	There is currently no way to specify to newsyslog(8) to
	notify (via kill) anyone else other then syslogd
	The main monster in need of this feature is, probably,
	Apache, but I'm sure many others would benefit as well.

>How-To-Repeat:


>Fix:

	Change the newsyslog(8). My understanding is, this would
	be best arranged, by adding two more fields in newsyslog's
	conf file (/etc/newsyslog.conf). One being a file-name,
	process-name, or PID (if numeric, it is PID, use . or / to
	force file-name), next one being the value of signal (numeric
	or literal). /* The third field added may be a name of the
	script to run everytime the action is taken by newsyslog. */
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jmg 
Responsible-Changed-By: jmg 
Responsible-Changed-When: Sun Mar 2 16:16:37 PST 1997 
Responsible-Changed-Why:  
I'll take this one...  I'm almost done with patches that should fix this. 

From: jmg@hydrogen.nike.efn.org (John-Mark Gurney)
To: freebsd-gnats-submit@freebsd.org
Cc: freebsd-current@freebsd.org (FreeBSD Current)
Subject: misc/2848 newsyslog only notifies syslogd
Date: Mon, 3 Mar 1997 00:00:16 -0800

 --+WCv1s2RzB2fBlYC
 
 well... I now have a set of patches that allows you to send a signal to a pid
 from a pid file...
 
 attached are the patches as they are actually quite long... if you con't read
 mime encoding you can obtain the patches from
 http://freefall.cdrom.com/~jmg/newsyslog.patch... it includes patches to the
 man page for the new usage information along with minor fixes to the man
 page...
 
 all I added is another flag `N' which is just a nop... it it a place holder for
 the flags when you don't want to specify any...
 
 I then added two more additional option flag... the first is the pid_file that
 you want to read the pid file from.. if this option isn't specified it will
 default to the syslog pid file...  these patches also modify newsyslog to
 obtain the syslogd pid file from the syslogd sources...
 
 the next is the name or number of the signal...  it can be something like
 `sigusr1', or `usr1'... if this option isn't specified it will default to
 SIGHUP...
 
 a sample like looks like:
 /var/log/testlog   600  2    4    *     N  /tmp/pidfile segv
 
 this will read the pid out of /tmp/pidfile and send it the segv signal when the
 log needs to be reopened... 
 
 if people could test this patch out... I would be greatful...  I had to add an
 ugly hack to get the parsing to work correctly because it was possible to
 "fall" off the end of a string and into other data which would corrupt the
 pid_file and signal options...  what really needs to happen is a way to
 "detect" end of line and be able to stop parsing... otherwise with the current
 implementation it continues past the end of the string...
 
 -- 
 John-Mark
 
 gurney_j@efn.org
 http://resnet.uoregon.edu/~gurney_j/
 Modem/FAX: (541) 683-6954   (FreeBSD Box)
 
 Live in Peace, destroy Micro$oft, support free software, run FreeBSD (unix)
 
 --+WCv1s2RzB2fBlYC
 Content-Disposition: attachment; filename=patch
 
 Index: Makefile
 ===================================================================
 RCS file: /usr/cvs/src/usr.sbin/newsyslog/Makefile,v
 retrieving revision 1.4
 diff -c -r1.4 Makefile
 *** Makefile	1997/02/22 16:08:24	1.4
 --- Makefile	1997/03/03 07:43:53
 ***************
 *** 8,13 ****
 --- 8,14 ----
   CFLAGS+= -DCOMPRESS_PATH=\"/usr/bin/gzip\"
   CFLAGS+= -DCOMPRESS_PROG=\"gzip\"
   CFLAGS+= -DCOMPRESS_POSTFIX=\".gz\"
 + CFLAGS+= -I${.CURDIR}/../syslogd
   
   BINOWN=	root
   
 Index: newsyslog.8
 ===================================================================
 RCS file: /usr/cvs/src/usr.sbin/newsyslog/newsyslog.8,v
 retrieving revision 1.5
 diff -c -r1.5 newsyslog.8
 *** newsyslog.8	1997/02/28 07:33:37	1.5
 --- newsyslog.8	1997/03/03 06:57:48
 ***************
 *** 17,44 ****
   .\" the suitability of this software for any purpose.  It is
   .\" provided "as is" without express or implied warranty.
   .\"
 ! .Dd "January 12, 1989"
   .Dt NEWSYSLOG 8
   .Os
   .Sh NAME
   .Nm newsyslog
   .Nd maintain system log files to manageable sizes
   .Sh SYNOPSIS
 ! .Nm newsyslog
   .Op Fl rnv
   .Op Fl f Ar config_file
   .Sh DESCRIPTION
 ! .Nm Newsyslog
   is a program that should be scheduled to run periodically by
   .Xr cron 8 .
   When it is executed it archives log files if necessary.  If a log file
   is determined to require archiving, 
 ! .Nm newsyslog
 ! rearranges the files so that ``logfile'' is empty, ``logfile.0'' has
 ! the last period's logs in it, ``logfile.1'' has the next to last
 ! period's logs in it, and so on, up to a user-specified number of
 ! archived logs.  Optionally the archived logs can be compressed to save
 ! space. 
   .Pp
   A log can be archived because of two reasons.  The log file can have
   grown bigger than a preset size in kilobytes, or a preset number of
 --- 17,48 ----
   .\" the suitability of this software for any purpose.  It is
   .\" provided "as is" without express or implied warranty.
   .\"
 ! .Dd January 12, 1989
   .Dt NEWSYSLOG 8
   .Os
   .Sh NAME
   .Nm newsyslog
   .Nd maintain system log files to manageable sizes
   .Sh SYNOPSIS
 ! .Nm
   .Op Fl rnv
   .Op Fl f Ar config_file
   .Sh DESCRIPTION
 ! .Nm
   is a program that should be scheduled to run periodically by
   .Xr cron 8 .
   When it is executed it archives log files if necessary.  If a log file
   is determined to require archiving, 
 ! .Nm
 ! rearranges the files so that
 ! .Dq Pa logfile
 ! is empty,
 ! .Dq Pa logfile.0
 ! has the last period's logs in it,
 ! .Dq Pa logfile.1
 ! has the next to last period's logs in it, and so on, up to a user-specified
 ! number of archived logs.  Optionally the archived logs can be compressed to
 ! save space. 
   .Pp
   A log can be archived because of two reasons.  The log file can have
   grown bigger than a preset size in kilobytes, or a preset number of
 ***************
 *** 50,73 ****
   without any ill effects.
   .Pp
   When starting up, 
 ! .Nm newsyslog
   reads in a configuration file to determine which logs should be looked
   at.  By default, this configuration file is 
   .Pa /etc/newsyslog.conf .
   Each line of the file contains information about a particular log file
   that should be handled by
 ! .Nm newsyslog .
 ! Each line has five mandatory fields and two optional fields, with a
   whitespace separating each field.  Blank lines or lines beginning with
 ! ``#'' are ignored.  The fields of the configuration file are as
 ! follows: 
   .Pp
   .Bl -tag -width logfile_namexxxx
   .It Ar logfile_name
   Name of the system log file to be archived.
   .It Ar owner.group
   Specifies the owner and group for the archive file.
 ! The "." is essential, even if the
   .Ar owner
   or
   .Ar group
 --- 54,79 ----
   without any ill effects.
   .Pp
   When starting up, 
 ! .Nm
   reads in a configuration file to determine which logs should be looked
   at.  By default, this configuration file is 
   .Pa /etc/newsyslog.conf .
   Each line of the file contains information about a particular log file
   that should be handled by
 ! .Nm Ns .
 ! Each line has five mandatory fields and four optional fields, with a
   whitespace separating each field.  Blank lines or lines beginning with
 ! .Dq #
 ! are ignored.  The fields of the configuration file are as follows: 
   .Pp
   .Bl -tag -width logfile_namexxxx
   .It Ar logfile_name
   Name of the system log file to be archived.
   .It Ar owner.group
   Specifies the owner and group for the archive file.
 ! The
 ! .Dq \&.
 ! is essential, even if the
   .Ar owner
   or
   .Ar group
 ***************
 *** 75,92 ****
   present in
   .Pa /etc/passwd
   or
 ! .Pa /etc/group.
   .It Ar mode 
   Specifies the mode of the log file and archives.
   .It Ar count
 ! Specifies the number of archive files to be kept
 ! besides the log file itself.
   .It Ar size
   When the size of the log file reaches
   .Ar size ,
   the log file will be trimmed as described above.  If this field
   is replaced by a
 ! .Ar * ,
   then the size of the log file is not taken into account
   when determining when to trim the log file.
   of archives
 --- 81,97 ----
   present in
   .Pa /etc/passwd
   or
 ! .Pa /etc/group .
   .It Ar mode 
   Specifies the mode of the log file and archives.
   .It Ar count
 ! Specifies the number of archive files to be kept besides the log file itself.
   .It Ar size
   When the size of the log file reaches
   .Ar size ,
   the log file will be trimmed as described above.  If this field
   is replaced by a
 ! .Dq * ,
   then the size of the log file is not taken into account
   when determining when to trim the log file.
   of archives
 ***************
 *** 95,101 ****
   .Ar interval
   hours have passed, the log file will be trimmed.  If this field is
   replaced by a
 ! .Ar * ,
   then the number of hours since the last time the log was
   trimmed will not be taken into consideration.
   .It Ar flags
 --- 100,106 ----
   .Ar interval
   hours have passed, the log file will be trimmed.  If this field is
   replaced by a
 ! .Dq * ,
   then the number of hours since the last time the log was
   trimmed will not be taken into consideration.
   .It Ar flags
 ***************
 *** 113,118 ****
 --- 118,143 ----
   .Nm
   inserts to indicate the fact that the logs have been
   turned over should not be included.
 + The
 + .Ar N
 + flag means no flags are specified.  This is used so that you can specify
 + the next option when you don't want to compress or mark the log as binary.
 + .It Ar pid_file
 + The
 + .Ar pid_file
 + is the file that the process id is to be read out of.  The process id is then
 + sent a signal to tell the process to reopen it's log file.  If
 + .Ar pid_file
 + is not specified it will default to
 + .Pa /var/run/syslog.pid
 + .It Ar signal
 + The
 + .Ar signal
 + is the name or number of the signal to be sent to the process id.
 + If
 + .Ar signal
 + is not specified it will default to
 + .Dv SIGHUP .
   .El
   .Sh OPTIONS
   The following options can be used with newsyslog:
 ***************
 *** 154,160 ****
   Theodore Ts'o, MIT Project Athena
   .Pp
   Copyright 1987, Massachusetts Institute of Technology
 ! .Sh "SEE ALSO"
   .Xr gzip 1 ,
   .Xr syslog 3 ,
   .Xr syslogd 8
 --- 179,185 ----
   Theodore Ts'o, MIT Project Athena
   .Pp
   Copyright 1987, Massachusetts Institute of Technology
 ! .Sh SEE ALSO
   .Xr gzip 1 ,
   .Xr syslog 3 ,
   .Xr syslogd 8
 Index: newsyslog.c
 ===================================================================
 RCS file: /usr/cvs/src/usr.sbin/newsyslog/newsyslog.c,v
 retrieving revision 1.9
 diff -c -r1.9 newsyslog.c
 *** newsyslog.c	1997/02/22 16:08:26	1.9
 --- newsyslog.c	1997/03/03 07:42:39
 ***************
 *** 36,42 ****
   #define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
   #endif
   #ifndef PIDFILE
 ! #define PIDFILE "/etc/syslog.pid"
   #endif
   #ifndef COMPRESS_PATH
   #define COMPRESS_PATH "/usr/ucb/compress" /* File compression program */
 --- 36,42 ----
   #define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
   #endif
   #ifndef PIDFILE
 ! #define PIDFILE _PATH_LOGPID
   #endif
   #ifndef COMPRESS_PATH
   #define COMPRESS_PATH "/usr/ucb/compress" /* File compression program */
 ***************
 *** 47,52 ****
 --- 47,58 ----
   #ifndef COMPRESS_POSTFIX
   #define COMPRESS_POSTFIX ".Z"
   #endif
 + #ifndef DEFAULT_SIGNAL
 + #define DEFAULT_SIGNAL	SIGHUP
 + #endif
 + #ifndef SIGNAL_PREFIX
 + #define SIGNAL_PREFIX "sig"
 + #endif
   
   #include <stdio.h>
   #include <stdlib.h>
 ***************
 *** 63,68 ****
 --- 69,75 ----
   #include <sys/stat.h>
   #include <sys/param.h>
   #include <sys/wait.h>
 + #include <pathnames.h>
   
   #define kbytes(size)  (((size) + 1023) >> 10)
   #ifdef _IBMR2
 ***************
 *** 84,89 ****
 --- 91,99 ----
           int     hours;          /* Hours between log trimming */
           int     permissions;    /* File permissions on the log */
           int     flags;          /* Flags (CE_COMPACT & CE_BINARY)  */
 + 	char	*pid_file;	/* PID file of program to HUP */
 + 	int	pid;		/* PID from file */
 + 	int	signal;		/* signal to deliever to process */
           struct conf_entry       *next; /* Linked list pointer */
   };
   
 ***************
 *** 93,99 ****
   int     noaction = 0;           /* Don't do anything, just show it */
   char    *conf = CONF;           /* Configuration file to use */
   time_t  timenow;
 - int     syslog_pid;             /* read in from /etc/syslog.pid */
   #define MIN_PID		3
   #define MAX_PID		30000   /* was 65534, see /usr/include/sys/proc.h */
   char    hostname[MAXHOSTNAMELEN+1]; /* hostname */
 --- 103,108 ----
 ***************
 *** 110,120 ****
   static void do_entry(struct conf_entry *ent);
   static void PRS(int argc,char **argv);
   static void usage();
 ! static void dotrim(char *log,int numdays,int falgs,int perm, int owner_uid,int group_gid);
   static int log_trim(char *log);
   static void compress_log(char *log);
   static int sizefile(char *file);
   static int age_old_log(char *file);
   
   int main(argc,argv)
           int argc;
 --- 119,131 ----
   static void do_entry(struct conf_entry *ent);
   static void PRS(int argc,char **argv);
   static void usage();
 ! static void dotrim(char *log,int numdays,int falgs,int perm, int owner_uid,int group_gid, int pid, char *pid_file, int sig);
   static int log_trim(char *log);
   static void compress_log(char *log);
   static int sizefile(char *file);
   static int age_old_log(char *file);
 + static int get_pid(char *file);
 + static char *strtoupper(const char *str);
   
   int main(argc,argv)
           int argc;
 ***************
 *** 137,142 ****
 --- 148,171 ----
           return(0);
   }
   
 + static int get_pid(char *file)
 + {
 + 	char line[13];
 + 	FILE *f;
 + 
 +         f = fopen(file,"r");
 +         if (f && fgets(line,sizeof(line), f)) {
 + 		if(f)
 + 			(void)fclose(f);
 +                 return atoi(line);
 + 	}
 + 
 + 	if (f)
 + 		(void)fclose(f);
 + 
 + 	return 0;
 + }
 + 
   static void do_entry(ent)
           struct conf_entry       *ent;
           
 ***************
 *** 173,179 ****
                                                  ent->log,ent->numlogs);
                           }
                           dotrim(ent->log, ent->numlogs, ent->flags,
 !                                ent->permissions, ent->uid, ent->gid);
                   } else {
                           if (verbose)
                                   printf("--> skipping\n");
 --- 202,209 ----
                                                  ent->log,ent->numlogs);
                           }
                           dotrim(ent->log, ent->numlogs, ent->flags,
 !                                ent->permissions, ent->uid, ent->gid, ent->pid,
 ! 			       ent->pid_file, ent->signal);
                   } else {
                           if (verbose)
                                   printf("--> skipping\n");
 ***************
 *** 186,193 ****
           char **argv;
   {
           int     c;
 -         FILE    *f;
 -         char    line[BUFSIZ];
   	char	*p;
   
           progname = argv[0];
 --- 216,221 ----
 ***************
 *** 195,208 ****
           daytime = ctime(&timenow) + 4;
           daytime[15] = '\0';
   
 -         /* Let's find the pid of syslogd */
 -         syslog_pid = 0;
 -         f = fopen(PIDFILE,"r");
 -         if (f && fgets(line,BUFSIZ,f))
 -                 syslog_pid = atoi(line);
 - 	if (f)
 - 		(void)fclose(f);
 - 
           /* Let's get our hostname */
           (void) gethostname(hostname, sizeof(hostname));
   
 --- 223,228 ----
 ***************
 *** 257,263 ****
                   f = stdin;
           if (!f)
                   err(1, "%s", conf);
 !         while (fgets(line,BUFSIZ,f)) {
                   if ((line[0]== '\n') || (line[0] == '#'))
                           continue;
                   errline = strdup(line);
 --- 277,283 ----
                   f = stdin;
           if (!f)
                   err(1, "%s", conf);
 !         while (memset(line, 0, BUFSIZ), fgets(line,BUFSIZ-5,f)) {
                   if ((line[0]== '\n') || (line[0] == '#'))
                           continue;
                   errline = strdup(line);
 ***************
 *** 340,350 ****
                                   working->flags |= CE_COMPACT;
                           else if ((*q == 'B') || (*q == 'b'))
                                   working->flags |= CE_BINARY;
 !                         else
                              errx(1, "Illegal flag in config file -- %c", *q);
                           q++;
                   }
                   
                   free(errline);
           }
           if (working)
 --- 360,415 ----
                                   working->flags |= CE_COMPACT;
                           else if ((*q == 'B') || (*q == 'b'))
                                   working->flags |= CE_BINARY;
 !                         else if ((*q == 'N') || (*q == 'n')) {
 ! 				/* nop */
 ! 			} else
                              errx(1, "Illegal flag in config file -- %c", *q);
                           q++;
                   }
 + 
 + 		q = parse = sob(++parse); /* Optional field */
 + 		*(parse = son(parse)) = '\0';
 + 		if(q && *q)
 + 			working->pid_file=strdup(q);
 + 		else
 + 			working->pid_file=NULL;
                   
 + 		if(working->pid_file == NULL)
 + 			working->pid_file=strdup(PIDFILE);
 + 
 + 		if((working->pid=get_pid(working->pid_file)) == 0)
 + 			errx(1, "can't read pid out of file %s",
 + 			    working->pid_file);
 + 
 +                 q = parse = sob(++parse); /* Optional field */
 +                 *(parse = son(parse)) = '\0';
 +                 if (q && *q) {
 + 			if(isdigit(*q)) {
 + 				/* they provided a decimal signal number */
 +                         	working->signal = atoi(q);
 + 				if (working->signal <= 0 ||
 + 				    working->signal >= NSIG)
 + 					errx(1, "signal %d is invalid in config line: %s",
 + 					    working->signal, errline);
 + 			} else {
 + 				/* search for a matching signal name */
 + 				int i;
 + 				if(!strncasecmp(q, SIGNAL_PREFIX,
 + 				    sizeof(SIGNAL_PREFIX)-1))
 + 					q += sizeof(SIGNAL_PREFIX)-1;
 + 				for (i=1; i < NSIG &&
 + 				   strcasecmp(q, sys_signame[i]); i++);
 + 				if(i == NSIG)
 + 					errx(1, "could not find signal %s, on line: %s",
 + 					    q, errline);
 + 				else
 + 					working->signal = i;
 + 			}
 + 		} else {
 + 			/* no signal provided, use default */
 +                         working->signal = DEFAULT_SIGNAL;
 + 		}
 + 
                   free(errline);
           }
           if (working)
 ***************
 *** 361,373 ****
           return(p);
   }
   
 ! static void dotrim(log,numdays,flags,perm,owner_uid,group_gid)
           char    *log;
           int     numdays;
           int     flags;
           int     perm;
           int     owner_uid;
           int     group_gid;
   {
           char    file1 [MAXPATHLEN+1], file2 [MAXPATHLEN+1];
           char    zfile1[MAXPATHLEN+1], zfile2[MAXPATHLEN+1];
 --- 426,441 ----
           return(p);
   }
   
 ! static void dotrim(log,numdays,flags,perm,owner_uid,group_gid,pid,pid_file,sig)
           char    *log;
           int     numdays;
           int     flags;
           int     perm;
           int     owner_uid;
           int     group_gid;
 + 	int	pid;
 + 	char	*pid_file;
 + 	int	sig;
   {
           char    file1 [MAXPATHLEN+1], file2 [MAXPATHLEN+1];
           char    zfile1[MAXPATHLEN+1], zfile2[MAXPATHLEN+1];
 ***************
 *** 451,463 ****
                   printf("chmod %o %s...",perm,log);
           else
                   (void) chmod(log,perm);
 !         if (noaction)
 !                 printf("kill -HUP %d (syslogd)\n",syslog_pid);
 !         else
 ! 	if (syslog_pid < MIN_PID || syslog_pid > MAX_PID) {
 ! 		warnx("preposterous process number: %d", syslog_pid);
 !         } else if (kill(syslog_pid,SIGHUP))
 !                 warn("could not restart syslogd");
           if (flags & CE_COMPACT) {
                   if (noaction)
                           printf("Compress %s.0\n",log);
 --- 519,532 ----
                   printf("chmod %o %s...",perm,log);
           else
                   (void) chmod(log,perm);
 !         if (noaction) {
 ! 		printf("kill -%s %d (%s)\n", strtoupper(sys_signame[sig]),
 ! 		    pid, pid_file);
 !         } else
 ! 	if (pid < MIN_PID || pid > MAX_PID) {
 ! 		warnx("preposterous process number %d from %s", pid, pid_file);
 !         } else if (kill(pid,sig))
 !                 warn("could not restart pid %d from %s", pid, pid_file);
           if (flags & CE_COMPACT) {
                   if (noaction)
                           printf("Compress %s.0\n",log);
 ***************
 *** 553,556 ****
 --- 622,642 ----
           while (p && *p && !isspace(*p))
                   p++;
           return(p);
 + }
 + 
 + static char *strtoupper(str)
 + 	register const char	*str;
 + {
 + 	static char *buf;
 + 	register int i;
 + 
 + 	if(buf)
 + 		free(buf);
 + 
 + 	buf=malloc(strlen(str)+1);
 + 
 + 	i=0;
 + 	while((buf[i++]=toupper(str[i])) != '\0');
 + 
 + 	return buf;
   }
 
 --+WCv1s2RzB2fBlYC--
State-Changed-From-To: open->closed 
State-Changed-By: brian 
State-Changed-When: Sat Sep 13 04:09:13 PDT 1997 
State-Changed-Why:  
A pidfile field was introduced by ache.  It's probably worth 
submitting these changes at some point as they're more flexable, 
but the problem is no longer a "fault" :-) 
>Unformatted:
