/*
* 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 (c) 2013 Gary Mills
* 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.
*/
#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,
"altcron", LOG_ALTCRON,
"authpriv", LOG_AUTHPRIV,
"ftp", LOG_FTP,
"ntp", LOG_NTP,
"audit", LOG_AUDIT,
"console", LOG_CONSOLE,
"cron", LOG_CRON,
"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);
}