logger.c revision 63402
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)logger.c	8.1 (Berkeley) 6/6/93";
43#endif
44static const char rcsid[] =
45  "$FreeBSD: head/usr.bin/logger/logger.c 63402 2000-07-18 08:56:54Z dwmalone $";
46#endif /* not lint */
47
48#include <sys/types.h>
49#include <sys/socket.h>
50#include <netinet/in.h>
51
52#include <ctype.h>
53#include <err.h>
54#include <netdb.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59
60#define	SYSLOG_NAMES
61#include <syslog.h>
62
63int	decode __P((char *, CODE *));
64int	pencode __P((char *));
65static void	logmessage __P((int, char *, char *));
66static void	usage __P((void));
67
68/*
69 * logger -- read and log utility
70 *
71 *	Reads from an input and arranges to write the result on the system
72 *	log.
73 */
74int
75main(argc, argv)
76	int argc;
77	char *argv[];
78{
79	int ch, logflags, pri;
80	char *tag, *host, buf[1024];
81
82	tag = NULL;
83	host = NULL;
84	pri = LOG_NOTICE;
85	logflags = 0;
86	unsetenv("TZ");
87	while ((ch = getopt(argc, argv, "f:h:ip:st:")) != -1)
88		switch((char)ch) {
89		case 'f':		/* file to log */
90			if (freopen(optarg, "r", stdin) == NULL)
91				err(1, "%s", optarg);
92			break;
93		case 'h':		/* hostname to deliver to */
94			host = optarg;
95			break;
96		case 'i':		/* log process id also */
97			logflags |= LOG_PID;
98			break;
99		case 'p':		/* priority */
100			pri = pencode(optarg);
101			break;
102		case 's':		/* log to standard error */
103			logflags |= LOG_PERROR;
104			break;
105		case 't':		/* tag */
106			tag = optarg;
107			break;
108		case '?':
109		default:
110			usage();
111		}
112	argc -= optind;
113	argv += optind;
114
115	/* setup for logging */
116	openlog(tag ? tag : getlogin(), logflags, 0);
117	(void) fclose(stdout);
118
119	/* log input line if appropriate */
120	if (argc > 0) {
121		register char *p, *endp;
122		int len;
123
124		for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
125			len = strlen(*argv);
126			if (p + len > endp && p > buf) {
127				logmessage(pri, host, buf);
128				p = buf;
129			}
130			if (len > sizeof(buf) - 1)
131				logmessage(pri, host, *argv++);
132			else {
133				if (p != buf)
134					*p++ = ' ';
135				bcopy(*argv++, p, len);
136				*(p += len) = '\0';
137			}
138		}
139		if (p != buf)
140			logmessage(pri, host, buf);
141	} else
142		while (fgets(buf, sizeof(buf), stdin) != NULL)
143			logmessage(pri, host, buf);
144	exit(0);
145}
146
147/*
148 *  Send the message to syslog, either on the local host, or on a remote host
149 */
150void
151logmessage(int pri, char *host, char *buf)
152{
153	static int sock = -1;
154	static struct sockaddr_in sin;
155	char *line;
156	int len;
157
158	if (host == NULL) {
159		syslog(pri, "%s", buf);
160		return;
161	}
162
163	if (sock == -1) {	/* set up socket stuff */
164		struct servent *sp;
165		struct hostent *hp = NULL;
166
167		sin.sin_family = AF_INET;
168
169		if ((sp = getservbyname("syslog", "udp")) == NULL)
170			warnx ("syslog/udp: unknown service");	/* not fatal */
171		sin.sin_port = (sp == NULL ? htons(514) : sp->s_port);
172
173		/* resolve hostname */
174		if (!(inet_aton(host, &sin.sin_addr)) &&
175		    (hp = gethostbyname(host)) == NULL)
176			errx(1, "unknown host: %s", host);
177		if (hp != NULL)
178			memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
179
180		sock = socket(PF_INET, SOCK_DGRAM, 0);
181		if (sock < 0)
182			errx(1, "socket");
183	}
184
185	if ((len = asprintf(&line, "<%d>%s", pri, buf)) == -1)
186		errx(1, "asprintf");
187
188	if (sendto(sock, line, len, 0, (struct sockaddr *)&sin, sizeof(sin))
189	    < len)
190		warnx ("sendmsg");
191
192	free(line);
193}
194
195/*
196 *  Decode a symbolic name to a numeric value
197 */
198int
199pencode(s)
200	register char *s;
201{
202	char *save;
203	int fac, lev;
204
205	for (save = s; *s && *s != '.'; ++s);
206	if (*s) {
207		*s = '\0';
208		fac = decode(save, facilitynames);
209		if (fac < 0)
210			errx(1, "unknown facility name: %s", save);
211		*s++ = '.';
212	}
213	else {
214		fac = 0;
215		s = save;
216	}
217	lev = decode(s, prioritynames);
218	if (lev < 0)
219		errx(1, "unknown priority name: %s", save);
220	return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
221}
222
223int
224decode(name, codetab)
225	char *name;
226	CODE *codetab;
227{
228	register CODE *c;
229
230	if (isdigit(*name))
231		return (atoi(name));
232
233	for (c = codetab; c->c_name; c++)
234		if (!strcasecmp(name, c->c_name))
235			return (c->c_val);
236
237	return (-1);
238}
239
240static void
241usage()
242{
243	(void)fprintf(stderr, "usage: %s\n",
244	    "logger [-is] [-f file] [-h host] [-p pri] [-t tag] [message ...]"
245	    );
246	exit(1);
247}
248