bool keyboard_immediate(bool echo, void (* character_taker)(char)) { termios buf; if (tcgetattr(0, &saved_termios)<0) return false; buf=saved_termios; buf.c_lflag &= ~ICANON; if (!echo) buf.c_lflag &= ~ECHO; buf.c_cc[VMIN]=1; buf.c_cc[VTIME]=0; if (tcsetattr(0, TCSAFLUSH, &buf)<0) return false; character_handler = character_taker; if (!atexitted) { atexit(tty_atexit); atexitted=true; } odd_keyboard=true; signal(SIGIO, sigio); int pid=getpid(); int flags=fcntl(0, F_GETFL, 0); fcntl(0, F_SETFL, flags | O_ASYNC | O_NONBLOCK); fcntl(0, F_SETOWN, pid); if (oldstdout==NULL) oldstdout=stdout; stdout=fwopen(NULL, stdwrite); return true; }
main() { run("-", stdout); run("funopen", funopen((void *)5, do_read, &do_write, do_seek, do_close)); run("fropen", fropen(NULL, do_read)); run("fwopen", fwopen(NULL, do_write)); }
void doformat(struct output *dest, const char *f, va_list ap) { FILE *fp; if ((fp = fwopen(dest, doformat_wr)) != NULL) { vfprintf(fp, f, ap); fclose(fp); } }
static void vsyslog1(int pri, const char *fmt, va_list ap) { struct timeval now; struct tm tm; char ch, *p; long tz_offset; int cnt, fd, saved_errno; char hostname[MAXHOSTNAMELEN], *stdp, tbuf[2048], fmt_cpy[1024], errstr[64], tz_sign; FILE *fp, *fmt_fp; struct bufcookie tbuf_cookie; struct bufcookie fmt_cookie; #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); pri &= LOG_PRIMASK|LOG_FACMASK; } saved_errno = errno; /* Check priority against setlogmask values. */ if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) return; /* Set default facility if none specified. */ if ((pri & LOG_FACMASK) == 0) pri |= LogFacility; /* Create the primary stdio hook */ tbuf_cookie.base = tbuf; tbuf_cookie.left = sizeof(tbuf); fp = fwopen(&tbuf_cookie, writehook); if (fp == NULL) return; /* Build the message according to RFC 5424. Tag and version. */ (void)fprintf(fp, "<%d>1 ", pri); /* Timestamp similar to RFC 3339. */ if (gettimeofday(&now, NULL) == 0 && localtime_r(&now.tv_sec, &tm) != NULL) { if (tm.tm_gmtoff < 0) { tz_sign = '-'; tz_offset = -tm.tm_gmtoff; } else { tz_sign = '+'; tz_offset = tm.tm_gmtoff; } (void)fprintf(fp, "%04d-%02d-%02d" /* Date. */ "T%02d:%02d:%02d.%06ld" /* Time. */ "%c%02ld:%02ld ", /* Time zone offset. */ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, now.tv_usec, tz_sign, tz_offset / 3600, (tz_offset % 3600) / 60); } else (void)fprintf(fp, "- "); /* Hostname. */ (void)gethostname(hostname, sizeof(hostname)); (void)fprintf(fp, "%s ", hostname); if (LogStat & LOG_PERROR) { /* Transfer to string buffer */ (void)fflush(fp); stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left); } /* * Application name, process ID, message ID and structured data. * Provide the process ID regardless of whether LOG_PID has been * specified, as it provides valuable information. Many * applications tend not to use this, even though they should. */ if (LogTag == NULL) LogTag = _getprogname(); (void)fprintf(fp, "%s %d - - ", LogTag == NULL ? "-" : LogTag, getpid()); /* Check to see if we can skip expanding the %m */ if (strstr(fmt, "%m")) { /* Create the second stdio hook */ fmt_cookie.base = fmt_cpy; fmt_cookie.left = sizeof(fmt_cpy) - 1; fmt_fp = fwopen(&fmt_cookie, writehook); if (fmt_fp == NULL) { fclose(fp); return; } /* * Substitute error message for %m. Be careful not to * molest an escaped percent "%%m". We want to pass it * on untouched as the format is later parsed by vfprintf. */ for ( ; (ch = *fmt); ++fmt) { if (ch == '%' && fmt[1] == 'm') { ++fmt; strerror_r(saved_errno, errstr, sizeof(errstr)); fputs(errstr, fmt_fp); } else if (ch == '%' && fmt[1] == '%') { ++fmt; fputc(ch, fmt_fp); fputc(ch, fmt_fp); } else { fputc(ch, fmt_fp); } } /* Null terminate if room */ fputc(0, fmt_fp); fclose(fmt_fp); /* Guarantee null termination */ fmt_cpy[sizeof(fmt_cpy) - 1] = '\0'; fmt = fmt_cpy; } (void)vfprintf(fp, fmt, ap); (void)fclose(fp); cnt = sizeof(tbuf) - tbuf_cookie.left; /* Remove a trailing newline */ if (tbuf[cnt - 1] == '\n') cnt--; /* Output to stderr if requested. */ if (LogStat & LOG_PERROR) { struct iovec iov[2]; struct iovec *v = iov; v->iov_base = stdp; v->iov_len = cnt - (stdp - tbuf); ++v; v->iov_base = "\n"; v->iov_len = 1; (void)_writev(STDERR_FILENO, iov, 2); } /* Get connected, output the message to the local logger. */ if (!opened) openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); connectlog(); /* * If the send() fails, there are two likely scenarios: * 1) syslogd was restarted * 2) /var/run/log is out of socket buffer space, which * in most cases means local DoS. * If the error does not indicate a full buffer, we address * case #1 by attempting to reconnect to /var/run/log[priv] * and resending the message once. * * If we are working with a privileged socket, the retry * attempts end there, because we don't want to freeze a * critical application like su(1) or sshd(8). * * Otherwise, we address case #2 by repeatedly retrying the * send() to give syslogd a chance to empty its socket buffer. */ if (send(LogFile, tbuf, cnt, 0) < 0) { if (errno != ENOBUFS) { /* * Scenario 1: syslogd was restarted * reconnect and resend once */ disconnectlog(); connectlog(); if (send(LogFile, tbuf, cnt, 0) >= 0) return; /* * if the resend failed, fall through to * possible scenario 2 */ } while (errno == ENOBUFS) { /* * Scenario 2: out of socket buffer space * possible DoS, fail fast on a privileged * socket */ if (status == CONNPRIV) break; _usleep(1); if (send(LogFile, tbuf, cnt, 0) >= 0) return; } } else return; /* * Output the message to the console; try not to block * as a blocking console should not stop other processes. * Make sure the error reported is the one from the syslogd failure. */ if (LogStat & LOG_CONS && (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >= 0) { struct iovec iov[2]; struct iovec *v = iov; p = strchr(tbuf, '>') + 3; v->iov_base = p; v->iov_len = cnt - (p - tbuf); ++v; v->iov_base = "\r\n"; v->iov_len = 2; (void)_writev(fd, iov, 2); (void)_close(fd); } }
void vsyslog(int pri, const char *fmt, va_list ap) { int cnt; char ch, *p; time_t now; int fd, saved_errno; char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26], errstr[64]; FILE *fp, *fmt_fp; struct bufcookie tbuf_cookie; struct bufcookie fmt_cookie; #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); pri &= LOG_PRIMASK|LOG_FACMASK; } saved_errno = errno; THREAD_LOCK(); /* Check priority against setlogmask values. */ if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) { THREAD_UNLOCK(); return; } /* Set default facility if none specified. */ if ((pri & LOG_FACMASK) == 0) pri |= LogFacility; /* Create the primary stdio hook */ tbuf_cookie.base = tbuf; tbuf_cookie.left = sizeof(tbuf); fp = fwopen(&tbuf_cookie, writehook); if (fp == NULL) { THREAD_UNLOCK(); return; } /* Build the message. */ (void)time(&now); (void)fprintf(fp, "<%d>", pri); (void)fprintf(fp, "%.15s ", ctime_r(&now, timbuf) + 4); if (LogStat & LOG_PERROR) { /* Transfer to string buffer */ (void)fflush(fp); stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left); } if (LogTag == NULL) LogTag = _getprogname(); if (LogTag != NULL) (void)fprintf(fp, "%s", LogTag); if (LogStat & LOG_PID) (void)fprintf(fp, "[%d]", getpid()); if (LogTag != NULL) { (void)fprintf(fp, ": "); } /* Check to see if we can skip expanding the %m */ if (strstr(fmt, "%m")) { /* Create the second stdio hook */ fmt_cookie.base = fmt_cpy; fmt_cookie.left = sizeof(fmt_cpy) - 1; fmt_fp = fwopen(&fmt_cookie, writehook); if (fmt_fp == NULL) { fclose(fp); THREAD_UNLOCK(); return; } /* * Substitute error message for %m. Be careful not to * molest an escaped percent "%%m". We want to pass it * on untouched as the format is later parsed by vfprintf. */ for ( ; (ch = *fmt); ++fmt) { if (ch == '%' && fmt[1] == 'm') { ++fmt; strerror_r(saved_errno, errstr, sizeof(errstr)); fputs(errstr, fmt_fp); } else if (ch == '%' && fmt[1] == '%') { ++fmt; fputc(ch, fmt_fp); fputc(ch, fmt_fp); } else { fputc(ch, fmt_fp); } } /* Null terminate if room */ fputc(0, fmt_fp); fclose(fmt_fp); /* Guarantee null termination */ fmt_cpy[sizeof(fmt_cpy) - 1] = '\0'; fmt = fmt_cpy; } (void)vfprintf(fp, fmt, ap); (void)fclose(fp); cnt = sizeof(tbuf) - tbuf_cookie.left; /* Remove a trailing newline */ if (tbuf[cnt - 1] == '\n') cnt--; /* Output to stderr if requested. */ if (LogStat & LOG_PERROR) { struct iovec iov[2]; struct iovec *v = iov; v->iov_base = stdp; v->iov_len = cnt - (stdp - tbuf); ++v; v->iov_base = "\n"; v->iov_len = 1; (void)_writev(STDERR_FILENO, iov, 2); } /* Get connected, output the message to the local logger. */ if (!opened) openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); connectlog(); /* * If the send() failed, there are two likely scenarios: * 1) syslogd was restarted * 2) /var/run/log is out of socket buffer space, which * in most cases means local DoS. * We attempt to reconnect to /var/run/log to take care of * case #1 and keep send()ing data to cover case #2 * to give syslogd a chance to empty its socket buffer. * * If we are working with a priveleged socket, then take * only one attempt, because we don't want to freeze a * critical application like su(1) or sshd(8). * */ if (send(LogFile, tbuf, cnt, 0) < 0) { if (errno != ENOBUFS) { disconnectlog(); connectlog(); } do { _usleep(1); if (send(LogFile, tbuf, cnt, 0) >= 0) { THREAD_UNLOCK(); return; } if (status == CONNPRIV) break; } while (errno == ENOBUFS); } else { THREAD_UNLOCK(); return; } /* * Output the message to the console; try not to block * as a blocking console should not stop other processes. * Make sure the error reported is the one from the syslogd failure. */ if (LogStat & LOG_CONS && (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) { struct iovec iov[2]; struct iovec *v = iov; p = strchr(tbuf, '>') + 1; v->iov_base = p; v->iov_len = cnt - (p - tbuf); ++v; v->iov_base = "\r\n"; v->iov_len = 2; (void)_writev(fd, iov, 2); (void)_close(fd); } THREAD_UNLOCK(); }