Download raw body.
newsyslog: support glob(3) through new G flag
On 2024-04-24 19:12, "Todd C. Miller" <Todd.Miller@sudo.ws> wrote:
> Do we really need yet another flag bit for this? If we want to
> support globbing it should be enough to check for glob characters
> in logfile_name and call glob(3) if they are present.
Thanks for your comment. This seems fair enough. I have attached an
updated diff with this change.
Best,
Alvar
diff --git usr.bin/newsyslog/newsyslog.8 usr.bin/newsyslog/newsyslog.8
index 9e3f84a0b26..4dd95cb8e12 100644
--- usr.bin/newsyslog/newsyslog.8
+++ usr.bin/newsyslog/newsyslog.8
@@ -170,7 +170,7 @@ By default, this configuration file is
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 up to three optional fields, with
+Each line has five mandatory fields and up to four optional fields, with
whitespace separating each field.
Blank lines or lines beginning with a hash mark
.Pq Ql #
@@ -180,6 +180,9 @@ follows:
.Bl -tag -width XXXXXXXXXXXXXXXX
.It Ar logfile_name
The full pathname of the system log file to be archived.
+This path might be a
+.Xr glob 7
+pattern, which will be expanded accordingly.
.It Ar owner:group
This optional field specifies the owner and group for the archive file.
The
@@ -359,8 +362,13 @@ rotate on every 5th day of the month at 6:00 hr
.It Ar flags
The optional
.Ar flags
-field specifies if the archives should have any special processing
-done to the archived log files.
+field specifies any special processing for each entry.
+Multiple
+.Ar flags
+can be concatenated together.
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Li Z
The
.Sq Z
flag will make the archive
@@ -368,7 +376,9 @@ files compressed to save space using
.Xr gzip 1
or
.Xr compress 1 ,
-depending on compilation options.
+depending on compilation options, defaulting to
+.Xr gzip 1 .
+.It Li B
The
.Sq B
flag means that the file is a
@@ -376,13 +386,16 @@ binary file, and so the ASCII message which
.Nm
inserts to indicate the fact that the logs have been turned over
should not be included.
+.It Li M
The
.Sq M
flag marks this entry as a monitored
log file.
+.It Li F
The
.Sq F
flag specifies that symbolic links should be followed.
+.El
.It Ar monitor
Specify the username (or email address) that should receive notification
messages if this is a monitored log file.
@@ -434,6 +447,7 @@ default configuration file
.Sh SEE ALSO
.Xr compress 1 ,
.Xr gzip 1 ,
+.Xr glob 7 ,
.Xr syslog 3 ,
.Xr syslogd 8
.Sh AUTHORS
diff --git usr.bin/newsyslog/newsyslog.c usr.bin/newsyslog/newsyslog.c
index 852f1dfac87..3fbf230d5a4 100644
--- usr.bin/newsyslog/newsyslog.c
+++ usr.bin/newsyslog/newsyslog.c
@@ -88,6 +88,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <glob.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
@@ -160,6 +161,7 @@ int stat_suffix(char *, size_t, char *, struct stat *,
int (*)(const char *, struct stat *));
off_t sizefile(struct stat *);
int parse_file(struct entrylist *, int *);
+int parse_entry(struct entrylist *, int *, int, struct conf_entry *);
time_t parse8601(char *);
time_t parseDWM(char *);
void child_killer(int);
@@ -471,12 +473,13 @@ int
parse_file(struct entrylist *list, int *nentries)
{
char line[BUFSIZ], *parse, *q, *errline, *group, *tmp, *ep;
- struct conf_entry *working;
- struct stat sb;
+ struct conf_entry *working, *working_glob;
+ size_t i;
int lineno = 0;
int ret = 0;
FILE *f;
long l;
+ glob_t g;
if (strcmp(conf, "-") == 0)
f = stdin;
@@ -504,9 +507,6 @@ nextline:
if (working->log == NULL)
err(1, NULL);
- if ((working->logbase = strrchr(working->log, '/')) != NULL)
- working->logbase++;
-
q = parse = missing_field(sob(++parse), errline, lineno);
*(parse = son(parse)) = '\0';
if ((group = strchr(q, ':')) != NULL ||
@@ -717,57 +717,111 @@ nextline:
goto nextline;
}
- /* If there is an arcdir, set working->backdir. */
- if (arcdir != NULL && working->logbase != NULL) {
- if (*arcdir == '/') {
- /* Fully qualified arcdir */
- working->backdir = arcdir;
- } else {
- /* arcdir is relative to log's parent dir */
- *(working->logbase - 1) = '\0';
- if ((asprintf(&working->backdir, "%s/%s",
- working->log, arcdir)) == -1)
- err(1, NULL);
- *(working->logbase - 1) = '/';
- }
- /* Ignore arcdir if it doesn't exist. */
- if (stat(working->backdir, &sb) != 0 ||
- !S_ISDIR(sb.st_mode)) {
- if (working->backdir != arcdir)
- free(working->backdir);
- working->backdir = NULL;
- }
- } else
- working->backdir = NULL;
-
- /* Make sure we can't oflow PATH_MAX */
- if (working->backdir != NULL) {
- if (snprintf(line, sizeof(line), "%s/%s.%d%s",
- working->backdir, working->logbase,
- working->numlogs, COMPRESS_POSTFIX) >= PATH_MAX) {
- warnx("%s:%d: pathname too long: %s"
- " --> skipping", conf, lineno, q);
+ if (strpbrk(working->log, "*?[")) {
+ /*
+ * This case also matches for escaped glob characters. However, the
+ * glob(3) function itself honors escape characters, thus resulting
+ * to a globed file list with only the desired logfile.
+ */
+ if (glob(working->log, GLOB_NOSORT, NULL, &g)) {
+ warnx("%s:%d: cannot glob(3), %s --> skipping",
+ conf, lineno, strerror(errno));
ret = 1;
goto nextline;
}
- } else {
- if (snprintf(line, sizeof(line), "%s.%d%s",
- working->log, working->numlogs, COMPRESS_POSTFIX)
- >= PATH_MAX) {
- warnx("%s:%d: pathname too long: %s"
- " --> skipping", conf, lineno,
- working->log);
+ DPRINTF(("%s:%d: expanded glob %s to %zu files\n",
+ conf, lineno, working->log, g.gl_pathc));
+
+ for (i = 0; i < g.gl_pathc; i++) {
+ working_glob = malloc(sizeof(*working));
+ if (working_glob == NULL)
+ err(1, NULL);
+
+ memcpy(working_glob, working, sizeof(*working));
+
+ if ((working_glob->log = strdup(g.gl_pathv[i])) == NULL)
+ err(1, NULL);
+
+ if (parse_entry(list, nentries, lineno, working_glob)) {
+ ret = 1;
+ goto nextline;
+ }
+ }
+
+ /*
+ * It is not necessary to duplicate and free the other three char
+ * pointers in conf_entry as those values are identical for each
+ * globed file. Even more important, later on they will only be
+ * referenced in a reading fashion.
+ */
+ free(working->log);
+ free(working);
+
+ globfree(&g);
+ } else
+ if (parse_entry(list, nentries, lineno, working)) {
ret = 1;
goto nextline;
}
- }
- TAILQ_INSERT_TAIL(list, working, next);
- (*nentries)++;
}
(void)fclose(f);
return (ret);
}
+int
+parse_entry(
+ struct entrylist *list, int *nentries,
+ int lineno, struct conf_entry *working
+)
+{
+ char line[BUFSIZ];
+ int linelen;
+ struct stat sb;
+
+ if ((working->logbase = strrchr(working->log, '/')) != NULL)
+ working->logbase++;
+
+ /* If there is an arcdir, set working->backdir. */
+ if (arcdir != NULL && working->logbase != NULL) {
+ if (*arcdir == '/') {
+ /* Fully qualified arcdir */
+ working->backdir = arcdir;
+ } else {
+ /* arcdir is relative to log's parent dir */
+ *(working->logbase - 1) = '\0';
+ if ((asprintf(&working->backdir, "%s/%s",
+ working->log, arcdir)) == -1)
+ err(1, NULL);
+ *(working->logbase - 1) = '/';
+ }
+ /* Ignore arcdir if it doesn't exist. */
+ if (stat(working->backdir, &sb) != 0 ||
+ !S_ISDIR(sb.st_mode)) {
+ if (working->backdir != arcdir)
+ free(working->backdir);
+ working->backdir = NULL;
+ }
+ } else
+ working->backdir = NULL;
+
+ /* Make sure we can't oflow PATH_MAX */
+ if (working->backdir != NULL)
+ linelen = snprintf(line, sizeof(line), "%s/%s.%d%s",
+ working->backdir, working->logbase,
+ working->numlogs, COMPRESS_POSTFIX);
+ else
+ linelen = snprintf(line, sizeof(line), "%s.%d%s",
+ working->log, working->numlogs, COMPRESS_POSTFIX);
+ if (linelen >= PATH_MAX) {
+ warnx("%s:%d: pathname too long: %s --> skipping", conf, lineno, line);
+ return 1;
+ }
+
+ TAILQ_INSERT_TAIL(list, working, next);
+ (*nentries)++;
+ return 0;
+}
+
char *
missing_field(char *p, char *errline, int lineno)
{
newsyslog: support glob(3) through new G flag