/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1983 Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)syslogd.c 5.13 (Berkeley) 5/26/86"; #endif /* not lint */ /* * syslogd -- log system messages * * This program implements a system log. It takes a series of lines. * Each line may have a priority, signified as "" as * the first characters of the line. If this is * not present, a default priority is used. * * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will * cause it to reread its configuration file. * * Defined Constants: * * MAXLINE -- the maximimum line length that can be handled. * NLOGS -- the maximum number of simultaneous log files. * DEFUPRI -- the default priority for user messages * DEFSPRI -- the default priority for kernel messages * * Author: Eric Allman * extensive changes by Ralph Campbell */ /* * Define this to test for "out of disk space". Creating the file * /tmp/ will cause to appear to be out of space. * * #define DUMMY_NOSPC */ #define NLOGS 50 /* max number of log files */ #define MAXLINE 1024 /* maximum line length */ #define DEFUPRI (LOG_USER|LOG_NOTICE) #define DEFSPRI (LOG_KERN|LOG_CRIT) #define MARKCOUNT 10 /* ratio of minor to major marks */ #define _BSD_SIGNALS #define SSS_SUPPORT 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SSS_SUPPORT #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _PATH_KLOG "/dev/klog" #define _PATH_LOGCONF "/etc/syslog.conf" #define strcpyn(a, b, n) strncpy(a, b, n) int flog; char *malloc(); char *LogName = _PATH_LOG; char *ConfFile = _PATH_LOGCONF; char *ctty = _PATH_CONSOLE; #define FDMASK(fd) (1 << (fd)) #define dprintf if (Debug) printf #define UNAMESZ 8 /* length of a login name */ #define MAXUNAMES 20 /* maximum number of user names */ #define MAXFNAME 200 /* max file pathname length */ #define NOPRI 0x10 /* the "no priority" priority */ #define LOG_MARK (LOG_NFACILITIES << 3) /* mark "facility" */ #define FORK_TIMEOUT 120 /* number of seconds between */ /* failed fork attempts */ #define FREEDISK 10240 /* amount of free disk space, in bytes, */ /* required to restart logging to a full */ /* partition */ /* * Flags to logmsg(). */ #define IGN_CONS 0x001 /* don't print on console */ #define SYNC_FILE 0x002 /* do fsync on file after printing */ #define NOCOPY 0x004 /* don't suppress duplicate messages */ #define ADDDATE 0x008 /* add a date to the message */ #define MARK 0x010 /* this message is a mark */ #define DO_CONS 0x020 /* send this to the console */ /* * This structure represents the files that will have log * copies printed. */ struct filed { short f_type; /* entry type, see below */ short f_file; /* file descriptor */ short f_status; /* status of filed */ time_t f_time; /* time this was last written */ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ char *f_filter; /* path of message filter or NULL */ union { char f_uname[MAXUNAMES][UNAMESZ+1]; struct { char f_hname[MAXHOSTNAMELEN+1]; struct sockaddr_in f_addr; unsigned short f_nfail1; unsigned short f_nfail2; time_t f_till; int f_nmissed; } f_forw; /* forwarding address */ char f_fname[MAXFNAME]; #ifdef SSS_SUPPORT struct { struct sockaddr_un su_addr; /* UNIX socket - destination address */ int su_addrlen; /* UNIX socket - address len */ } f_us; /* UNIX sockets support structure */ #endif } f_un; }; #ifdef SSS_SUPPORT #define fus_su f_un.f_us.su_addr #define fus_sal f_un.f_us.su_addrlen #endif /* values for f_type */ #define F_UNUSED 0 /* unused entry */ #define F_FILE 1 /* regular file */ #define F_TTY 2 /* terminal */ #define F_CONSOLE 3 /* console terminal */ #define F_FORW 4 /* remote machine */ #define F_USERS 5 /* list of users */ #define F_WALL 6 /* everyone logged on */ #define F_DOCONS 7 /* special stub for lfmt -c */ #ifdef SSS_SUPPORT #define F_UNIXSOCK 8 /* UNIX socket */ #endif /* values for f_status */ #define S_OK 0 /* operational */ #define S_NOSPC 1 /* no space available */ #define FW_MSG1 "sendto <%s>: Failed %d times" #define FW_MSG2 "sendto <%s>: No msgs. will be sent for %d seconds" #define FW_MSG3 "sendto <%s>: Closing connection due to persistent network problems (last %d sends failed)" #define FW_MSG4 "sendto <%s>: last %d messages lost" #define FW_MAXFAIL1 5 #define FW_MAXFAIL2 5 #define FW_SILENT_INTERVAL 60 /* seconds */ #ifdef SSS_SUPPORT char *TypeNames[9] = { "UNUSED", "FILE", "TTY", "CONSOLE", "FORW", "USERS", "WALL", "DOCONS", "UNIXSOCK" }; #else char *TypeNames[8] = { "UNUSED", "FILE", "TTY", "CONSOLE", "FORW", "USERS", "WALL", "DOCONS" }; #endif struct code { char *c_name; int c_val; }; struct code PriNames[] = { "panic", LOG_EMERG, "emerg", LOG_EMERG, "alert", LOG_ALERT, "crit", LOG_CRIT, "err", LOG_ERR, "error", LOG_ERR, "warn", LOG_WARNING, "warning", LOG_WARNING, "notice", LOG_NOTICE, "info", LOG_INFO, "debug", LOG_DEBUG, "none", NOPRI, NULL, -1 }; struct code FacNames[] = { "kern", LOG_KERN, "user", LOG_USER, "mail", LOG_MAIL, "daemon", LOG_DAEMON, "auth", LOG_AUTH, "security", LOG_AUTH, "mark", LOG_MARK, "syslog", LOG_SYSLOG, "lpr", LOG_LPR, "news", LOG_NEWS, "uucp", LOG_UUCP, "cron", LOG_CRON, "local0", LOG_LOCAL0, "local1", LOG_LOCAL1, "local2", LOG_LOCAL2, "local3", LOG_LOCAL3, "local4", LOG_LOCAL4, "local5", LOG_LOCAL5, "local6", LOG_LOCAL6, "local7", LOG_LOCAL7, NULL, -1 }; struct filed Files[NLOGS]; extern void reapchild(); int Debug; /* debug flag */ #ifdef SSS_SUPPORT int sssTagOn = 1; /* SSS tag enabled flag, default value is "on" */ #endif char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ char *LocalDomain; /* our local domain name */ int InetInuse = 0; /* non-zero if INET sockets are being used */ int LogPort; /* port number for INET connections */ char PrevLine[MAXLINE + 1]; /* copy of last line to supress repeats */ char PrevHost[MAXHOSTNAMELEN+1]; /* previous host */ int PrevFlags; int PrevPri; int PrevCount = 0; /* number of times seen */ int Initialized = 0; /* set when we have initialized ourselves */ int MarkInterval = 20; /* interval between marks in minutes */ int MarkSeq = 0; /* mark sequence number */ int finet, inetm; static int redo_host_lookup; /* gethostbyname failed during init() */ /* forward declarations */ void usage(); void opendevlog(), init(), untty(), logerror(); void cfline(), flushmsg(), wallmsg(), logmsg(); void domark(); void printline(), printlfmt(), printsys(); /* Flags set by signal handlers to indicate a need to call the routine */ static int need_inetbind; static int need_init; static int need_domark; void inithandler() { need_init = 1; } void bindhandler() { need_inetbind = 1; } void domarkhandler() { need_domark = 1; } /* * Initialize the syslog port used to listen for messages from other hosts * and to forward messages to other hosts. If we can't bind within the * specified time limit (approx. 2 * MAXBINDTIMEOUT), stop trying and * start the mark timer. */ #define MAXBINDTIMEOUT 160 void tryinetbind(first) int first; { struct servent *sp; struct sockaddr_in sin; static int timeout = 5; need_inetbind = 0; dprintf("tryinetbind %d\n", first); sp = getservbyname("syslog", "udp"); if (sp == NULL) goto retry; sin.sin_family = AF_INET; sin.sin_port = sp->s_port; sin.sin_addr.s_addr = INADDR_ANY; bzero(sin.sin_zero, sizeof sin.sin_zero); if (cap_bind(finet, (struct sockaddr *) &sin, sizeof(sin)) < 0) { retry: if (timeout < MAXBINDTIMEOUT) { signal(SIGALRM, bindhandler); timeout *= 2; alarm(timeout); return; } /* Give up -- fall through ... */ } else { inetm = FDMASK(finet); InetInuse = 1; LogPort = sp->s_port; } if (!first) { if (MarkInterval > 0) { (void) signal(SIGALRM, domarkhandler); (void) alarm(MarkInterval * 60 / MARKCOUNT); } init(); /* reconfigure forwarding ports */ } } main(argc, argv) int argc; char **argv; { register int i; register char *p; int fklog, klogm, len; struct sockaddr_in frominet; char line[MSG_BSIZE + 1]; extern void die(); int oerrno; int ch; #ifdef SSS_SUPPORT while ((ch = getopt(argc, argv, "dsf:m:p:")) != EOF) #else while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) #endif switch((char)ch) { case 'd': /* debug */ Debug++; break; case 'f': /* configuration file */ ConfFile = optarg; break; case 'm': /* mark interval */ MarkInterval = atoi(optarg); /* * 60? */ break; case 'p': /* path */ LogName = optarg; break; #ifdef SSS_SUPPORT case 's': /* turn off SSS tag for output */ sssTagOn = 0; break; #endif case '?': default: usage(); } if (argc -= optind) usage(); if (!Debug) { if (fork()) exit(0); for (i = 0; i < 10; i++) (void) close(i); (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); untty(); } else setlinebuf(stdout); (void) gethostname(LocalHostName, sizeof LocalHostName); if (p = index(LocalHostName, '.')) { *p++ = '\0'; LocalDomain = p; } else LocalDomain = ""; (void) signal(SIGTERM, die); (void) signal(SIGINT, Debug ? die : SIG_IGN); (void) signal(SIGQUIT, Debug ? die : SIG_IGN); (void) signal(SIGCHLD, reapchild); if (MarkInterval > 0) { (void) signal(SIGALRM, domarkhandler); (void) alarm(MarkInterval * 60 / MARKCOUNT); } opendevlog(); finet = socket(AF_INET, SOCK_DGRAM, 0); if (finet != -1 && tsix_on (finet) == -1) { close(finet); finet = -1; } if (finet >= 0) { tryinetbind(1); } if ((fklog = open(_PATH_KLOG, O_RDONLY)) >= 0) klogm = FDMASK(fklog); else { dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); klogm = 0; } dprintf("off & running....\n"); dprintf("unix=%d, inet=%d, klog=%d\n", flog, finet, fklog); init(); (void) signal(SIGHUP, inithandler); for (;;) { int nfds, readfds = FDMASK(flog) | inetm | klogm; errno = 0; dprintf("readfds = %#x\n", readfds); nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL, (fd_set *) NULL, (struct timeval *) NULL); oerrno = errno; if (Debug) { if (nfds > 0) { printf("got a message (%d, %#x)\n", nfds, readfds); } else { printf("select returned %d %s\n", nfds, nfds < 0 ? strerror(errno) : ""); } } /* Check if a signal came in */ if (need_inetbind) tryinetbind(0); if (need_init) init(); if (need_domark) { domark(); /* A previous gethostbyname failed to get an answer; * try again in case the name server is now available. */ if (redo_host_lookup) init(); } if (nfds <= 0) { if (nfds < 0 && oerrno != EINTR) { errno = oerrno; logerror("select"); } continue; } if (readfds & klogm) { i = read(fklog, line, sizeof(line) - 1); if (i > 0) { line[i] = '\0'; printsys(line); } else if (i < 0 && errno != EINTR) { logerror("klog"); fklog = -1; klogm = 0; } } if (readfds & FDMASK(flog)) { struct log_ctl hdr; struct strbuf dat, ctl; int flags = 0; dat.maxlen = MAXLINE; dat.buf = line; ctl.maxlen = sizeof(struct log_ctl); ctl.buf = (caddr_t)&hdr; i = getmsg(flog, &ctl, &dat, &flags); if (i == 0 && dat.len > 0) { line[dat.len] = '\0'; if ((hdr.pri & LOG_FACMASK) == LOG_LFMT) printlfmt(&hdr, line); else printline(LocalHostName, line); } else if (i < 0 && errno != EINTR) { close(flog); opendevlog(); } } if (readfds & inetm) { len = sizeof frominet; i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len); if (i > 0) { extern char *cvthname(); line[i] = '\0'; printline(cvthname(&frominet), line); } else if (i < 0 && errno != EINTR) logerror("recvfrom inet"); } } } void usage() { #ifdef SSS_SUPPORT fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile] [-s]\n"); #else fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n"); #endif exit(1); } void untty(void) { int i; if (!Debug) { i = open(_PATH_TTY, O_RDWR); if (i >= 0) { (void) ioctl(i, (int) TIOCNOTTY, (char *)0); (void) close(i); } } } static int cap_open(const char *file, int flags, ...) { static const cap_value_t open_caps[] = {CAP_DAC_WRITE, CAP_MAC_WRITE}; va_list ap; cap_t ocap; int r; ocap = cap_acquire(2, open_caps); va_start(ap, flags); if (flags & O_CREAT) r = open(file, flags, va_arg(ap, mode_t)); else r = open(file, flags); va_end(ap); cap_surrender(ocap); return(r); } /* * Take a raw input line, decode the message, and print the message * on the appropriate log files. */ void printline(hname, msg) char *hname; char *msg; { register char *p, *q; register int c; char line[MAXLINE + 1]; int pri; /* test for special codes */ pri = DEFUPRI; p = msg; repeat: if (*p == '<') { pri = 0; while (isdigit(*++p)) pri = 10 * pri + (*p - '0'); if (*p == '>') ++p; if (pri <= 0 || pri >= (LOG_NFACILITIES << 3)) pri = DEFUPRI; } /* don't allow users to log kernel messages */ if ((pri & LOG_PRIMASK) == LOG_KERN) pri |= LOG_USER; q = line; while ((c = *p++ & 0177) != '\0' && c != '\n' && q < &line[sizeof(line) - 1]) { if (iscntrl(c)) { *q++ = '^'; *q++ = c ^ 0100; } else *q++ = c; } *q = '\0'; #ifdef SSS_SUPPORT logmsg(pri, line, hname, 0, 0); #else logmsg(pri, line, hname, 0); #endif /* * Named pipes don't preserve record boundaries, so more than * one message can be retrieved in a single read. * Skip duplicate line feeds and go print the next message */ if (c == '\n') { while (*p == '\n') ++p; if (*p != '\0') { pri = DEFUPRI; goto repeat; } } } /* * Message is in funny lfmt format */ void printlfmt(hdr, msg) struct log_ctl *hdr; char *msg; { long flags = 0; char lfmt[MAXLINE]; char *lp, *nl; char *sev, *lab; int i; for (i = 0; i < sizeof(long); i++) flags = (flags << 8)|*msg++; if (flags & MM_CONSOLE) flags = DO_CONS; else flags = 0; lab = msg; while (*msg++ != '\0') ; sev = msg; while (*msg++ != '\0') ; strcpy(lfmt, ctime(&hdr->ttime)+4); lfmt[16] = '\0'; if (*lab) { strcat(lfmt, lab); strcat(lfmt, ": "); } if (*sev) { strcat(lfmt, sev); strcat(lfmt, ": "); } lp = lfmt+strlen(lfmt); while (nl = strchr(msg, '\n')) { *nl = '\0'; if (*msg) { strcat(lfmt, msg); #ifdef SSS_SUPPORT logmsg(hdr->pri&LOG_PRIMASK, lfmt, LocalHostName, 0, 0); #else logmsg(hdr->pri&LOG_PRIMASK, lfmt, LocalHostName, 0); #endif } msg = nl+1; *lp = '\0'; } if (*msg) { strcat(lfmt, msg); #ifdef SSS_SUPPORT logmsg(hdr->pri&LOG_PRIMASK, lfmt, LocalHostName, flags, 0); #else logmsg(hdr->pri&LOG_PRIMASK, lfmt, LocalHostName, flags); #endif } } /* * Take a raw input line from /dev/klog, split and format similar to syslog(). */ void printsys(msg) char *msg; { register char *p, *q; register int c; char line[MAXLINE + 1]; #ifdef SSS_SUPPORT char line2[MAXLINE + 33]; char *ctime_result; char *lp2; char *q2; char *p2; #endif int pri, flags; char *lp; time_t now; (void) time(&now); if (*msg == '\n') { while (*++msg == '\n') ; if (*msg == '\0') return; } #ifdef SSS_SUPPORT ctime_result = ctime(&now); lp = line + sprintf(line, "%.15s unix: ", ctime_result + 4); lp2 = line2 + sprintf(line2, "%.15s unix: ", ctime_result + 4); p2 = 0; #else lp = line + sprintf(line, "%.15s unix: ", ctime(&now) + 4); #endif for (p = msg; *p != '\0'; ) { flags = SYNC_FILE; /* fsync file after write */ pri = DEFSPRI; if (*p == '<') { pri = 0; while (isdigit(*++p)) pri = 10 * pri + (*p - '0'); if (*p == '>') ++p; if (pri <= 0 || pri >= (LOG_NFACILITIES << 3)) pri = DEFSPRI; #ifdef SSS_SUPPORT p2 = p; if(!sssTagOn && p[0] == '|' && p[1] == '$' && p[2] == '(') { p += 3; while(*p != '\0' && *p != ')') p++; if(*p == ')') p++; else p2 = 0; } else p2 = 0; #endif } else { /* kernel printf's come out on console */ flags |= IGN_CONS; #ifdef SSS_SUPPORT p2 = 0; #endif } q = lp; while (*p != '\0' && (c = *p++) != '\n' && q < &line[MAXLINE]) *q++ = c; *q = '\0'; #ifdef SSS_SUPPORT if(p2) { q2 = lp2; while (*p2 != '\0' && (c = *p2++) != '\n' && q2 < &line2[MAXLINE]) *q2++ = c; *q2 = '\0'; } logmsg(pri, line, LocalHostName, flags, p2 ? line2 : 0); #else logmsg(pri, line, LocalHostName, flags); #endif } } /* * Log a message to the appropriate log files, users, etc. based on * the priority. */ void #ifdef SSS_SUPPORT logmsg(pri, msg, from, flags, msg2) int pri; char *msg, *msg2, *from; int flags; #else logmsg(pri, msg, from, flags) int pri; char *msg, *from; int flags; #endif { register struct filed *f; register int l; int fac, prilev; time_t now; int omask; struct iovec iov[7]; register struct iovec *v = iov; char line[MAXLINE + 1]; char *msgbase; int msglen; char prilev_char[4]; char fac_string[LOG_NFACILITIES]="ABCDEFGHIJKLMNOPQRSTUVWX"; int didconsole; char spc; didconsole = 0; #ifdef SSS_SUPPORT dprintf("logmsg: pri %o, flags %x, from %s, msg %s, msg2 %s\n", pri, flags, from, msg, msg2); #else dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg); #endif omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); /* * Check to see if msg looks non-standard. */ if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') flags |= ADDDATE; if (!(flags & NOCOPY)) { if (flags & (ADDDATE|MARK)) flushmsg(); else if (!strcmp(msg + 16, PrevLine + 16) && PrevFlags == flags && PrevPri == pri && !strcmp(from, PrevHost)) { /* we found a match, update the time */ (void) strncpy(PrevLine, msg, 15); PrevCount++; (void) sigsetmask(omask); return; } else { /* new line, save it */ flushmsg(); (void) strncpy(PrevLine, msg, sizeof(PrevLine)-1); (void) strncpy(PrevHost, from, sizeof(PrevHost)-1); PrevFlags = flags; PrevPri = pri; } } /* extract facility and priority level */ fac = (pri & LOG_FACMASK) >> 3; if (flags & MARK) fac = LOG_NFACILITIES; prilev = pri & LOG_PRIMASK; (void) time(&now); if (flags & ADDDATE) v->iov_base = ctime(&now) + 4; else v->iov_base = msg; v->iov_len = 15; v++; v->iov_base = " "; v->iov_len = 1; v++; sprintf(prilev_char, "%1d%c:", prilev, fac_string[fac] ); v->iov_base = prilev_char; v->iov_len = 3; v++; v->iov_base = from; v->iov_len = strlen(v->iov_base); v++; v->iov_base = " "; v->iov_len = 1; v++; if (flags & ADDDATE) v->iov_base = msg; else v->iov_base = msg + 16; v->iov_len = strlen(v->iov_base); msgbase = v->iov_base; msglen = v->iov_len; v++; /* log the message to the particular outputs */ if (!Initialized) { int cfd = open(ctty, O_WRONLY); if (cfd >= 0) { v->iov_base = "\r\n"; v->iov_len = 2; (void) writev(cfd, iov, 6); (void) close(cfd); } untty(); (void) sigsetmask(omask); return; } for (f = Files; f < &Files[NLOGS]; f++) { char newmsg[MAXLINE+1]; /* skip messages that are incorrect priority */ if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI) continue; if (f->f_filter) { dprintf("Filtering to %s\n", f->f_filter); v[-1].iov_base = newmsg; v[-1].iov_len = MAXLINE; if (filtermsg(f->f_filter, msgbase, msglen, newmsg, &v[-1].iov_len,fac,prilev,from) == 0) { /* filter didn't want message logged */ dprintf("filter IGNORED message\n"); v[-1].iov_base = msgbase; v[-1].iov_len = msglen; continue; } } /* don't output marks to recently written files */ if ((flags & MARK) && (now - f->f_time) < (MarkInterval * 60 / 2)) continue; dprintf("Logging to %s", TypeNames[f->f_type]); f->f_time = now; switch (f->f_type) { case F_UNUSED: dprintf("\n"); break; #ifdef SSS_SUPPORT case F_UNIXSOCK: dprintf("%s\n",f->fus_su.sun_path); (void) sprintf(line, "<%d><%.15s> %s", pri, iov[0].iov_base, msg2 ? ((flags & ADDDATE) ? msg2 : msg2+16) : (char*)iov[5].iov_base); l = strlen(line); if (l > MAXLINE) l = MAXLINE; if(sendto(f->f_file, line, l, 0, (struct sockaddr*) &f->fus_su, f->fus_sal) != l) { dprintf("sendto error - %s\n",strerror(errno)); l = 0; } break; #endif case F_FORW: dprintf(" %s\n", f->f_un.f_forw.f_hname); /* * multihop: If we're forwarding an already- * forwarded msg, substitute the fromhost * for the date field. */ if (strcmp(from, LocalHostName) != 0) (void) sprintf(line, "<%d>%s %s", pri, iov[3].iov_base, iov[5].iov_base); else (void) sprintf(line, "<%d>%.15s %s", pri, iov[0].iov_base, iov[5].iov_base); l = strlen(line); if (l > MAXLINE) l = MAXLINE; if (f->f_un.f_forw.f_nfail1 >= FW_MAXFAIL1) { time_t now; now = time(0); if (now < f->f_un.f_forw.f_till) { /* * Not enough time elapsed since last * f_nfail1 errors. */ f->f_un.f_forw.f_nmissed++; break; } f->f_un.f_forw.f_nfail1 = 0; } if (sendto(f->f_file, line, l, 0, &f->f_un.f_forw.f_addr, sizeof f->f_un.f_forw.f_addr) != l) { /* * if error is operational error, then * ignore a few of them. */ int e = errno; if ((e == ENETDOWN) || (e == ENETUNREACH) || (e == ENETRESET)) { char emsg[MAXHOSTNAMELEN+100]; f->f_un.f_forw.f_nmissed++; f->f_un.f_forw.f_nfail1++; if (f->f_un.f_forw.f_nfail1 < FW_MAXFAIL1) break; sprintf(emsg, FW_MSG1, f->f_un.f_forw.f_hname, FW_MAXFAIL1); logerror(emsg); f->f_un.f_forw.f_nfail2++; if (f->f_un.f_forw.f_nfail2 < FW_MAXFAIL2) { time_t now; now = time(0); f->f_un.f_forw.f_till = now + FW_SILENT_INTERVAL; sprintf(emsg, FW_MSG2, f->f_un.f_forw.f_hname, FW_SILENT_INTERVAL); errno = e; logerror(emsg); break; } sprintf(emsg, FW_MSG3, f->f_un.f_forw.f_hname, FW_MAXFAIL1 * FW_MAXFAIL2); errno = e; logerror(emsg); } (void) close(f->f_file); f->f_type = F_UNUSED; errno = e; if ((e != ENETDOWN) && (e != ENETUNREACH) && (e != ENETRESET)) logerror("sendto"); } else { char emsg[MAXHOSTNAMELEN+100]; /* every successful send resets fail windows */ f->f_un.f_forw.f_nfail1 = 0; f->f_un.f_forw.f_nfail2 = 0; f->f_un.f_forw.f_till = 0; if (f->f_un.f_forw.f_nmissed) { sprintf(emsg, FW_MSG4, f->f_un.f_forw.f_hname, f->f_un.f_forw.f_nmissed); f->f_un.f_forw.f_nmissed = 0; errno = 0; logerror(emsg); } } break; case F_DOCONS: if (!(flags & DO_CONS) || didconsole) { dprintf(" (ignored)\n"); break; } /* FALL THROUGH */ case F_CONSOLE: if ((flags & IGN_CONS) || didconsole) { dprintf(" (ignored)\n"); break; } didconsole = 1; f->f_file = cap_open(f->f_un.f_fname, O_WRONLY); /* FALL THROUGH */ case F_TTY: case F_FILE: dprintf(" %s\n", f->f_un.f_fname); if (f->f_type != F_FILE) { v->iov_base = "\r\n"; v->iov_len = 2; } else { v->iov_base = "\n"; v->iov_len = 1; } /* * Prior to doing the write, see if we are in * an error condition. */ switch (f->f_status) { case S_OK: default: break; case S_NOSPC: /* * If we are in a low disk space situation, * check to see if there is any free space * available on the partition. There has * to be at least FREEDISK bytes available * to continue. */ if (chkdiskspace(f)) { char nbuf[MAXFNAME + 32]; f->f_file = cap_open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_CREAT, 0644); if (f->f_file < 0) { f->f_type = F_UNUSED; logerror(f->f_un.f_fname); } else { sprintf(nbuf, "%s: logging reenabled", f->f_un.f_fname); f->f_status = S_OK; errno = 0; logerror(nbuf); } } break; } /* * Check the status again. If it's not S_OK, * we're going to skip and go on. */ if (f->f_status != S_OK) { dprintf("\n"); break; /* end of case */ } #ifdef DUMMY_NOSPC spc = forcediskspace(f); #else /* DUMMY_NOSPC */ spc = 1; #endif /* DUMMY_NOSPC */ /* * Otherwise, attempt to write out the log data */ #ifdef DUMMY_NOSPC if (spc) { spc = (writev(f->f_file, iov, 7) >= 0); } else { errno = ENOSPC; } if (!spc) { #else /* DUMMY_NOSPC */ if (writev(f->f_file, iov, 7 ) < 0) { #endif /* DUMMY_NOSPC */ int e = errno; (void) close(f->f_file); f->f_file = -1; /* * Check for EIO on TTY's due to vhangup() XXX */ if (e == EIO && f->f_type != F_FILE) { f->f_file = cap_open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_CREAT, 0644); if (f->f_file < 0) { f->f_type = F_UNUSED; logerror(f->f_un.f_fname); } } else if (e == ENOSPC && f->f_type == F_FILE) { /* * Set the type to disk full */ f->f_status = S_NOSPC; errno = e; logerror(f->f_un.f_fname); } else { f->f_type = F_UNUSED; errno = e; logerror(f->f_un.f_fname); } } else if (flags & SYNC_FILE) (void) fsync(f->f_file); if (f->f_type == F_CONSOLE || f->f_type == F_DOCONS) { close(f->f_file); f->f_file = -1; } break; case F_USERS: case F_WALL: dprintf("\n"); v->iov_base = "\r\n"; v->iov_len = 2; wallmsg(f, iov); break; } if (f->f_filter) { v[-1].iov_base = msgbase; v[-1].iov_len = msglen; } } (void) sigsetmask(omask); } static int ftimeout; /* if 1, filter didn't respond in time */ static void filter_timeout() { ftimeout = 1; dprintf("filter timeout\n"); } filtermsg(filter, msg, len, newmsg, newlen,facility, priority, fromstr) char *filter; char *msg; int len; char *newmsg; int *newlen; /* in/out parameter */ int facility; int priority; char *fromstr; { int ip[2], op[2]; int pid, n, wpid; union wait status; char *whyfail; char msgbuf[128]; SIG_PF oldreap; SIG_PF oldalarm; int omask; struct itimerval it, oit; #ifdef SSS_SUPPORT static int fork_restart_time = 0; #else static fork_restart_time = 0; #endif /* * If a previous fork attempt failed due to EAGAIN, wait for the * timeout period to expire before trying to run a filter again. * This way we don't flood SYSLOG with messages about syslogd * not being able to fork. Just return the message unfiltered. */ if (fork_restart_time) if (fork_restart_time > time(NULL)) { strncpy(newmsg, msg, *newlen-1); *newlen = strlen(newmsg); return 1; } else fork_restart_time = 0; /* * Don't let reapchild() reap 'em -- we want to get the exit status. */ oldreap = signal(SIGCHLD, SIG_DFL); timerclear(&it.it_interval); timerclear(&it.it_value); (void) setitimer(ITIMER_REAL, &it, &oit); oldalarm = signal(SIGALRM, filter_timeout); /* Enable SIGALRM */ omask = sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); /* * Create two pipes, fork, and run the filter. */ ip[0] = ip[1] = op[0] = op[1] = -1; if (pipe(ip) < 0 || pipe(op) < 0) goto sysfail; pid = fork(); if (pid < 0) goto sysfail; if (pid == 0) { char envstr[128]; int i; for ( i = 0; FacNames[i].c_name; i++ ) if ((FacNames[i].c_val >> 3) == facility) break; if (FacNames[i].c_name) sprintf(envstr, "FACILITY=%s", FacNames[i].c_name); else sprintf(envstr, "FACILITY=%d", facility); putenv(strdup(envstr)); for ( i = 0; PriNames[i].c_name; i++ ) if (PriNames[i].c_val == priority) break; if (PriNames[i].c_name) sprintf(envstr, "PRIORITY=%s", PriNames[i].c_name); else sprintf(envstr, "PRIORITY=%d", priority); putenv(strdup(envstr)); sprintf(envstr, "FROM=%s", fromstr); putenv(strdup(envstr)); (void) close(ip[1]); (void) close(op[0]); dup2(ip[0], 0); dup2(op[1], 1); dup2(op[1], 2); setpgrp(); /* so we can kill entire process group if * process is too slow. */ for (n = getdtablehi(); --n > 2; ) (void) close(n); execlp(filter, filter, 0); exit(-1); } dprintf("filter: child %d\n", pid); /* Parent writes msg to ip, and waits up to 8 seconds for new msg */ if (write(ip[1], msg, len) < 0) goto sysfail; (void) close(ip[1]); (void) close(op[1]); /* close write ends */ /* If filter exits without writing anything into the pipe, that * means that the filter didn't want this particular message * logged. (If the filter is 'bad', or hung up, then the alarm * will go off, and we'll get back -1). */ ftimeout = 0; alarm(8); n = read(op[0], newmsg, *newlen); if (n < 0) { if (ftimeout) whyfail = "too slow"; else whyfail = strerror(errno); /* Don't go to fail or sysfail yet, still need to do the wait */ } /* * Child should have always started by this point, since the * read will block until the alarm expires or the filter completes. */ ftimeout = 0; alarm(2); wpid = waitpid(pid, (int *)&status, 0); alarm(0); if (n < 0) goto fail; else if (wpid == -1) { whyfail = msgbuf; if (ftimeout) { strcpy(whyfail, "filter took too long to exit"); kill(-pid, SIGKILL); /* kill entire process group */ sleep(1); reapchild(); } else sprintf(whyfail, "wait for filter failed: %s", strerror(errno)); goto fail; } else if (status.w_retcode) { whyfail = msgbuf; sprintf(whyfail, "exit status 0x%x", status.w_retcode); goto fail; } else if (status.w_termsig) { whyfail = msgbuf; sprintf(whyfail, "killed by signal %d", status.w_termsig); goto fail; } newmsg[n] = '\0'; *newlen = n; goto out; sysfail: if (errno == EAGAIN) fork_restart_time = time(NULL) + FORK_TIMEOUT; whyfail = strerror(errno); fail: *newlen = sprintf(newmsg, "%s [filter %s failed: %s]", msg, filter, whyfail); n = 1; /* we have something to log */ out: (void) close(ip[0]); (void) close(ip[1]); (void) close(op[0]); (void) close(op[1]); (void) signal(SIGALRM, oldalarm); (void) setitimer(ITIMER_REAL, &oit, NULL); (void) signal(SIGCHLD, oldreap); (void) sigsetmask(omask); return n; } /* * WALLMSG -- Write a message to the world at large * * Write the specified message to either the entire * world, or a list of approved users. */ void wallmsg(f, iov) register struct filed *f; struct iovec *iov; { register char *p; register int i; int ttyf, len; FILE *uf; static int reenter = 0; register struct utmp *ut; time_t now; char greetings[200]; int pid; if (reenter++) return; (void) time(&now); (void) sprintf(greetings, "\r\n\7Message from syslogd@%s at %.24s ...\r\n", iov[2].iov_base, ctime(&now)); len = strlen(greetings); /* scan the (automatically opened) user login file */ while (ut = getutent()) { /* is this slot used? */ if (ut->ut_name[0] == '\0') continue; if (ut->ut_type != USER_PROCESS) continue; /* * Don't allow someone to send to other than /dev devices * (covers a security hole if ut_line is a filename). */ if (index(ut->ut_line, '/') != NULL) continue; /* should we send the message to this user? */ if (f->f_type == F_USERS) { for (i = 0; i < MAXUNAMES; i++) { if (!f->f_un.f_uname[i][0]) { i = MAXUNAMES; break; } if (strncmp(f->f_un.f_uname[i], ut->ut_name, UNAMESZ) == 0) break; } if (i >= MAXUNAMES) continue; } /* compute the device name */ p = "/dev/12345678"; strcpyn(&p[5], ut->ut_line, UNAMESZ); /* * Might as well fork instead of using nonblocking I/O * and doing notty(). */ if ((pid = fork()) == 0) { if (f->f_type == F_WALL) { iov[0].iov_base = greetings; iov[0].iov_len = len; iov[1].iov_len = 0; } (void) sigsetmask(0); (void) signal(SIGALRM, SIG_DFL); (void) alarm(30); /* open the terminal */ ttyf = cap_open(p, O_WRONLY); if (ttyf >= 0) (void) writev(ttyf, iov, 6); exit(0); } dprintf("wallmsg: child %d\n", pid); /* avoid having them all pile up at once */ sleep(1); } /* close the user login file */ (void) endutent(); reenter = 0; } void reapchild() { union wait status; int pid; while ((pid=wait3((int *)&status, WNOHANG, (struct rusage *) NULL)) > 0) dprintf("reaped %d\n", pid); } /* * Return a printable representation of a host address. */ char * cvthname(f) struct sockaddr_in *f; { struct hostent *hp; register char *p; extern char *inet_ntoa(); dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); if (f->sin_family != AF_INET) { dprintf("Malformed from address\n"); return ("???"); } hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); if (hp == 0) { dprintf("Host name for your address (%s) unknown\n", inet_ntoa(f->sin_addr)); return (inet_ntoa(f->sin_addr)); } if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) *p = '\0'; return (hp->h_name); } void domark() { need_domark = 0; dprintf("domark\n"); if ((++MarkSeq % MARKCOUNT) == 0) #ifdef SSS_SUPPORT logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK, 0); #else logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); #endif else flushmsg(); alarm(MarkInterval * 60 / MARKCOUNT); } void flushmsg() { if (PrevCount == 0) return; if (PrevCount > 1) (void) sprintf(PrevLine+16, "last message repeated %d times", PrevCount); PrevCount = 0; #ifdef SSS_SUPPORT logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY, 0); #else logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY); #endif PrevLine[0] = '\0'; } /* * Print syslogd errors some place. */ void logerror(type) char *type; { char buf[MAXFNAME + 80]; int mask = LOG_SYSLOG; switch (errno) { case 0: (void) sprintf(buf, "syslogd: %s", type); mask |= LOG_ERR; break; case ENOSPC: (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno)); mask |= LOG_ALERT; break; default: (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno)); mask |= LOG_ERR; break; } dprintf("%s\n", buf); #ifdef SSS_SUPPORT logmsg(mask, buf, LocalHostName, ADDDATE, 0); #else logmsg(mask, buf, LocalHostName, ADDDATE); #endif } void die(sig) { char buf[100]; if (sig) { dprintf("syslogd: going down on signal %d\n", sig); flushmsg(); (void) sprintf(buf, "going down on signal %d", sig); logerror(buf); } exit(0); } /* * INIT -- Initialize syslogd from configuration table */ void init(void) { register int i; register FILE *cf; register struct filed *f; register char *p; char cline[MAXLINE], cbuffer[MAXLINE]; int omask; int restarting; /* Can be restarting or rebinding (name lookup) */ restarting = (need_init || !Initialized) ? 1 : 0; need_init = 0; dprintf("init\n"); omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); /* flush any pending output */ flushmsg(); /* * Close all open log files. */ for (f = Files; f < &Files[NLOGS]; f++) { if (f->f_filter) { free(f->f_filter); f->f_filter = NULL; } if (f->f_type == F_FILE || f->f_type == F_TTY #ifdef SSS_SUPPORT || f->f_type == F_FORW || f->f_type == F_UNIXSOCK) #else || f->f_type == F_FORW) #endif (void) close(f->f_file); f->f_type = F_UNUSED; } /* open the configuration file */ if ((cf = fopen(ConfFile, "r")) == NULL) { dprintf("cannot open %s\n", ConfFile); cfline("*.ERR\t/dev/console", &Files[0]); cfline("*.PANIC\t*", &Files[1]); #ifdef SSS_SUPPORT cfline("*.DEBUG\t@@/tmp/.eventmond.events.sock", &Files[2]); #endif (void) sigsetmask(omask); return; } setbuffer(cf, cbuffer, sizeof cbuffer); /* * Foreach line in the conf table, open that file. */ redo_host_lookup = 0; f = Files; while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) { /* check for end-of-section */ if (cline[0] == '\n' || cline[0] == '#') continue; /* strip off trailing whitespace & newline character */ p = index(cline, '\n'); if (p) do *p-- = '\0'; while (p >= cline && isspace(*p)); cfline(cline, f++); } if( f < &Files[NLOGS]) { /* special dummy entry for lfmt -c */ cfline("*.DEBUG\t/dev/console", f); f->f_type = F_DOCONS; } else dprintf("More than %d configuration lines in config file, rest ignored\n", NLOGS); /* close the configuration file */ (void) fclose(cf); Initialized = 1; if (Debug) { for (f = Files; f < &Files[NLOGS]; f++) { for (i = 0; i <= LOG_NFACILITIES; i++) if (f->f_pmask[i] == NOPRI) printf("X "); else printf("%d ", f->f_pmask[i]); printf("(%d) ", f->f_file); printf("%s: ", TypeNames[f->f_type]); switch (f->f_type) { case F_FILE: case F_TTY: case F_CONSOLE: printf("'%s'", f->f_un.f_fname); break; case F_FORW: printf("'%s'", f->f_un.f_forw.f_hname); break; case F_USERS: for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) printf("'%s', ", f->f_un.f_uname[i]); break; } if (f->f_filter) printf(" '%s'\n", f->f_filter); printf("\n"); } } (void) sigsetmask(omask); if (0 == restarting) return; #ifdef SSS_SUPPORT logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE, 0); #else logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); #endif dprintf("syslogd: restarted\n"); } void cfline(line, f) char *line; register struct filed *f; { register char *p; register char *q; register int i; char *bp; int pri; struct hostent *hp; char buf[MAXLINE]; dprintf("cfline(%s)\n", line); errno = 0; /* keep sys_errlist stuff out of logerror messages */ /* clear out file entry */ bzero((char *) f, sizeof *f); for (i = 0; i <= LOG_NFACILITIES; i++) f->f_pmask[i] = NOPRI; if (isspace(*line)) { /* leading whitespace is not permitted */ logerror("invalid line: leading whitespace is not permitted"); return; } /* scan through the list of selectors */ for (p = line; *p && *p != '\t';) { /* find the end of this facility name list */ for (q = p; *q && *q != '\t' && *q++ != '.'; ) continue; /* collect priority name */ for (bp = buf; *q && !index("\t,;", *q); ) *bp++ = *q++; *bp = '\0'; /* skip cruft */ while (index(", ;", *q)) q++; /* decode priority name */ pri = decode(buf, PriNames); if (pri < 0) { char xbuf[200]; (void) sprintf(xbuf, "unknown priority name \"%s\"", buf); logerror(xbuf); return; } /* scan facilities */ while (*p && !index("\t.;", *p)) { int i; for (bp = buf; *p && !index("\t,;.", *p); ) *bp++ = *p++; *bp = '\0'; if (*buf == '*') for (i = 0; i < LOG_NFACILITIES; i++) f->f_pmask[i] = pri; else { i = decode(buf, FacNames); if (i < 0) { char xbuf[200]; (void) sprintf(xbuf, "unknown facility name \"%s\"", buf); logerror(xbuf); return; } f->f_pmask[i >> 3] = pri; } while (*p == ',' || *p == ' ') p++; } p = q; } get_action: /* skip to action part */ while (isspace(*p)) p++; switch (*p) { case '@': #ifdef SSS_SUPPORT if(*(p+1) == '@') { p++; bzero((char *)&f->fus_su,sizeof(f->fus_su)); (void) strncpy(f->fus_su.sun_path, ++p, sizeof(f->fus_su.sun_path)-1); f->fus_su.sun_family = AF_UNIX; f->f_file = socket(AF_UNIX, SOCK_DGRAM, 0); if (f->f_file < 0) { logerror("Can't create UNIX socket"); break; } f->fus_sal = strlen(f->fus_su.sun_path)+sizeof(f->fus_su.sun_family); f->f_type = F_UNIXSOCK; break; } #endif if (!InetInuse) break; (void) strncpy(f->f_un.f_forw.f_hname, ++p, sizeof(f->f_un.f_forw.f_hname)-1); hp = gethostbyname(p); if (hp == NULL) { char buf[200]; (void) sprintf(buf, "can't forward to '%s': %s", p, hstrerror(h_errno)); errno = 0; logerror(buf); redo_host_lookup = 1; break; } bzero((char *) &f->f_un.f_forw.f_addr, sizeof f->f_un.f_forw.f_addr); f->f_un.f_forw.f_addr.sin_family = AF_INET; f->f_un.f_forw.f_addr.sin_port = LogPort; bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length); f->f_file = socket(AF_INET, SOCK_DGRAM, 0); if (f->f_file < 0) { logerror("socket"); break; } f->f_type = F_FORW; f->f_un.f_forw.f_nfail1 = 0; f->f_un.f_forw.f_nfail2 = 0; f->f_un.f_forw.f_till = 0; f->f_un.f_forw.f_nmissed = 0; break; case '/': (void) strncpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)-1); if ((f->f_file = cap_open(p, O_WRONLY|O_APPEND|O_CREAT,0644)) < 0) { f->f_file = F_UNUSED; logerror(p); break; } if (isatty(f->f_file)) { f->f_type = F_TTY; untty(); } else f->f_type = F_FILE; if (strcmp(p, ctty) == 0) close(f->f_file), /* keep closed between writes */ f->f_file = -1, f->f_type = F_CONSOLE; break; case '|': if (f->f_filter) { /* catch multiple filters */ errno = EINVAL; logerror(p); break; } /* skip white space between | and program name */ do { p++; } while (isspace(*p)); /* find end of program */ for (q = p; !isspace(*q); q++) continue; *q = '\0'; f->f_filter = strdup(p); if (f->f_filter == NULL) { logerror(p); break; } p = q+1; goto get_action; case '*': f->f_type = F_WALL; break; case '\0': if (f->f_filter) { /* no action for filter process */ char buf[100]; errno = EINVAL; (void) sprintf(buf, "%s ", f->f_filter); logerror(buf); free(f->f_filter); f->f_filter = NULL; } break; /* leave f->f_type set to F_UNUSED */ default: for (i = 0; i < MAXUNAMES && *p; i++) { for (q = p; *q && *q != ','; ) q++; (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ); if ((q - p) > UNAMESZ) f->f_un.f_uname[i][UNAMESZ] = '\0'; else f->f_un.f_uname[i][q - p] = '\0'; while (*q == ',' || isspace(*q)) q++; p = q; } f->f_type = F_USERS; break; } } /* * Decode a symbolic name to a numeric value */ decode(name, codetab) char *name; struct code *codetab; { register struct code *c; register char *p; char buf[40]; if (isdigit(*name)) return (atoi(name)); (void) strncpy(buf, name, sizeof(buf)-1); for (p = buf; *p; p++) if (isupper(*p)) *p = tolower(*p); for (c = codetab; c->c_name; c++) if (!strcmp(buf, c->c_name)) return (c->c_val); return (-1); } void opendevlog() { struct strioctl strio; flog = open(_PATH_LOG, O_RDWR); if (flog < 0) { logerror("open of " _PATH_LOG); die(0); } strio.ic_cmd = I_CONSLOG; strio.ic_timout = 0; strio.ic_len = 0; strio.ic_dp = 0; if (ioctl(flog,I_STR,&strio) < 0) logerror("set I_CONSLOG"); } /* * Return 1 if there is more than FREEDISK bytes available on the disk * partition represented by the 'filed', 0 otherwise. */ int chkdiskspace(struct filed *f) { #ifdef DUMMY_NOSPC if (!forcediskspace(f)) return 0; #else /* DUMMY_NOSPC */ struct statvfs64 s; __int64_t sz; int bsize; if (statvfs64(f->f_un.f_fname, &s) < 0) { return 0; } /* * Compute the size */ bsize = s.f_frsize ? s.f_frsize : s.f_bsize; sz = s.f_bfree * bsize; if (sz >= FREEDISK) return 1; else return 0; #endif /* DUMMY_NOSPC */ } #ifdef DUMMY_NOSPC /* * Decide if we're forcing a disk no space error. */ int forcediskspace(struct filed *f) { char buf[MAXFNAME + 32]; struct stat st; sprintf(buf, "/tmp%s", f->f_un.f_fname); if (stat(buf, &st) < 0) return 1; else return 0; } #endif /* DUMMY_NOSPC */