view usr/src/cmd/logger/logger.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*
 * University Copyright- Copyright (c) 1982, 1986, 1988
 * The Regents of the University of California
 * All Rights Reserved
 *
 * University Acknowledgment- Portions of this document are derived from
 * software developed by the University of California, Berkeley, and its
 * contributors.
 */

#pragma ident	"@(#)logger.c	1.20	07/05/23 SMI"

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <syslog.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <limits.h>
#include <pwd.h>
#include <errno.h>

#define	LOG_MARK	(LOG_NFACILITIES << 3)	/* mark "facility" */
#define	LOGGER_BUFLEN	1024

struct code {
	char	*c_name;
	int	c_val;
};

static struct code	PriNames[] = {
	"panic",	LOG_EMERG,
	"emerg",	LOG_EMERG,
	"alert",	LOG_ALERT,
	"crit",		LOG_CRIT,
	"err",		LOG_ERR,
	"error",	LOG_ERR,
	"warn",		LOG_WARNING,
	"warning", 	LOG_WARNING,
	"notice",	LOG_NOTICE,
	"info",		LOG_INFO,
	"debug",	LOG_DEBUG,
	NULL,		-1
};

static struct code	FacNames[] = {
	"kern",		LOG_KERN,
	"user",		LOG_USER,
	"mail",		LOG_MAIL,
	"daemon",	LOG_DAEMON,
	"auth",		LOG_AUTH,
	"security",	LOG_AUTH,
	"mark",		LOG_MARK,
	"syslog",	LOG_SYSLOG,
	"lpr",		LOG_LPR,
	"news",		LOG_NEWS,
	"uucp",		LOG_UUCP,
	"cron",		LOG_CRON,
	"audit",	LOG_AUDIT,
	"local0",	LOG_LOCAL0,
	"local1",	LOG_LOCAL1,
	"local2",	LOG_LOCAL2,
	"local3",	LOG_LOCAL3,
	"local4",	LOG_LOCAL4,
	"local5",	LOG_LOCAL5,
	"local6",	LOG_LOCAL6,
	"local7",	LOG_LOCAL7,
	NULL,		-1
};

static int	pencode(register char *);
static int	decode(char *, struct code *);
static void	bailout(char *, char *);
static void	usage(void);

/*
 *  LOGGER -- read and log utility
 *
 *	This routine reads from an input and arranges to write the
 *	result on the system log, along with a useful tag.
 */

int
main(int argc, char **argv)
{
	char tmp[23];
	char *tag = NULL;
	char *infile = NULL;
	char *buf = NULL;
	size_t buflen;
	int pri = LOG_NOTICE;
	int logflags = 0;
	int opt;
	int pid_len = 0;
	struct passwd *pw;
	uid_t u;
	char fmt_uid[16];
	char *p, *endp;
	size_t len;
	ptrdiff_t offset = 0;
	int status = 0;

	(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
#endif
	(void) textdomain(TEXT_DOMAIN);
	/* initialize */

	while ((opt = getopt(argc, argv, "it:p:f:")) != EOF)
		switch (opt) {

		    case 't':		/* tag */
			tag = optarg;
			break;

		    case 'p':		/* priority */
			pri = pencode(optarg);
			break;

		    case 'i':		/* log process id also */
			logflags |= LOG_PID;
			pid_len = sprintf(tmp, "%ld", (long)getpid());
			pid_len = (pid_len <= 0) ? 0 : pid_len +2;
			break;

		    case 'f':		/* file to log */
			if (strcmp(optarg, "-") == 0)
				break;
			infile = optarg;
			if (freopen(infile, "r", stdin) == NULL) {
				(void) fprintf(stderr, gettext("logger: "));
				perror(infile);
				exit(1);
			}
			break;

		    default:
			usage();
		}

		argc -= optind;
		argv = &argv[optind];

	if ((tag == NULL) && ((tag = getlogin()) == NULL)) {
		u = getuid();
		if ((pw = getpwuid(u)) == NULL) {
			(void) sprintf(fmt_uid, "%u", u);
			tag = fmt_uid;
		} else
			tag = pw->pw_name;
	}

	/* setup for logging */
	openlog(tag, logflags, 0);
	(void) fclose(stdout);

	/* log input line if appropriate */
	if (argc > 0) {
		/*
		 * Log arguments from command line
		 */
		int i;

		len = 0;
		for (i = 0; i < argc; i++) {
			len += strlen(argv[i]) + 1;	/* add 1 for <space> */
		}
		if ((buf = malloc(len + 1)) == NULL) {
			perror("logger");
			exit(1);
		}
		buf[0] = '\0';
		for (i = 0; i < argc; i++) {
			if (i != 0) {
				(void) strcat(buf, " ");
			}
			(void) strcat(buf, argv[i]);
		}
#ifdef DEBUG
		(void) fprintf(stderr, "len=%d, buf >%s<\n", len, buf);
#endif
		syslog(pri, "%s", buf);
	} else {
		/*
		 * Log arguments from stdin (or input file).
		 * When reading from stdin, logger grows its buffer if
		 * needed, to handle long lines.
		 */
		if ((buf = malloc(LOGGER_BUFLEN)) == NULL) {
			perror("logger");
			exit(1);
		}
		buflen = LOGGER_BUFLEN;
		p = buf;
		endp = buf + buflen;
		offset = 0;
		while (fgets(p, endp - p, stdin) != NULL) {
			len = strlen(p);
			if (p[len - 1] == '\n') {
#ifdef DEBUG
				(void) fprintf(stderr,
				    "p-buf =%d, len=%d, buflen=%d, buf >%s<\n",
				    p-buf, len, buflen, buf);
#endif
				syslog(pri, "%s", buf);
				p = buf;
				offset = 0;
			} else if (len < endp - p - 1) {
				/* short read or line with no <newline> */
				p += len;
				offset += len;
#ifdef DEBUG
				(void) fprintf(stderr,
				    "p-buf=%d, len=%d, buflen=%d, buf >%s<\n",
				    p-buf, len, buflen, buf);
#endif
				continue;
			} else {
				/* line longer than buflen, so get larger buf */
				buflen += LOGGER_BUFLEN;
				offset += len;
#ifdef DEBUG
				(void) fprintf(stderr,
				    "Realloc endp-p=%d, len=%d, offset=%d, "
				    "buflen %d\n",
				    endp - p, len, offset, buflen);
#endif
				if ((buf = realloc(buf, buflen)) == NULL) {
					perror("logger");
					exit(1);
				}
				p = buf + offset;
				endp = buf + buflen;
			}
		}	/* while */

		if (feof(stdin)) {
			if (p > buf) {
				/* the last line did not end with newline */
#ifdef DEBUG
				(void) fprintf(stderr,
				    "(2) p-buf=%d, len=%d, buflen=%d, "
				    "buf >%s<\n",
				    p-buf, len, buflen, buf);
#endif
				syslog(pri, "%s", buf);
			}
		} else {
			/*
			 * fgets() encountered an error.  Log unlogged data
			 * from earlier fgets() (if any).  Write null byte
			 * after last full read, in case the fgets() that
			 * encountered error removed it and failed to null
			 * terminate.
			 */
			perror("logger");
			if (p > buf) {
				*p = '\0';
				syslog(pri, "%s", buf);
			}
			status = 1;
		}
	}	/* else !(argc > 0) */
	free(buf);
	return (status);
}

/*
 *  Decode a symbolic name to a numeric value
 */


static int
pencode(s)
register char *s;
{
	register char *p;
	int lev;
	int fac = 0;

	for (p = s; *s && *s != '.'; s++);
	if (*s) {
		*s = '\0';
		fac = decode(p, FacNames);
		if (fac < 0)
			bailout("unknown facility name: ", p);
		*s++ = '.';
	} else
		s = p;
	lev = decode(s, PriNames);
	if (lev < 0)
		bailout("unknown priority name: ", s);

	return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
}


static int
decode(name, codetab)
char *name;
struct code *codetab;
{
	register struct code *c;

	if (isdigit(*name))
		return (atoi(name));

	for (c = codetab; c->c_name; c++)
		if (strcasecmp(name, c->c_name) == 0)
			return (c->c_val);

	return (-1);
}


static void
bailout(a, b)
char *a, *b;
{
	(void) fprintf(stderr, gettext("logger: %s%s\n"), a, b);
	exit(1);
}


static void
usage(void)
{
	(void) fprintf(stderr, gettext(
	    "Usage:\tlogger string\n"
	    "\tlogger [-i] [-f filename] [-p priority] [-t tag] "
		"[message] ...\n"));
	exit(1);
}