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 "altcron", LOG_ALTCRON, 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(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(char *s) 311 { 312 char *p; 313 int lev; 314 int fac = 0; 315 316 for (p = s; *s && *s != '.'; s++) 317 ; 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(char *name, struct code *codetab) 336 { 337 struct code *c; 338 339 if (isdigit(*name)) 340 return (atoi(name)); 341 342 for (c = codetab; c->c_name; c++) 343 if (strcasecmp(name, c->c_name) == 0) 344 return (c->c_val); 345 346 return (-1); 347 } 348 349 350 static void 351 bailout(char *a, char *b) 352 { 353 (void) fprintf(stderr, gettext("logger: %s%s\n"), a, b); 354 exit(1); 355 } 356 357 358 static void 359 usage(void) 360 { 361 (void) fprintf(stderr, gettext( 362 "Usage:\tlogger string\n" 363 "\tlogger [-i] [-f filename] [-p priority] [-t tag] " 364 "[message] ...\n")); 365 exit(1); 366 } 367