/* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Modified Sun Mar 12 10:39:22 1995, faith@cs.unc.edu for Linux * */ /* 1999-02-22 Arkadiusz Miƛkiewicz * - added Native Language Support * Sun Mar 21 1999 - Arnaldo Carvalho de Melo * - fixed strerr(errno) in gettext calls */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nls.h" #include "closestream.h" #include "pathnames.h" #include "ttymsg.h" #define ERR_BUFLEN (MAXNAMLEN + 1024) /* * Display the contents of a uio structure on a terminal. Used by wall(1), * syslogd(8), and talkd(8). Forks and finishes in child if write would block, * waiting up to tmout seconds. Returns pointer to error string on unexpected * error; string is not newline-terminated. Various "normal" errors are * ignored (exclusive-use, lack of permission, etc.). */ char * ttymsg(struct iovec *iov, size_t iovcnt, char *line, int tmout) { static char device[MAXNAMLEN]; static char errbuf[ERR_BUFLEN]; size_t cnt, left; ssize_t wret; struct iovec localiov[6]; int fd, forked = 0; ssize_t len = 0; if (iovcnt > ARRAY_SIZE(localiov)) { snprintf(errbuf, sizeof(errbuf), _("internal error: too many iov's")); return errbuf; } /* The old code here rejected the line argument when it contained a '/', saying: "A slash may be an attempt to break security...". However, if a user can control the line argument here then he can make this routine write to /dev/hda or /dev/sda already. So, this test was worthless, and these days it is also wrong since people use /dev/pts/xxx. */ len = snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line); if (len < 0 || (size_t)len >= sizeof(device)) { snprintf(errbuf, sizeof(errbuf), _("excessively long line arg")); return errbuf; } /* * open will fail on slip lines or exclusive-use lines * if not running as root; not an error. */ if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { if (errno == EBUSY || errno == EACCES) return NULL; len = snprintf(errbuf, sizeof(errbuf), "%s: %m", device); if (len < 0 || (size_t)len >= sizeof(errbuf)) snprintf(errbuf, sizeof(errbuf), _("open failed")); return errbuf; } for (cnt = left = 0; cnt < iovcnt; ++cnt) left += iov[cnt].iov_len; for (;;) { wret = writev(fd, iov, iovcnt); if (wret >= (ssize_t) left) break; if (wret >= 0) { left -= wret; if (iov != localiov) { memmove(localiov, iov, iovcnt * sizeof(struct iovec)); iov = localiov; } for (cnt = 0; wret >= (ssize_t) iov->iov_len; ++cnt) { wret -= iov->iov_len; ++iov; --iovcnt; } if (wret) { iov->iov_base = (char *) iov->iov_base + wret; iov->iov_len -= wret; } continue; } if (errno == EWOULDBLOCK) { int cpid, flags; sigset_t sigmask; if (forked) { close(fd); _exit(EXIT_FAILURE); } cpid = fork(); if (cpid < 0) { len = snprintf(errbuf, sizeof(errbuf), _("fork: %m")); if (len < 0 || (size_t)len >= sizeof(errbuf)) snprintf(errbuf, sizeof(errbuf), _("cannot fork")); close(fd); return errbuf; } if (cpid) { /* parent */ close(fd); return NULL; } forked++; /* wait at most tmout seconds */ signal(SIGALRM, SIG_DFL); signal(SIGTERM, SIG_DFL); /* XXX */ sigemptyset(&sigmask); sigprocmask (SIG_SETMASK, &sigmask, NULL); alarm((u_int)tmout); flags = fcntl(fd, F_GETFL); fcntl(flags, F_SETFL, (long) (flags & ~O_NONBLOCK)); continue; } /* * We get ENODEV on a slip line if we're running as root, * and EIO if the line just went away. */ if (errno == ENODEV || errno == EIO) break; if (close_fd(fd) != 0) warn(_("write failed: %s"), device); if (forked) _exit(EXIT_FAILURE); len = snprintf(errbuf, sizeof(errbuf), "%s: %m", device); if (len < 0 || (size_t)len >= sizeof(errbuf)) snprintf(errbuf, sizeof(errbuf), _("%s: BAD ERROR, message is " "far too long"), device); return errbuf; } if (forked) _exit(EXIT_SUCCESS); return NULL; }