/* $Id: aerr.C,v 1.4 2001/08/01 02:04:50 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "async.h" #include static suio *erruio = New suio; static void _err_output_async (suio *, int); static void _err_reset_async () { erruio->clear (); fdcb (errfd, selwrite, NULL); } void err_init () { int flags; erruio->clear (); if ((flags = fcntl (errfd, F_GETFL, 0)) != -1) fcntl (errfd, F_SETFL, flags|O_APPEND); _err_output = _err_output_async; _err_reset_hook = _err_reset_async; } void err_flush () { if (_err_output != _err_output_async) return; make_sync (errfd); erruio->output (errfd); } static void err_wcb () { int n; int cnt; if (!erruio->resid () || _err_output != _err_output_async) { fdcb (errfd, selwrite, NULL); return; } /* Try to write whole lines at a time. */ for (cnt = min (erruio->iovcnt (), (size_t) UIO_MAXIOV); cnt > 0 && (erruio->iov ()[cnt-1].iov_len == 0 || *((char *) erruio->iov ()[cnt-1].iov_base + erruio->iov ()[cnt-1].iov_len - 1) != '\n'); cnt--) ; if (!cnt) { if (erruio->iovcnt () < UIO_MAXIOV) { /* Wait for a carriage return */ fdcb (errfd, selwrite, NULL); return; } else cnt = -1; } /* Write asynchronously, but keep stderr synchronous in case of * emergency (e.g. maybe assert wants to fprintf to stderr). */ if (globaldestruction) n = erruio->output (errfd, cnt); else { _make_async (errfd); n = erruio->output (errfd, cnt); make_sync (errfd); } if (n < 0) err_reset (); if (erruio->resid () && !globaldestruction) fdcb (errfd, selwrite, wrap (err_wcb)); else fdcb (errfd, selwrite, NULL); } void _err_output_async (suio *uio, int flags) { int saved_errno = errno; if (flags & warnobj::panicflag) { make_sync (errfd); uio->output (errfd); abort (); } /* Start new iovecs after newlines so as to output entire lines when * possible. */ if (erruio->resid ()) { const iovec *iovp = erruio->iov () + erruio->iovcnt () - 1; if (((char *) iovp->iov_base)[iovp->iov_len - 1] == '\n') erruio->breakiov (); } erruio->copyu (uio); if (flags & warnobj::fatalflag) { err_flush (); exit (1); } err_wcb (); errno = saved_errno; } EXITFN (exitflush); static void exitflush () { if (_err_output != _err_output_async) { err_flush (); err_reset (); } }