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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 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 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <unistd.h> 44 #include <stdio.h> 45 #include <syslog.h> 46 #include <ctype.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <locale.h> 50 #include <limits.h> 51 #include <pwd.h> 52 #include <errno.h> 53 54 #define LOG_MARK (LOG_NFACILITIES << 3) /* mark "facility" */ 55 #define LOGGER_BUFLEN 1024 56 57 struct code { 58 char *c_name; 59 int c_val; 60 }; 61 62 static struct code PriNames[] = { 63 "panic", LOG_EMERG, 64 "emerg", LOG_EMERG, 65 "alert", LOG_ALERT, 66 "crit", LOG_CRIT, 67 "err", LOG_ERR, 68 "error", LOG_ERR, 69 "warn", LOG_WARNING, 70 "warning", LOG_WARNING, 71 "notice", LOG_NOTICE, 72 "info", LOG_INFO, 73 "debug", LOG_DEBUG, 74 NULL, -1 75 }; 76 77 static struct code FacNames[] = { 78 "kern", LOG_KERN, 79 "user", LOG_USER, 80 "mail", LOG_MAIL, 81 "daemon", LOG_DAEMON, 82 "auth", LOG_AUTH, 83 "security", LOG_AUTH, 84 "mark", LOG_MARK, 85 "syslog", LOG_SYSLOG, 86 "lpr", LOG_LPR, 87 "news", LOG_NEWS, 88 "uucp", LOG_UUCP, 89 "cron", LOG_CRON, 90 "audit", LOG_AUDIT, 91 "local0", LOG_LOCAL0, 92 "local1", LOG_LOCAL1, 93 "local2", LOG_LOCAL2, 94 "local3", LOG_LOCAL3, 95 "local4", LOG_LOCAL4, 96 "local5", LOG_LOCAL5, 97 "local6", LOG_LOCAL6, 98 "local7", LOG_LOCAL7, 99 NULL, -1 100 }; 101 102 static int pencode(register char *); 103 static int decode(char *, struct code *); 104 static void bailout(char *, char *); 105 static void usage(void); 106 107 /* 108 * LOGGER -- read and log utility 109 * 110 * This routine reads from an input and arranges to write the 111 * result on the system log, along with a useful tag. 112 */ 113 114 main(argc, argv) 115 int argc; 116 char **argv; 117 { 118 char tmp[23]; 119 char *tag = NULL; 120 char *infile = NULL; 121 char *buf = NULL; 122 size_t buflen; 123 int pri = LOG_NOTICE; 124 int logflags = 0; 125 int opt; 126 int pid_len = 0; 127 struct passwd *pw; 128 uid_t u; 129 char fmt_uid[16]; 130 char *p, *endp; 131 size_t len; 132 ptrdiff_t offset = 0; 133 int status = 0; 134 135 (void) setlocale(LC_ALL, ""); 136 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 137 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 138 #endif 139 (void) textdomain(TEXT_DOMAIN); 140 /* initialize */ 141 142 while ((opt = getopt(argc, argv, "it:p:f:")) != EOF) 143 switch (opt) { 144 145 case 't': /* tag */ 146 tag = optarg; 147 break; 148 149 case 'p': /* priority */ 150 pri = pencode(optarg); 151 break; 152 153 case 'i': /* log process id also */ 154 logflags |= LOG_PID; 155 pid_len = sprintf(tmp, "%ld", (long)getpid()); 156 pid_len = (pid_len <= 0) ? 0 : pid_len +2; 157 break; 158 159 case 'f': /* file to log */ 160 if (strcmp(optarg, "-") == 0) 161 break; 162 infile = optarg; 163 if (freopen(infile, "r", stdin) == NULL) 164 { 165 (void) fprintf(stderr, gettext("logger: ")); 166 perror(infile); 167 exit(1); 168 } 169 break; 170 171 default: 172 usage(); 173 } 174 175 argc -= optind; 176 argv = &argv[optind]; 177 178 if ((tag == NULL) && ((tag = getlogin()) == NULL)) { 179 u = getuid(); 180 if ((pw = getpwuid(u)) == NULL) { 181 (void) sprintf(fmt_uid, "%ld", u); 182 tag = fmt_uid; 183 } else 184 tag = pw->pw_name; 185 } 186 187 /* setup for logging */ 188 openlog(tag, logflags, 0); 189 (void) fclose(stdout); 190 191 /* log input line if appropriate */ 192 if (argc > 0) { 193 /* 194 * Log arguments from command line 195 */ 196 int i; 197 198 len = 0; 199 for (i = 0; i < argc; i++) { 200 len += strlen(argv[i]) + 1; /* add 1 for <space> */ 201 } 202 if ((buf = malloc(len + 1)) == NULL) { 203 perror("logger"); 204 exit(1); 205 } 206 buf[0] = '\0'; 207 for (i = 0; i < argc; i++) { 208 if (i != 0) { 209 (void) strcat(buf, " "); 210 } 211 (void) strcat(buf, argv[i]); 212 } 213 #ifdef DEBUG 214 (void) fprintf(stderr, "len=%d, buf >%s<\n", len, buf); 215 #endif 216 syslog(pri, "%s", buf); 217 } else { 218 /* 219 * Log arguments from stdin (or input file). 220 * When reading from stdin, logger grows its buffer if 221 * needed, to handle long lines. 222 */ 223 if ((buf = malloc(LOGGER_BUFLEN)) == NULL) { 224 perror("logger"); 225 exit(1); 226 } 227 buflen = LOGGER_BUFLEN; 228 p = buf; 229 endp = buf + buflen; 230 offset = 0; 231 while (fgets(p, endp - p, stdin) != NULL) { 232 len = strlen(p); 233 if (p[len - 1] == '\n') { 234 #ifdef DEBUG 235 (void) fprintf(stderr, 236 "p-buf =%d, len=%d, buflen=%d, buf >%s<\n", 237 p-buf, len, buflen, buf); 238 #endif 239 syslog(pri, "%s", buf); 240 p = buf; 241 offset = 0; 242 } else if (len < endp - p - 1) { 243 /* short read or line with no <newline> */ 244 p += len; 245 offset += len; 246 #ifdef DEBUG 247 (void) fprintf(stderr, 248 "p-buf=%d, len=%d, buflen=%d, buf >%s<\n", 249 p-buf, len, buflen, buf); 250 #endif 251 continue; 252 } else { 253 /* line longer than buflen, so get larger buf */ 254 buflen += LOGGER_BUFLEN; 255 offset += len; 256 #ifdef DEBUG 257 (void) fprintf(stderr, 258 "Realloc endp-p=%d, len=%d, offset=%d, " 259 "buflen %d\n", 260 endp - p, len, offset, buflen); 261 #endif 262 if ((buf = realloc(buf, buflen)) == NULL) { 263 perror("logger"); 264 exit(1); 265 } 266 p = buf + offset; 267 endp = buf + buflen; 268 } 269 } /* while */ 270 271 if (feof(stdin)) { 272 if (p > buf) { 273 /* the last line did not end with newline */ 274 #ifdef DEBUG 275 (void) fprintf(stderr, 276 "(2) p-buf=%d, len=%d, buflen=%d, " 277 "buf >%s<\n", 278 p-buf, len, buflen, buf); 279 #endif 280 syslog(pri, "%s", buf); 281 } 282 } else { 283 /* 284 * fgets() encountered an error. Log unlogged data 285 * from earlier fgets() (if any). Write null byte 286 * after last full read, in case the fgets() that 287 * encountered error removed it and failed to null 288 * terminate. 289 */ 290 perror("logger"); 291 if (p > buf) { 292 *p = '\0'; 293 syslog(pri, "%s", buf); 294 } 295 status = 1; 296 } 297 } /* else !(argc > 0) */ 298 free(buf); 299 return (status); 300 } 301 302 /* 303 * Decode a symbolic name to a numeric value 304 */ 305 306 307 static int 308 pencode(s) 309 register char *s; 310 { 311 register char *p; 312 int lev; 313 int fac = 0; 314 315 for (p = s; *s && *s != '.'; s++); 316 if (*s) { 317 *s = '\0'; 318 fac = decode(p, FacNames); 319 if (fac < 0) 320 bailout("unknown facility name: ", p); 321 *s++ = '.'; 322 } else 323 s = p; 324 lev = decode(s, PriNames); 325 if (lev < 0) 326 bailout("unknown priority name: ", s); 327 328 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); 329 } 330 331 332 static int 333 decode(name, codetab) 334 char *name; 335 struct code *codetab; 336 { 337 register 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(a, b) 352 char *a, *b; 353 { 354 (void) fprintf(stderr, gettext("logger: %s%s\n"), a, b); 355 exit(1); 356 } 357 358 359 static void 360 usage(void) 361 { 362 (void) fprintf(stderr, gettext( 363 "Usage:\tlogger string\n" 364 "\tlogger [-i] [-f filename] [-p priority] [-t tag] " 365 "[message] ...\n")); 366 exit(1); 367 } 368