1f0a68c5gad/*-
2f0a68c5gad * ------+---------+---------+-------- + --------+---------+---------+---------*
3f0a68c5gad * This file includes significant modifications done by:
4f0a68c5gad * Copyright (c) 2003, 2004  - Garance Alistair Drosehn <gad@FreeBSD.org>.
5f0a68c5gad * All rights reserved.
6f0a68c5gad *
7f0a68c5gad * Redistribution and use in source and binary forms, with or without
8f0a68c5gad * modification, are permitted provided that the following conditions
9f0a68c5gad * are met:
10f0a68c5gad *   1. Redistributions of source code must retain the above copyright
11f0a68c5gad *      notice, this list of conditions and the following disclaimer.
12f0a68c5gad *   2. Redistributions in binary form must reproduce the above copyright
13f0a68c5gad *      notice, this list of conditions and the following disclaimer in the
14f0a68c5gad *      documentation and/or other materials provided with the distribution.
15f0a68c5gad *
16f0a68c5gad * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f0a68c5gad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f0a68c5gad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f0a68c5gad * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f0a68c5gad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f0a68c5gad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f0a68c5gad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f0a68c5gad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f0a68c5gad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f0a68c5gad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f0a68c5gad * SUCH DAMAGE.
27f0a68c5gad *
28f0a68c5gad * ------+---------+---------+-------- + --------+---------+---------+---------*
29f0a68c5gad */
30f0a68c5gad
31adc7000graichen/*
32adc7000graichen * This file contains changes from the Open Software Foundation.
33adc7000graichen */
34adc7000graichen
35adc7000graichen/*
36aef627dhm * Copyright 1988, 1989 by the Massachusetts Institute of Technology
37aef627dhm *
38aef627dhm * Permission to use, copy, modify, and distribute this software and its
39aef627dhm * documentation for any purpose and without fee is hereby granted, provided
40aef627dhm * that the above copyright notice appear in all copies and that both that
41aef627dhm * copyright notice and this permission notice appear in supporting
42aef627dhm * documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
43aef627dhm * used in advertising or publicity pertaining to distribution of the
44aef627dhm * software without specific, written prior permission. M.I.T. and the M.I.T.
45aef627dhm * S.I.P.B. make no representations about the suitability of this software
46aef627dhm * for any purpose.  It is provided "as is" without express or implied
47aef627dhm * warranty.
48aef627dhm *
49aef627dhm */
50adc7000graichen
51adc7000graichen/*
52aef627dhm * newsyslog - roll over selected logs at the appropriate time, keeping the a
53aef627dhm * specified number of backup files around.
54adc7000graichen */
55adc7000graichen
567293a24obrien#include <sys/cdefs.h>
577293a24obrien__FBSDID("$FreeBSD$");
58adc7000graichen
592769786gad#define	OSF
60adc7000graichen
61b187b46maxim#include <sys/param.h>
62f0a68c5gad#include <sys/queue.h>
63f21f9ccmarkj#include <sys/sbuf.h>
64b187b46maxim#include <sys/stat.h>
65b187b46maxim#include <sys/wait.h>
66b187b46maxim
671af623esimon#include <assert.h>
682e4411ccharnier#include <ctype.h>
692e4411ccharnier#include <err.h>
70f4c5d52maxim#include <errno.h>
711af623esimon#include <dirent.h>
722e4411ccharnier#include <fcntl.h>
733e73a17gad#include <fnmatch.h>
74cd8d065sobomax#include <glob.h>
752e4411ccharnier#include <grp.h>
7627719c4wollman#include <paths.h>
772e4411ccharnier#include <pwd.h>
782e4411ccharnier#include <signal.h>
79adc7000graichen#include <stdio.h>
801af623esimon#include <libgen.h>
81adc7000graichen#include <stdlib.h>
82adc7000graichen#include <string.h>
8309536a5dab#include <syslog.h>
8427719c4wollman#include <time.h>
85285b22dalex#include <unistd.h>
86adc7000graichen
8727719c4wollman#include "pathnames.h"
886090914gad#include "extern.h"
8927719c4wollman
900b92471gad/*
910d3cc98mm * Compression types
920d3cc98mm */
937453e3ebapt#define	COMPRESS_TYPES  5	/* Number of supported compression types */
940d3cc98mm
950d3cc98mm#define	COMPRESS_NONE	0
960d3cc98mm#define	COMPRESS_GZIP	1
970d3cc98mm#define	COMPRESS_BZIP2	2
980d3cc98mm#define	COMPRESS_XZ	3
997453e3ebapt#define COMPRESS_ZSTD	4
1000d3cc98mm
1010d3cc98mm/*
1020b92471gad * Bit-values for the 'flags' parsed from a config-file entry.
1030b92471gad */
1042769786gad#define	CE_BINARY	0x0008	/* Logfile is in binary, do not add status */
1050b92471gad				/*    messages to logfile(s) when rotating. */
1062769786gad#define	CE_NOSIGNAL	0x0010	/* There is no process to signal when */
1070b92471gad				/*    trimming this file. */
1082769786gad#define	CE_TRIMAT	0x0020	/* trim file at a specific time. */
1092769786gad#define	CE_GLOB		0x0040	/* name of the log is file name pattern. */
1102769786gad#define	CE_SIGNALGROUP	0x0080	/* Signal a process-group instead of a single */
1111664ca4gad				/*    process when trimming this file. */
1122769786gad#define	CE_CREATE	0x0100	/* Create the log file if it does not exist. */
113848f68agad#define	CE_NODUMP	0x0200	/* Set 'nodump' on newly created log file. */
1141bbc0basobomax#define	CE_PID2CMD	0x0400	/* Replace PID file with a shell command.*/
115a910215eadler#define	CE_PLAIN0	0x0800	/* Do not compress zero'th history file */
116a86549amarkj#define	CE_RFC5424	0x1000	/* Use RFC5424 format rotation message */
11709536a5dab
1182769786gad#define	MIN_PID         5	/* Don't touch pids lower than this */
1192769786gad#define	MAX_PID		99999	/* was lower, see /usr/include/sys/proc.h */
12089abc18gad
1212769786gad#define	kbytes(size)  (((size) + 1023) >> 10)
12227719c4wollman
1233e7bce2gad#define	DEFAULT_MARKER	"<default>"
1243e7bce2gad#define	DEBUG_MARKER	"<debug>"
1254fcdf7cgordon#define	INCLUDE_MARKER	"<include>"
1261af623esimon#define	DEFAULT_TIMEFNAME_FMT	"%Y%m%dT%H%M%S"
1271af623esimon
1281af623esimon#define	MAX_OLDLOGS 65536	/* Default maximum number of old logfiles */
1293e7bce2gad
1300d3cc98mmstruct compress_types {
1310d3cc98mm	const char *flag;	/* Flag in configuration file */
1320d3cc98mm	const char *suffix;	/* Compression suffix */
1330d3cc98mm	const char *path;	/* Path to compression program */
134f21f9ccmarkj	const char **flags;	/* Compression program flags */
135f21f9ccmarkj	int nflags;		/* Program flags count */
1360d3cc98mm};
1370d3cc98mm
138f21f9ccmarkjstatic const char *gzip_flags[] = { "-f" };
139f21f9ccmarkj#define bzip2_flags gzip_flags
140f21f9ccmarkj#define xz_flags gzip_flags
141f21f9ccmarkjstatic const char *zstd_flags[] = { "-q", "--rm" };
14219f5c9dbapt
143c23d2a4edstatic const struct compress_types compress_type[COMPRESS_TYPES] = {
144f21f9ccmarkj	{ "", "", "", NULL, 0 },
145f21f9ccmarkj	{ "Z", ".gz", _PATH_GZIP, gzip_flags, nitems(gzip_flags) },
146f21f9ccmarkj	{ "J", ".bz2", _PATH_BZIP2, bzip2_flags, nitems(bzip2_flags) },
147f21f9ccmarkj	{ "X", ".xz", _PATH_XZ, xz_flags, nitems(xz_flags) },
148f21f9ccmarkj	{ "Y", ".zst", _PATH_ZSTD, zstd_flags, nitems(zstd_flags) }
1490d3cc98mm};
1500d3cc98mm
151adc7000graichenstruct conf_entry {
1525224579gordon	STAILQ_ENTRY(conf_entry) cf_nextp;
153b5fa5b4hm	char *log;		/* Name of the log */
1541bbc0basobomax	char *pid_cmd_file;		/* PID or command file */
1556133e17gad	char *r_reason;		/* The reason this file is being rotated */
1566a34ae8gad	int firstcreate;	/* Creating log for the first time (-C). */
1576133e17gad	int rotate;		/* Non-zero if this file should be rotated */
1583e7bce2gad	int fsize;		/* size found for the log file */
159b65d7a6gad	uid_t uid;		/* Owner of log */
160b65d7a6gad	gid_t gid;		/* Group of log */
161b5fa5b4hm	int numlogs;		/* Number of logs to keep */
1623e7bce2gad	int trsize;		/* Size cutoff to trigger trimming the log */
163b5fa5b4hm	int hours;		/* Hours between log trimming */
1648dafe43gad	struct ptime_data *trim_at;	/* Specific time to do trimming */
165985415fdelphij	unsigned int permissions;	/* File permissions on the log */
1660d3cc98mm	int flags;		/* CE_BINARY */
1670d3cc98mm	int compress;		/* Compression */
168b5fa5b4hm	int sig;		/* Signal to send */
16906f0413gad	int def_cfg;		/* Using the <default> rule for this file */
170adc7000graichen};
171adc7000graichen
172f0a68c5gadstruct sigwork_entry {
173f0a68c5gad	SLIST_ENTRY(sigwork_entry) sw_nextp;
174f0a68c5gad	int	 sw_signum;		/* the signal to send */
175f0a68c5gad	int	 sw_pidok;		/* true if pid value is valid */
176f0a68c5gad	pid_t	 sw_pid;		/* the process id from the PID file */
177f0a68c5gad	const char *sw_pidtype;		/* "daemon" or "process group" */
178d68a334markj	int	 sw_runcmd;		/* run command or send PID to signal */
1791bbc0basobomax	char	 sw_fname[1];		/* file the PID was read from or shell cmd */
180f0a68c5gad};
181f0a68c5gad
182f0a68c5gadstruct zipwork_entry {
183f0a68c5gad	SLIST_ENTRY(zipwork_entry) zw_nextp;
184f0a68c5gad	const struct conf_entry *zw_conf;	/* for chown/perm/flag info */
185f0a68c5gad	const struct sigwork_entry *zw_swork;	/* to know success of signal */
186f0a68c5gad	int	 zw_fsize;		/* size of the file to compress */
187f0a68c5gad	char	 zw_fname[1];		/* the file to compress */
188f0a68c5gad};
189f0a68c5gad
1904fcdf7cgordonstruct include_entry {
1914fcdf7cgordon	STAILQ_ENTRY(include_entry) inc_nextp;
1924fcdf7cgordon	const char *file;	/* Name of file to process */
1934fcdf7cgordon};
1944fcdf7cgordon
1951af623esimonstruct oldlog_entry {
1961af623esimon	char *fname;		/* Filename of the log file */
19763a10f1simon	time_t t;		/* Parsed timestamp of the logfile */
1981af623esimon};
1991af623esimon
2003e7bce2gadtypedef enum {
2013e7bce2gad	FREE_ENT, KEEP_ENT
2023e7bce2gad}	fk_entry;
20306f0413gad
2045224579gordonSTAILQ_HEAD(cflist, conf_entry);
205c23d2a4edstatic SLIST_HEAD(swlisthead, sigwork_entry) swhead =
206c23d2a4ed    SLIST_HEAD_INITIALIZER(swhead);
207c23d2a4edstatic SLIST_HEAD(zwlisthead, zipwork_entry) zwhead =
208c23d2a4ed    SLIST_HEAD_INITIALIZER(zwhead);
2094fcdf7cgordonSTAILQ_HEAD(ilist, include_entry);
210f0a68c5gad
2118dafe43gadint dbg_at_times;		/* -D Show details of 'trim_at' code */
2128dafe43gad
213c23d2a4edstatic int archtodir = 0;	/* Archive old logfiles to other directory */
214c23d2a4edstatic int createlogs;		/* Create (non-GLOB) logfiles which do not */
2156a34ae8gad				/*    already exist.  1=='for entries with */
2166a34ae8gad				/*    C flag', 2=='for all entries'. */
217b5fa5b4hmint verbose = 0;		/* Print out what's going on */
218c23d2a4edstatic int needroot = 1;	/* Root privs are necessary */
219b5fa5b4hmint noaction = 0;		/* Don't do anything, just show it */
220c23d2a4edstatic int norotate = 0;	/* Don't rotate */
221c23d2a4edstatic int nosignal;		/* Do not send any signals */
222c23d2a4edstatic int enforcepid = 0;	/* If PID file does not exist or empty, do nothing */
223c23d2a4edstatic int force = 0;		/* Force the trim no matter what */
224c23d2a4edstatic int rotatereq = 0;	/* -R = Always rotate the file(s) as given */
2256133e17gad				/*    on the command (this also requires   */
2266133e17gad				/*    that a list of files *are* given on  */
2276133e17gad				/*    the run command). */
228c23d2a4edstatic char *requestor;		/* The name given on a -R request */
229c23d2a4edstatic char *timefnamefmt = NULL;/* Use time based filenames instead of .0 */
230c23d2a4edstatic char *archdirname;	/* Directory path to old logfiles archive */
231c23d2a4edstatic char *destdir = NULL;	/* Directory to treat at root for logs */
232c23d2a4edstatic const char *conf;	/* Configuration file to use */
2338dafe43gad
2348dafe43gadstruct ptime_data *dbg_timenow;	/* A "timenow" value set via -D option */
235c23d2a4edstatic struct ptime_data *timenow; /* The time to use for checking at-fields */
236b5fa5b4hm
237d214277gad#define	DAYTIME_LEN	16
238c23d2a4edstatic char daytime[DAYTIME_LEN];/* The current time in human readable form,
239c23d2a4ed				  * used for rotation-tracking messages. */
24009536a5dab
24109536a5dab/* Another buffer to hold the current time in RFC5424 format. Fractional
24209536a5dab * seconds are allowed by the RFC, but are not included in the
24309536a5dab * rotation-tracking messages written by newsyslog and so are not accounted for
24409536a5dab * in the length below.
24509536a5dab */
24609536a5dab#define	DAYTIME_RFC5424_LEN	sizeof("YYYY-MM-DDTHH:MM:SS+00:00")
24709536a5dabstatic char daytime_rfc5424[DAYTIME_RFC5424_LEN];
24809536a5dab
249c23d2a4edstatic char hostname[MAXHOSTNAMELEN]; /* hostname */
2500bb8232edstatic size_t hostname_shortlen;
251adc7000graichen
252c23d2a4edstatic const char *path_syslogpid = _PATH_SYSLOGPID;
253c77452cbrian
2545224579gordonstatic struct cflist *get_worklist(char **files);
2555224579gordonstatic void parse_file(FILE *cf, struct cflist *work_p, struct cflist *glob_p,
2565a174e4dab		    struct conf_entry **defconf, struct ilist *inclist);
2574fcdf7cgordonstatic void add_to_queue(const char *fname, struct ilist *inclist);
258285b22dalexstatic char *sob(char *p);
259285b22dalexstatic char *son(char *p);
260b21b452gadstatic int isnumberstr(const char *);
2614fcdf7cgordonstatic int isglobstr(const char *);
262b5fa5b4hmstatic char *missing_field(char *p, char *errline);
2633e7bce2gadstatic void	 change_attrs(const char *, const struct conf_entry *);
2640d3cc98mmstatic const char *get_logfile_suffix(const char *logfile);
2653e7bce2gadstatic fk_entry	 do_entry(struct conf_entry *);
2663e7bce2gadstatic fk_entry	 do_rotate(const struct conf_entry *);
267f0a68c5gadstatic void	 do_sigwork(struct sigwork_entry *);
268f0a68c5gadstatic void	 do_zipwork(struct zipwork_entry *);
269f0a68c5gadstatic struct sigwork_entry *
270f0a68c5gad		 save_sigwork(const struct conf_entry *);
271f0a68c5gadstatic struct zipwork_entry *
272f0a68c5gad		 save_zipwork(const struct conf_entry *, const struct
273f0a68c5gad		    sigwork_entry *, int, const char *);
274f0a68c5gadstatic void	 set_swpid(struct sigwork_entry *, const struct conf_entry *);
2753e7bce2gadstatic int	 sizefile(const char *);
2765224579gordonstatic void expand_globs(struct cflist *work_p, struct cflist *glob_p);
2775224579gordonstatic void free_clist(struct cflist *list);
27806f0413gadstatic void free_entry(struct conf_entry *ent);
27906f0413gadstatic struct conf_entry *init_entry(const char *fname,
28006f0413gad		struct conf_entry *src_entry);
28189abc18gadstatic void parse_args(int argc, char **argv);
28251bcd03gadstatic int parse_doption(const char *doption);
28376dec25obrienstatic void usage(void);
284d1e43a2gadstatic int log_trim(const char *logname, const struct conf_entry *log_ent);
2853110b39markjstatic int age_old_log(const char *file);
2862837207gadstatic void savelog(char *from, char *to);
2876a34ae8gadstatic void createdir(const struct conf_entry *ent, char *dirpart);
2886a34ae8gadstatic void createlog(const struct conf_entry *ent);
289a040832baptstatic int parse_signal(const char *str);
290285b22dalex
2910b92471gad/*
2924f0e537gad * All the following take a parameter of 'int', but expect values in the
2934f0e537gad * range of unsigned char.  Define wrappers which take values of type 'char',
2944f0e537gad * whether signed or unsigned, and ensure they end up in the right range.
2950b92471gad */
2964f0e537gad#define	isdigitch(Anychar) isdigit((u_char)(Anychar))
2974f0e537gad#define	isprintch(Anychar) isprint((u_char)(Anychar))
2984f0e537gad#define	isspacech(Anychar) isspace((u_char)(Anychar))
2994f0e537gad#define	tolowerch(Anychar) tolower((u_char)(Anychar))
3000b92471gad
301aef627dhmint
302aef627dhmmain(int argc, char **argv)
303adc7000graichen{
3045224579gordon	struct cflist *worklist;
3055224579gordon	struct conf_entry *p;
306f0a68c5gad	struct sigwork_entry *stmp;
307f0a68c5gad	struct zipwork_entry *ztmp;
308f0a68c5gad
309f0a68c5gad	SLIST_INIT(&swhead);
310f0a68c5gad	SLIST_INIT(&zwhead);
311b5fa5b4hm
31289abc18gad	parse_args(argc, argv);
3133e73a17gad	argc -= optind;
3143e73a17gad	argv += optind;
3153e73a17gad
316b5fa5b4hm	if (needroot && getuid() && geteuid())
317b5fa5b4hm		errx(1, "must have root privs");
3185224579gordon	worklist = get_worklist(argv);
319b5fa5b4hm
3203e7bce2gad	/*
3213e7bce2gad	 * Rotate all the files which need to be rotated.  Note that
3223e7bce2gad	 * some users have *hundreds* of entries in newsyslog.conf!
3233e7bce2gad	 */
3245224579gordon	while (!STAILQ_EMPTY(worklist)) {
3255224579gordon		p = STAILQ_FIRST(worklist);
3265224579gordon		STAILQ_REMOVE_HEAD(worklist, cf_nextp);
3275224579gordon		if (do_entry(p) == FREE_ENT)
3285224579gordon			free_entry(p);
329b5fa5b4hm	}
3303e7bce2gad
331f0a68c5gad	/*
332f0a68c5gad	 * Send signals to any processes which need a signal to tell
333f0a68c5gad	 * them to close and re-open the log file(s) we have rotated.
334f0a68c5gad	 * Note that zipwork_entries include pointers to these
335f0a68c5gad	 * sigwork_entry's, so we can not free the entries here.
336f0a68c5gad	 */
337f0a68c5gad	if (!SLIST_EMPTY(&swhead)) {
338717539cgad		if (noaction || verbose)
339f0a68c5gad			printf("Signal all daemon process(es)...\n");
340f0a68c5gad		SLIST_FOREACH(stmp, &swhead, sw_nextp)
341f0a68c5gad			do_sigwork(stmp);
34287e8d06vangyzen		if (!(rotatereq && nosignal)) {
34387e8d06vangyzen			if (noaction)
34487e8d06vangyzen				printf("\tsleep 10\n");
34587e8d06vangyzen			else {
34687e8d06vangyzen				if (verbose)
34787e8d06vangyzen					printf("Pause 10 seconds to allow "
34887e8d06vangyzen					    "daemon(s) to close log file(s)\n");
34987e8d06vangyzen				sleep(10);
35087e8d06vangyzen			}
351717539cgad		}
352f0a68c5gad	}
353f0a68c5gad	/*
354f0a68c5gad	 * Compress all files that we're expected to compress, now
355f0a68c5gad	 * that all processes should have closed the files which
356f0a68c5gad	 * have been rotated.
357f0a68c5gad	 */
358f0a68c5gad	if (!SLIST_EMPTY(&zwhead)) {
359717539cgad		if (noaction || verbose)
360f0a68c5gad			printf("Compress all rotated log file(s)...\n");
361f0a68c5gad		while (!SLIST_EMPTY(&zwhead)) {
362f0a68c5gad			ztmp = SLIST_FIRST(&zwhead);
363f0a68c5gad			do_zipwork(ztmp);
364f0a68c5gad			SLIST_REMOVE_HEAD(&zwhead, zw_nextp);
365f0a68c5gad			free(ztmp);
366f0a68c5gad		}
367f0a68c5gad	}
368f0a68c5gad	/* Now free all the sigwork entries. */
369f0a68c5gad	while (!SLIST_EMPTY(&swhead)) {
370f0a68c5gad		stmp = SLIST_FIRST(&swhead);
371f0a68c5gad		SLIST_REMOVE_HEAD(&swhead, sw_nextp);
372f0a68c5gad		free(stmp);
373f0a68c5gad	}
374f0a68c5gad
375f4c5d52maxim	while (wait(NULL) > 0 || errno == EINTR)
376f4c5d52maxim		;
377b5fa5b4hm	return (0);
378adc7000graichen}
379adc7000graichen
38006f0413gadstatic struct conf_entry *
38106f0413gadinit_entry(const char *fname, struct conf_entry *src_entry)
38206f0413gad{
38306f0413gad	struct conf_entry *tempwork;
38406f0413gad
38506f0413gad	if (verbose > 4)
38606f0413gad		printf("\t--> [creating entry for %s]\n", fname);
38706f0413gad
38806f0413gad	tempwork = malloc(sizeof(struct conf_entry));
38906f0413gad	if (tempwork == NULL)
39006f0413gad		err(1, "malloc of conf_entry for %s", fname);
39106f0413gad
392626003dbrooks	if (destdir == NULL || fname[0] != '/')
393a8b1fd9brooks		tempwork->log = strdup(fname);
394a8b1fd9brooks	else
395a8b1fd9brooks		asprintf(&tempwork->log, "%s%s", destdir, fname);
39606f0413gad	if (tempwork->log == NULL)
39706f0413gad		err(1, "strdup for %s", fname);
39806f0413gad
39906f0413gad	if (src_entry != NULL) {
4001bbc0basobomax		tempwork->pid_cmd_file = NULL;
4011bbc0basobomax		if (src_entry->pid_cmd_file)
4021bbc0basobomax			tempwork->pid_cmd_file = strdup(src_entry->pid_cmd_file);
4036133e17gad		tempwork->r_reason = NULL;
4046a34ae8gad		tempwork->firstcreate = 0;
4056133e17gad		tempwork->rotate = 0;
4063e7bce2gad		tempwork->fsize = -1;
40706f0413gad		tempwork->uid = src_entry->uid;
40806f0413gad		tempwork->gid = src_entry->gid;
40906f0413gad		tempwork->numlogs = src_entry->numlogs;
4103e7bce2gad		tempwork->trsize = src_entry->trsize;
41106f0413gad		tempwork->hours = src_entry->hours;
4128dafe43gad		tempwork->trim_at = NULL;
4138dafe43gad		if (src_entry->trim_at != NULL)
4148dafe43gad			tempwork->trim_at = ptime_init(src_entry->trim_at);
41506f0413gad		tempwork->permissions = src_entry->permissions;
41606f0413gad		tempwork->flags = src_entry->flags;
4170d3cc98mm		tempwork->compress = src_entry->compress;
41806f0413gad		tempwork->sig = src_entry->sig;
41906f0413gad		tempwork->def_cfg = src_entry->def_cfg;
42006f0413gad	} else {
42106f0413gad		/* Initialize as a "do-nothing" entry */
4221bbc0basobomax		tempwork->pid_cmd_file = NULL;
4236133e17gad		tempwork->r_reason = NULL;
4246a34ae8gad		tempwork->firstcreate = 0;
4256133e17gad		tempwork->rotate = 0;
4263e7bce2gad		tempwork->fsize = -1;
427b65d7a6gad		tempwork->uid = (uid_t)-1;
428b65d7a6gad		tempwork->gid = (gid_t)-1;
42906f0413gad		tempwork->numlogs = 1;
4303e7bce2gad		tempwork->trsize = -1;
43106f0413gad		tempwork->hours = -1;
4328dafe43gad		tempwork->trim_at = NULL;
43306f0413gad		tempwork->permissions = 0;
43406f0413gad		tempwork->flags = 0;
4350d3cc98mm		tempwork->compress = COMPRESS_NONE;
43606f0413gad		tempwork->sig = SIGHUP;
43706f0413gad		tempwork->def_cfg = 0;
43806f0413gad	}
43906f0413gad
44006f0413gad	return (tempwork);
44106f0413gad}
44206f0413gad
44306f0413gadstatic void
44406f0413gadfree_entry(struct conf_entry *ent)
44506f0413gad{
44606f0413gad
44706f0413gad	if (ent == NULL)
44806f0413gad		return;
44906f0413gad
45006f0413gad	if (ent->log != NULL) {
45106f0413gad		if (verbose > 4)
45206f0413gad			printf("\t--> [freeing entry for %s]\n", ent->log);
45306f0413gad		free(ent->log);
45406f0413gad		ent->log = NULL;
45506f0413gad	}
45606f0413gad
4571bbc0basobomax	if (ent->pid_cmd_file != NULL) {
4581bbc0basobomax		free(ent->pid_cmd_file);
4591bbc0basobomax		ent->pid_cmd_file = NULL;
46006f0413gad	}
46106f0413gad
4626133e17gad	if (ent->r_reason != NULL) {
4636133e17gad		free(ent->r_reason);
4646133e17gad		ent->r_reason = NULL;
4656133e17gad	}
4666133e17gad
4678dafe43gad	if (ent->trim_at != NULL) {
4688dafe43gad		ptime_free(ent->trim_at);
4698dafe43gad		ent->trim_at = NULL;
4708dafe43gad	}
4718dafe43gad
47206f0413gad	free(ent);
47306f0413gad}
47406f0413gad
475aef627dhmstatic void
4765224579gordonfree_clist(struct cflist *list)
477cb92a79gad{
4785224579gordon	struct conf_entry *ent;
479cb92a79gad
4805224579gordon	while (!STAILQ_EMPTY(list)) {
4815224579gordon		ent = STAILQ_FIRST(list);
4825224579gordon		STAILQ_REMOVE_HEAD(list, cf_nextp);
483cb92a79gad		free_entry(ent);
484cb92a79gad	}
4855224579gordon
4865224579gordon	free(list);
4875224579gordon	list = NULL;
488cb92a79gad}
489cb92a79gad
4903e7bce2gadstatic fk_entry
491aef627dhmdo_entry(struct conf_entry * ent)
492adc7000graichen{
4932769786gad#define	REASON_MAX	80
4943e7bce2gad	int modtime;
4953e7bce2gad	fk_entry free_or_keep;
4968dafe43gad	double diffsecs;
4976133e17gad	char temp_reason[REASON_MAX];
49814f4e1dglebius	int oversized;
499b5fa5b4hm
5003e7bce2gad	free_or_keep = FREE_ENT;
5010d3cc98mm	if (verbose)
5020d3cc98mm		printf("%s <%d%s>: ", ent->log, ent->numlogs,
5030d3cc98mm		    compress_type[ent->compress].flag);
5043e7bce2gad	ent->fsize = sizefile(ent->log);
50514f4e1dglebius	oversized = ((ent->trsize > 0) && (ent->fsize >= ent->trsize));
506b5fa5b4hm	modtime = age_old_log(ent->log);
5076133e17gad	ent->rotate = 0;
5086a34ae8gad	ent->firstcreate = 0;
5093e7bce2gad	if (ent->fsize < 0) {
5106a34ae8gad		/*
5116a34ae8gad		 * If either the C flag or the -C option was specified,
5126a34ae8gad		 * and if we won't be creating the file, then have the
5136a34ae8gad		 * verbose message include a hint as to why the file
5146a34ae8gad		 * will not be created.
5156a34ae8gad		 */
5166a34ae8gad		temp_reason[0] = '\0';
5176a34ae8gad		if (createlogs > 1)
5186a34ae8gad			ent->firstcreate = 1;
5196a34ae8gad		else if ((ent->flags & CE_CREATE) && createlogs)
5206a34ae8gad			ent->firstcreate = 1;
5216a34ae8gad		else if (ent->flags & CE_CREATE)
522d214277gad			strlcpy(temp_reason, " (no -C option)", REASON_MAX);
5236a34ae8gad		else if (createlogs)
524d214277gad			strlcpy(temp_reason, " (no C flag)", REASON_MAX);
5256a34ae8gad
5266a34ae8gad		if (ent->firstcreate) {
5276a34ae8gad			if (verbose)
5286a34ae8gad				printf("does not exist -> will create.\n");
5296a34ae8gad			createlog(ent);
5306a34ae8gad		} else if (verbose) {
5316a34ae8gad			printf("does not exist, skipped%s.\n", temp_reason);
5326a34ae8gad		}
533b5fa5b4hm	} else {
53414f4e1dglebius		if (ent->flags & CE_TRIMAT && !force && !rotatereq &&
53514f4e1dglebius		    !oversized) {
5368dafe43gad			diffsecs = ptimeget_diff(timenow, ent->trim_at);
5378dafe43gad			if (diffsecs < 0.0) {
5388dafe43gad				/* trim_at is some time in the future. */
5398dafe43gad				if (verbose) {
5408dafe43gad					ptime_adjust4dst(ent->trim_at,
5418dafe43gad					    timenow);
54227719c4wollman					printf("--> will trim at %s",
5438dafe43gad					    ptimeget_ctime(ent->trim_at));
5448dafe43gad				}
545