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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 #pragma ident "%Z%%M% %I% %E% SMI"
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 "cron", LOG_CRON,
89 "audit", LOG_AUDIT,
90 "local0", LOG_LOCAL0,
91 "local1", LOG_LOCAL1,
92 "local2", LOG_LOCAL2,
93 "local3", LOG_LOCAL3,
94 "local4", LOG_LOCAL4,
95 "local5", LOG_LOCAL5,
96 "local6", LOG_LOCAL6,
97 "local7", LOG_LOCAL7,
98 NULL, -1
99 };
100
101 static int pencode(register char *);
102 static int decode(char *, struct code *);
103 static void bailout(char *, char *);
104 static void usage(void);
105
106 /*
107 * LOGGER -- read and log utility
108 *
109 * This routine reads from an input and arranges to write the
110 * result on the system log, along with a useful tag.
111 */
112
113 int
main(int argc,char ** argv)114 main(int argc, char **argv)
115 {
116 char tmp[23];
117 char *tag = NULL;
118 char *infile = NULL;
119 char *buf = NULL;
120 size_t buflen;
121 int pri = LOG_NOTICE;
122 int logflags = 0;
123 int opt;
124 int pid_len = 0;
125 struct passwd *pw;
126 uid_t u;
127 char fmt_uid[16];
128 char *p, *endp;
129 size_t len;
130 ptrdiff_t offset = 0;
131 int status = 0;
132
133 (void) setlocale(LC_ALL, "");
134 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
135 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
136 #endif
137 (void) textdomain(TEXT_DOMAIN);
138 /* initialize */
139
140 while ((opt = getopt(argc, argv, "it:p:f:")) != EOF)
141 switch (opt) {
142
143 case 't': /* tag */
144 tag = optarg;
145 break;
146
147 case 'p': /* priority */
148 pri = pencode(optarg);
149 break;
150
151 case 'i': /* log process id also */
152 logflags |= LOG_PID;
153 pid_len = sprintf(tmp, "%ld", (long)getpid());
154 pid_len = (pid_len <= 0) ? 0 : pid_len +2;
155 break;
156
157 case 'f': /* file to log */
158 if (strcmp(optarg, "-") == 0)
159 break;
160 infile = optarg;
161 if (freopen(infile, "r", stdin) == NULL) {
162 (void) fprintf(stderr, gettext("logger: "));
163 perror(infile);
164 exit(1);
165 }
166 break;
167
168 default:
169 usage();
170 }
171
172 argc -= optind;
173 argv = &argv[optind];
174
175 if ((tag == NULL) && ((tag = getlogin()) == NULL)) {
176 u = getuid();
177 if ((pw = getpwuid(u)) == NULL) {
178 (void) sprintf(fmt_uid, "%u", u);
179 tag = fmt_uid;
180 } else
181 tag = pw->pw_name;
182 }
183
184 /* setup for logging */
185 openlog(tag, logflags, 0);
186 (void) fclose(stdout);
187
188 /* log input line if appropriate */
189 if (argc > 0) {
190 /*
191 * Log arguments from command line
192 */
193 int i;
194
195 len = 0;
196 for (i = 0; i < argc; i++) {
197 len += strlen(argv[i]) + 1; /* add 1 for <space> */
198 }
199 if ((buf = malloc(len + 1)) == NULL) {
200 perror("logger");
201 exit(1);
202 }
203 buf[0] = '\0';
204 for (i = 0; i < argc; i++) {
205 if (i != 0) {
206 (void) strcat(buf, " ");
207 }
208 (void) strcat(buf, argv[i]);
209 }
210 #ifdef DEBUG
211 (void) fprintf(stderr, "len=%d, buf >%s<\n", len, buf);
212 #endif
213 syslog(pri, "%s", buf);
214 } else {
215 /*
216 * Log arguments from stdin (or input file).
217 * When reading from stdin, logger grows its buffer if
218 * needed, to handle long lines.
219 */
220 if ((buf = malloc(LOGGER_BUFLEN)) == NULL) {
221 perror("logger");
222 exit(1);
223 }
224 buflen = LOGGER_BUFLEN;
225 p = buf;
226 endp = buf + buflen;
227 offset = 0;
228 while (fgets(p, endp - p, stdin) != NULL) {
229 len = strlen(p);
230 if (p[len - 1] == '\n') {
231 #ifdef DEBUG
232 (void) fprintf(stderr,
233 "p-buf =%d, len=%d, buflen=%d, buf >%s<\n",
234 p-buf, len, buflen, buf);
235 #endif
236 syslog(pri, "%s", buf);
237 p = buf;
238 offset = 0;
239 } else if (len < endp - p - 1) {
240 /* short read or line with no <newline> */
241 p += len;
242 offset += len;
243 #ifdef DEBUG
244 (void) fprintf(stderr,
245 "p-buf=%d, len=%d, buflen=%d, buf >%s<\n",
246 p-buf, len, buflen, buf);
247 #endif
248 continue;
249 } else {
250 /* line longer than buflen, so get larger buf */
251 buflen += LOGGER_BUFLEN;
252 offset += len;
253 #ifdef DEBUG
254 (void) fprintf(stderr,
255 "Realloc endp-p=%d, len=%d, offset=%d, "
256 "buflen %d\n",
257 endp - p, len, offset, buflen);
258 #endif
259 if ((buf = realloc(buf, buflen)) == NULL) {
260 perror("logger");
261 exit(1);
262 }
263 p = buf + offset;
264 endp = buf + buflen;
265 }
266 } /* while */
267
268 if (feof(stdin)) {
269 if (p > buf) {
270 /* the last line did not end with newline */
271 #ifdef DEBUG
272 (void) fprintf(stderr,
273 "(2) p-buf=%d, len=%d, buflen=%d, "
274 "buf >%s<\n",
275 p-buf, len, buflen, buf);
276 #endif
277 syslog(pri, "%s", buf);
278 }
279 } else {
280 /*
281 * fgets() encountered an error. Log unlogged data
282 * from earlier fgets() (if any). Write null byte
283 * after last full read, in case the fgets() that
284 * encountered error removed it and failed to null
285 * terminate.
286 */
287 perror("logger");
288 if (p > buf) {
289 *p = '\0';
290 syslog(pri, "%s", buf);
291 }
292 status = 1;
293 }
294 } /* else !(argc > 0) */
295 free(buf);
296 return (status);
297 }
298
299 /*
300 * Decode a symbolic name to a numeric value
301 */
302
303
304 static int
pencode(s)305 pencode(s)
306 register char *s;
307 {
308 register char *p;
309 int lev;
310 int fac = 0;
311
312 for (p = s; *s && *s != '.'; s++);
313 if (*s) {
314 *s = '\0';
315 fac = decode(p, FacNames);
316 if (fac < 0)
317 bailout("unknown facility name: ", p);
318 *s++ = '.';
319 } else
320 s = p;
321 lev = decode(s, PriNames);
322 if (lev < 0)
323 bailout("unknown priority name: ", s);
324
325 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
326 }
327
328
329 static int
decode(name,codetab)330 decode(name, codetab)
331 char *name;
332 struct code *codetab;
333 {
334 register struct code *c;
335
336 if (isdigit(*name))
337 return (atoi(name));
338
339 for (c = codetab; c->c_name; c++)
340 if (strcasecmp(name, c->c_name) == 0)
341 return (c->c_val);
342
343 return (-1);
344 }
345
346
347 static void
bailout(a,b)348 bailout(a, b)
349 char *a, *b;
350 {
351 (void) fprintf(stderr, gettext("logger: %s%s\n"), a, b);
352 exit(1);
353 }
354
355
356 static void
usage(void)357 usage(void)
358 {
359 (void) fprintf(stderr, gettext(
360 "Usage:\tlogger string\n"
361 "\tlogger [-i] [-f filename] [-p priority] [-t tag] "
362 "[message] ...\n"));
363 exit(1);
364 }
365