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 */ 40 struct 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 */ 54 struct 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 61 static void 62 usage(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 72 int 73 main(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