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 2005 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 int 115 main(int argc, char **argv) 116 { 117 char tmp[23]; 118 char *tag = NULL; 119 char *infile = NULL; 120 char *buf = NULL; 121 size_t buflen; 122 int pri = LOG_NOTICE; 123 int logflags = 0; 124 int opt; 125 int pid_len = 0; 126 struct passwd *pw; 127 uid_t u; 128 char fmt_uid[16]; 129 char *p, *endp; 130 size_t len; 131 ptrdiff_t offset = 0; 132 int status = 0; 133 134 (void) setlocale(LC_ALL, ""); 135 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 136 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 137 #endif 138 (void) textdomain(TEXT_DOMAIN); 139 /* initialize */ 140 141 while ((opt = getopt(argc, argv, "it:p:f:")) != EOF) 142 switch (opt) { 143 144 case 't': /* tag */ 145 tag = optarg; 146 break; 147 148 case 'p': /* priority */ 149 pri = pencode(optarg); 150 break; 151 152 case 'i': /* log process id also */ 153 logflags |= LOG_PID; 154 pid_len = sprintf(tmp, "%ld", (long)getpid()); 155 pid_len = (pid_len <= 0) ? 0 : pid_len +2; 156 break; 157 158 case 'f': /* file to log */ 159 if (strcmp(optarg, "-") == 0) 160 break; 161 infile = optarg; 162 if (freopen(infile, "r", stdin) == NULL) { 163 (void) fprintf(stderr, gettext("logger: ")); 164 perror(infile); 165 exit(1); 166 } 167 break; 168 169 default: 170 usage(); 171 } 172 173 argc -= optind; 174 argv = &argv[optind]; 175 176 if ((tag == NULL) && ((tag = getlogin()) == NULL)) { 177 u = getuid(); 178 if ((pw = getpwuid(u)) == NULL) { 179 (void) sprintf(fmt_uid, "%ld", u); 180 tag = fmt_uid; 181 } else 182 tag = pw->pw_name; 183 } 184 185 /* setup for logging */ 186 openlog(tag, logflags, 0); 187 (void) fclose(stdout); 188 189 /* log input line if appropriate */ 190 if (argc > 0) { 191 /* 192 * Log arguments from command line 193 */ 194 int i; 195 196 len = 0; 197 for (i = 0; i < argc; i++) { 198 len += strlen(argv[i]) + 1; /* add 1 for <space> */ 199 } 200 if ((buf = malloc(len + 1)) == NULL) { 201 perror("logger"); 202 exit(1); 203 } 204 buf[0] = '\0'; 205 for (i = 0; i < argc; i++) { 206 if (i != 0) { 207 (void) strcat(buf, " "); 208 } 209 (void) strcat(buf, argv[i]); 210 } 211 #ifdef DEBUG 212 (void) fprintf(stderr, "len=%d, buf >%s<\n", len, buf); 213 #endif 214 syslog(pri, "%s", buf); 215 } else { 216 /* 217 * Log arguments from stdin (or input file). 218 * When reading from stdin, logger grows its buffer if 219 * needed, to handle long lines. 220 */ 221 if ((buf = malloc(LOGGER_BUFLEN)) == NULL) { 222 perror("logger"); 223 exit(1); 224 } 225 buflen = LOGGER_BUFLEN; 226 p = buf; 227 endp = buf + buflen; 228 offset = 0; 229 while (fgets(p, endp - p, stdin) != NULL) { 230 len = strlen(p); 231 if (p[len - 1] == '\n') { 232 #ifdef DEBUG 233 (void) fprintf(stderr, 234 "p-buf =%d, len=%d, buflen=%d, buf >%s<\n", 235 p-buf, len, buflen, buf); 236 #endif 237 syslog(pri, "%s", buf); 238 p = buf; 239 offset = 0; 240 } else if (len < endp - p - 1) { 241 /* short read or line with no <newline> */ 242 p += len; 243 offset += len; 244 #ifdef DEBUG 245 (void) fprintf(stderr, 246 "p-buf=%d, len=%d, buflen=%d, buf >%s<\n", 247 p-buf, len, buflen, buf); 248 #endif 249 continue; 250 } else { 251 /* line longer than buflen, so get larger buf */ 252 buflen += LOGGER_BUFLEN; 253 offset += len; 254 #ifdef DEBUG 255 (void) fprintf(stderr, 256 "Realloc endp-p=%d, len=%d, offset=%d, " 257 "buflen %d\n", 258 endp - p, len, offset, buflen); 259 #endif 260 if ((buf = realloc(buf, buflen)) == NULL) { 261 perror("logger"); 262 exit(1); 263 } 264 p = buf + offset; 265 endp = buf + buflen; 266 } 267 } /* while */ 268 269 if (feof(stdin)) { 270 if (p > buf) { 271 /* the last line did not end with newline */ 272 #ifdef DEBUG 273 (void) fprintf(stderr, 274 "(2) p-buf=%d, len=%d, buflen=%d, " 275 "buf >%s<\n", 276 p-buf, len, buflen, buf); 277 #endif 278 syslog(pri, "%s", buf); 279 } 280 } else { 281 /* 282 * fgets() encountered an error. Log unlogged data 283 * from earlier fgets() (if any). Write null byte 284 * after last full read, in case the fgets() that 285 * encountered error removed it and failed to null 286 * terminate. 287 */ 288 perror("logger"); 289 if (p > buf) { 290 *p = '\0'; 291 syslog(pri, "%s", buf); 292 } 293 status = 1; 294 } 295 } /* else !(argc > 0) */ 296 free(buf); 297 return (status); 298 } 299 300 /* 301 * Decode a symbolic name to a numeric value 302 */ 303 304 305 static int 306 pencode(s) 307 register char *s; 308 { 309 register char *p; 310 int lev; 311 int fac = 0; 312 313 for (p = s; *s && *s != '.'; s++); 314 if (*s) { 315 *s = '\0'; 316 fac = decode(p, FacNames); 317 if (fac < 0) 318 bailout("unknown facility name: ", p); 319 *s++ = '.'; 320 } else 321 s = p; 322 lev = decode(s, PriNames); 323 if (lev < 0) 324 bailout("unknown priority name: ", s); 325 326 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); 327 } 328 329 330 static int 331 decode(name, codetab) 332 char *name; 333 struct code *codetab; 334 { 335 register struct code *c; 336 337 if (isdigit(*name)) 338 return (atoi(name)); 339 340 for (c = codetab; c->c_name; c++) 341 if (strcasecmp(name, c->c_name) == 0) 342 return (c->c_val); 343 344 return (-1); 345 } 346 347 348 static void 349 bailout(a, b) 350 char *a, *b; 351 { 352 (void) fprintf(stderr, gettext("logger: %s%s\n"), a, b); 353 exit(1); 354 } 355 356 357 static void 358 usage(void) 359 { 360 (void) fprintf(stderr, gettext( 361 "Usage:\tlogger string\n" 362 "\tlogger [-i] [-f filename] [-p priority] [-t tag] " 363 "[message] ...\n")); 364 exit(1); 365 } 366