1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 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 #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 55 const 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 82 const 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 124 static int 125 str2inet(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 192 int 193 sockopen(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 242 int 243 sockopen(const char* path) 244 { 245 return -1; 246 } 247 248 #endif 249 250 void 251 sendlog(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))) 270 continue; 271 if ((log.fd = open(s, O_WRONLY|O_APPEND|O_NOCTTY)) < 0 && (log.fd = sockopen(s)) < 0) 272 continue; 273 fcntl(log.fd, F_SETFD, FD_CLOEXEC); 274 } 275 if (!n || write(log.fd, msg, n) > 0) 276 break; 277 close(log.fd); 278 log.fd = -1; 279 } 280 if (n && (log.flags & LOG_PERROR)) 281 write(2, msg, n); 282 } 283 284 static int 285 extend(Sfio_t* sp, void* vp, Sffmt_t* dp) 286 { 287 if (dp->fmt == 'm') 288 { 289 dp->flags |= SFFMT_VALUE; 290 dp->fmt = 's'; 291 dp->size = -1; 292 *((char**)vp) = fmterror(errno); 293 } 294 return 0; 295 } 296 297 void 298 vsyslog(int priority, const char* format, va_list ap) 299 { 300 register int c; 301 register char* s; 302 Sfio_t* sp; 303 Sffmt_t fmt; 304 char buf[16]; 305 306 if (!LOG_FACILITY(priority)) 307 priority |= log.facility; 308 if (!(priority & log.mask)) 309 return; 310 if (sp = sfstropen()) 311 { 312 sfputr(sp, fmttime("%b %d %H:%M:%S", time(NiL)), -1); 313 if (log.flags & LOG_LEVEL) 314 { 315 if ((c = LOG_SEVERITY(priority)) < elementsof(log_severity)) 316 s = (char*)log_severity[c].name; 317 else 318 sfsprintf(s = buf, sizeof(buf), "debug%d", c); 319 sfprintf(sp, " %-8s ", s); 320 if ((c = LOG_FACILITY(priority)) < elementsof(log_facility)) 321 s = (char*)log_facility[c].name; 322 else 323 sfsprintf(s = buf, sizeof(buf), "local%d", c); 324 sfprintf(sp, " %-8s ", s); 325 } 326 #if _lib_gethostname 327 if (!*log.host && gethostname(log.host, sizeof(log.host)-1)) 328 strcpy(log.host, "localhost"); 329 sfprintf(sp, " %s", log.host); 330 #endif 331 if (*log.ident) 332 sfprintf(sp, " %s", log.ident); 333 if (log.flags & LOG_PID) 334 { 335 if (!*log.ident) 336 sfprintf(sp, " "); 337 sfprintf(sp, "[%d]", getpid()); 338 } 339 if (format) 340 { 341 sfprintf(sp, ": "); 342 memset(&fmt, 0, sizeof(fmt)); 343 fmt.version = SFIO_VERSION; 344 fmt.form = (char*)format; 345 fmt.extf = extend; 346 va_copy(fmt.args, ap); 347 sfprintf(sp, "%!", &fmt); 348 } 349 if ((s = sfstrseek(sp, 0, SEEK_CUR)) && *(s - 1) != '\n') 350 sfputc(sp, '\n'); 351 if (s = sfstruse(sp)) 352 sendlog(s); 353 sfstrclose(sp); 354 } 355 } 356 357 void 358 syslog(int priority, const char* format, ...) 359 { 360 va_list ap; 361 362 va_start(ap, format); 363 vsyslog(priority, format, ap); 364 va_end(ap); 365 } 366 367 #endif 368