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