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(register 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
main(int argc,char ** argv)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
pencode(s)310 pencode(s)
311 register char *s;
312 {
313 register char *p;
314 int lev;
315 int fac = 0;
316
317 for (p = s; *s && *s != '.'; s++);
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
decode(name,codetab)335 decode(name, codetab)
336 char *name;
337 struct code *codetab;
338 {
339 register struct code *c;
340
341 if (isdigit(*name))
342 return (atoi(name));
343
344 for (c = codetab; c->c_name; c++)
345 if (strcasecmp(name, c->c_name) == 0)
346 return (c->c_val);
347
348 return (-1);
349 }
350
351
352 static void
bailout(a,b)353 bailout(a, b)
354 char *a, *b;
355 {
356 (void) fprintf(stderr, gettext("logger: %s%s\n"), a, b);
357 exit(1);
358 }
359
360
361 static void
usage(void)362 usage(void)
363 {
364 (void) fprintf(stderr, gettext(
365 "Usage:\tlogger string\n"
366 "\tlogger [-i] [-f filename] [-p priority] [-t tag] "
367 "[message] ...\n"));
368 exit(1);
369 }
370