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
 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
 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
 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
 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
 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 }