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