1/* $OpenBSD: syslogc.c,v 1.19 2021/11/15 15:14:24 millert Exp $ */
2
3/*
4 * Copyright (c) 2004 Damien Miller
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/un.h>
22
23#include <err.h>
24#include <stdio.h>
25#include <stdint.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#define DEFAULT_CTLSOCK		"/var/run/syslogd.sock"
31
32#define MAX_MEMBUF_NAME	64	/* Max length of membuf log name */
33
34/*
35 * Client protocol NB. all numeric fields in network byte order
36 */
37#define CTL_VERSION		2
38
39/* Request */
40struct ctl_cmd {
41	u_int32_t	version;
42#define CMD_READ	1	/* Read out log */
43#define CMD_READ_CLEAR	2	/* Read and clear log */
44#define CMD_CLEAR	3	/* Clear log */
45#define CMD_LIST	4	/* List available logs */
46#define CMD_FLAGS	5	/* Query flags only */
47#define CMD_READ_CONT	6	/* Read out log continuously */
48	u_int32_t	cmd;
49	u_int32_t	lines;
50	char		logname[MAX_MEMBUF_NAME];
51};
52
53/* Reply */
54struct ctl_reply_hdr {
55	u_int32_t	version;
56#define CTL_HDR_FLAG_OVERFLOW	0x01
57	u_int32_t	flags;
58	/* Reply text follows, up to MAX_MEMBUF long */
59};
60
61static void
62usage(void)
63{
64	extern char *__progname;
65
66	fprintf(stderr,
67	    "usage: %s [-Ccfo] [-n lines] [-s reporting_socket] logname\n"
68	    "       %s -q\n", __progname, __progname);
69	exit(1);
70}
71
72int
73main(int argc, char **argv)
74{
75	const char *ctlsock_path;
76	char buf[8192];
77	struct sockaddr_un ctl;
78	int ctlsock, ch, oflag, rval;
79	FILE *ctlf;
80	struct ctl_cmd cc;
81	struct ctl_reply_hdr rr;
82	const char *errstr;
83
84	memset(&cc, '\0', sizeof(cc));
85
86	ctlsock_path = DEFAULT_CTLSOCK;
87	rval = oflag = 0;
88	while ((ch = getopt(argc, argv, "Ccfhon:qs:")) != -1) {
89		switch (ch) {
90		case 'C':
91			cc.cmd = CMD_CLEAR;
92			break;
93		case 'c':
94			cc.cmd = CMD_READ_CLEAR;
95			break;
96		case 'h':
97			usage();
98			break;
99		case 'f':
100			cc.cmd = CMD_READ_CONT;
101			break;
102		case 'n':
103			cc.lines = strtonum(optarg, 1, UINT32_MAX, &errstr);
104			if (errstr)
105				errx(1, "number of lines is %s: %s",
106				    errstr, optarg);
107			break;
108		case 'o':
109			cc.cmd = CMD_FLAGS;
110			oflag = 1;
111			break;
112		case 'q':
113			cc.cmd = CMD_LIST;
114			break;
115		case 's':
116			ctlsock_path = optarg;
117			break;
118		default:
119			usage();
120			break;
121		}
122	}
123
124	if (cc.cmd == 0)
125		cc.cmd = CMD_READ;
126
127	if ((cc.cmd != CMD_LIST && optind != argc - 1) ||
128	    (cc.cmd == CMD_LIST && optind != argc))
129		usage();
130
131	if (cc.cmd != CMD_LIST) {
132		if (strlcpy(cc.logname, argv[optind], sizeof(cc.logname)) >=
133		    sizeof(cc.logname))
134			errx(1, "Specified log name is too long");
135	}
136
137	memset(&ctl, '\0', sizeof(ctl));
138	strlcpy(ctl.sun_path, ctlsock_path, sizeof(ctl.sun_path));
139	ctl.sun_family = AF_UNIX;
140
141	if ((ctlsock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
142		err(1, "socket");
143	if (connect(ctlsock, (struct sockaddr *)&ctl, sizeof(ctl)) == -1)
144		err(1, "connect: %s", ctl.sun_path);
145	if ((ctlf = fdopen(ctlsock, "r+")) == NULL)
146		err(1, "fdopen");
147
148	if (pledge("stdio", NULL) == -1)
149		err(1, "stdio");
150
151	cc.version = htonl(CTL_VERSION);
152	cc.cmd = htonl(cc.cmd);
153	/* Send command */
154	if (fwrite(&cc, sizeof(cc), 1, ctlf) != 1)
155		err(1, "fwrite");
156
157	fflush(ctlf);
158	setvbuf(ctlf, NULL, _IOLBF, 0);
159	setvbuf(stdout, NULL, _IOLBF, 0);
160
161	/* Fetch header */
162	if (fread(&rr, sizeof(rr), 1, ctlf) != 1)
163		err(1, "fread header");
164
165	if (ntohl(rr.version) != CTL_VERSION)
166		errx(1, "unsupported syslogd version");
167
168	/* Write out reply */
169	while ((fgets(buf, sizeof(buf), ctlf)) != NULL) {
170		if (!strcmp(buf, "<ENOBUFS>\n"))
171			fprintf(stderr, "syslogc [%s]: Lines were dropped!\n",
172			    cc.logname);
173		else
174			fputs(buf, stdout);
175	}
176
177	if (oflag && (ntohl(rr.flags) & CTL_HDR_FLAG_OVERFLOW)) {
178		printf("%s has overflowed\n", cc.logname);
179		rval = 1;
180	}
181
182	fclose(ctlf);
183	close(ctlsock);
184
185	exit(rval);
186}
187