xref: /illumos-gate/usr/src/cmd/logger/logger.c (revision 73b80b821da76082173547dd650e417f6916eb8b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2013 Gary Mills
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <syslog.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <locale.h>
49 #include <limits.h>
50 #include <pwd.h>
51 #include <errno.h>
52 
53 #define	LOG_MARK	(LOG_NFACILITIES << 3)	/* mark "facility" */
54 #define	LOGGER_BUFLEN	1024
55 
56 struct code {
57 	char	*c_name;
58 	int	c_val;
59 };
60 
61 static struct code	PriNames[] = {
62 	"panic",	LOG_EMERG,
63 	"emerg",	LOG_EMERG,
64 	"alert",	LOG_ALERT,
65 	"crit",		LOG_CRIT,
66 	"err",		LOG_ERR,
67 	"error",	LOG_ERR,
68 	"warn",		LOG_WARNING,
69 	"warning", 	LOG_WARNING,
70 	"notice",	LOG_NOTICE,
71 	"info",		LOG_INFO,
72 	"debug",	LOG_DEBUG,
73 	NULL,		-1
74 };
75 
76 static struct code	FacNames[] = {
77 	"kern",		LOG_KERN,
78 	"user",		LOG_USER,
79 	"mail",		LOG_MAIL,
80 	"daemon",	LOG_DAEMON,
81 	"auth",		LOG_AUTH,
82 	"security",	LOG_AUTH,
83 	"mark",		LOG_MARK,
84 	"syslog",	LOG_SYSLOG,
85 	"lpr",		LOG_LPR,
86 	"news",		LOG_NEWS,
87 	"uucp",		LOG_UUCP,
88 	"altcron",	LOG_ALTCRON,
89 	"authpriv",	LOG_AUTHPRIV,
90 	"ftp",		LOG_FTP,
91 	"ntp",		LOG_NTP,
92 	"audit",	LOG_AUDIT,
93 	"console",	LOG_CONSOLE,
94 	"cron",		LOG_CRON,
95 	"local0",	LOG_LOCAL0,
96 	"local1",	LOG_LOCAL1,
97 	"local2",	LOG_LOCAL2,
98 	"local3",	LOG_LOCAL3,
99 	"local4",	LOG_LOCAL4,
100 	"local5",	LOG_LOCAL5,
101 	"local6",	LOG_LOCAL6,
102 	"local7",	LOG_LOCAL7,
103 	NULL,		-1
104 };
105 
106 static int	pencode(char *);
107 static int	decode(char *, struct code *);
108 static void	bailout(char *, char *);
109 static void	usage(void);
110 
111 /*
112  *  LOGGER -- read and log utility
113  *
114  *	This routine reads from an input and arranges to write the
115  *	result on the system log, along with a useful tag.
116  */
117 
118 int
119 main(int argc, char **argv)
120 {
121 	char tmp[23];
122 	char *tag = NULL;
123 	char *infile = NULL;
124 	char *buf = NULL;
125 	size_t buflen;
126 	int pri = LOG_NOTICE;
127 	int logflags = 0;
128 	int opt;
129 	int pid_len = 0;
130 	struct passwd *pw;
131 	uid_t u;
132 	char fmt_uid[16];
133 	char *p, *endp;
134 	size_t len;
135 	ptrdiff_t offset = 0;
136 	int status = 0;
137 
138 	(void) setlocale(LC_ALL, "");
139 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
140 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
141 #endif
142 	(void) textdomain(TEXT_DOMAIN);
143 	/* initialize */
144 
145 	while ((opt = getopt(argc, argv, "it:p:f:")) != EOF)
146 		switch (opt) {
147 
148 		case 't':		/* tag */
149 			tag = optarg;
150 			break;
151 
152 		case 'p':		/* priority */
153 			pri = pencode(optarg);
154 			break;
155 
156 		case 'i':		/* log process id also */
157 			logflags |= LOG_PID;
158 			pid_len = sprintf(tmp, "%ld", (long)getpid());
159 			pid_len = (pid_len <= 0) ? 0 : pid_len +2;
160 			break;
161 
162 		case 'f':		/* file to log */
163 			if (strcmp(optarg, "-") == 0)
164 				break;
165 			infile = optarg;
166 			if (freopen(infile, "r", stdin) == NULL) {
167 				(void) fprintf(stderr, gettext("logger: "));
168 				perror(infile);
169 				exit(1);
170 			}
171 			break;
172 
173 		default:
174 			usage();
175 		}
176 
177 	argc -= optind;
178 	argv = &argv[optind];
179 
180 	if ((tag == NULL) && ((tag = getlogin()) == NULL)) {
181 		u = getuid();
182 		if ((pw = getpwuid(u)) == NULL) {
183 			(void) sprintf(fmt_uid, "%u", u);
184 			tag = fmt_uid;
185 		} else
186 			tag = pw->pw_name;
187 	}
188 
189 	/* setup for logging */
190 	openlog(tag, logflags, 0);
191 	(void) fclose(stdout);
192 
193 	/* log input line if appropriate */
194 	if (argc > 0) {
195 		/*
196 		 * Log arguments from command line
197 		 */
198 		int i;
199 
200 		len = 0;
201 		for (i = 0; i < argc; i++) {
202 			len += strlen(argv[i]) + 1;	/* add 1 for <space> */
203 		}
204 		if ((buf = malloc(len + 1)) == NULL) {
205 			perror("logger");
206 			exit(1);
207 		}
208 		buf[0] = '\0';
209 		for (i = 0; i < argc; i++) {
210 			if (i != 0) {
211 				(void) strcat(buf, " ");
212 			}
213 			(void) strcat(buf, argv[i]);
214 		}
215 #ifdef DEBUG
216 		(void) fprintf(stderr, "len=%d, buf >%s<\n", len, buf);
217 #endif
218 		syslog(pri, "%s", buf);
219 	} else {
220 		/*
221 		 * Log arguments from stdin (or input file).
222 		 * When reading from stdin, logger grows its buffer if
223 		 * needed, to handle long lines.
224 		 */
225 		if ((buf = malloc(LOGGER_BUFLEN)) == NULL) {
226 			perror("logger");
227 			exit(1);
228 		}
229 		buflen = LOGGER_BUFLEN;
230 		p = buf;
231 		endp = buf + buflen;
232 		offset = 0;
233 		while (fgets(p, endp - p, stdin) != NULL) {
234 			len = strlen(p);
235 			if (p[len - 1] == '\n') {
236 #ifdef DEBUG
237 				(void) fprintf(stderr,
238 				    "p-buf =%d, len=%d, buflen=%d, buf >%s<\n",
239 				    p-buf, len, buflen, buf);
240 #endif
241 				syslog(pri, "%s", buf);
242 				p = buf;
243 				offset = 0;
244 			} else if (len < endp - p - 1) {
245 				/* short read or line with no <newline> */
246 				p += len;
247 				offset += len;
248 #ifdef DEBUG
249 				(void) fprintf(stderr,
250 				    "p-buf=%d, len=%d, buflen=%d, buf >%s<\n",
251 				    p-buf, len, buflen, buf);
252 #endif
253 				continue;
254 			} else {
255 				/* line longer than buflen, so get larger buf */
256 				buflen += LOGGER_BUFLEN;
257 				offset += len;
258 #ifdef DEBUG
259 				(void) fprintf(stderr,
260 				    "Realloc endp-p=%d, len=%d, offset=%d, "
261 				    "buflen %d\n",
262 				    endp - p, len, offset, buflen);
263 #endif
264 				if ((buf = realloc(buf, buflen)) == NULL) {
265 					perror("logger");
266 					exit(1);
267 				}
268 				p = buf + offset;
269 				endp = buf + buflen;
270 			}
271 		}	/* while */
272 
273 		if (feof(stdin)) {
274 			if (p > buf) {
275 				/* the last line did not end with newline */
276 #ifdef DEBUG
277 				(void) fprintf(stderr,
278 				    "(2) p-buf=%d, len=%d, buflen=%d, "
279 				    "buf >%s<\n",
280 				    p-buf, len, buflen, buf);
281 #endif
282 				syslog(pri, "%s", buf);
283 			}
284 		} else {
285 			/*
286 			 * fgets() encountered an error.  Log unlogged data
287 			 * from earlier fgets() (if any).  Write null byte
288 			 * after last full read, in case the fgets() that
289 			 * encountered error removed it and failed to null
290 			 * terminate.
291 			 */
292 			perror("logger");
293 			if (p > buf) {
294 				*p = '\0';
295 				syslog(pri, "%s", buf);
296 			}
297 			status = 1;
298 		}
299 	}	/* else !(argc > 0) */
300 	free(buf);
301 	return (status);
302 }
303 
304 /*
305  *  Decode a symbolic name to a numeric value
306  */
307 
308 
309 static int
310 pencode(char *s)
311 {
312 	char *p;
313 	int lev;
314 	int fac = 0;
315 
316 	for (p = s; *s && *s != '.'; s++)
317 		;
318 	if (*s) {
319 		*s = '\0';
320 		fac = decode(p, FacNames);
321 		if (fac < 0)
322 			bailout("unknown facility name: ", p);
323 		*s++ = '.';
324 	} else
325 		s = p;
326 	lev = decode(s, PriNames);
327 	if (lev < 0)
328 		bailout("unknown priority name: ", s);
329 
330 	return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
331 }
332 
333 
334 static int
335 decode(char *name, struct code *codetab)
336 {
337 	struct code *c;
338 
339 	if (isdigit(*name))
340 		return (atoi(name));
341 
342 	for (c = codetab; c->c_name; c++)
343 		if (strcasecmp(name, c->c_name) == 0)
344 			return (c->c_val);
345 
346 	return (-1);
347 }
348 
349 
350 static void
351 bailout(char *a, char *b)
352 {
353 	(void) fprintf(stderr, gettext("logger: %s%s\n"), a, b);
354 	exit(1);
355 }
356 
357 
358 static void
359 usage(void)
360 {
361 	(void) fprintf(stderr, gettext(
362 	    "Usage:\tlogger string\n"
363 	    "\tlogger [-i] [-f filename] [-p priority] [-t tag] "
364 	    "[message] ...\n"));
365 	exit(1);
366 }
367