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