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