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         "bsdcron",      LOG_BSDCRON,
  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
 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
 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
 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
 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
 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 }