xref: /openbsd-src/usr.sbin/syslogc/syslogc.c (revision 10a7b75896683c64bfb039e81ab2b44ce1670578)
1*10a7b758Smillert /* $OpenBSD: syslogc.c,v 1.19 2021/11/15 15:14:24 millert Exp $ */
2ffb9ed4eSdjm 
3ffb9ed4eSdjm /*
4ffb9ed4eSdjm  * Copyright (c) 2004 Damien Miller
5ffb9ed4eSdjm  *
6ffb9ed4eSdjm  * Permission to use, copy, modify, and distribute this software for any
7ffb9ed4eSdjm  * purpose with or without fee is hereby granted, provided that the above
8ffb9ed4eSdjm  * copyright notice and this permission notice appear in all copies.
9ffb9ed4eSdjm  *
10ffb9ed4eSdjm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ffb9ed4eSdjm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ffb9ed4eSdjm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ffb9ed4eSdjm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ffb9ed4eSdjm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ffb9ed4eSdjm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ffb9ed4eSdjm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ffb9ed4eSdjm  */
18ffb9ed4eSdjm 
19ffb9ed4eSdjm #include <sys/types.h>
20ffb9ed4eSdjm #include <sys/socket.h>
21ffb9ed4eSdjm #include <sys/un.h>
22ffb9ed4eSdjm 
23ffb9ed4eSdjm #include <err.h>
24ffb9ed4eSdjm #include <stdio.h>
252cb6e4c6Ssthen #include <stdint.h>
26ffb9ed4eSdjm #include <stdlib.h>
27ffb9ed4eSdjm #include <string.h>
28ffb9ed4eSdjm #include <unistd.h>
29ffb9ed4eSdjm 
30ffb9ed4eSdjm #define DEFAULT_CTLSOCK		"/var/run/syslogd.sock"
31ffb9ed4eSdjm 
32ffb9ed4eSdjm #define MAX_MEMBUF_NAME	64	/* Max length of membuf log name */
331bde5b89Sdjm 
345b27f617Sdjm /*
355b27f617Sdjm  * Client protocol NB. all numeric fields in network byte order
365b27f617Sdjm  */
372cb6e4c6Ssthen #define CTL_VERSION		2
385b27f617Sdjm 
395b27f617Sdjm /* Request */
40ffb9ed4eSdjm struct ctl_cmd {
415b27f617Sdjm 	u_int32_t	version;
42ffb9ed4eSdjm #define CMD_READ	1	/* Read out log */
43ffb9ed4eSdjm #define CMD_READ_CLEAR	2	/* Read and clear log */
44ffb9ed4eSdjm #define CMD_CLEAR	3	/* Clear log */
45ffb9ed4eSdjm #define CMD_LIST	4	/* List available logs */
465b27f617Sdjm #define CMD_FLAGS	5	/* Query flags only */
47c5dd883eSmpf #define CMD_READ_CONT	6	/* Read out log continuously */
485b27f617Sdjm 	u_int32_t	cmd;
492cb6e4c6Ssthen 	u_int32_t	lines;
50ffb9ed4eSdjm 	char		logname[MAX_MEMBUF_NAME];
51ffb9ed4eSdjm };
52ffb9ed4eSdjm 
535b27f617Sdjm /* Reply */
545b27f617Sdjm struct ctl_reply_hdr {
555b27f617Sdjm 	u_int32_t	version;
565b27f617Sdjm #define CTL_HDR_FLAG_OVERFLOW	0x01
575b27f617Sdjm 	u_int32_t	flags;
585b27f617Sdjm 	/* Reply text follows, up to MAX_MEMBUF long */
595b27f617Sdjm };
605b27f617Sdjm 
61ffb9ed4eSdjm static void
usage(void)62ffb9ed4eSdjm usage(void)
63ffb9ed4eSdjm {
64ffb9ed4eSdjm 	extern char *__progname;
65ffb9ed4eSdjm 
662cb6e4c6Ssthen 	fprintf(stderr,
672cb6e4c6Ssthen 	    "usage: %s [-Ccfo] [-n lines] [-s reporting_socket] logname\n"
6885b719f4Ssobrado 	    "       %s -q\n", __progname, __progname);
69ffb9ed4eSdjm 	exit(1);
70ffb9ed4eSdjm }
71ffb9ed4eSdjm 
72ffb9ed4eSdjm int
main(int argc,char ** argv)73ffb9ed4eSdjm main(int argc, char **argv)
74ffb9ed4eSdjm {
75ffb9ed4eSdjm 	const char *ctlsock_path;
76ffb9ed4eSdjm 	char buf[8192];
77ffb9ed4eSdjm 	struct sockaddr_un ctl;
785b27f617Sdjm 	int ctlsock, ch, oflag, rval;
79ffb9ed4eSdjm 	FILE *ctlf;
80ffb9ed4eSdjm 	struct ctl_cmd cc;
815b27f617Sdjm 	struct ctl_reply_hdr rr;
822cb6e4c6Ssthen 	const char *errstr;
83ffb9ed4eSdjm 
84ffb9ed4eSdjm 	memset(&cc, '\0', sizeof(cc));
85ffb9ed4eSdjm 
86ffb9ed4eSdjm 	ctlsock_path = DEFAULT_CTLSOCK;
875b27f617Sdjm 	rval = oflag = 0;
882cb6e4c6Ssthen 	while ((ch = getopt(argc, argv, "Ccfhon:qs:")) != -1) {
89ffb9ed4eSdjm 		switch (ch) {
901bde5b89Sdjm 		case 'C':
911bde5b89Sdjm 			cc.cmd = CMD_CLEAR;
921bde5b89Sdjm 			break;
931bde5b89Sdjm 		case 'c':
941bde5b89Sdjm 			cc.cmd = CMD_READ_CLEAR;
951bde5b89Sdjm 			break;
96ffb9ed4eSdjm 		case 'h':
97ffb9ed4eSdjm 			usage();
98ffb9ed4eSdjm 			break;
99c5dd883eSmpf 		case 'f':
100c5dd883eSmpf 			cc.cmd = CMD_READ_CONT;
101c5dd883eSmpf 			break;
1022cb6e4c6Ssthen 		case 'n':
1032cb6e4c6Ssthen 			cc.lines = strtonum(optarg, 1, UINT32_MAX, &errstr);
1042cb6e4c6Ssthen 			if (errstr)
1052cb6e4c6Ssthen 				errx(1, "number of lines is %s: %s",
1062cb6e4c6Ssthen 				    errstr, optarg);
1072cb6e4c6Ssthen 			break;
1085b27f617Sdjm 		case 'o':
1095b27f617Sdjm 			cc.cmd = CMD_FLAGS;
1105b27f617Sdjm 			oflag = 1;
1115b27f617Sdjm 			break;
112ffb9ed4eSdjm 		case 'q':
113ffb9ed4eSdjm 			cc.cmd = CMD_LIST;
114ffb9ed4eSdjm 			break;
115ffb9ed4eSdjm 		case 's':
116ffb9ed4eSdjm 			ctlsock_path = optarg;
117ffb9ed4eSdjm 			break;
118ffb9ed4eSdjm 		default:
119ffb9ed4eSdjm 			usage();
120ffb9ed4eSdjm 			break;
121ffb9ed4eSdjm 		}
122ffb9ed4eSdjm 	}
123ffb9ed4eSdjm 
124ffb9ed4eSdjm 	if (cc.cmd == 0)
125ffb9ed4eSdjm 		cc.cmd = CMD_READ;
126ffb9ed4eSdjm 
127ffb9ed4eSdjm 	if ((cc.cmd != CMD_LIST && optind != argc - 1) ||
128ffb9ed4eSdjm 	    (cc.cmd == CMD_LIST && optind != argc))
129ffb9ed4eSdjm 		usage();
130ffb9ed4eSdjm 
131ffb9ed4eSdjm 	if (cc.cmd != CMD_LIST) {
1321bde5b89Sdjm 		if (strlcpy(cc.logname, argv[optind], sizeof(cc.logname)) >=
133ffb9ed4eSdjm 		    sizeof(cc.logname))
134ffb9ed4eSdjm 			errx(1, "Specified log name is too long");
135ffb9ed4eSdjm 	}
136ffb9ed4eSdjm 
1375613d0beSdjm 	memset(&ctl, '\0', sizeof(ctl));
138ffb9ed4eSdjm 	strlcpy(ctl.sun_path, ctlsock_path, sizeof(ctl.sun_path));
139ffb9ed4eSdjm 	ctl.sun_family = AF_UNIX;
140ffb9ed4eSdjm 
1411bde5b89Sdjm 	if ((ctlsock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
1423828a0eaSderaadt 		err(1, "socket");
143ffb9ed4eSdjm 	if (connect(ctlsock, (struct sockaddr *)&ctl, sizeof(ctl)) == -1)
1441bde5b89Sdjm 		err(1, "connect: %s", ctl.sun_path);
145ffb9ed4eSdjm 	if ((ctlf = fdopen(ctlsock, "r+")) == NULL)
146ffb9ed4eSdjm 		err(1, "fdopen");
1475b27f617Sdjm 
148a3cebea4Sderaadt 	if (pledge("stdio", NULL) == -1)
149a3cebea4Sderaadt 		err(1, "stdio");
150a3cebea4Sderaadt 
1515b27f617Sdjm 	cc.version = htonl(CTL_VERSION);
1525b27f617Sdjm 	cc.cmd = htonl(cc.cmd);
153ffb9ed4eSdjm 	/* Send command */
1541bde5b89Sdjm 	if (fwrite(&cc, sizeof(cc), 1, ctlf) != 1)
155ffb9ed4eSdjm 		err(1, "fwrite");
156ffb9ed4eSdjm 
157ffb9ed4eSdjm 	fflush(ctlf);
158b9a887b6Smillert 	setvbuf(ctlf, NULL, _IOLBF, 0);
159b9a887b6Smillert 	setvbuf(stdout, NULL, _IOLBF, 0);
160ffb9ed4eSdjm 
1615b27f617Sdjm 	/* Fetch header */
1625b27f617Sdjm 	if (fread(&rr, sizeof(rr), 1, ctlf) != 1)
1635b27f617Sdjm 		err(1, "fread header");
1645b27f617Sdjm 
1655b27f617Sdjm 	if (ntohl(rr.version) != CTL_VERSION)
1668df5ec29Sstevesk 		errx(1, "unsupported syslogd version");
1675b27f617Sdjm 
168ffb9ed4eSdjm 	/* Write out reply */
169c5dd883eSmpf 	while ((fgets(buf, sizeof(buf), ctlf)) != NULL) {
170c5dd883eSmpf 		if (!strcmp(buf, "<ENOBUFS>\n"))
171c5dd883eSmpf 			fprintf(stderr, "syslogc [%s]: Lines were dropped!\n",
172c5dd883eSmpf 			    cc.logname);
173c5dd883eSmpf 		else
174ffb9ed4eSdjm 			fputs(buf, stdout);
175c5dd883eSmpf 	}
176ffb9ed4eSdjm 
1775b27f617Sdjm 	if (oflag && (ntohl(rr.flags) & CTL_HDR_FLAG_OVERFLOW)) {
1785b27f617Sdjm 		printf("%s has overflowed\n", cc.logname);
1795b27f617Sdjm 		rval = 1;
1805b27f617Sdjm 	}
1815b27f617Sdjm 
182ffb9ed4eSdjm 	fclose(ctlf);
183ffb9ed4eSdjm 	close(ctlsock);
184ffb9ed4eSdjm 
1855b27f617Sdjm 	exit(rval);
186ffb9ed4eSdjm }
187