1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 /* 24 * syslog implementation 25 */ 26 27 #include <ast.h> 28 29 #if _lib_syslog 30 31 NoN(syslog) 32 33 #else 34 35 #define LOG_TABLES 36 37 #include "sysloglib.h" 38 39 #include <error.h> 40 #include <tm.h> 41 42 Syslog_state_t log = { LOG_USER, -1, 0, ~0 }; 43 44 static const Namval_t attempt[] = 45 { 46 "/dev/log", 0, 47 "lib/syslog/log", 0, 48 "/dev/console", LOG_CONS, 49 }; 50 51 const Namval_t log_facility[] = 52 { 53 "default", 0, 54 "user", LOG_USER, 55 "kernel", LOG_KERN, 56 "mail", LOG_MAIL, 57 "daemon", LOG_DAEMON, 58 "security", LOG_AUTH, 59 "syslog", LOG_SYSLOG, 60 "lpr", LOG_LPR, 61 "news", LOG_NEWS, 62 "uucp", LOG_UUCP, 63 "cron", LOG_CRON, 64 "audit", LOG_AUDIT, 65 "logalert", LOG_LFMT, 66 #ifdef LOG_SYSTEM2 67 "system2", LOG_SYSTEM2, 68 #endif 69 #ifdef LOG_SYSTEM1 70 "system1", LOG_SYSTEM1, 71 #endif 72 #ifdef LOG_SYSTEM0 73 "system0", LOG_SYSTEM0, 74 #endif 75 0, 0 76 }; 77 78 const Namval_t log_severity[] = 79 { 80 "panic", LOG_EMERG, 81 "alert", LOG_ALERT, 82 "critical", LOG_CRIT, 83 "error", LOG_ERR, 84 "warning", LOG_WARNING, 85 "notice", LOG_NOTICE, 86 "info", LOG_INFO, 87 "debug", LOG_DEBUG, 88 0, 0 89 }; 90 91 #if _UWIN 92 93 /* 94 * open /dev/(fdp|tcp|udp)/HOST/SERVICE for read 95 */ 96 97 #include <ctype.h> 98 #include <ls.h> 99 #include <sys/socket.h> 100 #include <sys/un.h> 101 #include <netdb.h> 102 #include <netinet/in.h> 103 104 #if !defined(htons) && !_lib_htons 105 # define htons(x) (x) 106 #endif 107 #if !defined(htonl) && !_lib_htonl 108 # define htonl(x) (x) 109 #endif 110 111 #ifndef INADDR_LOOPBACK 112 #define INADDR_LOOPBACK 0x7f000001L 113 #endif 114 115 /* 116 * convert s to sockaddr_in 117 * -1 returned on error 118 */ 119 120 static int 121 str2inet(register char* s, char* prot, struct sockaddr_in* addr) 122 { 123 register int c; 124 register int v; 125 register int n = 0; 126 unsigned long a = 0; 127 unsigned short p = 0; 128 129 if (!memcmp(s, "local/", 6)) 130 { 131 a = INADDR_LOOPBACK; 132 n = 4; 133 s += 6; 134 } 135 else if (!isdigit(*s)) 136 { 137 struct hostent* hp; 138 char* e = strchr(s, '/'); 139 140 if (!(e = strchr(s, '/'))) 141 return -1; 142 *e = 0; 143 hp = gethostbyname(s); 144 *e = '/'; 145 if (!hp || hp->h_addrtype != AF_INET || hp->h_length > sizeof(struct in_addr)) 146 return -1; 147 a = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr; 148 n = 6; 149 s = e + 1; 150 } 151 for (;;) 152 { 153 v = 0; 154 while ((c = *s++) >= '0' && c <= '9') 155 v = v * 10 + c - '0'; 156 if (++n <= 4) 157 a = (a << 8) | (v & 0xff); 158 else 159 { 160 if (n <= 5) 161 a = htonl(a); 162 if (c) 163 { 164 struct servent* sp; 165 166 if (!(sp = getservbyname(s - 1, prot))) 167 return -1; 168 p = sp->s_port; 169 } 170 else 171 p = htons(v); 172 break; 173 } 174 if (c != '.' && c != '/') 175 return -1; 176 } 177 memset((char*)addr, 0, sizeof(*addr)); 178 addr->sin_family = AF_INET; 179 addr->sin_addr.s_addr = a; 180 addr->sin_port = p; 181 return 0; 182 } 183 184 /* 185 * call this after open fails to see if path is a socket 186 */ 187 188 int 189 sockopen(const char* path) 190 { 191 int fd; 192 struct sockaddr_in addr; 193 char buf[PATH_MAX]; 194 195 if (pathgetlink(path, buf, sizeof(buf)) <= 0) 196 { 197 if (strlen(path) >= sizeof(buf)) 198 return -1; 199 strcpy(buf, path); 200 } 201 #if LOCAL 202 { 203 int ul; 204 struct sockaddr_un ua; 205 struct stat st; 206 207 if ((ul = strlen(buf)) < sizeof(ua.sun_path) && !stat(buf, &st) && S_ISSOCK(st.st_mode)) 208 { 209 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 210 return -1; 211 ua.sun_family = AF_UNIX; 212 strcpy(ua.sun_path, buf); 213 ul += sizeof(ua.sun_family) + 1; 214 if (!connect(fd, (struct sockaddr*)&ua, ul)) 215 return fd; 216 close(fd); 217 return -1; 218 } 219 } 220 #endif 221 if (!strmatch(buf, "/dev/(tcp|udp)/*/*")) 222 return -1; 223 buf[8] = 0; 224 if (str2inet(buf + 9, buf + 5, &addr)) 225 return -1; 226 if ((fd = socket(AF_INET, buf[5] == 't' ? SOCK_STREAM : SOCK_DGRAM, 0)) < 0) 227 return -1; 228 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr))) 229 { 230 close(fd); 231 return -1; 232 } 233 return fd; 234 } 235 236 #else 237 238 int 239 sockopen(const char* path) 240 { 241 return -1; 242 } 243 244 #endif 245 246 void 247 sendlog(const char* msg) 248 { 249 register char* s; 250 register Namval_t* p; 251 register int n; 252 253 n = msg ? strlen(msg) : 0; 254 for (;;) 255 { 256 if (log.fd < 0) 257 { 258 char buf[PATH_MAX]; 259 260 if (log.attempt >= elementsof(attempt)) 261 break; 262 p = (Namval_t*)&attempt[log.attempt++]; 263 if (p->value && !(p->value & log.flags)) 264 continue; 265 if (*(s = p->name) != '/' && !(s = pathpath(buf, s, "", PATH_REGULAR|PATH_READ))) 266 continue; 267 if ((log.fd = open(s, O_WRONLY|O_APPEND|O_NOCTTY)) < 0 && (log.fd = sockopen(s)) < 0) 268 continue; 269 fcntl(log.fd, F_SETFD, FD_CLOEXEC); 270 } 271 if (!n || write(log.fd, msg, n) > 0) 272 break; 273 close(log.fd); 274 log.fd = -1; 275 } 276 if (n && (log.flags & LOG_PERROR)) 277 write(2, msg, n); 278 } 279 280 static int 281 extend(Sfio_t* sp, void* vp, Sffmt_t* dp) 282 { 283 if (dp->fmt == 'm') 284 { 285 dp->flags |= SFFMT_VALUE; 286 dp->fmt = 's'; 287 dp->size = -1; 288 *((char**)vp) = fmterror(errno); 289 } 290 return 0; 291 } 292 293 void 294 vsyslog(int priority, const char* format, va_list ap) 295 { 296 register int c; 297 register char* s; 298 Sfio_t* sp; 299 Sffmt_t fmt; 300 char buf[16]; 301 302 if (!LOG_FACILITY(priority)) 303 priority |= log.facility; 304 if (!(priority & log.mask)) 305 return; 306 if (sp = sfstropen()) 307 { 308 sfputr(sp, fmttime("%b %d %H:%M:%S", time(NiL)), -1); 309 if (log.flags & LOG_LEVEL) 310 { 311 if ((c = LOG_SEVERITY(priority)) < elementsof(log_severity)) 312 s = (char*)log_severity[c].name; 313 else 314 sfsprintf(s = buf, sizeof(buf), "debug%d", c); 315 sfprintf(sp, " %-8s ", s); 316 if ((c = LOG_FACILITY(priority)) < elementsof(log_facility)) 317 s = (char*)log_facility[c].name; 318 else 319 sfsprintf(s = buf, sizeof(buf), "local%d", c); 320 sfprintf(sp, " %-8s ", s); 321 } 322 #if _lib_gethostname 323 if (!*log.host && gethostname(log.host, sizeof(log.host)-1)) 324 strcpy(log.host, "localhost"); 325 sfprintf(sp, " %s", log.host); 326 #endif 327 if (*log.ident) 328 sfprintf(sp, " %s", log.ident); 329 if (log.flags & LOG_PID) 330 { 331 if (!*log.ident) 332 sfprintf(sp, " "); 333 sfprintf(sp, "[%d]", getpid()); 334 } 335 if (format) 336 { 337 sfprintf(sp, ": "); 338 memset(&fmt, 0, sizeof(fmt)); 339 fmt.version = SFIO_VERSION; 340 fmt.form = (char*)format; 341 fmt.extf = extend; 342 va_copy(fmt.args, ap); 343 sfprintf(sp, "%!", &fmt); 344 } 345 if ((s = sfstrseek(sp, 0, SEEK_CUR)) && *(s - 1) != '\n') 346 sfputc(sp, '\n'); 347 if (s = sfstruse(sp)) 348 sendlog(s); 349 sfstrclose(sp); 350 } 351 } 352 353 void 354 syslog(int priority, const char* format, ...) 355 { 356 va_list ap; 357 358 va_start(ap, format); 359 vsyslog(priority, format, ap); 360 va_end(ap); 361 } 362 363 #endif 364