diff options
| author | jtc <jtc@NetBSD.org> | 1993-08-04 19:30:29 +0000 |
|---|---|---|
| committer | jtc <jtc@NetBSD.org> | 1993-08-04 19:30:29 +0000 |
| commit | 6964362f5bcd4e7b71ab23edd38df03e3a8eba20 (patch) | |
| tree | 95b2fe86c9d4bb344979cbb0523ae6bc41dccb4d /gnu | |
| parent | 7283ab9b15064eb3c97e3bb99c8f1aef16934d6b (diff) | |
Upgrade to Taylor UUCP 1.04
Diffstat (limited to 'gnu')
134 files changed, 33226 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/common_sources/chat.c b/gnu/libexec/uucp/common_sources/chat.c new file mode 100644 index 00000000000..86a68d9b945 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/chat.c @@ -0,0 +1,1429 @@ +/* chat.c + Chat routine for the UUCP package. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char chat_rcsid[] = "$Id: chat.c,v 1.1 1993/08/04 19:30:29 jtc Exp $"; +#endif + +#include <ctype.h> +#include <errno.h> + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "prot.h" +#include "system.h" + +/* Local functions. */ + +static int icexpect P((struct sconnection *qconn, int cstrings, + char **azstrings, size_t *aclens, + int ctimeout, boolean fstrip)); +static boolean fcsend P((struct sconnection *qconn, pointer puuconf, + const char *zsend, + const struct uuconf_system *qsys, + const struct uuconf_dialer *qdial, + const char *zphone, + boolean ftranslate, boolean fstrip)); +static boolean fcecho_send_strip P((struct sconnection *qconn, + const char *z, size_t clen)); +static boolean fcecho_send_nostrip P((struct sconnection *qconn, + const char *z, size_t clen)); +static boolean fcecho_send P((struct sconnection *qconn, const char *z, + size_t clen, boolean fstrip)); +static boolean fcphone P((struct sconnection *qconn, + pointer puuconf, + const struct uuconf_dialer *qdial, + const char *zphone, + boolean (*pfwrite) P((struct sconnection *qc, + const char *zwrite, + size_t cwrite)), + boolean ftranslate, boolean *pfquote)); +static boolean fctranslate P((pointer puuconf, const char *zphone, + const char **pzprefix, + const char **pzsuffix)); +static boolean fcprogram P((struct sconnection *qconn, pointer puuconf, + char **pzprogram, + const struct uuconf_system *qsys, + const struct uuconf_dialer *qdial, + const char *zphone, const char *zport, + long ibaud)); + +/* Run a chat script with the other system. The chat script is a + series of expect send pairs. We wait for the expect string to show + up, and then we send the send string. The chat string for a system + holds the expect and send strings separated by a single space. */ + +boolean +fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_chat *qchat; + const struct uuconf_system *qsys; + const struct uuconf_dialer *qdial; + const char *zphone; + boolean ftranslate; + const char *zport; + long ibaud; +{ + int cstrings; + char **azstrings; + size_t *aclens; + char **pzchat; + char *zbuf; + size_t cbuflen; + boolean fret; + int i; + + /* First run the program, if any. */ + if (qchat->uuconf_pzprogram != NULL) + { + if (! fcprogram (qconn, puuconf, qchat->uuconf_pzprogram, qsys, qdial, + zphone, zport, ibaud)) + return FALSE; + } + + /* If there's no chat script, we're done. */ + if (qchat->uuconf_pzchat == NULL) + return TRUE; + + if (qchat->uuconf_pzfail == NULL) + { + cstrings = 1; + azstrings = (char **) xmalloc (sizeof (char *)); + aclens = (size_t *) xmalloc (sizeof (size_t)); + } + else + { + char **pz; + + /* We leave string number 0 for the chat script. */ + cstrings = 1; + for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++) + ++cstrings; + + azstrings = (char **) xmalloc (cstrings * sizeof (char *)); + aclens = (size_t *) xmalloc (cstrings * sizeof (size_t)); + + /* Get the strings into the array, and handle all the escape + characters. */ + for (cstrings = 1, pz = qchat->uuconf_pzfail; + *pz != NULL; + cstrings++, pz++) + { + azstrings[cstrings] = zbufcpy (*pz); + aclens[cstrings] = cescape (azstrings[cstrings]); + } + } + + cbuflen = 0; + zbuf = NULL; + fret = TRUE; + + pzchat = qchat->uuconf_pzchat; + + while (*pzchat != NULL) + { + size_t clen; + + /* Loop over subexpects and subsends. */ + while (TRUE) + { + /* Copy the expect string into the buffer so that we can + modify it in cescape. */ + clen = strlen (*pzchat); + if (clen >= cbuflen) + { + ubuffree (zbuf); + zbuf = zbufalc (clen + 1); + cbuflen = clen; + } + memcpy (zbuf, *pzchat, clen + 1); + + azstrings[0] = zbuf; + if (azstrings[0][0] == '-') + ++azstrings[0]; + aclens[0] = cescape (azstrings[0]); + + if (aclens[0] == 0 + || (aclens[0] == 2 + && strcmp (azstrings[0], "\"\"") == 0)) + { + /* There is no subexpect sequence. If there is a + subsend sequence we move on to it. Otherwise we let + this expect succeed. This is somewhat inconsistent, + but it seems to be the traditional approach. */ + if (pzchat[1] == NULL || pzchat[1][0] != '-') + break; + } + else + { + int istr; + + istr = icexpect (qconn, cstrings, azstrings, aclens, + qchat->uuconf_ctimeout, + qchat->uuconf_fstrip); + + /* If we found the string, break out of the + subexpect/subsend loop. */ + if (istr == 0) + break; + + /* If we got an error, return FALSE. */ + if (istr < -1) + { + fret = FALSE; + break; + } + + /* If we found a failure string, log it and get out. */ + if (istr > 0) + { + ulog (LOG_ERROR, "Chat script failed: Got \"%s\"", + qchat->uuconf_pzfail[istr - 1]); + fret = FALSE; + break; + } + + /* We timed out; look for a send subsequence. If none, + the chat script has failed. */ + if (pzchat[1] == NULL || pzchat[1][0] != '-') + { + ulog (LOG_ERROR, "Timed out in chat script"); + fret = FALSE; + break; + } + } + + /* Send the send subsequence without the leading '-'. A + \"\" will send nothing. An empty string will send a + carriage return. */ + ++pzchat; + if (! fcsend (qconn, puuconf, *pzchat + 1, qsys, qdial, zphone, + ftranslate, qchat->uuconf_fstrip)) + { + fret = FALSE; + break; + } + + /* If there is no expect subsequence, we are done. */ + if (pzchat[1] == NULL || pzchat[1][0] != '-') + break; + + /* Move on to next expect subsequence. */ + ++pzchat; + } + + if (! fret) + break; + + /* Move on to the send string. If there is none, we have + succeeded. */ + do + { + ++pzchat; + } + while (*pzchat != NULL && (*pzchat)[0] == '-'); + + if (*pzchat == NULL) + break; + + if (**pzchat != '\0') + { + if (! fcsend (qconn, puuconf, *pzchat, qsys, qdial, zphone, + ftranslate, qchat->uuconf_fstrip)) + { + fret = FALSE; + break; + } + } + + ++pzchat; + } + + ubuffree (zbuf); + for (i = 1; i < cstrings; i++) + ubuffree (azstrings[i]); + xfree ((pointer) azstrings); + xfree ((pointer) aclens); + + return fret; +} + +/* Read characters and wait for one of a set of memory strings to come + in. This returns the index into the array of the string that + arrives, or -1 on timeout, or -2 on error. */ + +static int +icexpect (qconn, cstrings, azstrings, aclens, ctimeout, fstrip) + struct sconnection *qconn; + int cstrings; + char **azstrings; + size_t *aclens; + int ctimeout; + boolean fstrip; +{ + int i; + size_t cmax; + char *zhave; + size_t chave; + long iendtime; +#if DEBUG > 1 + int cchars; + int iolddebug; +#endif + + cmax = aclens[0]; + for (i = 1; i < cstrings; i++) + if (cmax < aclens[i]) + cmax = aclens[i]; + + zhave = zbufalc (cmax); + chave = 0; + + iendtime = ixsysdep_time ((long *) NULL) + ctimeout; + +#if DEBUG > 1 + cchars = 0; + iolddebug = iDebug; + if (FDEBUGGING (DEBUG_CHAT)) + { + udebug_buffer ("icexpect: Looking for", azstrings[0], + aclens[0]); + ulog (LOG_DEBUG_START, "icexpect: Got \""); + iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); + } +#endif + + while (TRUE) + { + int bchar; + + /* If we have no more time, get out. */ + if (ctimeout <= 0) + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + ulog (LOG_DEBUG_END, "\" (timed out)"); + iDebug = iolddebug; + } +#endif + ubuffree (zhave); + return -1; + } + + /* Read one character at a time. We could use a more complex + algorithm to read in larger batches, but it's probably not + worth it. If the buffer is full, shift it left; we already + know that no string matches, and the buffer holds the largest + string, so this can't lose a match. */ + if (chave >= cmax) + { + size_t imove; + + for (imove = 0; imove < cmax - 1; imove++) + zhave[imove] = zhave[imove + 1]; + --chave; + } + + /* The timeout/error return values from breceive_char are the + same as for this function. */ + bchar = breceive_char (qconn, ctimeout, TRUE); + if (bchar < 0) + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + /* If there was an error, it will probably be logged in + the middle of our string, but this is only debugging + so it's not a big deal. */ + ulog (LOG_DEBUG_END, "\" (%s)", + bchar == -1 ? "timed out" : "error"); + iDebug = iolddebug; + } +#endif + ubuffree (zhave); + return bchar; + } + + /* Strip the parity bit if desired. */ + if (fstrip) + bchar &= 0x7f; + + zhave[chave] = (char) bchar; + ++chave; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + char ab[5]; + + ++cchars; + if (cchars > 60) + { + ulog (LOG_DEBUG_END, "\""); + ulog (LOG_DEBUG_START, "icexpect: Got \""); + cchars = 0; + } + (void) cdebug_char (ab, bchar); + ulog (LOG_DEBUG_CONTINUE, "%s", ab); + } +#endif + + /* See if any of the strings can be found in the buffer. Since + we read one character at a time, the string can only be found + at the end of the buffer. */ + for (i = 0; i < cstrings; i++) + { + if (aclens[i] <= chave + && memcmp (zhave + chave - aclens[i], azstrings[i], + aclens[i]) == 0) + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + if (i == 0) + ulog (LOG_DEBUG_END, "\" (found it)"); + else + { + ulog (LOG_DEBUG_END, "\""); + udebug_buffer ("icexpect: Found", azstrings[i], + aclens[i]); + } + iDebug = iolddebug; + } +#endif + ubuffree (zhave); + return i; + } + } + + ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL)); + } +} + +#if DEBUG > 1 + +/* Debugging function for fcsend. This takes the fquote variable, the + length of the string (0 if this an informational string which can + be printed directly) and the string itself. It returns the new + value for fquote. The fquote variable is TRUE if the debugging + output is in the middle of a quoted string. */ + +static size_t cCsend_chars; +static int iColddebug; + +static boolean fcsend_debug P((boolean, size_t, const char *)); + +static boolean +fcsend_debug (fquote, clen, zbuf) + boolean fquote; + size_t clen; + const char *zbuf; +{ + size_t cwas; + + if (! FDEBUGGING (DEBUG_CHAT)) + return TRUE; + + cwas = cCsend_chars; + if (clen > 0) + cCsend_chars += clen; + else + cCsend_chars += strlen (zbuf); + if (cCsend_chars > 60 && cwas > 10) + { + ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : ""); + fquote = FALSE; + ulog (LOG_DEBUG_START, "fcsend: Writing"); + cCsend_chars = 0; + } + + if (clen == 0) + { + ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf); + return FALSE; + } + else + { + int i; + + if (! fquote) + ulog (LOG_DEBUG_CONTINUE, " \""); + for (i = 0; i < clen; i++) + { + char ab[5]; + + (void) cdebug_char (ab, zbuf[i]); + ulog (LOG_DEBUG_CONTINUE, "%s", ab); + } + + return TRUE; + } +} + +/* Finish up the debugging information for fcsend. */ + +static void ucsend_debug_end P((boolean, boolean)); + +static void +ucsend_debug_end (fquote, ferr) + boolean fquote; + boolean ferr; +{ + if (! FDEBUGGING (DEBUG_CHAT)) + return; + + if (fquote) + ulog (LOG_DEBUG_CONTINUE, "\""); + + if (ferr) + ulog (LOG_DEBUG_CONTINUE, " (error)"); + + ulog (LOG_DEBUG_END, "%s", ""); + + iDebug = iColddebug; +} + +#else /* DEBUG <= 1 */ + +/* Use macro definitions to make fcsend look neater. */ + +#define fcsend_debug(fquote, clen, zbuf) TRUE + +#define ucsend_debug_end(fquote, ferror) + +#endif /* DEBUG <= 1 */ + +/* Send a string out. This has to parse escape sequences as it goes. + Note that it handles the dialer escape sequences (\e, \E, \D, \T) + although they make no sense for chatting with a system. */ + +static boolean +fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip) + struct sconnection *qconn; + pointer puuconf; + const char *z; + const struct uuconf_system *qsys; + const struct uuconf_dialer *qdial; + const char *zphone; + boolean ftranslate; + boolean fstrip; +{ + boolean fnocr; + boolean (*pfwrite) P((struct sconnection *, const char *, size_t)); + char *zcallout_login; + char *zcallout_pass; + boolean fquote; + + if (strcmp (z, "\"\"") == 0) + return TRUE; + + fnocr = FALSE; + pfwrite = fconn_write; + zcallout_login = NULL; + zcallout_pass = NULL; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + ulog (LOG_DEBUG_START, "fcsend: Writing"); + fquote = FALSE; + cCsend_chars = 0; + iColddebug = iDebug; + iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT); + } +#endif + + while (*z != '\0') + { + const char *zlook; + boolean fsend; + char bsend; + + zlook = z + strcspn ((char *) z, "\\BE"); + + if (zlook > z) + { + size_t c; + + c = zlook - z; + fquote = fcsend_debug (fquote, c, z); + if (! (*pfwrite) (qconn, z, c)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + + if (*zlook == '\0') + break; + + z = zlook; + + fsend = FALSE; + switch (*z) + { + case 'B': + if (strncmp (z, "BREAK", 5) == 0) + { + fquote = fcsend_debug (fquote, (size_t) 0, "break"); + if (! fconn_break (qconn)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + fnocr = TRUE; + z += 5; + } + else + { + fsend = TRUE; + bsend = 'B'; + ++z; + } + break; + case 'E': + if (strncmp (z, "EOT", 3) == 0) + { + fsend = TRUE; + bsend = '\004'; + fnocr = TRUE; + z += 3; + } + else + { + fsend = TRUE; + bsend = 'E'; + ++z; + } + break; + case '\\': + ++z; + switch (*z) + { + case '-': + fsend = TRUE; + bsend = '-'; + break; + case 'b': + fsend = TRUE; + bsend = '\b'; + break; + case 'c': + fnocr = TRUE; + break; + case 'd': + fquote = fcsend_debug (fquote, (size_t) 0, "sleep"); + usysdep_sleep (2); + break; + case 'e': + fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off"); + pfwrite = fconn_write; + break; + case 'E': + fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-on"); + if (fstrip) + pfwrite = fcecho_send_strip; + else + pfwrite = fcecho_send_nostrip; + break; + case 'K': + fquote = fcsend_debug (fquote, (size_t) 0, "break"); + if (! fconn_break (qconn)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + break; + case 'n': + fsend = TRUE; + bsend = '\n'; + break; + case 'N': + fsend = TRUE; + bsend = '\0'; + break; + case 'p': + fquote = fcsend_debug (fquote, (size_t) 0, "pause"); + usysdep_pause (); + break; + case 'r': + fsend = TRUE; + bsend = '\r'; + break; + case 's': + fsend = TRUE; + bsend = ' '; + break; + case 't': + fsend = TRUE; + bsend = '\t'; + break; + case '\0': + --z; + /* Fall through. */ + case '\\': + fsend = TRUE; + bsend = '\\'; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + fsend = TRUE; + bsend = *z - '0'; + if (z[1] >= '0' && z[1] <= '7') + bsend = (char) (8 * bsend + *++z - '0'); + if (z[1] >= '0' && z[1] <= '7') + bsend = (char) (8 * bsend + *++z - '0'); + break; + case 'x': + fsend = TRUE; + bsend = 0; + while (isxdigit (BUCHAR (z[1]))) + { + if (isdigit (BUCHAR (z[1]))) + bsend = (char) (16 * bsend + *++z - '0'); + else if (isupper (BUCHAR (z[1]))) + bsend = (char) (16 * bsend + *++z - 'A'); + else + bsend = (char) (16 * bsend + *++z - 'a'); + } + break; + case 'L': + { + const char *zlog; + + if (qsys == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\L"); + return FALSE; + } + zlog = qsys->uuconf_zcall_login; + if (zlog == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "No login defined"); + return FALSE; + } + if (zlog[0] == '*' && zlog[1] == '\0') + { + if (zcallout_login == NULL) + { + int iuuconf; + + iuuconf = uuconf_callout (puuconf, qsys, + &zcallout_login, + &zcallout_pass); + if (iuuconf == UUCONF_NOT_FOUND + || zcallout_login == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "No login defined"); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ucsend_debug_end (fquote, TRUE); + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + } + zlog = zcallout_login; + } + fquote = fcsend_debug (fquote, (size_t) 0, "login"); + fquote = fcsend_debug (fquote, strlen (zlog), zlog); + if (! (*pfwrite) (qconn, zlog, strlen (zlog))) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + break; + case 'P': + { + const char *zpass; + + if (qsys == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\P"); + return FALSE; + } + zpass = qsys->uuconf_zcall_password; + if (zpass == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "No password defined"); + return FALSE; + } + if (zpass[0] == '*' && zpass[1] == '\0') + { + if (zcallout_pass == NULL) + { + int iuuconf; + + iuuconf = uuconf_callout (puuconf, qsys, + &zcallout_login, + &zcallout_pass); + if (iuuconf == UUCONF_NOT_FOUND + || zcallout_pass == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "No password defined"); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ucsend_debug_end (fquote, TRUE); + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + } + zpass = zcallout_pass; + } + fquote = fcsend_debug (fquote, (size_t) 0, "password"); + fquote = fcsend_debug (fquote, strlen (zpass), zpass); + if (! (*pfwrite) (qconn, zpass, strlen (zpass))) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + break; + case 'D': + if (qdial == NULL || zphone == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\D"); + return FALSE; + } + fquote = fcsend_debug (fquote, (size_t) 0, "\\D"); + if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, + ftranslate, &fquote)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + break; + case 'T': + if (qdial == NULL || zphone == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\T"); + return FALSE; + } + fquote = fcsend_debug (fquote, (size_t) 0, "\\T"); + if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, TRUE, + &fquote)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + break; + case 'M': + if (qdial == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\M"); + return FALSE; + } + fquote = fcsend_debug (fquote, (size_t) 0, "ignore-carrier"); + if (! fconn_carrier (qconn, FALSE)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + break; + case 'm': + if (qdial == NULL) + { + ucsend_debug_end (fquote, TRUE); + ulog (LOG_ERROR, "Illegal use of \\m"); + return FALSE; + } + if (qdial->uuconf_fcarrier) + { + fquote = fcsend_debug (fquote, (size_t) 0, "need-carrier"); + if (! fconn_carrier (qconn, TRUE)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + break; + default: + /* This error message will screw up any debugging + information, but it's easily avoidable. */ + ulog (LOG_ERROR, + "Unrecognized escape sequence \\%c in send string", + *z); + fsend = TRUE; + bsend = *z; + break; + } + ++z; + break; +#if DEBUG > 0 + default: + ulog (LOG_FATAL, "fcsend: Can't happen"); + break; +#endif + } + + if (fsend) + { + fquote = fcsend_debug (fquote, (size_t) 1, &bsend); + if (! (*pfwrite) (qconn, &bsend, (size_t) 1)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + } + + xfree ((pointer) zcallout_login); + xfree ((pointer) zcallout_pass); + + /* Output a final carriage return, unless there was a \c. Don't + bother to check for an echo. */ + if (! fnocr) + { + char b; + + b = '\r'; + fquote = fcsend_debug (fquote, (size_t) 1, &b); + if (! fconn_write (qconn, &b, (size_t) 1)) + { + ucsend_debug_end (fquote, TRUE); + return FALSE; + } + } + + ucsend_debug_end (fquote, FALSE); + + return TRUE; +} + +/* Write out a phone number with optional dialcode translation. The + pfquote argument is only used for debugging. */ + +static boolean +fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, pfquote) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_dialer *qdial; + const char *zphone; + boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite, + size_t cwrite)); + boolean ftranslate; + boolean *pfquote; +{ + const char *zprefix, *zsuffix; + + if (ftranslate) + { + if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix)) + return FALSE; + } + else + { + zprefix = zphone; + zsuffix = NULL; + } + + while (zprefix != NULL) + { + while (TRUE) + { + const char *z; + const char *zstr; + + z = zprefix + strcspn ((char *) zprefix, "=-"); + if (z > zprefix) + { + size_t clen; + + clen = z - zprefix; + *pfquote = fcsend_debug (*pfquote, clen, zprefix); + if (! (*pfwrite) (qconn, zprefix, clen)) + return FALSE; + } + + if (*z == '=') + zstr = qdial->uuconf_zdialtone; + else if (*z == '-') + zstr = qdial->uuconf_zpause; + else /* *z == '\0' */ + break; + + if (zstr != NULL) + { + *pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr); + if (! (*pfwrite) (qconn, zstr, strlen (zstr))) + return FALSE; + } + + zprefix = z + 1; + } + + zprefix = zsuffix; + zsuffix = NULL; + } + + return TRUE; +} + +/* Given a phone number, run it through dial code translation + returning two strings. */ + +static boolean +fctranslate (puuconf, zphone, pzprefix, pzsuffix) + pointer puuconf; + const char *zphone; + const char **pzprefix; + const char **pzsuffix; +{ + int iuuconf; + char *zdialcode, *zto; + const char *zfrom; + char *ztrans; + + *pzprefix = zphone; + *pzsuffix = NULL; + + zdialcode = zbufalc (strlen (zphone) + 1); + zfrom = zphone; + zto = zdialcode; + while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom))) + *zto++ = *zfrom++; + *zto = '\0'; + + if (*zdialcode == '\0') + { + ubuffree (zdialcode); + return TRUE; + } + + iuuconf = uuconf_dialcode (puuconf, zdialcode, &ztrans); + + ubuffree (zdialcode); + + if (iuuconf == UUCONF_NOT_FOUND) + return TRUE; + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + else + { + /* We really should figure out a way to free up ztrans here. */ + *pzprefix = ztrans; + *pzsuffix = zfrom; + return TRUE; + } +} + +/* Write out a string making sure the each character is echoed back. + There are two versions of this function, one which strips the + parity bit from the characters and one which does not. This is so + that I can use a single function pointer in fcsend, and to avoid + using any static variables so that I can put chat scripts in a + library some day. */ + +static boolean +fcecho_send_strip (qconn, zwrite, cwrite) + struct sconnection *qconn; + const char *zwrite; + size_t cwrite; +{ + return fcecho_send (qconn, zwrite, cwrite, TRUE); +} + +static boolean +fcecho_send_nostrip (qconn, zwrite, cwrite) + struct sconnection *qconn; + const char *zwrite; + size_t cwrite; +{ + return fcecho_send (qconn, zwrite, cwrite, FALSE); +} + +static boolean +fcecho_send (qconn, zwrite, cwrite, fstrip) + struct sconnection *qconn; + const char *zwrite; + size_t cwrite; + boolean fstrip; +{ + const char *zend; + + zend = zwrite + cwrite; + + for (; zwrite < zend; zwrite++) + { + int b; + char bwrite; + + bwrite = *zwrite; + if (! fconn_write (qconn, &bwrite, (size_t) 1)) + return FALSE; + if (fstrip) + bwrite &= 0x7f; + do + { + /* We arbitrarily wait five seconds for the echo. */ + b = breceive_char (qconn, 5, TRUE); + /* Now b == -1 on timeout, -2 on error. */ + if (b < 0) + { + if (b == -1) + ulog (LOG_ERROR, "Character not echoed"); + return FALSE; + } + if (fstrip) + b &= 0x7f; + } + while (b != BUCHAR (bwrite)); + } + + return TRUE; +} + +/* Run a chat program. Expand any escape sequences and call a system + dependent program to run it. */ + +static boolean +fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud) + struct sconnection *qconn; + pointer puuconf; + char **pzprogram; + const struct uuconf_system *qsys; + const struct uuconf_dialer *qdial; + const char *zphone; + const char *zport; + long ibaud; +{ + size_t cargs; + char **pzpass, **pzarg; + char **pz; + char *zcallout_login; + char *zcallout_pass; + boolean fret; + + cargs = 1; + for (pz = pzprogram; *pz != NULL; pz++) + ++cargs; + + pzpass = (char **) xmalloc (cargs * sizeof (char *)); + + zcallout_login = NULL; + zcallout_pass = NULL; + fret = TRUE; + + /* Copy the string into memory expanding escape sequences. */ + for (pz = pzprogram, pzarg = pzpass; *pz != NULL; pz++, pzarg++) + { + const char *zfrom; + size_t calc, clen; + char *zto; + + if (strchr (*pz, '\\') == NULL) + { + *pzarg = zbufcpy (*pz); + continue; + } + + *pzarg = NULL; + zto = NULL; + calc = 0; + clen = 0; + + for (zfrom = *pz; *zfrom != '\0'; zfrom++) + { + const char *zadd = NULL; + size_t cadd; + char abadd[15]; + + if (*zfrom != '\\') + { + if (clen + 2 > calc) + { + char *znew; + + calc = clen + 50; + znew = zbufalc (calc); + memcpy (znew, *pzarg, clen); + ubuffree (*pzarg); + *pzarg = znew; + zto = znew + clen; + } + *zto++ = *zfrom; + ++clen; + continue; + } + + ++zfrom; + switch (*zfrom) + { + case '\0': + --zfrom; + /* Fall through. */ + case '\\': + zadd = "\\"; + break; + case 'L': + { + const char *zlog; + + if (qsys == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\L"); + fret = FALSE; + break; + } + zlog = qsys->uuconf_zcall_login; + if (zlog == NULL) + { + ulog (LOG_ERROR, "chat-program: No login defined"); + fret = FALSE; + break; + } + if (zlog[0] == '*' && zlog[1] == '\0') + { + if (zcallout_login == NULL) + { + int iuuconf; + + iuuconf = uuconf_callout (puuconf, qsys, + &zcallout_login, + &zcallout_pass); + if (iuuconf == UUCONF_NOT_FOUND + || zcallout_login == NULL) + { + ulog (LOG_ERROR, + "chat-program: No login defined"); + fret = FALSE; + break; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + break; + } + } + zlog = zcallout_login; + } + zadd = zlog; + } + break; + case 'P': + { + const char *zpass; + + if (qsys == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\P"); + fret = FALSE; + break; + } + zpass = qsys->uuconf_zcall_password; + if (zpass == NULL) + { + ulog (LOG_ERROR, "chat-program: No password defined"); + fret = FALSE; + break; + } + if (zpass[0] == '*' && zpass[1] == '\0') + { + if (zcallout_pass == NULL) + { + int iuuconf; + + iuuconf = uuconf_callout (puuconf, qsys, + &zcallout_login, + &zcallout_pass); + if (iuuconf == UUCONF_NOT_FOUND + || zcallout_pass == NULL) + { + ulog (LOG_ERROR, + "chat-program: No password defined"); + fret = FALSE; + break; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + break; + } + } + zpass = zcallout_pass; + } + zadd = zpass; + } + break; + case 'D': + if (qdial == NULL || zphone == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\D"); + fret = FALSE; + break; + } + zadd = zphone; + break; + case 'T': + { + const char *zprefix, *zsuffix; + + if (qdial == NULL || zphone == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\T"); + fret = FALSE; + break; + } + + if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix)) + { + fret = FALSE; + break; + } + + if (zsuffix == NULL) + zadd = zprefix; + else + { + size_t cprefix; + + cprefix = strlen (zprefix); + if (clen + cprefix + 1 > calc) + { + char *znew; + + calc = clen + cprefix + 20; + znew = zbufalc (calc); + memcpy (znew, *pzarg, clen); + ubuffree (*pzarg); + *pzarg = znew; + zto = znew + clen; + } + memcpy (zto, zprefix, cprefix); + zto += cprefix; + clen += cprefix; + zadd = zsuffix; + } + } + break; + case 'Y': + if (zLdevice == NULL && zport == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\Y"); + fret = FALSE; + break; + } + /* zLdevice will generally make more sense than zport, but + it might not be set yet. */ + zadd = zLdevice; + if (zadd == NULL) + zadd = zport; + break; + case 'Z': + if (qsys == NULL) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\Z"); + fret = FALSE; + break; + } + zadd = qsys->uuconf_zname; + break; + case 'S': + { + if (ibaud == 0) + { + ulog (LOG_ERROR, "chat-program: Illegal use of \\S"); + fret = FALSE; + break; + } + sprintf (abadd, "%ld", ibaud); + zadd = abadd; + } + break; + default: + { + ulog (LOG_ERROR, + "chat-program: Unrecognized escape sequence \\%c", + *zfrom); + abadd[0] = *zfrom; + abadd[1] = '\0'; + zadd = abadd; + } + break; + } + + if (! fret) + break; + + cadd = strlen (zadd); + if (clen + cadd + 1 > calc) + { + char *znew; + + calc = clen + cadd + 20; + znew = zbufalc (calc); + memcpy (znew, *pzarg, clen); + ubuffree (*pzarg); + *pzarg = znew; + zto = znew + clen; + } + memcpy (zto, zadd, cadd + 1); + zto += cadd; + clen += cadd; + } + + if (! fret) + break; + + *zto++ = '\0'; + ++clen; + } + + *pzarg = NULL; + + if (fret) + fret = fconn_run_chat (qconn, pzpass); + + for (pz = pzpass; *pz != NULL; pz++) + ubuffree (*pz); + xfree ((pointer) pzpass); + xfree ((pointer) zcallout_login); + xfree ((pointer) zcallout_pass); + + return fret; +} diff --git a/gnu/libexec/uucp/common_sources/conf.h b/gnu/libexec/uucp/common_sources/conf.h new file mode 100644 index 00000000000..431ba4d11b1 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/conf.h @@ -0,0 +1,444 @@ +/* conf.h. Generated automatically by configure. */ +/* Configuration header file for Taylor UUCP. -*- C -*- */ + +/* Set MAIL_PROGRAM to a program which takes a mail address as an + argument and accepts a mail message to send to that address on + stdin (e.g. "/bin/mail"). */ +#define MAIL_PROGRAM "/usr/bin/mail" + +/* Set ECHO_PROGRAM to a program which echoes its arguments; if echo + is a shell builtin you can just use "echo". */ +#define ECHO_PROGRAM "echo" + +/* The following macros indicate what header files you have. Set the + macro to 1 if you have the corresponding header file, or 0 if you + do not. */ +#define HAVE_STDDEF_H 1 /* <stddef.h> */ +#define HAVE_STRING_H 1 /* <string.h> */ +#define HAVE_STRINGS_H 1 /* <strings.h> */ +#define HAVE_UNISTD_H 1 /* <unistd.h> */ +#define HAVE_STDLIB_H 1 /* <stdlib.h> */ +#define HAVE_LIMITS_H 1 /* <limits.h> */ +#define HAVE_TIME_H 1 /* <time.h> */ +#define HAVE_SYS_WAIT_H 1 /* <sys/wait.h> */ +#define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */ +#define HAVE_DIRENT_H 1 /* <dirent.h> */ +#define HAVE_MEMORY_H 1 /* <memory.h> */ +#define HAVE_SYS_PARAM_H 1 /* <sys/param.h> */ +#define HAVE_UTIME_H 1 /* <utime.h> */ +#define HAVE_FCNTL_H 1 /* <fcntl.h> */ +#define HAVE_SYS_FILE_H 1 /* <sys/file.h> */ +#define HAVE_SYS_TIMES_H 1 /* <sys/times.h> */ +#define HAVE_LIBC_H 0 /* <libc.h> */ +#define HAVE_SYSEXITS_H 1 /* <sysexits.h> */ +#define HAVE_POLL_H 0 /* <poll.h> */ +#define HAVE_TIUSER_H 0 /* <tiuser.h> */ +#define HAVE_XTI_H 0 /* <xti.h> */ +#define HAVE_SYS_TLI_H 0 /* <sys/tli.h> */ +#define HAVE_STROPTS_H 0 /* <stropts.h> */ +#define HAVE_FTW_H 0 /* <ftw.h> */ +#define HAVE_GLOB_H 1 /* <glob.h> */ +#define HAVE_SYS_SELECT_H 0 /* <sys/select.h> */ +#define HAVE_SYS_TYPES_TCP_H 0 /* <sys/types.tcp.h> */ + +/* If major and minor are not defined in <sys/types.h>, but are in + <sys/mkdev.h>, set MAJOR_IN_MKDEV to 1. If they are in + <sys/sysmacros.h>, set MAJOR_IN_SYSMACROS to 1. */ +#define MAJOR_IN_MKDEV 0 +#define MAJOR_IN_SYSMACROS 0 + +/* If the macro offsetof is not defined in <stddef.h>, you may give it + a definition here. If you do not, the code will use a definition + (in uucp.h) that should be fairly portable. */ +/* #define offsetof */ + +/* Set RETSIGTYPE to the return type of a signal handler. On newer + systems this will be void; some older systems use int. */ +#define RETSIGTYPE void + +/* Set HAVE_SYS_TIME_AND_TIME_H to 1 if <time.h> and <sys/time.h> can both + be included in a single source file; if you don't have either or both of + them, it doesn't matter what you set this to. */ +#define HAVE_SYS_TIME_AND_TIME_H 1 + +/* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if <termios.h> and <sys/ioctl.h> + can both be included in a single source file; if you don't have either + or both of them, it doesn't matter what you set this to. */ +#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1 + +/* If you are configuring by hand, you should set one of the terminal + driver options in policy.h. If you are autoconfiguring, the script + will check whether your system defines CBREAK, which is a terminal + setting; if your system supports CBREAK, and you don't set a terminal + driver in policy.h, the code will assume that you have a BSD style + terminal driver. */ +#define HAVE_CBREAK 1 + +/* The package needs several standard types. If you are using the + configure script, it will look in standard places for these types, + and give default definitions for them here if it doesn't find them. + The default definitions should work on most systems, but you may + want to check them. If you are configuring by hand, you will have + to figure out whether the types are defined on your system, and + what they should be defined to. + + Any type that is not defined on your system should get a macro + definition. The definition should be of the name of the type in + all capital letters. For example, #define PID_T int. If the type + is defined in a standard header file, the macro name should not be + defined. */ + +/* The type pid_t is used to hold a process ID number. It is normally + defined in <sys/types.h>. This is the type returned by the + functions fork or getpid. Usually int will work fine. */ +#undef PID_T + +/* The type uid_t is used to hold a user ID number. It is normally + defined in <sys/types.h>. This is the type returned by the getuid + function. Usually int will work fine. */ +#undef UID_T + +/* The type gid_t is used to hold a group ID number. It is sometimes + defined in <sys/types.h>. This is the type returned by the getgid + function. Usually int will work fine. */ +#undef GID_T + +/* The type off_t is used to hold an offset in a file. It is sometimes + defined in <sys/types.h>. This is the type of the second argument to + the lseek function. Usually long will work fine. */ +#undef OFF_T + +/* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined + in <signal.h> as required by ANSI C. */ +#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 1 + +/* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined + in <sys/types.h>. This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is + set to 1. */ +#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0 + +/* The type sig_atomic_t is used to hold a value which may be + referenced in a single atomic operation. If it is not defined in + either <signal.h> or <sys/types.h>, you may want to give it a + definition here. If you don't, the code will use char. If your + compiler does not support sig_atomic_t, there is no type which is + really correct; fortunately, for this package it does not really + matter very much. */ +#undef SIG_ATOMIC_T + +/* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in + <stddef.h> as required by ANSI C. */ +#define HAVE_SIZE_T_IN_STDDEF_H 1 + +/* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in + <sys/types.h>. This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set + to 1. */ +#define HAVE_SIZE_T_IN_TYPES_H 1 + +/* The type size_t is used to hold the size of an object. In + particular, an argument of this type is passed as the size argument + to the malloc and realloc functions. If size_t is not defined in + either <stddef.h> or <sys/types.h>, you may want to give it a + definition here. If you don't, the code will use unsigned. */ +#undef SIZE_T + +/* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in + <time.h>, as required by the ANSI C standard. */ +#define HAVE_TIME_T_IN_TIME_H 1 + +/* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in + <sys/types.h>. This is ignored if HAVE_TIME_T_IN_TIME_H is set to + 1. */ +#define HAVE_TIME_T_IN_TYPES_H 1 + +/* When Taylor UUCP is talking to another instance of itself, it will + tell the other side the size of a file before it is transferred. + If the package can determine how much disk space is available, it + will use this information to avoid filling up the disk. Define one + of the following macros to tell the code how to determine the + amount of available disk space. It is possible that none of these + are appropriate; it will do no harm to use none of them, but, of + course, nothing will then prevent the package from filling up the + disk. Note that this space check is only useful when talking to + another instance of Taylor UUCP. + + STAT_STATVFS statvfs function + STAT_STATFS2_BSIZE two argument statfs function with f_bsize field + STAT_STATFS2_FSIZE two argument statfs function with f_fsize field + STAT_STATFS2_FS_DATA two argument statfs function with fd_req field + STAT_STATFS4 four argument statfs function + STAT_USTAT the ustat function with 512 byte blocks. */ +#define STAT_STATVFS 0 +#define STAT_STATFS2_BSIZE 0 +#define STAT_STATFS2_FSIZE 1 +#define STAT_STATFS2_FS_DATA 0 +#define STAT_STATFS4 0 +#define STAT_USTAT 0 + +/* Set HAVE_VOID to 1 if the compiler supports declaring functions with + a return type of void and casting values to void. */ +#define HAVE_VOID 1 + +/* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned + char. */ +#define HAVE_UNSIGNED_CHAR 1 + +/* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in <errno.h>. */ +#define HAVE_ERRNO_DECLARATION 1 + +/* There are now a number of functions to check for. For each of + these, the macro HAVE_FUNC should be set to 1 if your system has + FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system + has vfprintf, 0 otherwise. */ + +/* Taylor UUCP will take advantage of the following functions if they + are available, but knows how to deal with their absence. */ +#define HAVE_VFPRINTF 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_LTRUNC 0 +#define HAVE_WAITPID 1 +#define HAVE_WAIT4 1 +#define HAVE_GLOB 1 +#define HAVE_SETREUID 1 + +/* There are several functions which are replaced in the subdirectory + lib. If they are missing, the configure script will automatically + add them to lib/Makefile to force them to be recompiled. If you + are configuring by hand, you will have to do this yourself. The + string @LIBOBJS@ in lib/Makefile.in should be replaced by a list of + object files in lib/Makefile. The following comments tell you + which object file names to add (they are generally fairly obvious, + given that the file names have no more than six characters before + the period). */ + +/* For each of these functions, if it does not exist, the indicated + object file should be added to lib/Makefile. */ +#define HAVE_BSEARCH 1 /* bsrch.o */ +#define HAVE_GETLINE 0 /* getlin.o */ +#define HAVE_MEMCHR 1 /* memchr.o */ +#define HAVE_STRDUP 1 /* strdup.o */ +#define HAVE_STRSTR 1 /* strstr.o */ +#define HAVE_STRTOL 1 /* strtol.o */ + +/* If neither of these functions exists, you should add bzero.o to + lib/Makefile. */ +#define HAVE_BZERO 1 +#define HAVE_MEMSET 1 + +/* If neither of these functions exists, you should add memcmp.o to + lib/Makefile. */ +#define HAVE_MEMCMP 1 +#define HAVE_BCMP 1 + +/* If neither of these functions exists, you should add memcpy.o to + lib/Makefile. */ +#define HAVE_MEMCPY 1 +#define HAVE_BCOPY 1 + +/* If neither of these functions exists, you should add strcas.o to + lib/Makefile. */ +#define HAVE_STRCASECMP 1 +#define HAVE_STRICMP 0 + +/* If neither of these functions exists, you should add strncs.o to + lib/Makefile. */ +#define HAVE_STRNCASECMP 1 +#define HAVE_STRNICMP 0 + +/* If neither of these functions exists, you should add strchr.o to + lib/Makefile. */ +#define HAVE_STRCHR 1 +#define HAVE_INDEX 1 + +/* If neither of these functions exists, you should add strrch.o to + lib/Makefile. */ +#define HAVE_STRRCHR 1 +#define HAVE_RINDEX 1 + +/* There are also Unix specific functions which are replaced in the + subdirectory unix. If they are missing, the configure script will + automatically add them to unix/Makefile to force them to be + recompiled. If you are configuring by hand, you will have to do + this yourself. The string @UNIXOBJS@ in unix/Makefile.in should be + replaced by a list of object files in unix/Makefile. The following + comments tell you which object file names to add. */ + +/* For each of these functions, if it does not exist, the indicated + object file should be added to unix/Makefile. */ +#define HAVE_OPENDIR 1 /* dirent.o */ +#define HAVE_DUP2 1 /* dup2.o */ +#define HAVE_FTW 0 /* ftw.o */ +#define HAVE_REMOVE 1 /* remove.o */ +#define HAVE_RENAME 1 /* rename.o */ +#define HAVE_STRERROR 1 /* strerr.o */ + +/* The code needs to know how to create directories. If you have the + mkdir function, set HAVE_MKDIR to 1 and replace @UUDIR@ in + Makefile.in with '# ' (the configure script will set @UUDIR@ + according to the variable UUDIR). Otherwise, set HAVE_MKDIR to 0, + remove @UUDIR@ from Makefile.in, set MKDIR_PROGRAM to the name of + the program which will create a directory named on the command line + (e.g., "/bin/mkdir"), and add mkdir.o to the @UNIXOBJS@ string in + unix/Makefile.in. */ +#define HAVE_MKDIR 1 +#define MKDIR_PROGRAM unused + +/* The code also needs to know how to remove directories. If you have + the rmdir function, set HAVE_RMDIR to 1. Otherwise, set + RMDIR_PROGRAM to the name of the program which will remove a + directory named on the command line (e.g., "/bin/rmdir") and add + rmdir.o to the @UNIXOBJS@ string in unix/Makefile.in. */ +#define HAVE_RMDIR 1 +#define RMDIR_PROGRAM unused + +/* The code needs to know to how to get the name of the current + directory. If getcwd is available it will be used, otherwise if + getwd is available it will be used. Otherwise, set PWD_PROGRAM to + the name of the program which will print the name of the current + working directory (e.g., "/bin/pwd") and add getcwd.o to the + @UNIXOBJS@ string in unix/Makefile.in. */ +#define HAVE_GETCWD 1 +#define HAVE_GETWD 1 +#define PWD_PROGRAM unused + +/* If you have either sigsetjmp or setret, it will be used instead of + setjmp. These functions will only be used if your system restarts + system calls after interrupts (see HAVE_RESTARTABLE_SYSCALLS, + below). */ +#define HAVE_SIGSETJMP 0 +#define HAVE_SETRET 0 + +/* The code needs to know what function to use to set a signal + handler. If will try to use each of the following functions in + turn. If none are available, it will use signal, which is assumed + to always exist. */ +#define HAVE_SIGACTION 1 +#define HAVE_SIGVEC 1 +#define HAVE_SIGSET 0 + +/* If the code is going to use sigvec (HAVE_SIGACTION is 0 and + HAVE_SIGVEC is 1), then HAVE_SIGVEC_SV_FLAGS must be set to 1 if + the sigvec structure contains the sv_flags field, or 0 if the + sigvec structure contains the sv_onstack field. If the code is not + going to use sigvec, it doesn't matter what this is set to. */ +#define HAVE_SIGVEC_SV_FLAGS 1 + +/* The code will try to use each of the following functions in turn + when blocking signals from delivery. If none are available, a + relatively unimportant race condition will exist. */ +#define HAVE_SIGPROCMASK 1 +#define HAVE_SIGBLOCK 1 +#define HAVE_SIGHOLD 0 + +/* If you have either of the following functions, it will be used to + determine the number of file descriptors which may be open. + Otherwise, the code will use OPEN_MAX if defined, then NOFILE if + defined, then 20. */ +#define HAVE_GETDTABLESIZE 1 +#define HAVE_SYSCONF 0 + +/* The code will use one of the following functions when detaching + from a terminal. One of these must exist. */ +#define HAVE_SETPGRP 1 +#define HAVE_SETSID 1 + +/* If you do not specify the local node name in the main configuration + file, Taylor UUCP will try to use each of the following functions + in turn. If neither is available, you must specify the local node + name in the configuration file. */ +#define HAVE_GETHOSTNAME 1 +#define HAVE_UNAME 0 + +/* The code will try to use each of the following functions in turn to + determine the current time. If none are available, it will use + time, which is assumed to always exist. */ +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_FTIME 0 + +/* If neither gettimeofday nor ftime is available, the code will use + times (if available) to measure a span of time. See also the + discussion of TIMES_TICK in policy.h. */ +#define HAVE_TIMES 1 + +/* When a chat script requests a pause of less than a second with \p, + Taylor UUCP will try to use each of the following functions in + turn. If none are available, it will sleep for a full second. + Also, the (non-portable) tstuu program requires either select or + poll. */ +#define HAVE_NAPMS 0 +#define HAVE_NAP 0 +#define HAVE_USLEEP 1 +#define HAVE_POLL 0 +#define HAVE_SELECT 1 + +/* If the getgrent function is available, it will be used to determine + all the groups a user belongs to when checking file access + permissions. */ +#define HAVE_GETGRENT 1 + +/* If the socket function is available, TCP support code will be + compiled in. */ +#define HAVE_SOCKET 1 + +/* If the t_open function is available, TLI support code will be + compiled in. This may require adding a library, such as -lnsl or + -lxti, to the Makefile variables LIBS. */ +#define HAVE_T_OPEN 0 + +/* That's the end of the list of the functions. Now there are a few + last miscellaneous items. */ + +/* On some systems the following functions are declared in such a way + that the code cannot make a simple extern. On other systems, these + functions are not declared at all, and the extern is required. If + a declaration of the function, as shown, compiles on your system, + set the value to 1. Not all functions declared externally are + listed here, only the ones with which I have had trouble. */ +/* extern long times (); */ +#define TIMES_DECLARATION_OK 0 +/* extern struct passwd *getpwnam (); */ +#define GETPWNAM_DECLARATION_OK 1 +/* extern struct passwd *getpwuid (); */ +#define GETPWUID_DECLARATION_OK 0 +/* extern struct group *getgrent (); */ +#define GETGRENT_DECLARATION_OK 1 + +/* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and + your setpgrp calls takes 2 arguments (on System V they generally + take no arguments). You can safely set this to 1 on System V, + provided the call will compile without any errors. */ +#define HAVE_BSD_PGRP 0 + +/* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header + file <sys/wait.h>. */ +#define HAVE_UNION_WAIT 1 + +/* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names + longer than 14 characters. */ +#define HAVE_LONG_FILE_NAMES 1 + +/* If slow system calls are restarted after interrupts, set + HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION + is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and + SV_INTERRUPT is defined in <signal.h>. In both of these cases + system calls can be prevented from restarting. */ +#define HAVE_RESTARTABLE_SYSCALLS 1 + +/* Some systems supposedly need the following macros to be defined. + These are handled by the configure script (it will turn #undef into + #define when appropriate, which is why the peculiar #ifndef #undef + construction is used). If you are configuring by hand, you may add + appropriate definitions here, or just add them to CFLAGS when + running make. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif +#ifndef _POSIX_SOURCE +#undef _POSIX_SOURCE +#endif +#ifndef _MINIX +#undef _MINIX +#endif +#ifndef _POSIX_1_SOURCE +#undef _POSIX_1_SOURCE +#endif diff --git a/gnu/libexec/uucp/common_sources/conn.c b/gnu/libexec/uucp/common_sources/conn.c new file mode 100644 index 00000000000..df35e8297f6 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/conn.c @@ -0,0 +1,552 @@ +/* conn.c + Connection routines for the Taylor UUCP package. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/04 19:30:39 jtc Exp $"; +#endif + +#include <ctype.h> + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" + +static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf, + struct uuconf_dialer *qdialer, + const char *zphone, boolean ftranslate)); + +/* Create a new connection. This relies on system dependent functions + to set the qcmds and psysdep fields. If qport is NULL, it opens a + standard input port. */ + +boolean +fconn_init (qport, qconn) + struct uuconf_port *qport; + struct sconnection *qconn; +{ + qconn->qport = qport; + switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype) + { + case UUCONF_PORTTYPE_STDIN: + return fsysdep_stdin_init (qconn); + case UUCONF_PORTTYPE_MODEM: + return fsysdep_modem_init (qconn); + case UUCONF_PORTTYPE_DIRECT: + return fsysdep_direct_init (qconn); +#if HAVE_TCP + case UUCONF_PORTTYPE_TCP: + return fsysdep_tcp_init (qconn); +#endif +#if HAVE_TLI + case UUCONF_PORTTYPE_TLI: + return fsysdep_tli_init (qconn); +#endif + default: + ulog (LOG_ERROR, "Unknown port type"); + return FALSE; + } +} + +/* Connection dispatch routines. */ + +/* Free a connection. */ + +void +uconn_free (qconn) + struct sconnection *qconn; +{ + (*qconn->qcmds->pufree) (qconn); +} + +/* Lock a connection. */ + +boolean +fconn_lock (qconn, fin) + struct sconnection *qconn; + boolean fin; +{ + boolean (*pflock) P((struct sconnection *, boolean)); + + pflock = qconn->qcmds->pflock; + if (pflock == NULL) + return TRUE; + return (*pflock) (qconn, fin); +} + +/* Unlock a connection. */ + +boolean +fconn_unlock (qconn) + struct sconnection *qconn; +{ + boolean (*pfunlock) P((struct sconnection *)); + + pfunlock = qconn->qcmds->pfunlock; + if (pfunlock == NULL) + return TRUE; + return (*pfunlock) (qconn); +} + +/* Open a connection. */ + +boolean +fconn_open (qconn, ibaud, ihighbaud, fwait) + struct sconnection *qconn; + long ibaud; + long ihighbaud; + boolean fwait; +{ + boolean fret; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_PORT)) + { + char abspeed[20]; + + if (ibaud == (long) 0) + strcpy (abspeed, "default speed"); + else + sprintf (abspeed, "speed %ld", ibaud); + + if (qconn->qport == NULL) + ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)", + abspeed); + else if (qconn->qport->uuconf_zname == NULL) + ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)", + abspeed); + else + ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)", + qconn->qport->uuconf_zname, abspeed); + } +#endif + + /* If the system provides a range of baud rates, we select the + highest baud rate supported by the port. */ + if (ihighbaud != 0 && qconn->qport != NULL) + { + struct uuconf_port *qport; + + qport = qconn->qport; + ibaud = ihighbaud; + if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) + { + if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0) + { + if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud) + ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud; + } + else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0) + ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud; + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) + { + if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0) + ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; + } + } + + /* This will normally be overridden by the port specific open + routine. */ + if (qconn->qport == NULL) + ulog_device ("stdin"); + else + ulog_device (qconn->qport->uuconf_zname); + + fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait); + + if (! fret) + ulog_device ((const char *) NULL); + + return fret; +} + +/* Close a connection. */ + +boolean +fconn_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + boolean fret; + + DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection"); + + /* Don't report hangup signals while we're closing. */ + fLog_sighup = FALSE; + + fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess); + + /* Make sure any signal reporting has been done before we set + fLog_sighup back to TRUE. */ + ulog (LOG_ERROR, (const char *) NULL); + fLog_sighup = TRUE; + + ulog_device ((const char *) NULL); + + return fret; +} + +/* Reset the connection. */ + +boolean +fconn_reset (qconn) + struct sconnection *qconn; +{ + DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection"); + + return (*qconn->qcmds->pfreset) (qconn); +} + +/* Dial out on the connection. */ + +boolean +fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialerfound; +{ + struct uuconf_dialer sdialer; + enum tdialerfound tfound; + boolean (*pfdial) P((struct sconnection *, pointer, + const struct uuconf_system *, const char *, + struct uuconf_dialer *, enum tdialerfound *)); + + if (qdialer == NULL) + qdialer = &sdialer; + if (ptdialerfound == NULL) + ptdialerfound = &tfound; + + qdialer->uuconf_zname = NULL; + *ptdialerfound = DIALERFOUND_FALSE; + + pfdial = qconn->qcmds->pfdial; + if (pfdial == NULL) + return TRUE; + return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound); +} + +/* Read data from the connection. */ + +boolean +fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport) + struct sconnection *qconn; + char *zbuf; + size_t *pclen; + size_t cmin; + int ctimeout; + boolean freport; +{ + boolean fret; + + fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout, + freport); + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_INCOMING)) + udebug_buffer ("fconn_read: Read", zbuf, *pclen); + else if (FDEBUGGING (DEBUG_PORT)) + ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen); +#endif + + return fret; +} + +/* Write data to the connection. */ + +boolean +fconn_write (qconn, zbuf, clen) + struct sconnection *qconn; + const char *zbuf; + size_t clen; +{ +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_OUTGOING)) + udebug_buffer ("fconn_write: Writing", zbuf, clen); + else if (FDEBUGGING (DEBUG_PORT)) + ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen); +#endif + + return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen); +} + +/* Read and write data. */ + +boolean +fconn_io (qconn, zwrite, pcwrite, zread, pcread) + struct sconnection *qconn; + const char *zwrite; + size_t *pcwrite; + char *zread; + size_t *pcread; +{ + boolean fret; +#if DEBUG > 1 + size_t cwrite = *pcwrite; + size_t cread = *pcread; + + if (cread == 0 || cwrite == 0) + ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu", + (unsigned long) cread, (unsigned long) cwrite); +#endif + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_OUTGOING)) + udebug_buffer ("fconn_io: Writing", zwrite, cwrite); +#endif + + fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread); + + DEBUG_MESSAGE4 (DEBUG_PORT, + "fconn_io: Wrote %lu of %lu, read %lu of %lu", + (unsigned long) *pcwrite, (unsigned long) cwrite, + (unsigned long) *pcread, (unsigned long) cread); + +#if DEBUG > 1 + if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING)) + udebug_buffer ("fconn_io: Read", zread, *pcread); +#endif + + return fret; +} + +/* Send a break character to a connection. Some port types may not + support break characters, in which case we just return TRUE. */ + +boolean +fconn_break (qconn) + struct sconnection *qconn; +{ + boolean (*pfbreak) P((struct sconnection *)); + + pfbreak = *qconn->qcmds->pfbreak; + if (pfbreak == NULL) + return TRUE; + + DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character"); + + return (*pfbreak) (qconn); +} + +/* Change the setting of a connection. Some port types may not + support this, in which case we just return TRUE. */ + +boolean +fconn_set (qconn, tparity, tstrip, txonxoff) + struct sconnection *qconn; + enum tparitysetting tparity; + enum tstripsetting tstrip; + enum txonxoffsetting txonxoff; +{ + boolean (*pfset) P((struct sconnection *, enum tparitysetting, + enum tstripsetting, enum txonxoffsetting)); + + pfset = qconn->qcmds->pfset; + if (pfset == NULL) + return TRUE; + + DEBUG_MESSAGE3 (DEBUG_PORT, + "fconn_set: Changing setting to %d, %d, %d", + (int) tparity, (int) tstrip, (int) txonxoff); + + return (*pfset) (qconn, tparity, tstrip, txonxoff); +} + +/* Require or ignore carrier on a connection. */ + +boolean +fconn_carrier (qconn, fcarrier) + struct sconnection *qconn; + boolean fcarrier; +{ + boolean (*pfcarrier) P((struct sconnection *, boolean)); + + pfcarrier = qconn->qcmds->pfcarrier; + if (pfcarrier == NULL) + return TRUE; + return (*pfcarrier) (qconn, fcarrier); +} + +/* Run a chat program on a connection. */ + +boolean +fconn_run_chat (qconn, pzprog) + struct sconnection *qconn; + char **pzprog; +{ + return (*qconn->qcmds->pfchat) (qconn, pzprog); +} + +/* Get the baud rate of a connection. */ + +long +iconn_baud (qconn) + struct sconnection *qconn; +{ + long (*pibaud) P((struct sconnection *)); + + pibaud = qconn->qcmds->pibaud; + if (pibaud == NULL) + return 0; + return (*pibaud) (qconn); +} + +/* Modem dialing routines. */ + +/*ARGSUSED*/ +boolean +fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialerfound; +{ + *ptdialerfound = DIALERFOUND_FALSE; + + if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) + { + char **pz; + boolean ffirst; + + /* The pzdialer field is a sequence of dialer/token pairs. The + dialer portion names a dialer to use. The token portion is + what \D and \T in the chat script expand to. If there is no + token for the last dialer, the phone number for the system is + used. */ + ffirst = TRUE; + pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer; + while (*pz != NULL) + { + int iuuconf; + struct uuconf_dialer *q; + struct uuconf_dialer s; + const char *ztoken; + boolean ftranslate; + + if (! ffirst) + q = &s; + else + q = qdialer; + + iuuconf = uuconf_dialer_info (puuconf, *pz, q); + if (iuuconf == UUCONF_NOT_FOUND) + { + ulog (LOG_ERROR, "%s: Dialer not found", *pz); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + ++pz; + ztoken = *pz; + + ftranslate = FALSE; + if (ztoken == NULL + || strcmp (ztoken, "\\D") == 0) + ztoken = zphone; + else if (strcmp (ztoken, "\\T") == 0) + { + ztoken = zphone; + ftranslate = TRUE; + } + + if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate)) + { + (void) uuconf_dialer_free (puuconf, q); + if (! ffirst) + (void) uuconf_dialer_free (puuconf, qdialer); + return FALSE; + } + + if (ffirst) + { + *ptdialerfound = DIALERFOUND_FREE; + ffirst = FALSE; + } + else + (void) uuconf_dialer_free (puuconf, q); + + if (*pz != NULL) + ++pz; + } + + return TRUE; + } + else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL) + { + struct uuconf_dialer *q; + + q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer; + *qdialer = *q; + *ptdialerfound = DIALERFOUND_TRUE; + return fcdo_dial (qconn, puuconf, q, zphone, FALSE); + } + else + { + ulog (LOG_ERROR, "No dialer information"); + return FALSE; + } +} + +/* Actually use a dialer. We set up the modem (which may include + opening the dialer device), run the chat script, and finish dealing + with the modem. */ + +static boolean +fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdial; + const char *zphone; + boolean ftranslate; +{ + const char *zname; + + if (! fsysdep_modem_begin_dial (qconn, qdial)) + return FALSE; + + if (qconn->qport == NULL) + zname = NULL; + else + zname = qconn->qport->uuconf_zname; + + if (! fchat (qconn, puuconf, &qdial->uuconf_schat, + (const struct uuconf_system *) NULL, qdial, + zphone, ftranslate, zname, iconn_baud (qconn))) + return FALSE; + + return fsysdep_modem_end_dial (qconn, qdial); +} diff --git a/gnu/libexec/uucp/common_sources/conn.h b/gnu/libexec/uucp/common_sources/conn.h new file mode 100644 index 00000000000..59d4881b07f --- /dev/null +++ b/gnu/libexec/uucp/common_sources/conn.h @@ -0,0 +1,312 @@ +/* conn.h + Header file for routines which manipulate connections. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#ifndef CONN_H + +#define CONN_H + +#if ANSI_C +/* These structures are used in prototypes but are not defined in this + header file. */ +struct uuconf_system; +struct uuconf_dialer; +struct uuconf_chat; +#endif + +/* This structure represents a connection. */ + +struct sconnection +{ + /* Pointer to command table for this type of connection. */ + const struct sconncmds *qcmds; + /* Pointer to system dependent information. */ + pointer psysdep; + /* Pointer to system independent information. */ + struct uuconf_port *qport; +}; + +/* Whether fconn_dial got a dialer. */ + +enum tdialerfound +{ + /* Did not find a dialer. */ + DIALERFOUND_FALSE, + /* Found a dialer which does not need to be freed. */ + DIALERFOUND_TRUE, + /* Found a dialer which does need to be freed. */ + DIALERFOUND_FREE +}; + +/* Parity settings to pass to fconn_set. */ + +enum tparitysetting +{ + /* Do not change output parity generation. */ + PARITYSETTING_DEFAULT, + /* No parity (all eight output bits used). */ + PARITYSETTING_NONE, + /* Even parity. */ + PARITYSETTING_EVEN, + /* Odd parity. */ + PARITYSETTING_ODD, + /* Mark parity. */ + PARITYSETTING_MARK, + /* Space parity. */ + PARITYSETTING_SPACE +}; + +/* Type of strip control argument to fconn_set. */ + +enum tstripsetting +{ + /* Do not change the stripping of input characters. */ + STRIPSETTING_DEFAULT, + /* Do not strip input characters to seven bits. */ + STRIPSETTING_EIGHTBITS, + /* Strip input characters to seven bits. */ + STRIPSETTING_SEVENBITS +}; + +/* Type of XON/XOFF control argument to fconn_set. */ + +enum txonxoffsetting +{ + /* Do not change XON/XOFF handshake setting. */ + XONXOFF_DEFAULT, + /* Do not do XON/XOFF handshaking. */ + XONXOFF_OFF, + /* Do XON/XOFF handshaking. */ + XONXOFF_ON +}; + +/* A command table holds the functions which implement actions for + each different kind of connection. */ + +struct sconncmds +{ + /* Free up a connection. */ + void (*pufree) P((struct sconnection *qconn)); + /* Lock the connection. The fin argument is TRUE if the connection + is to be used for an incoming call. May be NULL. */ + boolean (*pflock) P((struct sconnection *qconn, boolean fin)); + /* Unlock the connection. May be NULL. */ + boolean (*pfunlock) P((struct sconnection *qconn)); + /* Open the connection. */ + boolean (*pfopen) P((struct sconnection *qconn, long ibaud, + boolean fwait)); + /* Close the connection. */ + boolean (*pfclose) P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); + /* Reset the connection so that another call may be accepted. */ + boolean (*pfreset) P((struct sconnection *qconn)); + /* Dial a number on a connection. This set *qdialer to the dialer + used, if any, and sets *ptdialerfound appropriately. The qsys + and zphone arguments are for the chat script. This field may be + NULL. */ + boolean (*pfdial) P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialerfound)); + /* Read data from a connection, with a timeout in seconds. When + called *pclen is the length of the buffer; on successful return + *pclen is the number of bytes read into the buffer. The cmin + argument is the minimum number of bytes to read before returning + ahead of a timeout. */ + boolean (*pfread) P((struct sconnection *qconn, char *zbuf, size_t *pclen, + size_t cmin, int ctimeout, boolean freport)); + /* Write data to the connection. */ + boolean (*pfwrite) P((struct sconnection *qconn, const char *zbuf, + size_t clen)); + /* Read and write data to the connection. This reads and writes + data until either all passed in data has been written or the read + buffer has been filled. When called *pcread is the size of the + read buffer and *pcwrite is the number of bytes to write; on + successful return *pcread is the number of bytes read and + *pcwrite is the number of bytes written. */ + boolean (*pfio) P((struct sconnection *qconn, const char *zwrite, + size_t *pcwrite, char *zread, size_t *pcread)); + /* Send a break character. This field may be NULL. */ + boolean (*pfbreak) P((struct sconnection *qconn)); + /* Change the connection setting. This field may be NULL. */ + boolean (*pfset) P((struct sconnection *qconn, + enum tparitysetting tparity, + enum tstripsetting tstrip, + enum txonxoffsetting txonxoff)); + /* Require or ignore carrer. This field may be NULL. */ + boolean (*pfcarrier) P((struct sconnection *qconn, + boolean fcarrier)); + /* Run a chat program on a connection. */ + boolean (*pfchat) P((struct sconnection *qconn, char **pzprog)); + /* Get the baud rate of a connection. This field may be NULL. */ + long (*pibaud) P((struct sconnection *qconn)); +}; + +/* Connection functions. */ + +/* Initialize a connection. This must be called before any of the + other connection functions are called. It initializes the fields + of qconn. It returns FALSE on error. */ +extern boolean fconn_init P((struct uuconf_port *qport, + struct sconnection *qconn)); + +/* Free up connection data. */ +extern void uconn_free P((struct sconnection *qconn)); + +/* Lock a connection. The fin argument is TRUE if the port is to be + used for an incoming call; certains type of Unix locking need this + information because they need to open the port. */ +extern boolean fconn_lock P((struct sconnection *qconn, boolean fin)); + +/* Unlock a connection. */ +extern boolean fconn_unlock P((struct sconnection *qconn)); + +/* Open a connection. If ibaud is 0, the natural baud rate of the + port is used. If ihighbaud is not 0, fconn_open chooses the + highest supported baud rate between ibaud and ihighbaud. If fwait + is TRUE, this should wait for an incoming call. */ +extern boolean fconn_open P((struct sconnection *qconn, long ibaud, + long ihighbaud, boolean fwait)); + +/* Close a connection. The fsuccess argument is TRUE if the + conversation completed normally, FALSE if it is being aborted. */ +extern boolean fconn_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); + +/* Reset a connection such that another call may be accepted. */ +extern boolean fconn_reset P((struct sconnection *q)); + +/* Dial out on a connection. The qsys and zphone arguments are for + the chat scripts; zphone is the phone number to dial. If qdialer + is not NULL, *qdialer will be set to the dialer information used if + any; *ptdialerfound will be set appropriately. */ +extern boolean fconn_dial P((struct sconnection *q, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialerfound)); + +/* Read from a connection. + zbuf -- buffer to read bytes into + *pclen on call -- length of zbuf + *pclen on successful return -- number of bytes read + cmin -- minimum number of bytes to read before returning ahead of timeout + ctimeout -- timeout in seconds, 0 if none + freport -- whether to report errors. */ +extern boolean fconn_read P((struct sconnection *qconn, char *zbuf, + size_t *pclen, size_t cmin, + int ctimeout, boolean freport)); + +/* Write to a connection. */ +extern boolean fconn_write P((struct sconnection *qconn, const char *zbuf, + size_t cbytes)); + +/* Read and write to a connection. This reads and writes data until + either all passed-in data has been written or the read buffer is + full. + zwrite -- buffer to write bytes from + *pcwrite on call -- number of bytes to write + *pcwrite on successful return -- number of bytes written + zread -- buffer to read bytes into + *pcread on call -- size of read buffer + *pcread on successful return -- number of bytes read. */ +extern boolean fconn_io P((struct sconnection *qconn, const char *zwrite, + size_t *pcwrite, char *zread, size_t *pcread)); + +/* Send a break character to a connection. */ +extern boolean fconn_break P((struct sconnection *qconn)); + +/* Change the settings of a connection. This allows independent + control over the parity of output characters, whether to strip + input characters, and whether to do XON/XOFF handshaking. There is + no explicit control over parity checking of input characters. This + function returns FALSE on error. Attempts to set values not + supported by the hardware are silently ignored. */ +extern boolean fconn_set P((struct sconnection *qconn, + enum tparitysetting tparity, + enum tstripsetting tstrip, + enum txonxoffsetting txonxoff)); + +/* Get the baud rate of a connection. */ +extern long iconn_baud P((struct sconnection *qconn)); + +/* Do a chat script with a system. */ +extern boolean fchat P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_chat *qchat, + const struct uuconf_system *qsys, + const struct uuconf_dialer *qdialer, + const char *zphone, boolean ftranslate, + const char *zport, long ibaud)); + +/* Tell the connection to either require or ignore carrier as fcarrier + is TRUE or FALSE respectively. This is called with fcarrier TRUE + when \m is encountered in a chat script, and with fcarrier FALSE + when \M is encountered. */ +extern boolean fconn_carrier P((struct sconnection *qconn, + boolean fcarrier)); + +/* Run a chat program on a connection. */ +extern boolean fconn_run_chat P((struct sconnection *qconn, + char **pzprog)); + +/* Dialing out on a modem is partially system independent. This is + the modem dialing routine. */ +extern boolean fmodem_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialerfound)); + +/* Begin dialing out. This should open the dialer device if there is + one, toggle DTR if requested and possible, and tell the port to + ignore carrier. It should return FALSE on error. */ +extern boolean fsysdep_modem_begin_dial P((struct sconnection *qconn, + struct uuconf_dialer *qdial)); + +/* Finish dialing out on a modem. This should close the dialer device + if there is one. If the dialer and the port both support carrier, + the connection should be told to pay attention to carrier. If it + is possible to wait for carrier to come on, and the dialer and the + port both the port support carrier, it should wait until carrier + comes on. */ +extern boolean fsysdep_modem_end_dial P((struct sconnection *qconn, + struct uuconf_dialer *qdial)); + +/* System dependent initialization routines. */ +extern boolean fsysdep_stdin_init P((struct sconnection *qconn)); +extern boolean fsysdep_modem_init P((struct sconnection *qconn)); +extern boolean fsysdep_direct_init P((struct sconnection *qconn)); +#if HAVE_TCP +extern boolean fsysdep_tcp_init P((struct sconnection *qconn)); +#endif +#if HAVE_TLI +extern boolean fsysdep_tli_init P((struct sconnection *qconn)); +#endif + +#endif /* ! defined (CONN_H) */ diff --git a/gnu/libexec/uucp/common_sources/copy.c b/gnu/libexec/uucp/common_sources/copy.c new file mode 100644 index 00000000000..6956bb3d7cf --- /dev/null +++ b/gnu/libexec/uucp/common_sources/copy.c @@ -0,0 +1,202 @@ +/* copy.c + Copy one file to another for the UUCP package. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char copy_rcsid[] = "$Id: copy.c,v 1.1 1993/08/04 19:30:44 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "system.h" +#include "sysdep.h" + +#include <stdio.h> +#include <errno.h> + +/* Copy one file to another. */ + +#if USE_STDIO + +boolean +fcopy_file (zfrom, zto, fpublic, fmkdirs) + const char *zfrom; + const char *zto; + boolean fpublic; + boolean fmkdirs; +{ + FILE *efrom; + boolean fret; + + efrom = fopen (zfrom, BINREAD); + if (efrom == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zfrom, strerror (errno)); + return FALSE; + } + + fret = fcopy_open_file (efrom, zto, fpublic, fmkdirs); + (void) fclose (efrom); + return fret; +} + +boolean +fcopy_open_file (efrom, zto, fpublic, fmkdirs) + FILE *efrom; + const char *zto; + boolean fpublic; + boolean fmkdirs; +{ + FILE *eto; + char ab[8192]; + int c; + + eto = esysdep_fopen (zto, fpublic, FALSE, fmkdirs); + if (eto == NULL) + return FALSE; + + while ((c = fread (ab, sizeof (char), sizeof ab, efrom)) != 0) + { + if (fwrite (ab, sizeof (char), (size_t) c, eto) != c) + { + ulog (LOG_ERROR, "fwrite: %s", strerror (errno)); + (void) fclose (eto); + (void) remove (zto); + return FALSE; + } + } + + if (fclose (eto) != 0) + { + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + (void) remove (zto); + return FALSE; + } + + return TRUE; +} + +#else /* ! USE_STDIO */ + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +boolean +fcopy_file (zfrom, zto, fpublic, fmkdirs) + const char *zfrom; + const char *zto; + boolean fpublic; + boolean fmkdirs; +{ + int ofrom; + boolean fret; + + ofrom = open (zfrom, O_RDONLY | O_NOCTTY, 0); + if (ofrom < 0) + { + ulog (LOG_ERROR, "open (%s): %s", zfrom, strerror (errno)); + return FALSE; + } + + fret = fcopy_open_file (ofrom, zto, fpublic, fmkdirs); + (void) close (ofrom); + return fret; +} + +boolean +fcopy_open_file (ofrom, zto, fpublic, fmkdirs) + int ofrom; + const char *zto; + boolean fpublic; + boolean fmkdirs; +{ + int oto; + char ab[8192]; + int c; + + /* These file mode arguments are from the UNIX version of sysdep.h; + each system dependent header file will need their own + definitions. */ + oto = creat (zto, fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE); + if (oto < 0) + { + if (errno == ENOENT && fmkdirs) + { + if (! fsysdep_make_dirs (zto, fpublic)) + return FALSE; + oto = creat (zto, + fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE); + } + if (oto < 0) + { + ulog (LOG_ERROR, "open (%s): %s", zto, strerror (errno)); + return FALSE; + } + } + + while ((c = read (ofrom, ab, sizeof ab)) > 0) + { + if (write (oto, ab, (size_t) c) != c) + { + ulog (LOG_ERROR, "write: %s", strerror (errno)); + (void) close (oto); + (void) remove (zto); + return FALSE; + } + } + + if (close (oto) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + (void) remove (zto); + return FALSE; + } + + if (c < 0) + { + ulog (LOG_ERROR, "read: %s", strerror (errno)); + (void) remove (zto); + return FALSE; + } + + return TRUE; +} + +#endif /* ! USE_STDIO */ diff --git a/gnu/libexec/uucp/common_sources/cu.h b/gnu/libexec/uucp/common_sources/cu.h new file mode 100644 index 00000000000..5a514ee3bfe --- /dev/null +++ b/gnu/libexec/uucp/common_sources/cu.h @@ -0,0 +1,80 @@ +/* cu.h + Header file for cu. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* The user settable variables supported by cu. */ + +/* The escape character used to introduce a special command. The + escape character is the first character of this string. */ +extern const char *zCuvar_escape; + +/* Whether to delay for a second before printing the host name after + seeing an escape character. */ +extern boolean fCuvar_delay; + +/* The input characters which finish a line. The escape character is + only recognized following one of these characters. */ +extern const char *zCuvar_eol; + +/* Whether to transfer binary data (nonprintable characters other than + newline and tab) when sending a file. If this is FALSE, then + newline is changed to carriage return. */ +extern boolean fCuvar_binary; + +/* A prefix string to use before sending a binary character from a + file; this is only used if fCuvar_binary is TRUE. */ +extern const char *zCuvar_binary_prefix; + +/* Whether to check for echoes of characters sent when sending a file. + This is ignored if fCuvar_binary is TRUE. */ +extern boolean fCuvar_echocheck; + +/* A character to look for after each newline is sent when sending a + file. The character is the first character in this string, except + that a '\0' means that no echo check is done. */ +extern const char *zCuvar_echonl; + +/* The timeout to use when looking for an character. */ +extern int cCuvar_timeout; + +/* The character to use to kill a line if an echo check fails. The + first character in this string is sent. */ +extern const char *zCuvar_kill; + +/* The number of times to try resending a line if the echo check keeps + failing. */ +extern int cCuvar_resend; + +/* The string to send at the end of a file sent with ~>. */ +extern const char *zCuvar_eofwrite; + +/* The string to look for to finish a file received with ~<. For tip + this is a collection of single characters, but I don't want to do + that because it means that there are characters which cannot be + received. */ +extern const char *zCuvar_eofread; + +/* Whether to provide verbose information when sending or receiving a + file. */ +extern boolean fCuvar_verbose; diff --git a/gnu/libexec/uucp/common_sources/getopt.h b/gnu/libexec/uucp/common_sources/getopt.h new file mode 100644 index 00000000000..1a70e027714 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/getopt.h @@ -0,0 +1,120 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + This file was modified slightly by Ian Lance Taylor, November 1992, + for Taylor UUCP. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ian Lance Taylor <ian@airs.com> added the following defines for + Taylor UUCP. This avoids reported conflicts with system getopt + definitions. */ +#define getopt gnu_getopt +#define optarg gnu_optarg +#define optind gnu_optind +#define opterr gnu_opterr + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +enum _argtype +{ + no_argument, + required_argument, + optional_argument +}; + +extern int getopt P((int argc, char *const *argv, const char *shortopts)); +extern int getopt_long P((int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind)); +extern int getopt_long_only P((int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind)); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal P((int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only)); + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/gnu/libexec/uucp/common_sources/log.c b/gnu/libexec/uucp/common_sources/log.c new file mode 100644 index 00000000000..b55ca8b10b9 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/log.c @@ -0,0 +1,699 @@ +/* log.c + Routines to add entries to the log files. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char log_rcsid[] = "$Id: log.c,v 1.1 1993/08/04 19:30:50 jtc Exp $"; +#endif + +#include <errno.h> + +#if ANSI_C +#include <stdarg.h> +#endif + +#if HAVE_TIME_H +#include <time.h> +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* Local functions. */ + +static const char *zldate_and_time P((void)); + +/* Log file name. */ +static const char *zLogfile; + +/* The function to call when a LOG_FATAL error occurs. */ +static void (*pfLfatal) P((void)); + +/* Whether to go to a file. */ +static boolean fLfile; + +/* ID number. */ +static int iLid; + +/* The current user name. */ +static char *zLuser; + +/* The current system name. */ +static char *zLsystem; + +/* The current device name. */ +char *zLdevice; + +/* The open log file. */ +static FILE *eLlog; + +/* Whether we have tried to open the log file. We need this because + we don't want to keep trying to open the log file if we failed the + first time. It can't be static because under HAVE_HDB_LOGGING we + may have to write to various different log files. */ +static boolean fLlog_tried; + +#if DEBUG > 1 +/* Debugging file name. */ +static const char *zLdebugfile; + +/* The open debugging file. */ +static FILE *eLdebug; + +/* Whether we've tried to open the debugging file. */ +static boolean fLdebug_tried; + +/* Whether we've written out any debugging information. */ +static boolean fLdebugging; +#endif + +/* Statistics file name. */ +static const char *zLstatsfile; + +/* The open statistics file. */ +static FILE *eLstats; + +/* Whether we've tried to open the statistics file. */ +static boolean fLstats_tried; + +/* The array of signals. The elements are only set to TRUE by the + default signal handler. They are only set to FALSE if we don't + care whether we got the signal or not. */ +volatile sig_atomic_t afSignal[INDEXSIG_COUNT]; + +/* The array of signals to log. The elements are only set to TRUE by + the default signal handler. They are set to FALSE when the signal + is logged in ulog. This means that if a signal comes in at just + the right time we won't log it (or, rather, we'll log it once + instead of twice), but that is not a catatrophe. */ +volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT]; + +/* Flag that indicates SIGHUP is worth logging. */ +boolean fLog_sighup = TRUE; + +/* Signal names to use when logging signals. */ +static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES; + +/* If not NULL, ulog calls this function before outputting anything. + This is used to support cu. */ +void (*pfLstart) P((void)); + +/* If not NULL, ulog calls this function after outputting everything. + This is used to support cu. */ +void (*pfLend) P((void)); + +/* Set the function to call on a LOG_FATAL error. */ + +void +ulog_fatal_fn (pfn) + void (*pfn) P((void)); +{ + pfLfatal = pfn; +} + +/* Decide whether to send log message to the file or not. */ + +void +ulog_to_file (puuconf, ffile) + pointer puuconf; + boolean ffile; +{ + int iuuconf; + + iuuconf = uuconf_logfile (puuconf, &zLogfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#if DEBUG > 1 + iuuconf = uuconf_debugfile (puuconf, &zLdebugfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); +#endif + + iuuconf = uuconf_statsfile (puuconf, &zLstatsfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + fLfile = ffile; +} + +/* Set the ID number. This will be called by the usysdep_initialize + if there is something sensible to set it to. */ + +void +ulog_id (i) + int i; +{ + iLid = i; +} + +/* Set the user we are making log entries for. The arguments will be + copied into memory. */ + +void +ulog_user (zuser) + const char *zuser; +{ + ubuffree (zLuser); + zLuser = zbufcpy (zuser); +} + +/* Set the system name we are making log entries for. The name is copied + into memory. */ + +void +ulog_system (zsystem) + const char *zsystem; +{ + if (zsystem == NULL + || zLsystem == NULL + || strcmp (zsystem, zLsystem) != 0) + { + ubuffree (zLsystem); + zLsystem = zbufcpy (zsystem); +#if HAVE_HDB_LOGGING + /* Under HDB logging we now must write to a different log file. */ + ulog_close (); +#endif /* HAVE_HDB_LOGGING */ + } +} + +/* Set the device name. This is copied into memory. */ + +void +ulog_device (zdevice) + const char *zdevice; +{ + ubuffree (zLdevice); + zLdevice = zbufcpy (zdevice); +} + +/* Make a log entry. We make a token concession to non ANSI_C systems, + but it clearly won't always work. */ + +#if ! ANSI_C +#undef HAVE_VFPRINTF +#endif + +/*VARARGS2*/ +#if HAVE_VFPRINTF +void +ulog (enum tlog ttype, const char *zmsg, ...) +#else +void +ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j) + enum tlog ttype; + const char *zmsg; +#endif +{ +#if HAVE_VFPRINTF + va_list parg; +#endif + FILE *e, *edebug; + boolean fstart, fend; + const char *zhdr, *zstr; + + /* Log any received signal. We do it this way to avoid calling ulog + from the signal handler. A few routines call ulog to get this + message out with zmsg == NULL. */ + { + static boolean fdoing_sigs; + + if (! fdoing_sigs) + { + int isig; + + fdoing_sigs = TRUE; + for (isig = 0; isig < INDEXSIG_COUNT; isig++) + { + if (afLog_signal[isig]) + { + afLog_signal[isig] = FALSE; + + /* Apparently SunOS sends SIGINT rather than SIGHUP + when hanging up, so we don't log either signal if + fLog_sighup is FALSE. */ + if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT) + || fLog_sighup) + ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]); + } + } + fdoing_sigs = FALSE; + } + } + + if (zmsg == NULL) + return; + +#if DEBUG > 1 + /* If we've had a debugging file open in the past, then we want to + write all log file entries to the debugging file even if it's + currently closed. */ + if (fLfile + && eLdebug == NULL + && ! fLdebug_tried + && (fLdebugging || (int) ttype >= (int) LOG_DEBUG)) + { + fLdebug_tried = TRUE; + eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE); + fLdebugging = TRUE; + } +#endif /* DEBUG > 1 */ + + if (! fLfile) + e = stderr; +#if DEBUG > 1 + else if ((int) ttype >= (int) LOG_DEBUG) + { + e = eLdebug; + + /* If we can't open the debugging file, don't output any + debugging messages. */ + if (e == NULL) + return; + } +#endif /* DEBUG > 1 */ + else + { + if (eLlog == NULL && ! fLlog_tried) + { + fLlog_tried = TRUE; +#if ! HAVE_HDB_LOGGING + eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE); +#else /* HAVE_HDB_LOGGING */ + { + const char *zsys; + char *zfile; + + /* We want to write to .Log/program/system, e.g. + .Log/uucico/uunet. The system name may not be set. */ + if (zLsystem == NULL) + zsys = "ANY"; + else + zsys = zLsystem; + + zfile = zbufalc (strlen (zLogfile) + + strlen (abProgram) + + strlen (zsys) + + 1); + sprintf (zfile, zLogfile, abProgram, zsys); + eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE); + ubuffree (zfile); + } +#endif /* HAVE_HDB_LOGGING */ + + if (eLlog == NULL) + { + /* We can't open the log file. We don't even have a + safe way to report this problem, since we may not be + able to write to stderr (it may, for example, be + attached to the incoming call). */ + if (pfLfatal != NULL) + (*pfLfatal) (); + usysdep_exit (FALSE); + } + } + + e = eLlog; + + /* eLlog might be NULL here because we might try to open the log + file recursively via esysdep_fopen. */ + if (e == NULL) + return; + } + + if (pfLstart != NULL) + (*pfLstart) (); + + edebug = NULL; +#if DEBUG > 1 + if ((int) ttype < (int) LOG_DEBUG) + edebug = eLdebug; +#endif + + fstart = TRUE; + fend = TRUE; + + switch (ttype) + { + case LOG_NORMAL: + zhdr = ""; + break; + case LOG_ERROR: + zhdr = "ERROR: "; + break; + case LOG_FATAL: + zhdr = "FATAL: "; + break; +#if DEBUG > 1 + case LOG_DEBUG: + zhdr = "DEBUG: "; + break; + case LOG_DEBUG_START: + zhdr = "DEBUG: "; + fend = FALSE; + break; + case LOG_DEBUG_CONTINUE: + zhdr = NULL; + fstart = FALSE; + fend = FALSE; + break; + case LOG_DEBUG_END: + zhdr = NULL; + fstart = FALSE; + break; +#endif + default: + zhdr = "???: "; + break; + } + + if (fstart) + { + if (! fLfile) + { + fprintf (e, "%s: ", abProgram); + if (edebug != NULL) + fprintf (edebug, "%s: ", abProgram); + } + else + { +#if HAVE_TAYLOR_LOGGING + fprintf (e, "%s ", abProgram); + if (edebug != NULL) + fprintf (edebug, "%s ", abProgram); +#else /* ! HAVE_TAYLOR_LOGGING */ + fprintf (e, "%s ", zLuser == NULL ? "uucp" : zLuser); + if (edebug != NULL) + fprintf (edebug, "%s ", zLuser == NULL ? "uucp" : zLuser); +#endif /* HAVE_TAYLOR_LOGGING */ + + fprintf (e, "%s ", zLsystem == NULL ? "-" : zLsystem); + if (edebug != NULL) + fprintf (edebug, "%s ", zLsystem == NULL ? "-" : zLsystem); + +#if HAVE_TAYLOR_LOGGING + fprintf (e, "%s ", zLuser == NULL ? "-" : zLuser); + if (edebug != NULL) + fprintf (edebug, "%s ", zLuser == NULL ? "-" : zLuser); +#endif /* HAVE_TAYLOR_LOGGING */ + + zstr = zldate_and_time (); + fprintf (e, "(%s", zstr); + if (edebug != NULL) + fprintf (edebug, "(%s", zstr); + + if (iLid != 0) + { +#if ! HAVE_HDB_LOGGING +#if HAVE_TAYLOR_LOGGING + fprintf (e, " %d", iLid); + if (edebug != NULL) + fprintf (edebug, " %d", iLid); +#else /* ! HAVE_TAYLOR_LOGGING */ + fprintf (e, "-%d", iLid); + if (edebug != NULL) + fprintf (edebug, "-%d", iLid); +#endif /* ! HAVE_TAYLOR_LOGGING */ +#else /* HAVE_HDB_LOGGING */ + + /* I assume that the second number here is meant to be + some sort of file sequence number, and that it should + correspond to the sequence number in the statistics + file. I don't have any really convenient way to do + this, so I won't unless somebody thinks it's very + important. */ + fprintf (e, ",%d,%d", iLid, 0); + if (edebug != NULL) + fprintf (edebug, ",%d,%d", iLid, 0); +#endif /* HAVE_HDB_LOGGING */ + } + + fprintf (e, ") "); + if (edebug != NULL) + fprintf (edebug, ") "); + + fprintf (e, "%s", zhdr); + if (edebug != NULL) + fprintf (edebug, "%s", zhdr); + } + } + +#if HAVE_VFPRINTF + va_start (parg, zmsg); + vfprintf (e, zmsg, parg); + va_end (parg); + if (edebug != NULL) + { + va_start (parg, zmsg); + vfprintf (edebug, zmsg, parg); + va_end (parg); + } +#else /* ! HAVE_VFPRINTF */ + fprintf (e, zmsg, a, b, c, d, f, g, h, i, j); + if (edebug != NULL) + fprintf (edebug, zmsg, a, b, c, d, f, g, h, i, j); +#endif /* ! HAVE_VFPRINTF */ + + if (fend) + { + fprintf (e, "\n"); + if (edebug != NULL) + fprintf (edebug, "\n"); + } + + (void) fflush (e); + if (edebug != NULL) + (void) fflush (edebug); + + if (pfLend != NULL) + (*pfLend) (); + + if (ttype == LOG_FATAL) + { + if (pfLfatal != NULL) + (*pfLfatal) (); + usysdep_exit (FALSE); + } + +#if CLOSE_LOGFILES + ulog_close (); +#endif +} + +/* Log a uuconf error. */ + +void +ulog_uuconf (ttype, puuconf, iuuconf) + enum tlog ttype; + pointer puuconf; + int iuuconf; +{ + char ab[512]; + + (void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab); + ulog (ttype, "%s", ab); +} + +/* Close the log file. There's nothing useful we can do with errors, + so we don't check for them. */ + +void +ulog_close () +{ + /* Make sure we logged any signal we received. */ + ulog (LOG_ERROR, (const char *) NULL); + + if (eLlog != NULL) + { + (void) fclose (eLlog); + eLlog = NULL; + fLlog_tried = FALSE; + } + +#if DEBUG > 1 + if (eLdebug != NULL) + { + (void) fclose (eLdebug); + eLdebug = NULL; + fLdebug_tried = FALSE; + } +#endif +} + +/* Add an entry to the statistics file. We may eventually want to put + failed file transfers in here, but we currently do not. */ + +/*ARGSUSED*/ +void +ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster) + boolean fsucceeded; + const char *zuser; + const char *zsystem; + boolean fsent; + long cbytes; + long csecs; + long cmicros; + boolean fmaster; +{ + long cbps; + + /* The seconds and microseconds are now counted independently, so + they may be out of synch. */ + if (cmicros < 0) + { + csecs -= ((- cmicros) / 1000000L) + 1; + cmicros = 1000000L - ((- cmicros) % 1000000L); + } + if (cmicros >= 1000000L) + { + csecs += cmicros / 10000000L; + cmicros = cmicros % 1000000L; + } + + /* On a system which can determine microseconds we might very well + have both csecs == 0 and cmicros == 0. */ + if (csecs == 0 && cmicros < 1000) + cbps = 0; + else + { + long cmillis; + + /* This computation will not overflow provided csecs < 2147483 + and cbytes and cbps both fit in a long. */ + cmillis = csecs * 1000 + cmicros / 1000; + cbps = ((cbytes / cmillis) * 1000 + + ((cbytes % cmillis) * 1000) / cmillis); + } + + if (eLstats == NULL) + { + if (fLstats_tried) + return; + fLstats_tried = TRUE; + eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE); + if (eLstats == NULL) + return; + } + +#if HAVE_TAYLOR_LOGGING + fprintf (eLstats, + "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec)\n", + zuser, zsystem, zldate_and_time (), + fsucceeded ? "" : "failed after ", + fsent ? "sent" : "received", + cbytes, csecs, cmicros / 1000, cbps); +#endif /* HAVE_TAYLOR_LOGGING */ +#if HAVE_V2_LOGGING + fprintf (eLstats, + "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n", + zuser, zsystem, zldate_and_time (), + (long) time ((time_t *) NULL), + fsent ? "sent" : "received", + fsucceeded ? "data" : "failed after", + cbytes, csecs + cmicros / 500000); +#endif /* HAVE_V2_LOGGING */ +#if HAVE_HDB_LOGGING + { + static int iseq; + + /* I don't know what the 'C' means. The sequence number should + probably correspond to the sequence number in the log file, but + that is currently always 0; using this fake sequence number + will still at least reveal which transfers are from different + calls. We don't report a failed data transfer with this + format. */ + if (! fsucceeded) + return; + ++iseq; + fprintf (eLstats, + "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld %s\n", + zsystem, zuser, fmaster ? 'M' : 'S', zldate_and_time (), + iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice, + fsent ? "->" : "<-", + cbytes, csecs, cmicros / 1000, cbps, + "bytes/sec"); + } +#endif /* HAVE_HDB_LOGGING */ + + (void) fflush (eLstats); + +#if CLOSE_LOGFILES + ustats_close (); +#endif +} + +/* Close the statistics file. */ + +void +ustats_close () +{ + if (eLstats != NULL) + { + if (fclose (eLstats) != 0) + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + eLstats = NULL; + fLstats_tried = FALSE; + } +} + +/* Return the date and time in a form used for a log entry. */ + +static const char * +zldate_and_time () +{ + long isecs, imicros; + struct tm s; +#if HAVE_TAYLOR_LOGGING + static char ab[sizeof "1991-12-31 12:00:00.00"]; +#endif +#if HAVE_V2_LOGGING + static char ab[sizeof "12/31-12:00"]; +#endif +#if HAVE_HDB_LOGGING + static char ab[sizeof "12/31-12:00:00"]; +#endif + + isecs = ixsysdep_time (&imicros); + usysdep_localtime (isecs, &s); + +#if HAVE_TAYLOR_LOGGING + sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d", + s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour, + s.tm_min, s.tm_sec, (int) (imicros / 10000)); +#endif +#if HAVE_V2_LOGGING + sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday, + s.tm_hour, s.tm_min); +#endif +#if HAVE_HDB_LOGGING + sprintf (ab, "%d/%d-%02d:%02d:%02d", s.tm_mon + 1, s.tm_mday, + s.tm_hour, s.tm_min, s.tm_sec); +#endif + + return ab; +} diff --git a/gnu/libexec/uucp/common_sources/policy.h b/gnu/libexec/uucp/common_sources/policy.h new file mode 100644 index 00000000000..f79942915de --- /dev/null +++ b/gnu/libexec/uucp/common_sources/policy.h @@ -0,0 +1,521 @@ +/* policy.h + Configuration file for policy decisions. To be edited on site. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* This header file contains macro definitions which must be set by + each site before compilation. The first few are system + characteristics that can not be easily discovered by the + configuration script. Most are configuration decisions that must + be made by the local administrator. */ + +/* System characteristics. */ + +/* This code tries to use several ANSI C features, including + prototypes, stdarg.h, the const qualifier and the types void + (including void * pointers) and unsigned char. By default it will + use these features if the compiler defines __STDC__. If your + compiler supports these features but does not define __STDC__, you + should set ANSI_C to 1. If your compiler does not support these + features but defines __STDC__ (no compiler should do this, in my + opinion), you should set ANSI_C to 0. In most cases (or if you're + not sure) just leave the line below commented out. */ +/* #define ANSI_C 1 */ + +/* Set USE_STDIO to 1 if data files should be read using the stdio + routines (fopen, fread, etc.) rather than the UNIX unbuffered I/O + calls (open, read, etc.). Unless you know your stdio is really + rotten, you should leave this as 1. */ +#define USE_STDIO 1 + +/* Exactly one of the following macros must be set to 1. Many modern + systems support more than one of these choices through some form of + compilation environment, in which case the setting will depend on + the compilation environment you use. If you have a reasonable + choice between options, I suspect that TERMIO or TERMIOS will be + more efficient than TTY, but I have not done any head to head + comparisons. + + If you don't set any of these macros, the code below will guess. + It will doubtless be wrong on some systems. + + HAVE_BSD_TTY -- Use the 4.2BSD tty routines + HAVE_SYSV_TERMIO -- Use the System V termio routines + HAVE_POSIX_TERMIOS -- Use the POSIX termios routines + */ +#define HAVE_BSD_TTY 0 +#define HAVE_SYSV_TERMIO 0 +#define HAVE_POSIX_TERMIOS 1 + +/* This code tries to guess which terminal driver to use if you did + not make a choice above. It is in this file to make it easy to + figure out what's happening if something goes wrong. */ + +#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS == 0 +#if HAVE_CBREAK +#undef HAVE_BSD_TTY +#define HAVE_BSD_TTY 1 +#else +#undef HAVE_SYSV_TERMIO +#define HAVE_SYSV_TERMIO 1 +#endif +#endif + +/* On some systems a write to a serial port will block even if the + file descriptor has been set to not block. File transfer can be + more efficient if the package knows that a write to the serial port + will not block; however, if the write does block unexpectedly then + data loss is possible at high speeds. + + If writes to a serial port always block even when requested not to, + you should set HAVE_UNBLOCKED_WRITES to 0; otherwise you should set + it to 1. In general on System V releases without STREAMS-based + ttys (e.g., before SVR4) HAVE_UNBLOCKED_WRITES should be 0 and on + BSD or SVR4 it should be 1. + + If HAVE_UNBLOCKED_WRITES is set to 1 when it should be 0 you may + see an unexpectedly large number of transmission errors, or, if you + have hardware handshaking, transfer times may be lower than + expected (but then, they always are). If HAVE_UNBLOCKED_WRITES is + set to 0 when it should be 1, file transfer will use more CPU time + than necessary. If you are unsure, setting HAVE_UNBLOCKED_WRITES + to 0 should always be safe. */ +#define HAVE_UNBLOCKED_WRITES 1 + +/* When the code does do a blocking write, it wants to write the + largest amount of data which the kernel will accept as a single + unit. On BSD this is typically the value of OBUFSIZ in + <sys/tty.h>, usually 100. On System V before SVR4 this is + typically the size of a clist, CLSIZE in <sys/tty.h>, which is + usually 64. On SVR4, which uses STREAMS-based ttys, 2048 is + reasonable. Define SINGLE_WRITE to the correct value for your + system. If SINGLE_WRITE is too large, data loss may occur. If + SINGLE_WRITE is too small, file transfer will use more CPU time + than necessary. If you have no idea, 64 should work on most modern + systems. */ +#define SINGLE_WRITE 100 + +/* Some tty drivers, such as those from SCO and AT&T's Unix PC, have a + bug in the implementation of ioctl() that causes CLOCAL to be + ineffective until the port is opened a second time. If + HAVE_CLOCAL_BUG is set to 1, code will be added to do this second + open on the port. Set this if you are getting messages that say + "Line disconnected" while in the dial chat script after only + writing the first few characters to the port. This bug causes the + resetting of CLOCAL to have no effect, so the "\m" (require + carrier) escape sequence won't function properly in dialer chat + scripts. */ +#define HAVE_CLOCAL_BUG 0 + +/* On some systems, such as SCO Xenix, resetting DTR on a port + apparently prevents getty from working on the port, and thus + prevents anybody from dialing in. If HAVE_RESET_BUG is set to 1, + DTR will not be reset when a serial port is closed. */ +#define HAVE_RESET_BUG 0 + +/* The Sony NEWS reportedly handles no parity by clearing both the odd + and even parity bits in the sgtty structure, unlike most BSD based + systems in which no parity is indicated by setting both the odd and + even parity bits. Setting HAVE_PARITY_BUG to 1 will handle this + correctly. */ +#define HAVE_PARITY_BUG 0 + +#if HAVE_BSD_TTY +#ifdef sony +#undef HAVE_PARITY_BUG +#define HAVE_PARITY_BUG 1 +#endif +#endif + +/* On Ultrix 4.0, at least, setting CBREAK causes input characters to + be stripped, regardless of the setting of LPASS8 and LLITOUT. This + can be worked around by using the termio call to reset ISTRIP. + This probably does not apply to any other operating system. + Setting HAVE_STRIP_BUG to 1 will use this workaround. */ +#define HAVE_STRIP_BUG 0 + +#if HAVE_BSD_TTY +#ifdef ultrix +#undef HAVE_STRIP_BUG +#define HAVE_STRIP_BUG 1 +#endif +#endif + +/* TIMES_TICK is the fraction of a second which times(2) returns (for + example, if times returns 100ths of a second TIMES_TICK should be + set to 100). On a true POSIX system (one which has the sysconf + function and also has _SC_CLK_TCK defined in <unistd.h>) TIMES_TICK + may simply be left as 0. On some systems the environment variable + HZ is what you want for TIMES_TICK, but on some other systems HZ + has the wrong value; check the man page. If you leave this set to + 0, the code will try to guess; it will doubtless be wrong on some + non-POSIX systems. If TIMES_TICK is wrong the code may report + incorrect file transfer times in the statistics file, but on many + systems times(2) will actually not be used and this value will not + matter at all. */ +#define TIMES_TICK 0 + +/* If your system does not support saved set user ID, set + HAVE_SAVED_SETUID to 0. However, this is ignored if your system + has the setreuid function. Most modern Unixes have one or the + other. If your system has the setreuid function, don't worry about + this define, or about the following discussion. + + If you set HAVE_SAVED_SETUID to 0, you will not be able to use uucp + to transfer files that the uucp user can not read. Basically, you + will only be able to use uucp on world-readable files. If you set + HAVE_SAVED_SETUID to 1, but your system does not have saved set + user ID, uucp will fail with an error message whenever anybody + other than the uucp user uses it. */ +#define HAVE_SAVED_SETUID 1 + +/* On some systems, such as the DG Aviion and, possibly, the RS/6000, + the setreuid function is broken. It should be possible to use + setreuid to swap the real and effective user ID's, but on some + systems it will not change the real user ID (I believe this is due + to a misreading of the POSIX standard). On such a system you must + set HAVE_BROKEN_SETREUID to 1; if you do not, you will get error + messages from setreuid. Systems on which setreuid exists but is + broken pretty much always have saved setuid. */ +#define HAVE_BROKEN_SETREUID 0 + +/* On the 3B2, and possibly other systems, nap takes an argument in + hundredths of a second rather than milliseconds. I don't know of + any way to test for this. Set HAVE_HUNDREDTHS_NAP to 1 if this is + true on your system. This does not matter if your system does not + have the nap function. */ +#define HAVE_HUNDREDTHS_NAP 0 + +/* Set PS_PROGRAM to the program to run to get a process status, + including the arguments to pass it. This is used by ``uustat -p''. + Set HAVE_PS_MULTIPLE to 1 if a comma separated list of process + numbers may be appended (e.g. ``ps -flp1,10,100''). Otherwise ps + will be invoked several times, with a single process number append + each time. The default definitions should work on most systems, + although some (such as the NeXT) will complain about the 'p' + option; for those, use the second set of definitions. The third + set of definitions are appropriate for System V. To use the second + or third set of definitions, change the ``#if 1'' to ``#if 0'' and + change the appropriate ``#if 0'' to ``#if 1''. */ +#if 1 +#define PS_PROGRAM "/bin/ps -lp" +#define HAVE_PS_MULTIPLE 0 +#endif +#if 0 +#define PS_PROGRAM "/bin/ps -l" +#define HAVE_PS_MULTIPLE 0 +#endif +#if 0 +#define PS_PROGRAM "/bin/ps -flp" +#define HAVE_PS_MULTIPLE 1 +#endif + +/* If you use other programs that also lock devices, such as cu or + uugetty, the other programs and UUCP must agree on whether a device + is locked. This is typically done by creating a lock file in a + specific directory; the lock files are generally named + LCK..something or LK.something. If the LOCKDIR macro is defined, + these lock files will be placed in the named directory; otherwise + they will be placed in the default spool directory. On some HDB + systems the lock files are placed in /etc/locks. On some they are + placed in /usr/spool/locks. On the NeXT they are placed in + /usr/spool/uucp/LCK. */ +/* #define LOCKDIR "/usr/spool/uucp" */ +/* #define LOCKDIR "/etc/locks" */ +/* #define LOCKDIR "/usr/spool/locks" */ +/* #define LOCKDIR "/usr/spool/uucp/LCK" */ +#define LOCKDIR "/var/spool/lock" + +/* You must also specify the format of the lock files by setting + exactly one of the following macros to 1. Check an existing lock + file to decide which of these choices is more appropriate. + + The HDB style is to write the locking process ID in ASCII, passed + to ten characters, followed by a newline. + + The V2 style is to write the locking process ID as four binary + bytes in the host byte order. Many BSD derived systems use this + type of lock file, including the NeXT. + + SCO lock files are similar to HDB lock files, but always lock the + lowercase version of the tty (i.e., LCK..tty2a is created if you + are locking tty2A). They are appropriate if you are using Taylor + UUCP on an SCO Unix, SCO Xenix, or SCO Open Desktop system. + + SVR4 lock files are also similar to HDB lock files, but they use a + different naming convention. The filenames are LK.xxx.yyy.zzz, + where xxx is the major device number of the device holding the + special device file, yyy is the major device number of the port + device itself, and zzz is the minor device number of the port + device. + + Coherent use a completely different method of terminal locking. + See unix/cohtty for details. For locks other than for terminals, + HDB type lock files are used. */ +#define HAVE_V2_LOCKFILES 0 +#define HAVE_HDB_LOCKFILES 1 +#define HAVE_SCO_LOCKFILES 0 +#define HAVE_SVR4_LOCKFILES 0 +#define HAVE_COHERENT_LOCKFILES 0 + +/* If your system supports Internet mail addresses (which look like + user@host.domain rather than system!user), HAVE_INTERNET_MAIL + should be set to 1. This is checked by uuxqt when sending error + (or success, if requested) notifications to the person who + submitted the job. */ +#define HAVE_INTERNET_MAIL 1 + +/* Adminstrative decisions. */ + +/* Set USE_RCS_ID to 1 if you want the RCS ID strings compiled into + the executable. Leaving them out will decrease the executable + size. Leaving them in will make it easier to determine which + version you are running. */ +#define USE_RCS_ID 1 + +/* DEBUG controls how much debugging information is compiled into the + code. If DEBUG is defined as 0, no sanity checks will be done and + no debugging messages will be compiled in. If DEBUG is defined as + 1 sanity checks will be done but there will still be no debugging + messages. If DEBUG is 2 than debugging messages will be compiled + in. When initially testing, DEBUG should be 2, and you should + probably leave it at 2 unless a small reduction in the executable + file size will be very helpful. */ +#define DEBUG 2 + +/* Set the default grade to use for a uucp command if the -g option is + not used. The grades, from highest to lowest, are 0 to 9, A to Z, + a to z. */ +#define BDEFAULT_UUCP_GRADE ('N') + +/* Set the default grade to use for a uux command if the -g option is + not used. */ +#define BDEFAULT_UUX_GRADE ('N') + +/* To compile in use of the new style of configuration files described + in the documentation, set HAVE_TAYLOR_CONFIG to 1. */ +#define HAVE_TAYLOR_CONFIG 1 + +/* To compile in use of V2 style configuration files (L.sys, L-devices + and so on), set HAVE_V2_CONFIG to 1. To compile in use of HDB + style configuration files (Systems, Devices and so on) set + HAVE_HDB_CONFIG to 1. The files will be looked up in the + oldconfigdir directory as defined in the Makefile. + + You may set any or all of HAVE_TAYLOR_CONFIG, HAVE_V2_CONFIG and + HAVE_HDB_CONFIG to 1 (you must set at least one of the macros). + When looking something up (a system, a port, etc.) the new style + configuration files will be read first, followed by the V2 + configuration files, followed by the HDB configuration files. */ +#define HAVE_V2_CONFIG 0 +#define HAVE_HDB_CONFIG 0 + +/* Exactly one of the following macros must be set to 1. The exact + format of the spool directories is explained in unix/spool.c. + + SPOOLDIR_V2 -- Use a Version 2 (original UUCP) style spool directory + SPOOLDIR_BSD42 -- Use a BSD 4.2 style spool directory + SPOOLDIR_BSD43 -- Use a BSD 4.3 style spool directory + SPOOLDIR_HDB -- Use a HDB (BNU) style spool directory + SPOOLDIR_ULTRIX -- Use an Ultrix style spool directory + SPOOLDIR_SVR4 -- Use a System V Release 4 spool directory + SPOOLDIR_TAYLOR -- Use a new style spool directory + + If you are not worried about compatibility with a currently running + UUCP, use SPOOLDIR_TAYLOR. */ +#define SPOOLDIR_V2 0 +#define SPOOLDIR_BSD42 0 +#define SPOOLDIR_BSD43 0 +#define SPOOLDIR_HDB 0 +#define SPOOLDIR_ULTRIX 0 +#define SPOOLDIR_SVR4 0 +#define SPOOLDIR_TAYLOR 1 + +/* You must select which type of logging you want by setting exactly + one of the following to 1. These control output to the log file + and to the statistics file. + + If you define HAVE_TAYLOR_LOGGING, each line in the log file will + look something like this: + + uucico uunet uucp (1991-12-10 09:04:34.45 16390) Receiving uunet/D./D.uunetSwJ72 + + and each line in the statistics file will look something like this: + + uucp uunet (1991-12-10 09:04:40.20) received 2371 bytes in 5 seconds (474 bytes/sec) + + If you define HAVE_V2_LOGGING, each line in the log file will look + something like this: + + uucico uunet uucp (12/10-09:04 16390) Receiving uunet/D./D.uunetSwJ72 + + and each line in the statistics file will look something like this: + + uucp uunet (12/10-09:04 16390) (692373862) received data 2371 bytes 5 seconds + + If you define HAVE_HDB_LOGGING, each program will by default use a + separate log file. For uucico talking to uunet, for example, it + will be /usr/spool/uucp/.Log/uucico/uunet. Each line will look + something like this: + + uucp uunet (12/10-09:04:22,16390,1) Receiving uunet/D./D.uunetSwJ72 + + and each line in the statistics file will look something like this: + + uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, 474 bytes/sec + + The main reason to prefer one format over another is that you may + have shell scripts which expect the files to have a particular + format. If you have none, choose whichever format you find more + appealing. */ +#define HAVE_TAYLOR_LOGGING 1 +#define HAVE_V2_LOGGING 0 +#define HAVE_HDB_LOGGING 0 + +/* If you would like the log, debugging and statistics files to be + closed after each message, set CLOSE_LOGFILES to 1. This will + permit the log files to be easily moved. If a log file does not + exist when a new message is written out, it will be created. + Setting CLOSE_LOGFILES to 1 will obviously require slightly more + processing time. */ +#define CLOSE_LOGFILES 0 + +/* The name of the default spool directory. If HAVE_TAYLOR_CONFIG is + set to 1, this may be overridden by the ``spool'' command in the + configuration file. */ +#define SPOOLDIR "/var/spool/uucp" + +/* The name of the default public directory. If HAVE_TAYLOR_CONFIG is + set to 1, this may be overridden by the ``pubdir'' command in the + configuration file. Also, a particular system may be given a + specific public directory by using the ``pubdir'' command in the + system file. */ +#define PUBDIR "/var/spool/uucppublic" + +/* The default command path. This is a space separated list of + directories. Remote command executions requested by uux are looked + up using this path. If you are using HAVE_TAYLOR_CONFIG, the + command path may be overridden for a particular system. For most + systems, you should just make sure that the programs rmail and + rnews can be found using this path. */ +#define CMDPATH "/bin /usr/bin /usr/local/bin" + +/* The default amount of free space to require for systems that do not + specify an amount with the ``free-space'' command. This is only + used when talking to another instance of Taylor UUCP; if accepting + a file would not leave at least this many bytes free on the disk, + it will be refused. */ +#define DEFAULT_FREE_SPACE (50000) + +/* While a file is being received, Taylor UUCP will periodically check + to see if there is enough free space remaining on the disk. If + there is not enough space available on the disk (as determined by + DEFAULT_FREE_SPACE, above, or the ``free-space'' command for the + system) the communication will be aborted. The disk will be + checked each time FREE_SPACE_DELTA bytes are received. Lower + values of FREE_SPACE_DELTA are less likely to fill up the disk, but + will also waste more time checking the amount of free space. To + avoid checking the disk while the file is being received, set + FREE_SPACE_DELTA to 0. */ +#define FREE_SPACE_DELTA (10240) + +/* It is possible for an execute job to request to be executed using + sh(1), rather than execve(2). This is such a security risk, it is + being disabled by default; to allow such jobs, set the following + macro to 1. */ +#define ALLOW_SH_EXECUTION 0 + +/* If a command executed on behalf of a remote system takes a filename + as an argument, a security breach may be possible (note that on my + system neither of the default commands, rmail and rnews, take + filename arguments). If you set ALLOW_FILENAME_ARGUMENTS to 0, all + arguments to a command will be checked; if any argument + 1) starts with ../ + 2) contains the string /../ + 3) begins with a / but does not name a file that may be sent or + received (according to the specified ``remote-send'' and + ``remote-receive'') + the command will be rejected. By default, any argument is + permitted. */ +#define ALLOW_FILENAME_ARGUMENTS 1 + +#if HAVE_TAYLOR_LOGGING + +/* The default log file when using HAVE_TAYLOR_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile'' + command in the configuration file. */ +#define LOGFILE "/var/spool/uucp/Log" + +/* The default statistics file when using HAVE_TAYLOR_LOGGING. When + using HAVE_TAYLOR_CONFIG, this may be overridden by the + ``statfile'' command in the configuration file. */ +#define STATFILE "/var/spool/uucp/Stats" + +/* The default debugging file when using HAVE_TAYLOR_LOGGING. When + using HAVE_TAYLOR_CONFIG, this may be overridden by the + ``debugfile'' command in the configuration file. */ +#define DEBUGFILE "/var/spool/uucp/Debug" + +#endif /* HAVE_TAYLOR_LOGGING */ + +#if HAVE_V2_LOGGING + +/* The default log file when using HAVE_V2_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile'' + command in the configuration file. */ +#define LOGFILE "/var/spool/uucp/LOGFILE" + +/* The default statistics file when using HAVE_V2_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile'' + command in the configuration file. */ +#define STATFILE "/var/spool/uucp/SYSLOG" + +/* The default debugging file when using HAVE_V2_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile'' + command in the configuration file. */ +#define DEBUGFILE "/var/spool/uucp/DEBUG" + +#endif /* HAVE_V2_LOGGING */ + +#if HAVE_HDB_LOGGING + +/* The default log file when using HAVE_HDB_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile'' + command in the configuration file. The first %s in the string will + be replaced by the program name (e.g. uucico); the second %s will + be replaced by the system name (if there is no appropriate system, + "ANY" will be used). No other '%' character may appear in the + string. */ +#define LOGFILE "/var/spool/uucp/.Log/%s/%s" + +/* The default statistics file when using HAVE_HDB_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile'' + command in the configuration file. */ +#define STATFILE "/var/spool/uucp/.Admin/xferstats" + +/* The default debugging file when using HAVE_HDB_LOGGING. When using + HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile'' + command in the configuration file. */ +#define DEBUGFILE "/var/spool/uucp/.Admin/audit.local" + +#endif /* HAVE_HDB_LOGGING */ diff --git a/gnu/libexec/uucp/common_sources/prot.c b/gnu/libexec/uucp/common_sources/prot.c new file mode 100644 index 00000000000..4cc224ef0f9 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/prot.c @@ -0,0 +1,237 @@ +/* prot.c + Protocol support routines to move commands and data around. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char prot_rcsid[] = "$Id: prot.c,v 1.1 1993/08/04 19:30:55 jtc Exp $"; +#endif + +#include <errno.h> + +#include "uudefs.h" +#include "system.h" +#include "conn.h" +#include "prot.h" + +/* Variables visible to the protocol-specific routines. */ + +/* Buffer to hold received data. */ +char abPrecbuf[CRECBUFLEN]; + +/* Index of start of data in abPrecbuf. */ +int iPrecstart; + +/* Index of end of data (first byte not included in data) in abPrecbuf. */ +int iPrecend; + +/* We want to output and input at the same time, if supported on this + machine. If we have something to send, we send it all while + accepting a large amount of data. Once we have sent everything we + look at whatever we have received. If data comes in faster than we + can send it, we may run out of buffer space. */ + +boolean +fsend_data (qconn, zsend, csend, fdoread) + struct sconnection *qconn; + const char *zsend; + size_t csend; + boolean fdoread; +{ + if (! fdoread) + return fconn_write (qconn, zsend, csend); + + while (csend > 0) + { + size_t crec, csent; + + if (iPrecend < iPrecstart) + crec = iPrecstart - iPrecend - 1; + else + { + crec = CRECBUFLEN - iPrecend; + if (iPrecstart == 0) + --crec; + } + + csent = csend; + + if (! fconn_io (qconn, zsend, &csent, abPrecbuf + iPrecend, &crec)) + return FALSE; + + csend -= csent; + zsend += csent; + + iPrecend = (iPrecend + crec) % CRECBUFLEN; + } + + return TRUE; +} + +/* Read data from the other system when we have nothing to send. The + argument cneed is the amount of data the caller wants, and ctimeout + is the timeout in seconds. The function sets *pcrec to the amount + of data which was actually received, which may be less than cneed + if there isn't enough room in the receive buffer. If no data is + received before the timeout expires, *pcrec will be returned as 0. + If an error occurs, the function returns FALSE. If the freport + argument is FALSE, no error should be reported. */ + +boolean +freceive_data (qconn, cneed, pcrec, ctimeout, freport) + struct sconnection *qconn; + size_t cneed; + size_t *pcrec; + int ctimeout; + boolean freport; +{ + /* Set *pcrec to the maximum amount of data we can read. fconn_read + expects *pcrec to be the buffer size, and sets it to the amount + actually received. */ + if (iPrecend < iPrecstart) + *pcrec = iPrecstart - iPrecend - 1; + else + { + *pcrec = CRECBUFLEN - iPrecend; + if (iPrecstart == 0) + --(*pcrec); + } + +#if DEBUG > 0 + /* If we have no room in the buffer, we're in trouble. The + protocols must be written to ensure that this can't happen. */ + if (*pcrec == 0) + ulog (LOG_FATAL, "freceive_data: No room in buffer"); +#endif + + /* If we don't have room for all the data the caller wants, we + simply have to expect less. We'll get the rest later. */ + if (*pcrec < cneed) + cneed = *pcrec; + + if (! fconn_read (qconn, abPrecbuf + iPrecend, pcrec, cneed, ctimeout, + freport)) + return FALSE; + + iPrecend = (iPrecend + *pcrec) % CRECBUFLEN; + + return TRUE; +} + +/* Read a single character. Get it out of the receive buffer if it's + there, otherwise ask freceive_data for at least one character. + This is used because as a protocol is shutting down freceive_data + may read ahead and eat characters that should be read outside the + protocol routines. We call freceive_data rather than fconn_read + with an argument of 1 so that we can get all the available data in + a single system call. The ctimeout argument is the timeout in + seconds; the freport argument is FALSE if no error should be + reported. This returns a character, or -1 on timeout or -2 on + error. */ + +int +breceive_char (qconn, ctimeout, freport) + struct sconnection *qconn; + int ctimeout; + boolean freport; +{ + char b; + + if (iPrecstart == iPrecend) + { + size_t crec; + + if (! freceive_data (qconn, sizeof (char), &crec, ctimeout, freport)) + return -2; + if (crec == 0) + return -1; + } + + b = abPrecbuf[iPrecstart]; + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + return BUCHAR (b); +} + +/* Send mail about a file transfer. We send to the given mailing + address if there is one, otherwise to the user. */ + +boolean +fmail_transfer (fsuccess, zuser, zmail, zwhy, zfromfile, zfromsys, + ztofile, ztosys, zsaved) + boolean fsuccess; + const char *zuser; + const char *zmail; + const char *zwhy; + const char *zfromfile; + const char *zfromsys; + const char *ztofile; + const char *ztosys; + const char *zsaved; +{ + const char *zsendto; + const char *az[20]; + int i; + + if (zmail != NULL && *zmail != '\0') + zsendto = zmail; + else + zsendto = zuser; + + i = 0; + az[i++] = "The file\n\t"; + if (zfromsys != NULL) + { + az[i++] = zfromsys; + az[i++] = "!"; + } + az[i++] = zfromfile; + if (fsuccess) + az[i++] = "\nwas successfully transferred to\n\t"; + else + az[i++] = "\ncould not be transferred to\n\t"; + if (ztosys != NULL) + { + az[i++] = ztosys; + az[i++] = "!"; + } + az[i++] = ztofile; + az[i++] = "\nas requested by\n\t"; + az[i++] = zuser; + if (! fsuccess) + { + az[i++] = "\nfor the following reason:\n\t"; + az[i++] = zwhy; + az[i++] = "\n"; + } + if (zsaved != NULL) + { + az[i++] = zsaved; + az[i++] = "\n"; + } + + return fsysdep_mail (zsendto, + fsuccess ? "UUCP succeeded" : "UUCP failed", + i, az); +} diff --git a/gnu/libexec/uucp/common_sources/prot.h b/gnu/libexec/uucp/common_sources/prot.h new file mode 100644 index 00000000000..4e2bb584d84 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/prot.h @@ -0,0 +1,250 @@ +/* prot.h + Protocol header file. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* We need the definition of uuconf_cmdtab to declare the protocol + parameter arrays. */ +#ifndef UUCONF_H +#include "uuconf.h" +#endif + +#if ANSI_C +/* These structures are used in prototypes but are not defined in this + header file. */ +struct sdaemon; +struct sconnection; +struct stransfer; +#endif + +/* The sprotocol structure holds information and functions for a specific + protocol (e.g. the 'g' protocol). */ + +struct sprotocol +{ + /* The name of the protocol (e.g. 'g'). */ + char bname; + /* Reliability requirements, an or of UUCONF_RELIABLE_xxx defines + from uuconf.h. */ + int ireliable; + /* The maximum number of channels this protocol can support. */ + int cchans; + /* Protocol parameter commands. */ + struct uuconf_cmdtab *qcmds; + /* A routine to start the protocol. If *pzlog is set to be + non-NULL, it is an informative message to be logged; it should + then be passed to ubuffree. */ + boolean (*pfstart) P((struct sdaemon *qdaemon, char **pzlog)); + /* Shutdown the protocol. */ + boolean (*pfshutdown) P((struct sdaemon *qdaemon)); + /* Send a command to the other side. */ + boolean (*pfsendcmd) P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); + /* Get buffer to space to fill with data. This should set *pcdata + to the amount of data desired. */ + char *(*pzgetspace) P((struct sdaemon *qdaemon, size_t *pcdata)); + /* Send data to the other side. The argument z must be a return + value of pzgetspace. The ipos argument is the file position, and + is ignored by most protocols. */ + boolean (*pfsenddata) P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); + /* Wait for data to come in and call fgot_data with it until + fgot_data sets *pfexit. */ + boolean (*pfwait) P((struct sdaemon *qdaemon)); + /* Handle any file level actions that need to be taken. If a file + transfer is starting rather than ending, fstart is TRUE. If the + file is being sent rather than received, fsend is TRUE. If + fstart and fsend are both TRUE, cbytes holds the size of the + file. If *pfhandled is set to TRUE, then the protocol routine + has taken care of queueing up qtrans for the next action. */ + boolean (*pffile) P((struct sdaemon *qdaemon, struct stransfer *qtrans, + boolean fstart, boolean fsend, long cbytes, + boolean *pfhandled)); +}; + +/* Send data to the other system. If the fread argument is TRUE, this + will also receive data into the receive buffer abPrecbuf; fread is + passed as TRUE if the protocol expects data to be coming back, to + make sure the input buffer does not fill up. Returns FALSE on + error. */ +extern boolean fsend_data P((struct sconnection *qconn, + const char *zsend, size_t csend, + boolean fdoread)); + +/* Receive data from the other system when there is no data to send. + The cneed argument is the amount of data desired and the ctimeout + argument is the timeout in seconds. This will set *pcrec to the + amount of data received. It will return FALSE on error. If a + timeout occurs, it will return TRUE with *pcrec set to zero. */ +extern boolean freceive_data P((struct sconnection *qconn, size_t cneed, + size_t *pcrec, int ctimeout, + boolean freport)); + +/* Get one character from the remote system, going through the + procotol buffering. The ctimeout argument is the timeout in + seconds, and the freport argument is TRUE if errors should be + reported (when closing a connection it is pointless to report + errors). This returns a character or -1 on a timeout or -2 on an + error. */ +extern int breceive_char P((struct sconnection *qconn, + int ctimeout, boolean freport)); + +/* Compute a 32 bit CRC of a data buffer, given an initial CRC. */ +extern unsigned long icrc P((const char *z, size_t c, unsigned long ick)); + +/* The initial CRC value to use for a new buffer. */ +#if ANSI_C +#define ICRCINIT (0xffffffffUL) +#else +#define ICRCINIT ((unsigned long) 0xffffffffL) +#endif + +/* The size of the receive buffer. */ +#define CRECBUFLEN (16384) + +/* Buffer to hold received data. */ +extern char abPrecbuf[CRECBUFLEN]; + +/* Index of start of data in abPrecbuf. */ +extern int iPrecstart; + +/* Index of end of data (first byte not included in data) in abPrecbuf. */ +extern int iPrecend; + +/* There are a couple of variables and functions that are shared by + the 'i' and 'j' protocols (the 'j' protocol is just a wrapper + around the 'i' protocol). These belong in a separate header file, + protij.h, but I don't want to create one for just a couple of + things. */ + +/* An escape sequence of characters for the 'j' protocol to avoid + (protocol parameter ``avoid''). */ +extern const char *zJavoid_parameter; + +/* Timeout to use when sending the 'i' protocol SYNC packet (protocol + parameter ``sync-timeout''). */ +extern int cIsync_timeout; + +/* Shared startup routine for the 'i' and 'j' protocols. */ +extern boolean fijstart P((struct sdaemon *qdaemon, char **pzlog, + int imaxpacksize, + boolean (*pfsend) P((struct sconnection *qconn, + const char *zsend, + size_t csend, + boolean fdoread)), + boolean (*pfreceive) P((struct sconnection *qconn, + size_t cneed, + size_t *pcrec, + int ctimeout, + boolean freport)))); + +/* Prototypes for 'g' protocol functions. */ + +extern struct uuconf_cmdtab asGproto_params[]; +extern boolean fgstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean fbiggstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean fgshutdown P((struct sdaemon *qdaemon)); +extern boolean fgsendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *zggetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean fgsenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean fgwait P((struct sdaemon *qdaemon)); + +/* Prototypes for 'f' protocol functions. */ + +extern struct uuconf_cmdtab asFproto_params[]; +extern boolean ffstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean ffshutdown P((struct sdaemon *qdaemon)); +extern boolean ffsendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *zfgetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean ffsenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean ffwait P((struct sdaemon *qdaemon)); +extern boolean fffile P((struct sdaemon *qdaemon, struct stransfer *qtrans, + boolean fstart, boolean fsend, long cbytes, + boolean *pfhandled)); + +/* Prototypes for 't' protocol functions. */ + +extern struct uuconf_cmdtab asTproto_params[]; +extern boolean ftstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean ftshutdown P((struct sdaemon *qdaemon)); +extern boolean ftsendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *ztgetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean ftsenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean ftwait P((struct sdaemon *qdaemon)); +extern boolean ftfile P((struct sdaemon *qdaemon, struct stransfer *qtrans, + boolean fstart, boolean fsend, long cbytes, + boolean *pfhandled)); + +/* Prototypes for 'e' protocol functions. */ + +extern struct uuconf_cmdtab asEproto_params[]; +extern boolean festart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean feshutdown P((struct sdaemon *qdaemon)); +extern boolean fesendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *zegetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean fesenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean fewait P((struct sdaemon *qdaemon)); +extern boolean fefile P((struct sdaemon *qdaemon, struct stransfer *qtrans, + boolean fstart, boolean fsend, long cbytes, + boolean *pfhandled)); + +/* Prototypes for 'i' protocol functions. */ + +extern struct uuconf_cmdtab asIproto_params[]; +extern boolean fistart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean fishutdown P((struct sdaemon *qdaemon)); +extern boolean fisendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *zigetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean fisenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean fiwait P((struct sdaemon *qdaemon)); + +/* Prototypes for 'j' protocol functions. The 'j' protocol mostly + uses the 'i' protocol functions, but it has a couple of functions + of its own. */ +extern boolean fjstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean fjshutdown P((struct sdaemon *qdaemon)); + +/* Prototypes for 'a' protocol functions (these use 'z' as the second + character because 'a' is a modified Zmodem protocol). */ +extern struct uuconf_cmdtab asZproto_params[]; +extern boolean fzstart P((struct sdaemon *qdaemon, char **pzlog)); +extern boolean fzshutdown P((struct sdaemon *qdaemon)); +extern boolean fzsendcmd P((struct sdaemon *qdaemon, const char *z, + int ilocal, int iremote)); +extern char *zzgetspace P((struct sdaemon *qdaemon, size_t *pcdata)); +extern boolean fzsenddata P((struct sdaemon *qdaemon, char *z, size_t c, + int ilocal, int iremote, long ipos)); +extern boolean fzwait P((struct sdaemon *qdaemon)); +extern boolean fzfile P((struct sdaemon *qdaemon, struct stransfer *qtrans, + boolean fstart, boolean fsend, long cbytes, + boolean *pfhandled)); diff --git a/gnu/libexec/uucp/common_sources/sysdep.h b/gnu/libexec/uucp/common_sources/sysdep.h new file mode 100644 index 00000000000..47675ac2385 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/sysdep.h @@ -0,0 +1,530 @@ +/* sysh.unx -*- C -*- + The header file for the UNIX system dependent routines. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#ifndef SYSH_UNX_H + +#define SYSH_UNX_H + +#if ANSI_C +/* These structures are used in prototypes but are not defined in this + header file. */ +struct uuconf_system; +struct sconnection; +#endif + +/* Make sure the defines do not conflict. These are in this file + because they are Unix dependent. */ +#if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_COHERENT_LOCKFILES != 1 + #error LOCKFILES define not set or duplicated +#endif + +/* SCO and SVR4 lockfiles are basically just like HDB lockfiles. */ +#if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES +#undef HAVE_HDB_LOCKFILES +#define HAVE_HDB_LOCKFILES 1 +#endif + +#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS != 1 + #error Terminal driver define not set or duplicated +#endif + +#if SPOOLDIR_V2 + SPOOLDIR_BSD42 + SPOOLDIR_BSD43 + SPOOLDIR_HDB + SPOOLDIR_ULTRIX + SPOOLDIR_SVR4 + SPOOLDIR_TAYLOR != 1 + #error Spool directory define not set or duplicated +#endif + +/* If setreuid is broken, don't use it. */ +#if HAVE_BROKEN_SETREUID +#undef HAVE_SETREUID +#define HAVE_SETREUID 0 +#endif + +/* Get some standard types from the configuration header file. */ +#ifdef PID_T +typedef PID_T pid_t; +#endif + +#ifdef UID_T +typedef UID_T uid_t; +#endif + +#ifdef GID_T +typedef GID_T gid_t; +#endif + +#ifdef OFF_T +typedef OFF_T off_t; +#endif + +/* On Unix, binary files are the same as text files. */ +#define BINREAD "r" +#define BINWRITE "w" + +/* If we have sigaction, we can force system calls to not be + restarted. */ +#if HAVE_SIGACTION +#undef HAVE_RESTARTABLE_SYSCALLS +#define HAVE_RESTARTABLE_SYSCALLS 0 +#endif + +/* If we have sigvec, and we have HAVE_SIGVEC_SV_FLAGS, and + SV_INTERRUPT is defined, we can force system calls to not be + restarted (signal.h is included by uucp.h before this point, so + SV_INTERRUPT will be defined by now if it it ever is). */ +#if HAVE_SIGVEC && HAVE_SIGVEC_SV_FLAGS +#ifdef SV_INTERRUPT +#undef HAVE_RESTARTABLE_SYSCALLS +#define HAVE_RESTARTABLE_SYSCALLS 0 +#endif +#endif + +/* If we were cross-configured, we will have a value of -1 for + HAVE_RESTARTABLE_SYSCALLS. In this case, we try to guess what the + correct value should be. Yuck. If we have sigvec, but neither of + the above cases applied (which we know because they would have + changed HAVE_RESTARTABLE_SYSCALLS) then we are probably on 4.2BSD + and system calls are automatically restarted. Otherwise, assume + that they are not. */ +#if HAVE_RESTARTABLE_SYSCALLS == -1 +#undef HAVE_RESTARTABLE_SYSCALLS +#if HAVE_SIGVEC +#define HAVE_RESTARTABLE_SYSCALLS 1 +#else +#define HAVE_RESTARTABLE_SYSCALLS 0 +#endif +#endif /* HAVE_RESTARTABLE_SYSCALLS == -1 */ + +/* We don't handle sigset in combination with restartable system + calls, so we check for it although this combination will never + happen. */ +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && HAVE_SIGSET +#if HAVE_RESTARTABLE_SYSCALLS +#undef HAVE_SIGSET +#define HAVE_SIGSET 0 +#endif +#endif + +/* If we don't have restartable system calls, we can ignore + fsysdep_catch, usysdep_start_catch and usysdep_end_catch. + Otherwise fsysdep_catch has to do a setjmp. */ + +#if ! HAVE_RESTARTABLE_SYSCALLS + +#define fsysdep_catch() (TRUE) +#define usysdep_start_catch() +#define usysdep_end_catch() +#define CATCH_PROTECT + +#else /* HAVE_RESTARTABLE_SYSCALLS */ + +#if HAVE_SETRET && ! HAVE_SIGSETJMP +#include <setret.h> +#define setjmp setret +#define longjmp longret +#define jmp_buf ret_buf +#else /* ! HAVE_SETRET || HAVE_SIGSETJMP */ +#include <setjmp.h> +#if HAVE_SIGSETJMP +#undef setjmp +#undef longjmp +#undef jmp_buf +#define setjmp(s) sigsetjmp ((s), TRUE) +#define longjmp siglongjmp +#define jmp_buf sigjmp_buf +#endif /* HAVE_SIGSETJMP */ +#endif /* ! HAVE_SETRET || HAVE_SIGSETJMP */ + +extern volatile sig_atomic_t fSjmp; +extern volatile jmp_buf sSjmp_buf; + +#define fsysdep_catch() (setjmp (sSjmp_buf) == 0) + +#define usysdep_start_catch() (fSjmp = TRUE) + +#define usysdep_end_catch() (fSjmp = FALSE) + +#define CATCH_PROTECT volatile + +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + +/* Get definitions for the terminal driver. */ + +#if HAVE_BSD_TTY +#include <sgtty.h> +struct sbsd_terminal +{ + struct sgttyb stty; + struct tchars stchars; + struct ltchars sltchars; +}; +typedef struct sbsd_terminal sterminal; +#define fgetterminfo(o, q) \ + (ioctl ((o), TIOCGETP, &(q)->stty) == 0 \ + && ioctl ((o), TIOCGETC, &(q)->stchars) == 0 \ + && ioctl ((o), TIOCGLTC, &(q)->sltchars) == 0) +#define fsetterminfo(o, q) \ + (ioctl ((o), TIOCSETN, &(q)->stty) == 0 \ + && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \ + && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0) +#define fsetterminfodrain(o, q) \ + (ioctl ((o), TIOCSETP, &(q)->stty) == 0 \ + && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \ + && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0) +#endif /* HAVE_BSD_TTY */ + +#if HAVE_SYSV_TERMIO +#include <termio.h> +typedef struct termio sterminal; +#define fgetterminfo(o, q) (ioctl ((o), TCGETA, (q)) == 0) +#define fsetterminfo(o, q) (ioctl ((o), TCSETA, (q)) == 0) +#define fsetterminfodrain(o, q) (ioctl ((o), TCSETAW, (q)) == 0) +#endif /* HAVE_SYSV_TERMIO */ + +#if HAVE_POSIX_TERMIOS +#include <termios.h> +typedef struct termios sterminal; +#define fgetterminfo(o, q) (tcgetattr ((o), (q)) == 0) +#define fsetterminfo(o, q) (tcsetattr ((o), TCSANOW, (q)) == 0) +#define fsetterminfodrain(o, q) (tcsetattr ((o), TCSADRAIN, (q)) == 0) + +/* On some systems it is not possible to include both <sys/ioctl.h> + and <termios.h> in the same source files; I don't really know why. + On such systems, we pretend that we don't have <sys/ioctl.h>. */ +#if ! HAVE_TERMIOS_AND_SYS_IOCTL_H +#undef HAVE_SYS_IOCTL_H +#define HAVE_SYS_IOCTL_H 0 +#endif + +#endif /* HAVE_POSIX_TERMIOS */ + +/* The root directory (this is needed by the system independent stuff + as the default for local-send). */ +#define ZROOTDIR "/" + +/* The name of the execution directory within the spool directory + (this is need by the system independent uuxqt.c). */ +#define XQTDIR ".Xqtdir" + +/* The name of the directory in which we preserve file transfers that + failed. */ +#define PRESERVEDIR ".Preserve" + +/* The length of the sequence number used in a file name. */ +#define CSEQLEN (4) + +/* Get some standard definitions. Avoid including the files more than + once--some might have been included by uucp.h. */ +#if USE_STDIO && HAVE_UNISTD_H +#include <unistd.h> +#endif +#if ! USE_TYPES_H +#include <sys/types.h> +#endif +#include <sys/stat.h> + +/* Get definitions for the file permission bits. */ + +#ifndef S_IRWXU +#define S_IRWXU 0700 +#endif +#ifndef S_IRUSR +#define S_IRUSR 0400 +#endif +#ifndef S_IWUSR +#define S_IWUSR 0200 +#endif +#ifndef S_IXUSR +#define S_IXUSR 0100 +#endif + +#ifndef S_IRWXG +#define S_IRWXG 0070 +#endif +#ifndef S_IRGRP +#define S_IRGRP 0040 +#endif +#ifndef S_IWGRP +#define S_IWGRP 0020 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 +#endif + +#ifndef S_IRWXO +#define S_IRWXO 0007 +#endif +#ifndef S_IROTH +#define S_IROTH 0004 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0002 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 +#endif + +#ifndef S_ISDIR +#ifdef S_IFDIR +#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) +#else /* ! defined (S_IFDIR) */ +#define S_ISDIR(i) (((i) & 0170000) == 040000) +#endif /* ! defined (S_IFDIR) */ +#endif /* ! defined (S_ISDIR) */ + +/* We need the access macros. */ +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 +#endif /* ! defined (R_OK) */ + +/* We create files with these modes (should this be configurable?). */ +#define IPRIVATE_FILE_MODE (S_IRUSR | S_IWUSR) +#define IPUBLIC_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) + +/* We create directories with this mode (should this be configurable?). */ +#define IDIRECTORY_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#define IPUBLIC_DIRECTORY_MODE (S_IRWXU | S_IRWXG | S_IRWXO) + +#if ! HAVE_OPENDIR + +/* Define some structures to use if we don't have opendir, etc. These + will only work if we have the old Unix filesystem, with a 2 byte + inode and a 14 byte filename. */ + +#include <sys/dir.h> + +struct dirent +{ + char d_name[DIRSIZ + 1]; +}; + +typedef struct +{ + int o; + struct dirent s; +} DIR; + +extern DIR *opendir P((const char *zdir)); +extern struct dirent *readdir P((DIR *)); +extern int closedir P((DIR *)); + +#endif /* ! HAVE_OPENDIR */ + +#if ! HAVE_FTW_H + +/* If there is no <ftw.h>, define the ftw constants. */ + +#define FTW_F (0) +#define FTW_D (1) +#define FTW_DNR (2) +#define FTW_NS (3) + +#endif /* ! HAVE_FTW_H */ + +/* This structure holds the system dependent information we keep for a + connection. This is used by the TCP and TLI code. */ + +struct ssysdep_conn +{ + /* File descriptor. */ + int o; + /* Device name. */ + char *zdevice; + /* File status flags. */ + int iflags; + /* File status flags for descriptor 1 (-1 if not standard input). */ + int istdout_flags; + /* Hold the real descriptor when using a dialer device. */ + int ohold; + /* TRUE if this is a terminal and the remaining fields are valid. */ + boolean fterminal; + /* TRUE if this is a TLI descriptor. */ + boolean ftli; + /* Baud rate. */ + long ibaud; + /* Original terminal settings. */ + sterminal sorig; + /* Current terminal settings. */ + sterminal snew; +#if HAVE_COHERENT_LOCKFILES + /* On Coherent we need to hold on to the real port name which will + be used to enable the port. Ick. */ + char *zenable; +#endif +}; + +/* These functions do I/O and chat scripts to a port. They are called + by the TCP and TLI routines. */ +extern boolean fsysdep_conn_read P((struct sconnection *qconn, + char *zbuf, size_t *pclen, + size_t cmin, int ctimeout, + boolean freport)); +extern boolean fsysdep_conn_write P((struct sconnection *qconn, + const char *zbuf, size_t clen)); +extern boolean fsysdep_conn_io P((struct sconnection *qconn, + const char *zwrite, size_t *pcwrite, + char *zread, size_t *pcread)); +extern boolean fsysdep_conn_chat P((struct sconnection *qconn, + char **pzprog)); + +/* Set a signal handler. */ +extern void usset_signal P((int isig, RETSIGTYPE (*pfn) P((int)), + boolean fforce, boolean *pfignored)); + +/* Default signal handler. This sets the appropriate element of the + afSignal array. If system calls are automatically restarted, it + may do a longjmp to an fsysdep_catch. */ +extern RETSIGTYPE ussignal P((int isig)); + +/* Try to fork, repeating several times. */ +extern pid_t ixsfork P((void)); + +/* Spawn a job. Returns the process ID of the spawned job or -1 on + error. The following macros may be passed in aidescs. */ + +/* Set descriptor to /dev/null. */ +#define SPAWN_NULL (-1) +/* Set element of aidescs to a pipe for caller to read from. */ +#define SPAWN_READ_PIPE (-2) +/* Set element of aidescs to a pipe for caller to write to. */ +#define SPAWN_WRITE_PIPE (-3) + +extern pid_t ixsspawn P((const char **pazargs, int *aidescs, + boolean fkeepuid, boolean fkeepenv, + const char *zchdir, boolean fnosigs, + boolean fshell, const char *zpath, + const char *zuu_machine, + const char *zuu_user)); + +/* Do a form of popen using ixsspawn. */ +extern FILE *espopen P((const char **pazargs, boolean frd, + pid_t *pipid)); + +/* Wait for a particular process to finish, returning the exit status. + The process ID should be pid_t, but we can't put that in a + prototype. */ +extern int ixswait P((unsigned long ipid, const char *zreport)); + +/* Find a spool file in the spool directory. For a local file, the + bgrade argument is the grade of the file. This is needed for + SPOOLDIR_SVR4. */ +extern char *zsfind_file P((const char *zsimple, const char *zsystem, + int bgrade)); + +/* Return the grade given a sequence number. */ +extern char bsgrade P((pointer pseq)); + +/* Lock a string. */ +extern boolean fsdo_lock P((const char *, boolean fspooldir, + boolean *pferr)); + +/* Unlock a string. */ +extern boolean fsdo_unlock P((const char *, boolean fspooldir)); + +/* Check access for a particular user name, or NULL to check access + for any user. */ +extern boolean fsuser_access P((const struct stat *, int imode, + const char *zuser)); + +/* Stick two directories and a file name together. */ +extern char *zsappend3 P((const char *zdir1, const char *zdir2, + const char *zfile)); + +/* Stick three directories and a file name together. */ +extern char *zsappend4 P((const char *zdir1, const char *zdir2, + const char *zdir3, const char *zfile)); + +/* Get a temporary file name. */ +extern char *zstemp_file P((const struct uuconf_system *qsys)); + +/* Get a command file name. */ +extern char *zscmd_file P((const struct uuconf_system *qsys, int bgrade)); + +/* Get a jobid from a system, a file name, and a grade. */ +extern char *zsfile_to_jobid P((const struct uuconf_system *qsys, + const char *zfile, + int bgrade)); + +/* Get a file name from a jobid. This also returns the associated system + in *pzsystem and the grade in *pbgrade. */ +extern char *zsjobid_to_file P((const char *zid, char **pzsystem, + char *pbgrade)); + +/* See whether there is a spool directory for a system when using + SPOOLDIR_ULTRIX. */ +extern boolean fsultrix_has_spool P((const char *zsystem)); + +#if HAVE_COHERENT_LOCKFILES +/* Lock a coherent tty. */ +extern boolean lockttyexist P((const char *z)); +extern boolean fscoherent_disable_tty P((const char *zdevice, + char **pzenable)); +#endif + +/* Some replacements for standard Unix functions. */ + +#if ! HAVE_DUP2 +extern int dup2 P((int oold, int onew)); +#endif + +#if ! HAVE_FTW +extern int ftw P((const char *zdir, + int (*pfn) P((const char *zfile, + const struct stat *qstat, + int iflag)), + int cdescriptors)); +#endif + +#if ! HAVE_GETCWD && ! HAVE_GETWD +extern char *getcwd P((char *zbuf, size_t cbuf)); +#endif + +#if ! HAVE_MKDIR +extern int mkdir P((const char *zdir, int imode)); +#endif + +#if ! HAVE_RENAME +extern int rename P((const char *zold, const char *znew)); +#endif + +#if ! HAVE_RMDIR +extern int rmdir P((const char *zdir)); +#endif + +/* The working directory from which the program was run (this is set + by usysdep_initialize if called with INIT_GETCWD). */ +extern char *zScwd; + +/* The spool directory name. */ +extern const char *zSspooldir; + +/* The lock directory name. */ +extern const char *zSlockdir; + +/* The local UUCP name (needed for some spool directory stuff). */ +extern const char *zSlocalname; + +#endif /* ! defined (SYSH_UNX_H) */ diff --git a/gnu/libexec/uucp/common_sources/system.h b/gnu/libexec/uucp/common_sources/system.h new file mode 100644 index 00000000000..aa9d2a41a45 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/system.h @@ -0,0 +1,950 @@ +/* system.h + Header file for system dependent stuff in the Taylor UUCP package. + This file is not itself system dependent. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#ifndef SYSTEM_H + +#define SYSTEM_H + +#if ANSI_C +/* These structures are used in prototypes but are not defined in this + header file. */ +struct tm; +struct uuconf_system; +struct uuconf_port; +struct sconnection; +struct sstatus; +struct scmd; +#endif + +/* Any function which returns an error should also report an error + message, unless otherwise indicated. + + Any function that returns a char *, rather than a const char *, is + returning a pointer to a buffer allocated by zbufalc which must be + freed using ubuffree, unless otherwise indicated. */ + +/* The maximum length of a remote system name. */ +extern size_t cSysdep_max_name_len; + +/* Initialize. If something goes wrong, this routine should just + exit. The flag argument is 0, or a combination of any of the + following flags. */ + +/* This program needs to know the current working directory. This is + used because on Unix it can be expensive to determine the current + working directory (some versions of getcwd fork a process), but in + most cases we don't need to know it. However, we are going to + chdir to the spool directory (unless INIT_CHDIR is set), so we have + to get the cwd now if we are ever going to get it. Both uucp and + uux use the function fsysdep_needs_cwd to determine whether they + will need the current working directory, and pass the argument to + usysdep_initialize appropriately. There's probably a cleaner way + to handle this, but this will suffice for now. */ +#define INIT_GETCWD (01) + +/* This program should not chdir to the spool directory. This may + only make sense on Unix. It is set by cu. */ +#define INIT_NOCHDIR (02) + +/* This program needs special access to the spool directories. That + means, on Unix, this program is normally installed setuid. */ +#define INIT_SUID (04) + +extern void usysdep_initialize P((pointer puuconf, int iflags)); + +/* Exit the program. The fsuccess argument indicates whether to + return an indication of success or failure to the outer + environment. This routine should not return. */ +extern void usysdep_exit P((boolean fsuccess)); + +/* Called when a non-standard configuration file is being used, to + avoid handing out privileged access. If it returns FALSE, default + configuration file will be used. This is called before the + usysdep_initialize function is called. */ +extern boolean fsysdep_other_config P((const char *)); + +/* Detach from the controlling terminal. This probably only makes + sense on Unix. It is called by uucico to try to get the modem port + as a controlling terminal. It is also called by uucico before it + starts up uuxqt, so that uuxqt will be a complete daemon. */ +extern void usysdep_detach P((void)); + +/* Get the local node name if it is not specified in the configuration + files. Returns NULL on error; otherwise the return value should + point to a static buffer. */ +extern const char *zsysdep_localname P((void)); + +/* Get the login name. This is used when uucico is started up with no + arguments in slave mode, which causes it to assume that somebody + has logged in. It also used by uucp and uux for recording the user + name. This may not return NULL. The return value should point to + a static buffer. */ +extern const char *zsysdep_login_name P((void)); + +/* Set a signal handler for a signal. If the signal occurs, the + appropriate element of afSignal should be set to the signal number + (see the declaration of afSignal in uucp.h). This routine might be + able to just use signal, but Unix requires more complex handling. + This is called before usysdep_initialize. */ +extern void usysdep_signal P((int isig)); + +/* Catch a signal. This is actually defined as a macro in the system + dependent header file, and the prototype here just indicates how it + should be called. It is called before a routine which must exit if + a signal occurs, and is expected to set do a setjmp (which is why + it must be a macro). It is actually only called in one place in + the system independent code, before the call to read stdin in uux. + This is needed to handle 4.2 BSD restartable system calls, which + require a longjmp. On systems which don't need to do + setjmp/longjmp around system calls, this can be redefined in + sysdep.h to TRUE. It should return TRUE if the routine should + proceed, or FALSE if a signal occurred. After having this return + TRUE, usysdep_start_catch should be used to start catching the + signal; this basically tells the signal handler that it's OK to do + the longjmp, if fsysdep_catch did not already do so. */ +#ifndef fsysdep_catch +extern boolean fsysdep_catch P((void)); +#endif + +/* Start catching a signal. This is called after fsysdep_catch to + tell the signal handler to go ahead and do the longjmp. This may + be implemented as a macro in sysdep.h. */ +#ifndef usysdep_start_catch +extern void usysdep_start_catch P((void)); +#endif + +/* Stop catching a signal. This is called when it is no longer + necessary for fsysdep_catch to handle signals. This may be + implemented as a macro in sysdep.h. */ +#ifndef usysdep_end_catch +extern void usysdep_end_catch P((void)); +#endif + +/* Link two files. On Unix this should attempt the link. If it + succeeds it should return TRUE with *pfworked set to TRUE. If the + link fails because it must go across a device, it should return + TRUE with *pfworked set to FALSE. If the link fails for some other + reason, it should log an error message and return FALSE. On a + system which does not support links to files, this should just + return TRUE with *pfworked set to FALSE. */ +extern boolean fsysdep_link P((const char *zfrom, const char *zto, + boolean *pfworked)); + +/* Get the port name. This is used when uucico is started up in slave + mode to figure out which port was used to call in so that it can + determine any appropriate protocol parameters. This may return + NULL if the port cannot be determined, which will just mean that no + protocol parameters are applied. The name returned should be the + sort of name that would appear in the port file. This should set + *pftcp_port to TRUE if it can determine that the port is a TCP + connection rather than a normal serial port. The return value (if + not NULL) should point to a static buffer. */ +extern const char *zsysdep_port_name P((boolean *pftcp_port)); + +/* Expand a file name on the local system. On Unix, if the zfile + argument begins with ~user/ it goes in that users home directory, + and if it begins with ~/ it goes in the public directory (the + public directory is passed to this routine, since each system may + have its own public directory). Similar conventions may be + desirable on other systems. This should always return an absolute + path name, probably in the public directory. It should return NULL + on error; otherwise the return value should be allocated using + zbufcpy or zbufalc. */ +extern char *zsysdep_local_file P((const char *zname, + const char *zpubdir)); + +/* Return whether a file name is in a directory, and check for read or + write access. This should check whether zfile is within zdir (or + is zdir itself). If it is not, it should return FALSE. If zfile + is in zdir, then fcheck indicates whether further checking should + be done. If fcheck is FALSE, no further checking is done. + Otherwise, if freadable is TRUE the user zuser should have search + access to all directories from zdir down to zfile and should have + read access on zfile itself (if zfile does not exist, or is not a + regular file, this function may return FALSE but does not have to). + If freadable is FALSE, the user zuser should have search access to + all directories from zdir down to zfile and should have write + access on zfile (which may be a directory, or may not actually + exist, which is acceptable). The zuser argument may be NULL, in + which case the check should be made for any user, not just zuser. + There is no way for this function to return error. */ +extern boolean fsysdep_in_directory P((const char *zfile, + const char *zdir, + boolean fcheck, + boolean freadable, + const char *zuser)); + +/* Return TRUE if a file exists, FALSE otherwise. There is no way to + return error. */ +extern boolean fsysdep_file_exists P((const char *zfile)); + +/* Start up a program. The code expects fsysdep_run to return after + doing a fork, but at least for now everything will work fine if it + does not (on a system which does not support forking). The three + string arguments may be catenated together to form the program to + execute; I did it this way to make it easy to call execl(2), and + because I never needed more than two arguments. The program will + always be "uucico" or "uuxqt". The return value will be passed + directly to usysdep_exit, and should be TRUE on success, FALSE on + error. */ +extern boolean fsysdep_run P((const char *zprogram, const char *zarg1, + const char *zarg2)); + +/* Send a mail message. This function will be passed an array of + strings. All necessary newlines are already included; the strings + should simply be concatenated together to form the mail message. + It should return FALSE on error, although the return value is often + ignored. */ +extern boolean fsysdep_mail P((const char *zto, const char *zsubject, + int cstrs, const char **paz)); + +/* Get the time in seconds since some epoch. The actual epoch is + unimportant, so long as the time values are consistent across + program executions and the value is never negative. If the + pimicros argument is not NULL, it should be set to the number of + microseconds (if this is not available, *pimicros should be set to + zero). */ +extern long ixsysdep_time P((long *pimicros)); + +/* Get the time in seconds and microseconds (millionths of a second) + since some epoch. The actual epoch is not important, and it may + change in between program invocations; this is provided because on + Unix the times function may be used. If microseconds can not be + determined, *pimicros can just be set to zero. */ +extern long ixsysdep_process_time P((long *pimicros)); + +/* Parse the value returned by ixsysdep_time into a struct tm. I + assume that this structure is defined in <time.h>. This is + basically just localtime, except that the ANSI function takes a + time_t which may not be what is returned by ixsysdep_time. */ +extern void usysdep_localtime P((long itime, struct tm *q)); + +/* Sleep for a number of seconds. */ +extern void usysdep_sleep P((int cseconds)); + +/* Pause for half a second, or 1 second if subsecond sleeps are not + possible. */ +extern void usysdep_pause P((void)); + +/* Lock a remote system. This should return FALSE if the system is + already locked (no error should be reported). */ +extern boolean fsysdep_lock_system P((const struct uuconf_system *qsys)); + +/* Unlock a remote system. This should return FALSE on error + (although the return value is generally ignored). */ +extern boolean fsysdep_unlock_system P((const struct uuconf_system *qsys)); + +/* Get the conversation sequence number for a remote system, and + increment it for next time. This should return -1 on error. */ +extern long ixsysdep_get_sequence P((const struct uuconf_system *qsys)); + +/* Get the status of a remote system. This should return FALSE on + error. Otherwise it should set *qret to the status. If no status + information is available, this should set *qret to sensible values + and return TRUE. If pfnone is not NULL, then it should be set to + TRUE if no status information was available or FALSE otherwise. */ +extern boolean fsysdep_get_status P((const struct uuconf_system *qsys, + struct sstatus *qret, + boolean *pfnone)); + +/* Set the status of a remote system. This should return FALSE on + error. The system will be locked before this call is made. */ +extern boolean fsysdep_set_status P((const struct uuconf_system *qsys, + const struct sstatus *qset)); + +/* See whether a remote system is permitted to log in. This is just + to support the remote.unknown shell script for HDB. The zscript + argument is the script name, as return by uuconf_remote_unknown. + The zsystem argument is the name given by the remote system. If + the system is not permitted to log in, this function should log an + error and return FALSE. */ +extern boolean fsysdep_unknown_caller P((const char *zscript, + const char *zsystem)); + +/* Check whether there is work for a remote system. It should return + TRUE if there is work, FALSE otherwise; there is no way to indicate + an error. */ +extern boolean fsysdep_has_work P((const struct uuconf_system *qsys)); + +/* Initialize the work scan. This will be called before + fsysdep_get_work. The bgrade argument is the minimum grade of + execution files that should be considered (e.g. a bgrade of 'd' + will allow all grades from 'A' to 'Z' and 'a' to 'd'). This + function should return FALSE on error. */ +extern boolean fsysdep_get_work_init P((const struct uuconf_system *qsys, + int bgrade)); + +/* Get the next command to be executed for a remote system. The + bgrade argument will be the same as for fsysdep_get_work_init; + probably only one of these functions will use it, namely the + function for which it is more convenient. This should return FALSE + on error. The structure pointed to by qcmd should be filled in. + The strings may point into a static buffer; they will be copied out + if necessary. If there is no more work, this should set qcmd->bcmd + to 'H' and return TRUE. This should set qcmd->pseq to something + which can be passed to fsysdep_did_work to remove the job from the + queue when it has been completed. This may set qcmd->bcmd to 'P' + to represent a poll file; the main code will just pass the pseq + element of such a structure to fsysdep_did_work if the system is + called. */ +extern boolean fsysdep_get_work P((const struct uuconf_system *qsys, + int bgrade, struct scmd *qcmd)); + +/* Remove a job from the work queue. This must also remove the + temporary file used for a send command, if there is one. It should + return FALSE on error. */ +extern boolean fsysdep_did_work P((pointer pseq)); + +/* Save the temporary file for a send command. This function should + return a string that will be put into a mail message. On success + this string should say something like ``The file has been saved as + ...''. On failure it could say something like ``The file could not + be saved because ...''. If there is no temporary file, or for some + reason it's not appropriate to include a message, this function + should just return NULL. This function is used when a file send + fails for some reason, to make sure that we don't completely lost + the file. */ +extern const char *zsysdep_save_temp_file P((pointer pseq)); + +/* Cleanup anything left over by fsysdep_get_work_init and + fsysdep_get_work. This may be called even though + fsysdep_get_work_init has not been. */ +extern void usysdep_get_work_free P((const struct uuconf_system *qsys)); + +/* Add a base name to a file if it is a directory. If zfile names a + directory, then return a string naming a file within the directory + with the base file name of zname. This should return NULL on + error. */ +extern char *zsysdep_add_base P((const char *zfile, + const char *zname)); + +/* Get a file name from the spool directory. This should return NULL + on error. The pseq argument is TRUE if the file was found from + searching the work directory; this is, unfortunately, needed to + support SVR4 spool directories. */ +extern char *zsysdep_spool_file_name P((const struct uuconf_system *qsys, + const char *zfile, + pointer pseq)); + +/* Make necessary directories. This should create all non-existent + directories for a file. If the fpublic argument is TRUE, anybody + should be permitted to create and remove files in the directory; + otherwise anybody can list the directory, but only the UUCP system + can create and remove files. It should return FALSE on error. */ +extern boolean fsysdep_make_dirs P((const char *zfile, boolean fpublic)); + +/* Create a stdio file, setting appropriate protection. If the + fpublic argument is TRUE, the file is made publically accessible; + otherwise it is treated as a private data file. If the fappend + argument is TRUE, the file is opened in append mode; otherwise any + previously existing file of the same name is removed. If the + fmkdirs argument is TRUE, then any necessary directories should + also be created. On a system in which file protections are + unimportant and the necessary directories exist, this may be + implemented as + + fopen (zfile, fappend ? "a" : "w"); + + */ +extern FILE *esysdep_fopen P((const char *zfile, boolean fpublic, + boolean fappend, boolean fmkdirs)); + +/* Open a file, using the access permission of the user who invoked + the program. The frd argument is TRUE if the file should be opened + for reading, and the fbinary argument is TRUE if the file should be + opened as a binary file (this is ignored on Unix, since there all + files are binary files). This returns an openfile_t, not a FILE *. + This is supposed to be able to open a file even if it can not be + read by the uucp user. This is not possible on some older Unix + systems. */ +extern openfile_t esysdep_user_fopen P((const char *zfile, + boolean frd, boolean fbinary)); + +/* Open a file to send to another system; the qsys argument is the + system the file is being sent to. If fcheck is TRUE, it should + make sure that the file is readable by zuser (if zuser is NULL the + file must be readable by anybody). This is to eliminate a window + between fsysdep_in_directory and esysdep_open_send. If an error + occurs, it should return EFILECLOSED. */ +extern openfile_t esysdep_open_send P((const struct uuconf_system *qsys, + const char *zname, + boolean fcheck, + const char *zuser)); + +/* Return a temporary file name to receive into. This file will be + opened by esysdep_open_receive. The qsys argument is the system + the file is coming from, the zto argument is the name the file will + have after it has been fully received, and the ztemp argument, if + it is not NULL, is from the command sent by the remote system. The + return value must be freed using ubuffree. The function should + return NULL on error. */ +extern char *zsysdep_receive_temp P((const struct uuconf_system *qsys, + const char *zfile, + const char *ztemp)); + +/* Open a file to receive from another system. The zreceive argument + is the return value of zsysdep_receive_temp with the same qsys, + zfile and ztemp arguments. If the function can determine that this + file has already been partially received, it should set *pcrestart + to the number of bytes that have been received. If the file has + not been partially received, *pcrestart should be set to -1. The + function should return EFILECLOSED on error. After the file is + written, fsysdep_move_file will be called to move the file to its + final destination, and to set the correct file mode. */ +extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys, + const char *zto, + const char *ztemp, + const char *zreceive, + long *pcrestart)); + +/* Move a file. This is used to move a received file to its final + location. The zto argument is the file to create. The zorig + argument is the name of the file to move. If fmkdirs is TRUE, then + any necessary directories are created; fpublic indicates whether + they should be publically writeable or not. If fcheck is TRUE, + this should make sure the directory is writeable by the user zuser + (if zuser is NULL, then it must be writeable by any user); this is + to avoid a window of vulnerability between fsysdep_in_directory and + fsysdep_move_file. This function should return FALSE on error; the + zorig file should be removed even if an error occurs. */ +extern boolean fsysdep_move_file P((const char *zorig, const char *zto, + boolean fmkdirs, boolean fpublic, + boolean fcheck, const char *zuser)); + +/* Change the mode of a file. The imode argument is a Unix mode. + This should return FALSE on error. */ +extern boolean fsysdep_change_mode P((const char *zfile, + unsigned int imode)); + +/* Truncate a file which we are receiving into. This may be done by + closing the original file, removing it and reopening it. This + should return FALSE on error. */ +extern openfile_t esysdep_truncate P((openfile_t e, const char *zname)); + +/* It is possible for the acknowledgement of a received file to be + lost. The sending system will then now know that the file was + correctly received, and will send it again. This can be a problem + particularly with protocols which support channels, since they may + send several small files in a single window, all of which may be + received correctly although the sending system never sees the + acknowledgement. If these files involve an execution, the + execution will happen twice, which will be bad. + + This function is called when a file is completely received. It is + supposed to try and remember the reception, in case the connection + is lost. It is passed the system, the file name to receive to, and + the temporary file name from the sending system. It should return + FALSE on error. */ +extern boolean fsysdep_remember_reception P((const struct uuconf_system *qsys, + const char *zto, + const char *ztemp)); + +/* This function is called to see if a file has already been received + successfully. It gets the same arguments as + fsysdep_remember_reception. It should return TRUE if the file was + already received, FALSE otherwise. There is no way to report + error. */ +extern boolean fsysdep_already_received P((const struct uuconf_system *qsys, + const char *zto, + const char *ztemp)); + +/* This function is called when it is no longer necessary to remember + that a file has been received. This will be called when the + protocol knows that the receive message has been acknowledged. It + gets the same arguments as fsysdep_remember_reception. it should + return FALSE on error. */ +extern boolean fsysdep_forget_reception P((const struct uuconf_system *qsys, + const char *zto, + const char *ztemp)); + +/* Start expanding a wildcarded file name. This should return FALSE + on error; otherwise subsequent calls to zsysdep_wildcard should + return file names. */ +extern boolean fsysdep_wildcard_start P((const char *zfile)); + +/* Get the next wildcard name. This should return NULL when there are + no more names to return. The return value should be freed using + ubuffree. The argument should be the same as that to + fsysdep_wildcard_start. There is no way to return error. */ +extern char *zsysdep_wildcard P((const char *zfile)); + +/* Finish getting wildcard names. This may be called before or after + zsysdep_wildcard has returned NULL. It should return FALSE on + error. */ +extern boolean fsysdep_wildcard_end P((void)); + +/* Prepare to execute a bunch of file transfer requests. This should + make an entry in the spool directory so that the next time uucico + is started up it will transfer these files. The bgrade argument + specifies the grade of the commands. The commands themselves are + in the pascmds array, which has ccmds entries. The function should + return NULL on error, or the jobid on success. The jobid is a + string that may be printed or passed to fsysdep_kill_job and + related functions, but is otherwise uninterpreted. */ +extern char *zsysdep_spool_commands P((const struct uuconf_system *qsys, + int bgrade, int ccmds, + const struct scmd *pascmds)); + +/* Get a file name to use for a data file to be copied to another + system. The ztname, zdname and zxname arguments will all either be + NULL or point to an array of CFILE_NAME_LEN characters in length. + The ztname array should be set to a temporary file name that could + be passed to zsysdep_spool_file_name to retrieve the return value + of this function; this will be appropriate for the temporary name + in a send request. The zdname array should be set to a data file + name that is appropriate for the spool directory of the other + system; this will be appropriate for the name of the destination + file in a send request of a data file for an execution of some + sort. The zxname array should be set to an execute file name that + is appropriate for the other system. The zlocalname argument is + the name of the local system as seen by the remote system, the + bgrade argument is the grade, and fxqt is TRUE if this file is + going to become an execution file. This should return NULL on + error. */ +#define CFILE_NAME_LEN (15) + +extern char *zsysdep_data_file_name P((const struct uuconf_system *qsys, + const char *zlocalname, + int bgrade, boolean fxqt, + char *ztname, char *zdname, + char *zxname)); + +/* Get a name for a local execute file. This is used by uux for a + local command with remote files. Returns NULL on error. */ +extern char *zsysdep_xqt_file_name P((void)); + +/* Beginning getting execute files. To get a list of execute files, + first fsysdep_get_xqt_init is called, then zsysdep_get_xqt is + called several times until it returns NULL, then finally + usysdep_get_xqt_free is called. */ +extern boolean fsysdep_get_xqt_init P((void)); + +/* Get the next execute file. This should return NULL when finished + (with *pferr set to FALSE). On an error this should return NULL + with *pferr set to TRUE. This should set *pzsystem to the name of + the system for which the execute file was created. Both the return + value and *pzsystem should be freed using ubuffree. */ +extern char *zsysdep_get_xqt P((char **pzsystem, + boolean *pferr)); + +/* Clean up after getting execute files. */ +extern void usysdep_get_xqt_free P((void)); + +/* Get the absolute pathname of a command to execute. This is given + the legal list of commands (which may be the special case "ALL") + and the path. It must return an absolute pathname to the command. + If it gets an error it should set *pferr to TRUE and return NULL; + if the command is not found it should set *pferr to FALSE and + return NULL. */ +extern char *zsysdep_find_command P((const char *zcmd, char **pzcmds, + char **pzpath, boolean *pferr)); + +/* Expand file names for uuxqt. This exists because uuxqt on Unix has + to expand file names which begin with a ~. It does not want to + expand any other type of file name, and it turns a double ~ into a + single one without expanding. If this returns NULL, the file does + not need to be changed; otherwise it returns a zbufalc'ed string. + There is no way to report error. */ +extern char *zsysdep_xqt_local_file P((const struct uuconf_system *qsys, + const char *zfile)); + +#if ! ALLOW_FILENAME_ARGUMENTS +/* Check an argument to an execution command to make sure that it + doesn't refer to a file name that may not be accessed. This should + check the argument to see if it is a filename. If it is, it should + either reject it out of hand or it should call fin_directory_list + on the file with both qsys->zremote_receive and qsys->zremote_send. + If the file is rejected, it should log an error and return FALSE. + Otherwise it should return TRUE. */ +extern boolean fsysdep_xqt_check_file P((const struct uuconf_system *qsys, + const char *zfile)); +#endif /* ! ALLOW_FILENAME_ARGUMENTS */ + +/* Run an execute file. The arguments are: + + qsys -- system for which execute file was created + zuser -- user who requested execution + pazargs -- list of arguments to command (element 0 is command) + zfullcmd -- command and arguments stuck together in one string + zinput -- file name for standard input (may be NULL) + zoutput -- file name for standard output (may be NULL) + fshell -- if TRUE, use /bin/sh to execute file + ilock -- return value of ixsysdep_lock_uuxqt + pzerror -- set to name of standard error file + pftemp -- set to TRUE if error is temporary, FALSE otherwise + + If fshell is TRUE, the command should be executed with /bin/sh + (obviously, this can only really be done on Unix systems). If an + error occurs this should return FALSE and set *pftemp + appropriately. *pzerror should be freed using ubuffree. */ +extern boolean fsysdep_execute P((const struct uuconf_system *qsys, + const char *zuser, + const char **pazargs, + const char *zfullcmd, + const char *zinput, + const char *zoutput, + boolean fshell, + int ilock, + char **pzerror, + boolean *pftemp)); + +/* Lock for uuxqt execution. If the cmaxuuxqts argument is not zero, + this should make sure that no more than cmaxuuxqts uuxqt processes + are running at once. Also, only one uuxqt may execute a particular + command (specified by the -c option) at a time. If zcmd is not + NULL, it is a command that must be locked. This should return a + nonnegative number which will be passed to other routines, + including fsysdep_unlock_uuxqt, or -1 on error. */ +extern int ixsysdep_lock_uuxqt P((const char *zcmd, + int cmaxuuxqts)); + +/* Unlock a uuxqt process. This is passed the return value of + ixsysdep_lock_uuxqt, as well as the arguments passed to + ixsysdep_lock_uuxqt. It may return FALSE on error, but at present + the return value is ignored. */ +extern boolean fsysdep_unlock_uuxqt P((int iseq, const char *zcmd, + int cmaxuuxqts)); + +/* See whether a particular uuxqt command is locked. This should + return TRUE if the command is locked (because ixsysdep_lock_uuxqt + was called with it as an argument), FALSE otherwise. There is no + way to return error. */ +extern boolean fsysdep_uuxqt_locked P((const char *zcmd)); + +/* Lock an execute file in order to execute it. This should return + FALSE if the execute file is already locked. There is no way to + return error. */ +extern boolean fsysdep_lock_uuxqt_file P((const char *zfile)); + +/* Unlock an execute file. This should return FALSE on error. */ +extern boolean fsysdep_unlock_uuxqt_file P((const char *zfile)); + +/* Lock the execution directory. The ilock argument is the return + value of ixsysdep_lock_uuxqt. This should return FALSE if the + directory is already locked. There is no way to return error. */ +extern boolean fsysdep_lock_uuxqt_dir P((int ilock)); + +/* Remove all files in the execution directory, and unlock it. This + should return FALSE on error. */ +extern boolean fsysdep_unlock_uuxqt_dir P((int ilock)); + +/* Move files into or out of the execution directory. The code will + already have checked that all the files exist. The elements in the + pzfrom array will be complete filenames, and the elements in the + pzto array will be either NULL (in which case the file should not + be moved) or simple base names. If fto is TRUE, the files in + pzfrom should be moved to pzto; otherwise, the files in pzto should + be moved to pzfrom (this is used if a temporary failure occurs, in + which case the execution will be retried later). If pzinput and + *pzinput are not NULL, then it is the name of the standard input + file; if it is the same as any element of pzfrom, then *pzinput + should be set to the zbufcpy of the corresponding pzto value, if + any. */ +extern boolean fsysdep_move_uuxqt_files P((int cfiles, + const char *const *pzfrom, + const char *const *pzto, + boolean fto, int ilock, + char **pzinput)); + +/* Expand a file name on the local system, defaulting to the current + directory. This is just like zsysdep_local_file, except that + relative files are placed in the working directory the program + started in rather than in the public directory. This should return + NULL on error. */ +extern char *zsysdep_local_file_cwd P((const char *zname, + const char *zpubdir)); + +/* Add the working directory to a file name. The named file is + actually on a remote system. If the file already has a directory, + it should not be changed. This should return NULL on error. */ +extern char *zsysdep_add_cwd P((const char *zfile)); + +/* See whether a file name will need the current working directory + when zsysdep_local_file_cwd or zsysdep_add_cwd is called on it. + This will be called before usysdep_initialize. It should just + check whether the argument is an absolute path. See the comment + above usysdep_initialize in this file for an explanation of why + things are done this way. */ +extern boolean fsysdep_needs_cwd P((const char *zfile)); + +/* Get the base name of a file. The file will be a local file name, + and this function should return the base file name, ideally in a + form which will make sense on most systems; it will be used if the + destination of a uucp is a directory. */ +extern char *zsysdep_base_name P((const char *zfile)); + +/* Return a filename within a directory. */ +extern char *zsysdep_in_dir P((const char *zdir, const char *zfile)); + +/* Get the mode of a file. This should return a Unix style file mode. + It should return 0 on error. */ +extern unsigned int ixsysdep_file_mode P((const char *zfile)); + +/* See whether the user has access to a file. This is called by uucp + and uux to prevent copying of a file which uucp can read but the + user cannot. If access is denied, this should log an error message + and return FALSE. */ +extern boolean fsysdep_access P((const char *zfile)); + +/* See whether the daemon has access to a file. This is called by + uucp and uux when a file is queued up for transfer without being + copied into the spool directory. It is merely an early error + check, as the daemon would of course discover the error itself when + it tried the transfer. If access would be denied, this should log + an error message and return FALSE. */ +extern boolean fsysdep_daemon_access P((const char *zfile)); + +/* Translate a destination from system!user to a place in the public + directory where uupick will get the file. On Unix this produces + system!~/receive/user/localname, and that's probably what it has to + produce on any other system as well. Returns NULL on a usage + error, or otherwise returns string allocated by zbufcpy. */ +extern char *zsysdep_uuto P((const char *zdest, + const char *zlocalname)); + +/* Return TRUE if a pathname exists and is a directory. */ +extern boolean fsysdep_directory P((const char *zpath)); + +/* Walk a directory tree. The zdir argument is the directory to walk. + The pufn argument is a function to call on each regular file in the + tree. The first argument to pufn should be the full filename; the + second argument to pufn should be the filename relative to zdir; + the third argument to pufn should be the pinfo argument to + usysdep_walk_tree. The usysdep_walk_tree function should return + FALSE on error. */ +extern boolean usysdep_walk_tree P((const char *zdir, + void (*pufn) P((const char *zfull, + const char *zrelative, + pointer pinfo)), + pointer pinfo)); + +/* Return the jobid of a work file, given the sequence value. On + error this should log an error and return NULL. The jobid is a + string which may be printed out and read in and passed to + fsysdep_kill_job, etc., but is not otherwise interpreted. */ +extern char *zsysdep_jobid P((const struct uuconf_system *qsys, + pointer pseq)); + +/* See whether the current user is permitted to kill jobs submitted by + another user. This should return TRUE if permission is granted, + FALSE otherwise. */ +extern boolean fsysdep_privileged P((void)); + +/* Kill a job, given the jobid. This should remove all associated + files and in general eliminate the job completely. On error it + should log an error message and return FALSE. */ +extern boolean fsysdep_kill_job P((pointer puuconf, + const char *zjobid)); + +/* Rejuvenate a job, given the jobid. If possible, this should update + the time associated with the job such that it will not be + eliminated by uustat -K or similar programs that check the creation + time. This should affect the return value of ixsysdep_work_time. + On error it should log an error message and return FALSE. */ +extern boolean fsysdep_rejuvenate_job P((pointer puuconf, + const char *zjobid)); + +/* Get the time a job was queued, given the sequence number. There is + no way to indicate error. The return value must use the same epoch + as ixsysdep_time. */ +extern long ixsysdep_work_time P((const struct uuconf_system *qsys, + pointer pseq)); + +/* Get the time a file was created. This is called by uustat on + execution files. There is no way to indicate error. The return + value must use the same epoch as ixsysdep_time. */ +extern long ixsysdep_file_time P((const char *zfile)); + +/* Get the size in bytes of a file. If this file does not exist, this + should not give an error message, but should return -1. If some + other error occurs, this should return -2. */ +extern long csysdep_size P((const char *zfile)); + +/* Return the amount of free space on the containing the given file + name (the file may or may not exist). If the amount of free space + cannot be determined, the function should return -1. */ +extern long csysdep_bytes_free P((const char *zfile)); + +/* Start getting status information for all systems with available + status information. There may be status information for unknown + systems, which is why this series of functions is used. The phold + argument is used to pass information around, to possibly avoid the + use of static variables. On error this should log an error and + return FALSE. */ +extern boolean fsysdep_all_status_init P((pointer *phold)); + +/* Get status information for the next system. This should return the + system name and fill in the qstat argument. The phold argument + will be that set by fsysdep_all_status_init. On error this should + log an error, set *pferr to TRUE, and return NULL. */ +extern char *zsysdep_all_status P((pointer phold, boolean *pferr, + struct sstatus *qstat)); + +/* Free up anything allocated by fsysdep_all_status_init and + zsysdep_all_status. The phold argument is that set by + fsysdep_all_status_init. */ +extern void usysdep_all_status_free P((pointer phold)); + +/* Display the process status of all processes holding lock files. + This is uustat -p. The return value is passed to usysdep_exit. */ +extern boolean fsysdep_lock_status P((void)); + +/* Return TRUE if the user has legitimate access to the port. This is + used by cu to control whether the user can open a port directly, + rather than merely being able to dial out on it. Opening a port + directly allows the modem to be reprogrammed. */ +extern boolean fsysdep_port_access P((struct uuconf_port *qport)); + +/* Return whether the given port could be named by the given line. On + Unix, the line argument would be something like "ttyd0", and this + function should return TRUE if the named port is "/dev/ttyd0". */ +extern boolean fsysdep_port_is_line P((struct uuconf_port *qport, + const char *zline)); + +/* Set the terminal into raw mode. In this mode no input characters + should be treated specially, and characters should be made + available as they are typed. The original terminal mode should be + saved, so that it can be restored by fsysdep_terminal_restore. If + flocalecho is TRUE, then local echoing should still be done; + otherwise echoing should be disabled. This function returns FALSE + on error. */ +extern boolean fsysdep_terminal_raw P((boolean flocalecho)); + +/* Restore the terminal back to the original setting, before + fsysdep_terminal_raw was called. Returns FALSE on error. */ +extern boolean fsysdep_terminal_restore P((void)); + +/* Read a line from the terminal. The fsysdep_terminal_raw function + will have been called. This should print the zprompt argument + (unless it is NULL) and return the line, allocated by zbufcpy, or + NULL on error. */ +extern char *zsysdep_terminal_line P((const char *zprompt)); + +/* Write a line to the terminal, ending with a newline. This is + basically just puts (zline, stdout), except that the terminal will + be in raw mode, so on ASCII Unix systems the line needs to end with + \r\n. */ +extern boolean fsysdep_terminal_puts P((const char *zline)); + +/* If faccept is TRUE, permit the user to generate signals from the + terminal. If faccept is FALSE, turn signals off again. After + fsysdep_terminal_raw is called, signals should be off. Return + FALSE on error. */ +extern boolean fsysdep_terminal_signals P((boolean faccept)); + +/* The cu program expects the system dependent code to handle the + details of copying data from the communications port to the + terminal. This should be set up by fsysdep_cu_init, and done while + fsysdep_cu is called. It is permissible to do it on a continual + basis (on Unix a subprocess handles it) so long as the copying can + be stopped by the fsysdep_cu_copy function. + + The fsysdep_cu_init function does any system dependent + initialization needed for this. */ +extern boolean fsysdep_cu_init P((struct sconnection *qconn)); + +/* Copy all data from the communications port to the terminal, and all + data from the terminal to the communications port. Keep this up + until the escape character *zCuvar_escape is seen. Set *pbcmd to + the character following the escape character; after the escape + character, zlocalname should be printed, possibly after a delay. + If two escape characters are entered in sequence, this function + should send a single escape character to the port, and not return. + Returns FALSE on error. */ +extern boolean fsysdep_cu P((struct sconnection *qconn, + char *pbcmd, + const char *zlocalname)); + +/* If fcopy is TRUE, start copying data from the communications port + to the terminal. If fcopy is FALSE, stop copying data. This + function may be called several times during a cu session. It + should return FALSE on error. */ +extern boolean fsysdep_cu_copy P((boolean fcopy)); + +/* Stop copying data from the communications port to the terminal, and + generally clean up after fsysdep_cu_init and fsysdep_cu. Returns + FALSE on error. */ +extern boolean fsysdep_cu_finish P((void)); + +/* Run a shell command. If zcmd is NULL, or *zcmd == '\0', just + start up a shell. The second argument is one of the following + values. This should return FALSE on error. */ +enum tshell_cmd +{ + /* Attach stdin and stdout to the terminal. */ + SHELL_NORMAL, + /* Attach stdout to the communications port, stdin to the terminal. */ + SHELL_STDOUT_TO_PORT, + /* Attach stdin to the communications port, stdout to the terminal. */ + SHELL_STDIN_FROM_PORT, + /* Attach both stdin and stdout to the communications port. */ + SHELL_STDIO_ON_PORT +}; + +extern boolean fsysdep_shell P((struct sconnection *qconn, + const char *zcmd, + enum tshell_cmd tcmd)); + +/* Change directory. If zdir is NULL, or *zdir == '\0', change to the + user's home directory. Return FALSE on error. */ +extern boolean fsysdep_chdir P((const char *zdir)); + +/* Suspend the current process. This is only expected to work on Unix + versions that support SIGTSTP. In general, people can just shell + out. */ +extern boolean fsysdep_suspend P((void)); + +/* Start getting files for uupick. The zsystem argument may be NULL + to get files from all systems, or it may specify a particular + system. The zpubdir argument is the public directory to use. This + returns FALSE on error. */ +extern boolean fsysdep_uupick_init P((const char *zsystem, + const char *zpubdir)); + +/* Get the next file for uupick. This returns the basic file name. + It sets *pzfull to the full name, and *pzfrom to the name of the + system which sent this file over; both should be freed using + ubuffree. *pzfull should be passed to ubuffree after it is no + longer needed. The zsystem and zpubdir arguments should be the + same as the arguments to fsysdep_uupick_init. This returns NULL + when all files been returned. */ +extern char *zsysdep_uupick P((const char *zsystem, const char *zpubdir, + char **pzfrom, char **pzfull)); + +/* Clean up after getting files for uupick. */ +extern boolean fsysdep_uupick_free P((const char *zsystem, + const char *zpubdir)); + +/* Translate a local file name for uupick. On Unix this is just like + zsysdep_local_file_cwd except that a file beginning with ~/ is + placed in the user's home directory rather than in the public + directory. */ +extern char *zsysdep_uupick_local_file P((const char *zfile)); + +/* Remove a directory and all the files in it. */ +extern boolean fsysdep_rmdir P((const char *zdir)); + +#endif /* ! defined (SYSTEM_H) */ diff --git a/gnu/libexec/uucp/common_sources/tcp.c b/gnu/libexec/uucp/common_sources/tcp.c new file mode 100644 index 00000000000..c38760da85c --- /dev/null +++ b/gnu/libexec/uucp/common_sources/tcp.c @@ -0,0 +1,470 @@ +/* tcp.c + Code to handle TCP connections. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tcp_rcsid[] = "$Id: tcp.c,v 1.1 1993/08/04 19:31:06 jtc Exp $"; +#endif + +#if HAVE_TCP + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_TYPES_TCP_H +#include <sys/types.tcp.h> +#endif +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* This code handles TCP connections. It assumes a Berkeley socket + interface. */ + +/* The normal "uucp" port number. */ +#define IUUCP_PORT (540) + +/* Local functions. */ +static void utcp_free P((struct sconnection *qconn)); +static boolean ftcp_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftcp_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftcp_reset P((struct sconnection *qconn)); +static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); +static int itcp_port_number P((const char *zport)); + +/* The command table for a TCP connection. */ +static const struct sconncmds stcpcmds = +{ + utcp_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftcp_open, + ftcp_close, + ftcp_reset, + ftcp_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Initialize a TCP connection. */ + +boolean +fsysdep_tcp_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->zdevice = NULL; + q->iflags = -1; + q->istdout_flags = -1; + q->fterminal = FALSE; + q->ftli = FALSE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stcpcmds; + return TRUE; +} + +/* Free a TCP connection. */ + +static void +utcp_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Open a TCP connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftcp_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + struct sockaddr_in s; + const char *zport; + uid_t iuid, ieuid; + + ulog_device ("TCP"); + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + qsysdep->o = socket (AF_INET, SOCK_STREAM, 0); + if (qsysdep->o < 0) + { + ulog (LOG_ERROR, "socket: %s", strerror (errno)); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* If we aren't waiting for a connection, we're done. */ + if (! fwait) + return TRUE; + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + bzero ((pointer) &s, sizeof s); + s.sin_family = AF_INET; + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + s.sin_addr.s_addr = htonl (INADDR_ANY); + + /* Swap to our real user ID when doing the bind call. This will + permit the server to use privileged TCP ports when invoked by + root. We only swap if our effective user ID is not root, so that + the program can also be made suid root in order to get privileged + ports when invoked by anybody. */ + iuid = getuid (); + ieuid = geteuid (); + if (ieuid != 0) + { +#if HAVE_SETREUID + /* Swap the effective user id and the real user id. We can then + swap them back again when we want to return to the uucp + user's permissions. */ + if (setreuid (ieuid, iuid) < 0) + { + ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", + (long) ieuid, (long) iuid, strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set the effective user id to the real user id. Since the + effective user id is the saved setuid we will able to set + back to it later. If the real user id is root we will not be + able to switch back and forth, but that doesn't matter since + we only want to switch once. */ + if (setuid (iuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, + strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } +#else /* ! HAVE_SAVED_SETUID */ + /* There's no way to switch between real permissions and + effective permissions. Just try the bind with the uucp + permissions. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + } + + if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + ulog (LOG_FATAL, "bind: %s", strerror (errno)); + + /* Now swap back to the uucp user ID. */ + if (ieuid != 0) + { +#if HAVE_SETREUID + if (setreuid (iuid, ieuid) < 0) + { + ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", + (long) iuid, (long) ieuid, strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set ourselves back to our original effective user id. */ + if (setuid ((uid_t) ieuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, + strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } +#else /* ! HAVE_SAVED_SETUID */ + /* We didn't switch, no need to switch back. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + } + + if (listen (qsysdep->o, 5) < 0) + ulog (LOG_FATAL, "listen: %s", strerror (errno)); + + while (! FGOT_SIGNAL ()) + { + size_t clen; + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Waiting for connections"); + + clen = sizeof s; + onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen); + if (onew < 0) + ulog (LOG_FATAL, "accept: %s", strerror (errno)); + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + (void) close (qsysdep->o); + qsysdep->o = onew; + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftcp_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + fret = TRUE; + if (qsysdep->o >= 0 && close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + qsysdep->o = -1; + return fret; +} + +/* Reset the port. This will be called by a child which was forked + off in ftcp_open, above. We don't want uucico to continue looping + and giving login prompts, so we pretend that we received a SIGINT + signal. This should probably be handled more cleanly. The signal + will not be recorded in the log file because we don't set + afLog_signal[INDEXSIG_SIGINT]. */ + +/*ARGSUSED*/ +static boolean +ftcp_reset (qconn) + struct sconnection *qconn; +{ + afSignal[INDEXSIG_SIGINT] = TRUE; + return TRUE; +} + +/* Dial out on a TCP port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialer; +{ + struct ssysdep_conn *qsysdep; + const char *zhost; + struct hostent *q; + struct sockaddr_in s; + const char *zport; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialer = DIALERFOUND_FALSE; + + zhost = zphone; + if (zhost == NULL) + { + if (qsys == NULL) + { + ulog (LOG_ERROR, "No address for TCP connection"); + return FALSE; + } + zhost = qsys->uuconf_zname; + } + + errno = 0; + q = gethostbyname ((char *) zhost); + if (q == NULL) + { + if (errno == 0) + ulog (LOG_ERROR, "%s: unknown host name", zhost); + else + ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno)); + return FALSE; + } + + s.sin_family = q->h_addrtype; + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); + + if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + { + ulog (LOG_ERROR, "connect: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Get the port number given a name. The argument will almost always + be "uucp" so we cache that value. The return value is always in + network byte order. This returns -1 on error. */ + +static int +itcp_port_number (zname) + const char *zname; +{ + boolean fuucp; + static int iuucp; + int i; + char *zend; + struct servent *q; + + fuucp = strcmp (zname, "uucp") == 0; + if (fuucp && iuucp != 0) + return iuucp; + + /* Try it as a number first. */ + i = strtol ((char *) zname, &zend, 10); + if (i != 0 && *zend == '\0') + return htons (i); + + q = getservbyname ((char *) zname, (char *) "tcp"); + if (q == NULL) + { + /* We know that the "uucp" service should be 540, even if isn't + in /etc/services. */ + if (fuucp) + { + iuucp = htons (IUUCP_PORT); + return iuucp; + } + ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno)); + return -1; + } + + if (fuucp) + iuucp = q->s_port; + + return q->s_port; +} + +#endif /* HAVE_TCP */ diff --git a/gnu/libexec/uucp/common_sources/tli.c b/gnu/libexec/uucp/common_sources/tli.c new file mode 100644 index 00000000000..6958b80b470 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/tli.c @@ -0,0 +1,644 @@ +/* tli.c + Code to handle TLI connections. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tli_rcsid[] = "$Id: tli.c,v 1.1 1993/08/04 19:31:09 jtc Exp $"; +#endif + +#if HAVE_TLI + +#include "sysdep.h" +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_TIUSER_H +#include <tiuser.h> +#else +#if HAVE_XTI_H +#include <xti.h> +#else +#if HAVE_SYS_TLI_H +#include <sys/tli.h> +#endif +#endif +#endif + +#if HAVE_STROPTS_H +#include <stropts.h> +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* The arguments to t_alloca have two different names. I want the + SVID ones, not the XPG3 ones. */ +#ifndef T_BIND +#define T_BIND T_BIND_STR +#endif +#ifndef T_CALL +#define T_CALL T_CALL_STR +#endif + +/* Hopefully these externs will not cause any trouble. This is how + they are shown in the SVID. */ +extern int t_errno; +extern char *t_errlist[]; +extern int t_nerr; + +#ifndef t_alloc +extern pointer t_alloc (); +#endif + +/* This code handles TLI connections. It's Unix specific. It's + largely based on code from Unix Network Programming, by W. Richard + Stevens. */ + +/* Local functions. */ +static const char *ztlierror P((void)); +static void utli_free P((struct sconnection *qconn)); +static boolean ftli_push P((struct sconnection *qconn)); +static boolean ftli_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftli_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftli_reset P((struct sconnection *qconn)); +static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); + +/* The command table for a TLI connection. */ +static const struct sconncmds stlicmds = +{ + utli_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftli_open, + ftli_close, + ftli_reset, + ftli_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Get a TLI error string. */ + +static const char * +ztlierror () +{ + if (t_errno == TSYSERR) + return strerror (errno); + if (t_errno < 0 || t_errno >= t_nerr) + return "Unknown TLI error"; + return t_errlist[t_errno]; +} + +/* Initialize a TLI connection. */ + +boolean +fsysdep_tli_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->zdevice = NULL; + q->iflags = -1; + q->istdout_flags = -1; + q->fterminal = FALSE; + q->ftli = TRUE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stlicmds; + return TRUE; +} + +/* Free a TLI connection. */ + +static void +utli_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Push all desired modules onto a TLI stream. If the user requests a + STREAMS connection without giving a list of modules, we just push + tirdwr. If the I_PUSH ioctl is not defined on this system, we just + ignore any list of modules. */ + +static boolean +ftli_push (qconn) + struct sconnection *qconn; +{ +#ifdef I_PUSH + + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL) + { + char **pz; + + for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush; + *pz != NULL; + pz++) + { + if (ioctl (qsysdep->o, I_PUSH, *pz) < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz, + strerror (errno)); + return FALSE; + } + } + } + else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + { + if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s", + strerror (errno)); + return FALSE; + } + } + + /* If we have just put the connection into stream mode, we must turn + off the TLI flag to avoid using TLI calls on it. */ + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + qsysdep->ftli = FALSE; + +#endif /* defined (I_PUSH) */ + + return TRUE; +} + +/* Open a TLI connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftli_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + const char *zdevice; + char *zfreedev; + const char *zservaddr; + char *zfreeaddr; + struct t_bind *qtbind; + struct t_call *qtcall; + + /* Unlike most other device types, we don't bother to call + ulog_device here, because fconn_open calls it with the name of + the port anyhow. */ + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice; + if (zdevice == NULL) + zdevice = qconn->qport->uuconf_zname; + + zfreedev = NULL; + if (*zdevice != '/') + { + zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice)); + sprintf (zfreedev, "/dev/%s", zdevice); + zdevice = zfreedev; + } + + qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (qsysdep->o < 0) + { + ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ()); + ubuffree (zfreedev); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* If we aren't waiting for a connection, we can bind to any local + address, and then we're finished. */ + if (! fwait) + { + ubuffree (zfreedev); + if (t_bind (qsysdep->o, (struct t_bind *) NULL, + (struct t_bind *) NULL) < 0) + { + ulog (LOG_ERROR, "t_bind: %s", ztlierror ()); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + return TRUE; + } + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL); + if (qtbind == NULL) + ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ()); + + zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr; + if (zservaddr == NULL) + ulog (LOG_FATAL, "Can't run as TLI server; no server address"); + + zfreeaddr = zbufcpy (zservaddr); + qtbind->addr.len = cescape (zfreeaddr); + if (qtbind->addr.len > qtbind->addr.maxlen) + ulog (LOG_FATAL, "%s: TLI server address too long (max %d)", + zservaddr, qtbind->addr.maxlen); + memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len); + ubuffree (zfreeaddr); + + qtbind->qlen = 5; + + if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0) + ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ()); + + (void) t_free ((pointer) qtbind, T_BIND); + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL); + if (qtcall == NULL) + ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ()); + + while (! FGOT_SIGNAL ()) + { + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Waiting for connections"); + + if (t_listen (qsysdep->o, qtcall) < 0) + ulog (LOG_FATAL, "t_listen: %s", ztlierror ()); + + onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (onew < 0) + ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ()); + + if (fcntl (onew, F_SETFD, + fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) + ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + + if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0) + ulog (LOG_FATAL, "t_bind: %s", ztlierror ()); + + if (t_accept (qsysdep->o, onew, qtcall) < 0) + { + /* We may have received a disconnect. */ + if (t_errno != TLOOK) + ulog (LOG_FATAL, "t_accept: %s", ztlierror ()); + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ()); + (void) t_close (onew); + continue; + } + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + ulog_close (); + + (void) t_close (qsysdep->o); + qsysdep->o = onew; + + /* Push any desired modules. */ + if (! ftli_push (qconn)) + _exit (EXIT_FAILURE); + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) t_close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftli_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + fret = TRUE; + if (qsysdep->o >= 0) + { + if (qsysdep->ftli) + { + if (t_close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "t_close: %s", ztlierror ()); + fret = FALSE; + } + } + else + { + if (close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + } + + qsysdep->o = -1; + } + + return fret; +} + +/* Reset the port. This will be called by a child which was forked + off in ftli_open, above. We don't want uucico to continue looping + and giving login prompts, so we pretend that we received a SIGINT + signal. This should probably be handled more cleanly. The signal + will not be recorded in the log file because we don't set + afLog_signal[INDEXSIG_SIGINT]. */ + +/*ARGSUSED*/ +static boolean +ftli_reset (qconn) + struct sconnection *qconn; +{ + afSignal[INDEXSIG_SIGINT] = TRUE; + return TRUE; +} + +/* Dial out on a TLI port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialerfound; +{ + struct ssysdep_conn *qsysdep; + char **pzdialer; + const char *zaddr; + struct t_call *qtcall; + char *zescape; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialerfound = DIALERFOUND_FALSE; + + pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer; + if (*pzdialer == NULL) + pzdialer = NULL; + + /* If the first dialer is "TLI" or "TLIS", we use the first token + (pzdialer[1]) as the address to connect to. */ + zaddr = zphone; + if (pzdialer != NULL + && (strcmp (pzdialer[0], "TLI") == 0 + || strcmp (pzdialer[0], "TLIS") == 0)) + { + if (pzdialer[1] == NULL) + ++pzdialer; + else + { + if (strcmp (pzdialer[1], "\\D") != 0 + && strcmp (pzdialer[1], "\\T") != 0) + zaddr = pzdialer[1]; + pzdialer += 2; + } + } + + if (zaddr == NULL) + { + ulog (LOG_ERROR, "No address for TLI connection"); + return FALSE; + } + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR); + if (qtcall == NULL) + { + ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ()); + return FALSE; + } + + zescape = zbufcpy (zaddr); + qtcall->addr.len = cescape (zescape); + if (qtcall->addr.len > qtcall->addr.maxlen) + { + ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr, + qtcall->addr.maxlen); + ubuffree (zescape); + return FALSE; + } + memcpy (qtcall->addr.buf, zescape, qtcall->addr.len); + ubuffree (zescape); + + if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0) + { + if (t_errno != TLOOK) + ulog (LOG_ERROR, "t_connect: %s", ztlierror ()); + else + { + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ()); + else + ulog (LOG_ERROR, "Connection refused"); + } + return FALSE; + } + + /* We've connected to the remote. Push any desired modules. */ + if (! ftli_push (qconn)) + return FALSE; + + /* Handle the rest of the dialer sequence. This is similar to + fmodem_dial, and they should, perhaps, be combined somehow. */ + if (pzdialer != NULL) + { + boolean ffirst; + + ffirst = TRUE; + while (*pzdialer != NULL) + { + int iuuconf; + struct uuconf_dialer *q; + struct uuconf_dialer s; + const char *ztoken; + boolean ftranslate; + + if (! ffirst) + q = &s; + else + q = qdialer; + + iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q); + if (iuuconf == UUCONF_NOT_FOUND) + { + ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + ++pzdialer; + ztoken = *pzdialer; + + ftranslate = FALSE; + if (ztoken == NULL + || strcmp (ztoken, "\\D") == 0) + ztoken = zphone; + else if (strcmp (ztoken, "\\T") == 0) + { + ztoken = zphone; + ftranslate = TRUE; + } + + if (! fchat (qconn, puuconf, &q->uuconf_schat, + (const struct uuconf_system *) NULL, q, + zphone, ftranslate, qconn->qport->uuconf_zname, + (long) 0)) + { + (void) uuconf_dialer_free (puuconf, q); + if (! ffirst) + (void) uuconf_dialer_free (puuconf, qdialer); + return FALSE; + } + + if (ffirst) + { + *ptdialerfound = DIALERFOUND_FREE; + ffirst = FALSE; + } + else + (void) uuconf_dialer_free (puuconf, q); + + if (*pzdialer != NULL) + ++pzdialer; + } + } + + return TRUE; +} + +#endif /* HAVE_TLI */ diff --git a/gnu/libexec/uucp/common_sources/trans.h b/gnu/libexec/uucp/common_sources/trans.h new file mode 100644 index 00000000000..79c380ea48d --- /dev/null +++ b/gnu/libexec/uucp/common_sources/trans.h @@ -0,0 +1,268 @@ +/* trans.h + Header file for file and command transfer routines. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* The maximum possible number of channels. */ +#define IMAX_CHAN (16) + +/* The ifeatures field of the sdaemon structure is an or of the + following values. These values are sent during the uucico + handshake, and MUST NOT CHANGE. */ + +/* File size negotiation. */ +#define FEATURE_SIZES (01) + +/* File transfer restart. */ +#define FEATURE_RESTART (02) + +/* The E (execute) command. */ +#define FEATURE_EXEC (04) + +/* Version 1.03: requires decimal size in S and R command. Needless + to say, this should not be used by any new programs. */ +#define FEATURE_V103 (010) + +/* SVR4 UUCP: expects dummy string between notify field and size field + in send command. There is probably some meaning to this string, + but I don't know what it is. If I ever find out, this flag will + still be used to indicate it. */ +#define FEATURE_SVR4 (020) + +/* This structure is used to hold information concerning the + communication link established with the remote system. */ + +struct sdaemon +{ + /* Global uuconf pointer. */ + pointer puuconf; + /* Remote system information. */ + const struct uuconf_system *qsys; + /* Local name being used. */ + const char *zlocalname; + /* Connection structure. */ + struct sconnection *qconn; + /* Protocol being used. */ + const struct sprotocol *qproto; + /* The largest file size permitted for a local request. */ + long clocal_size; + /* The largest file size permitted for a remote request. */ + long cremote_size; + /* The largest file size that may ever be transferred. */ + long cmax_ever; + /* The remote system ulimit. */ + long cmax_receive; + /* Features supported by the remote side. */ + int ifeatures; + /* TRUE if we should request the remote side to hang up. */ + boolean frequest_hangup; + /* TRUE if the remote side requested a hangup. */ + boolean fhangup_requested; + /* TRUE if we are hanging up. */ + boolean fhangup; + /* TRUE if the local system is currently the master. */ + boolean fmaster; + /* TRUE if the local system placed the call. */ + boolean fcaller; + /* UUCONF_RELIABLE_* flags for the connection. */ + int ireliable; + /* If fcaller is FALSE, the lowest grade which may be transferred + during this call. */ + char bgrade; +}; + +/* This structure is used to hold a file or command transfer which is + in progress. */ + +struct stransfer +{ + /* Next file transfer in queue. */ + struct stransfer *qnext; + /* Previous file transfer in queue. */ + struct stransfer *qprev; + /* Points to the queue this structure is on. */ + struct stransfer **pqqueue; + /* The function to call to send some data. */ + boolean (*psendfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon)); + /* The function to call when data is received. */ + boolean (*precfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); + /* Type specific information. */ + pointer pinfo; + /* TRUE if we are sending the file e (this is used to avoid a call + to psendfn). */ + boolean fsendfile; + /* TRUE if we are receiving the file e (this is used to avoid a call + to precfn). */ + boolean frecfile; + /* The file to read or write. */ + openfile_t e; + /* The position we are at in the file. */ + long ipos; + /* TRUE if we are waiting for a command string. */ + boolean fcmd; + /* The command string we have so far. */ + char *zcmd; + /* The length of the command string we have so far. */ + size_t ccmd; + /* Local destination number. */ + int ilocal; + /* Remote destination number. */ + int iremote; + /* The command. */ + struct scmd s; + /* A message to log when work starts. */ + char *zlog; + /* The process time; imicros can be negative. */ + long isecs; + long imicros; + /* Number of bytes sent or received. */ + long cbytes; +}; + +/* Reasons that a file transfer might fail. */ + +enum tfailure +{ + /* No failure. */ + FAILURE_NONE, + /* No permission for operation. */ + FAILURE_PERM, + /* Can't open necessary file. */ + FAILURE_OPEN, + /* Not enough space to receive file. */ + FAILURE_SIZE, + /* File was received in a previous conversation. */ + FAILURE_RECEIVED +}; + +/* The main loop which talks to the remote system, passing transfer + requests and file back and forth. */ +extern boolean floop P((struct sdaemon *qdaemon)); + +/* Allocate a new transfer structure. */ +extern struct stransfer *qtransalc P((struct scmd *qcmd)); + +/* Free a transfer structure. */ +extern void utransfree P((struct stransfer *qtrans)); + +/* Queue up local requests. If pfany is not NULL, this sets *pfany to + TRUE if there are, in fact, any local requests which can be done at + this point. */ +extern boolean fqueue P((struct sdaemon *qdaemon, boolean *pfany)); + +/* Clear away any queued requests. This may be called more than once + at the end of a call. */ +extern void uclear_queue P((struct sdaemon *qdaemon)); + +/* Queue a new transfer request made by the local system. */ +extern boolean fqueue_local P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* Queue a new transfer request made by the remote system. */ +extern boolean fqueue_remote P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* Queue a transfer request which wants to send something. */ +extern boolean fqueue_send P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* Queue a transfer request which wants to receiving something. */ +extern boolean fqueue_receive P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* Prepare to send a file by local or remote request. */ +extern boolean flocal_send_file_init P((struct sdaemon *qdaemon, + struct scmd *qcmd)); +extern boolean fremote_send_file_init P((struct sdaemon *qdaemon, + struct scmd *qcmd, + int iremote)); + +/* Prepare to receive a file by local or remote request. */ +extern boolean flocal_rec_file_init P((struct sdaemon *qdaemon, + struct scmd *qcmd)); +extern boolean fremote_rec_file_init P((struct sdaemon *qdaemon, + struct scmd *qcmd, + int iremote)); + +/* Prepare to request work by local or remote request. */ +extern boolean flocal_xcmd_init P((struct sdaemon *qdaemon, + struct scmd *qcmd)); +extern boolean fremote_xcmd_init P((struct sdaemon *qdaemon, + struct scmd *qcmd, + int iremote)); + +/* We have lost the connection; record any in progress file transfers + in the statistics file and discard any temporary files. */ +extern void ufailed P((struct sdaemon *qdaemon)); + +/* Check that there is enough disk space for a file receive. Return + FALSE if there is not. */ +extern boolean frec_check_free P((struct stransfer *qtrans, + long cfree_space)); + +/* Discard the temporary file being used to receive a file, if + appropriate. */ +extern boolean frec_discard_temp P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* Handle data received by a protocol. This is called by the protocol + specific routines as data comes in. The data is passed as two + buffers because that is convenient for packet based protocols, but + normally csecond will be 0. The ilocal argument is the local + channel number, and the iremote argument is the remote channel + number. Either may be -1, if the protocol does not have channels. + The ipos argument is the position in the file, if the protocol + knows it; for most protocols, this will be -1. The fallacked + argument should be set to TRUE if the remote has acknowledged all + outstanding data; see uwindow_acked, below, for details. This will + set *pfexit to TRUE if there is something for the main loop to do. + A file is complete is when a zero length buffer is passed (cfirst + == 0). A command is complete when data containing a null byte is + passed. This will return FALSE on error. If the protocol pfwait + entry point should exit and let the top level loop continue, + *pfexit will be set to TRUE (if pfexit is not NULL). This will not + set *pfexit to FALSE, so the caller must do that. */ +extern boolean fgot_data P((struct sdaemon *qdaemon, + const char *zfirst, size_t cfirst, + const char *zsecond, size_t csecond, + int ilocal, int iremote, + long ipos, boolean fallacked, + boolean *pfexit)); + +/* This routine is called when an ack is sent for a file receive. */ +extern void usent_receive_ack P((struct sdaemon *qdaemon, + struct stransfer *qtrans)); + +/* A protocol may call this routine to indicate the packets have been + acknowledged by the remote system. If the fallacked argument is + TRUE, then all outstanding packets have been acknowledged; for + convenience, this may also be indicated by passing fallacked as + TRUE to fgot_data, above. Otherwise this routine should be called + each time a complete window is acked by the remote system. The + transfer code uses this information to keep track of when an + acknowledgement of a file receive has been seen by the other side, + so that file receives may be handled cleanly if the connection is + lost. */ +extern void uwindow_acked P((struct sdaemon *qdaemon, + boolean fallacked)); diff --git a/gnu/libexec/uucp/common_sources/util.c b/gnu/libexec/uucp/common_sources/util.c new file mode 100644 index 00000000000..2ddc2608ddc --- /dev/null +++ b/gnu/libexec/uucp/common_sources/util.c @@ -0,0 +1,144 @@ +/* util.c + A couple of UUCP utility functions. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char util_rcsid[] = "$Id: util.c,v 1.1 1993/08/04 19:31:13 jtc Exp $"; +#endif + +#include <ctype.h> + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* Get information for an unknown system. This will leave the name + allocated on the heap. We could fix this by breaking the + abstraction and adding the name to qsys->palloc. It makes sure the + name is not too long, but takes no other useful action. */ + +boolean +funknown_system (puuconf, zsystem, qsys) + pointer puuconf; + const char *zsystem; + struct uuconf_system *qsys; +{ + char *z; + int iuuconf; + + if (strlen (zsystem) <= cSysdep_max_name_len) + z = zbufcpy (zsystem); + else + { + char **pznames, **pz; + boolean ffound; + + z = zbufalc (cSysdep_max_name_len + 1); + memcpy (z, zsystem, cSysdep_max_name_len); + z[cSysdep_max_name_len] = '\0'; + + iuuconf = uuconf_system_names (puuconf, &pznames, TRUE); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + ffound = FALSE; + for (pz = pznames; *pz != NULL; pz++) + { + if (strcmp (*pz, z) == 0) + ffound = TRUE; + xfree ((pointer) *pz); + } + xfree ((pointer) pznames); + + if (ffound) + { + ubuffree (z); + return FALSE; + } + } + + iuuconf = uuconf_system_unknown (puuconf, qsys); + if (iuuconf == UUCONF_NOT_FOUND) + { + ubuffree (z); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + for (; qsys != NULL; qsys = qsys->uuconf_qalternate) + qsys->uuconf_zname = z; + + return TRUE; +} + +/* See whether a file is in a directory list, and make sure the user + has appropriate access. */ + +boolean +fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser) + const char *zfile; + char **pzdirs; + const char *zpubdir; + boolean fcheck; + boolean freadable; + const char *zuser; +{ + boolean fmatch; + char **pz; + + fmatch = FALSE; + + for (pz = pzdirs; *pz != NULL; pz++) + { + char *zuse; + + if (pz[0][0] == '!') + { + zuse = zsysdep_local_file (*pz + 1, zpubdir); + if (zuse == NULL) + return FALSE; + + if (fsysdep_in_directory (zfile, zuse, FALSE, + FALSE, (const char *) NULL)) + fmatch = FALSE; + } + else + { + zuse = zsysdep_local_file (*pz, zpubdir); + if (zuse == NULL) + return FALSE; + + if (fsysdep_in_directory (zfile, zuse, fcheck, + freadable, zuser)) + fmatch = TRUE; + } + + ubuffree (zuse); + } + + return fmatch; +} diff --git a/gnu/libexec/uucp/common_sources/uuconf.h b/gnu/libexec/uucp/common_sources/uuconf.h new file mode 100644 index 00000000000..4bf6bccbf3f --- /dev/null +++ b/gnu/libexec/uucp/common_sources/uuconf.h @@ -0,0 +1,1496 @@ +/* uuconf.h + Header file for UUCP configuration routines. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The use of an object file which uses material from this header + file, and from no other portion of the uuconf library, is + unrestricted, as described in paragraph 4 of section 5 of version 2 + of the GNU Library General Public License (this sentence is merely + informative, and does not modify the License in any way). + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#ifndef UUCONF_H + +#define UUCONF_H + +#include <stdio.h> + +/* The macro UUCONF_ANSI_C may be used to override __STDC__. */ +#ifndef UUCONF_ANSI_C +#ifdef __STDC__ +#define UUCONF_ANSI_C 1 +#else /* ! defined (__STDC__) */ +#define UUCONF_ANSI_C 0 +#endif /* ! defined (__STDC__) */ +#endif /* ! defined (UUCONF_ANSI_C) */ + +#if UUCONF_ANSI_C +#define UUCONF_CONST const +typedef void *UUCONF_POINTER; +#include <stddef.h> +typedef size_t UUCONF_SIZE_T; +#else +#define UUCONF_CONST +typedef char *UUCONF_POINTER; +typedef unsigned int UUCONF_SIZE_T; +#endif + +/* The field names of each of the following structures begin with + "uuconf_". This is to avoid any conflicts with user defined + macros. The first character following the "uuconf_" string + indicates the type of the field. + + z -- a string (char *) + c -- a count (normally int) + i -- an integer value (normally int) + f -- a boolean value (normally int) + b -- a single character value (char or int) + t -- an enum (enum XX) + s -- a structure (struct XX) + u -- a union (union XX) + q -- a pointer to a structure (struct XX *) + p -- a pointer to something other than a string + */ + +/* The information which is kept for a chat script. */ + +struct uuconf_chat +{ + /* The script itself. This is a NULL terminated list of expect/send + pairs. The first string is an expect string. A string starting + with a '-' indicates subsend string; the following strings which + start with '-' are subexpect/subsend strings. This field may be + NULL, in which case there is no chat script (but pzprogram may + hold a program to run). */ + char **uuconf_pzchat; + /* The chat program to run. This is a NULL terminated list of + arguments; element 0 if the program. May be NULL, in which case + there is no program. */ + char **uuconf_pzprogram; + /* The timeout in seconds to use for expect strings in the chat + script. */ + int uuconf_ctimeout; + /* The NULL terminated list of failure strings. If any of these + strings appear, the chat script is aborted. May be NULL, in + which case there are no failure strings. */ + char **uuconf_pzfail; + /* Non-zero if incoming characters should be stripped to seven bits + (by anding with 0x7f). */ + int uuconf_fstrip; +}; + +/* The information which is kept for a time specification. This is a + linked list of structures. Each element of the list represents a + span of time, giving a starting time and an ending time. The time + only depends on the day of the week, not on the day of the month or + of the year. The time is only specified down to the minute, not + down to the second or below. The list is sorted by starting time. + + The starting and ending time are expressed in minutes since the + beginning of the week, which is considered to be 12 midnight on + Sunday. Thus 60 is 1 am on Sunday, 1440 (== 60 * 24) is 12 + midnight on Monday, and the largest possible value is 10080 (== 60 + * 24 * 7) which is 12 midnight on the following Sunday. + + Each span of time has a value associated with it. This is the + lowest grade or the largest file size that may be transferred + during that time, depending on the source of the time span. When + time specifications overlap, the value used for the overlap is the + higher grade or the smaller file size. Thus specifying + ``call-timegrade z Any'' and ``call-timegrade Z Mo'' means that + only grade Z or higher may be sent on Monday, since Z is the higer + grade of the overlapping spans. The final array wil have no + overlaps. + + Each span also has a retry time associated with it. This permits + different retry times to be used at different times of day. The + retry time is only relevant if the span came from a ``time'' or + ``timegrade'' command for a system. */ + +struct uuconf_timespan +{ + /* Next element in list. */ + struct uuconf_timespan *uuconf_qnext; + /* Starting minute (-1 at the end of the array). */ + int uuconf_istart; + /* Ending minute. */ + int uuconf_iend; + /* Value for this span (lowest grade or largest file that may be + transferred at this time). */ + long uuconf_ival; + /* Retry time. */ + int uuconf_cretry; +}; + +/* The information which is kept for protocol parameters. Protocol + parameter information is stored as an array of the following + structures. */ + +struct uuconf_proto_param +{ + /* The name of the protocol to which this entry applies. This is + '\0' for the last element of the array. */ + int uuconf_bproto; + /* Specific entries for this protocol. This points to an array + ending in an element with a uuconf_cargs field of 0. */ + struct uuconf_proto_param_entry *uuconf_qentries; +}; + +/* Each particular protocol parameter entry is one of the following + structures. */ + +struct uuconf_proto_param_entry +{ + /* The number of arguments to the ``protocol-parameter'' command + (not counting ``protocol-parameter'' itself). This is 0 for the + last element of the array. */ + int uuconf_cargs; + /* The actual arguments to the ``protocol-parameter'' command; this + is an array with cargs entries. */ + char **uuconf_pzargs; +}; + +/* The information which is kept for a system. The zname and zalias + fields will be the same for all alternates. Every other fields is + specific to the particular alternate in which it appears (although + most will be the same for all alternates). */ + +struct uuconf_system +{ + /* The name of the system. */ + char *uuconf_zname; + /* A list of aliases for the system. This is a NULL terminated list + of strings. May be NULL, in which case there are no aliases. */ + char **uuconf_pzalias; + /* A linked list of alternate call in or call out information. Each + alternative way to call this system occupies an element of this + list. May be NULL, in which case there are no alternates. */ + struct uuconf_system *uuconf_qalternate; + /* The name for this particular alternate. May be NULL, in which + case this alternate does not have a name. */ + char *uuconf_zalternate; + /* If non-zero, this alternate may be used for calling out. */ + int uuconf_fcall; + /* If non-zero, this alternate may be used for accepting a call. */ + int uuconf_fcalled; + /* The times at which this system may be called. The ival field of + each uuconf_timespan structure is the lowest grade which may be + transferred at that time. The cretry field is the number of + minutes to wait before retrying the call, or 0 if it was not + specified. May be NULL, in which case the system may never be + called. */ + struct uuconf_timespan *uuconf_qtimegrade; + /* The times at which to request a particular grade of the system + when calling it, and the grades to request. The ival field of + each uuconf_timespan structure is the lowest grade which the + other system should transfer at that time. May be NULL, in which + case there are no grade restrictions. */ + struct uuconf_timespan *uuconf_qcalltimegrade; + /* The maximum number of times to retry calling this system. If + this is 0, there is no limit. */ + int uuconf_cmax_retries; + /* The number of minutes to wait between successful calls to a + system. */ + int uuconf_csuccess_wait; + /* The size restrictions by time for local requests during a locally + placed call. The ival field of each uuconf_timespan structure is + the size in bytes of the largest file which may be transferred at + that time. May be NULL, in which case there are no size + restrictions. */ + struct uuconf_timespan *uuconf_qcall_local_size; + /* The size restrictions by time for remote requests during a + locally placed call. May be NULL. */ + struct uuconf_timespan *uuconf_qcall_remote_size; + /* The size restrictions by time for local requests during a + remotely placed call. May be NULL. */ + struct uuconf_timespan *uuconf_qcalled_local_size; + /* The size restrictions by time for remote requests during a + remotely placed call. May be NULL. */ + struct uuconf_timespan *uuconf_qcalled_remote_size; + /* Baud rate, or speed. Zero means any baud rate. If ihighbaud is + non-zero, this is the low baud rate of a range. */ + long uuconf_ibaud; + /* If non-zero, ibaud is the low baud rate of a range and ihighbaud + is the high baud rate. */ + long uuconf_ihighbaud; + /* Port name to use. May be NULL. If an HDB configuration file + contains a modem class (alphabetic characters preceeding the baud + rate), the class is appended to the port name. */ + char *uuconf_zport; + /* Specific port information, if the system entry includes port + information. May be NULL. */ + struct uuconf_port *uuconf_qport; + /* Phone number to call, or address to use for a TCP connection. + May be NULL, in which case a dialer script may not use \D or \T + for this system, and a TCP port will use the system name. */ + char *uuconf_zphone; + /* Chat script to use when logging in to the system. */ + struct uuconf_chat uuconf_schat; + /* Login name to use for \L in the login chat script. This should + normally be accessed via uuconf_callout. If it is "*", + uuconf_callout will look it up in the call out file. This may be + NULL, in which case the login script may not use \L. */ + char *uuconf_zcall_login; + /* Password to use for \P in the login chat script. This should + normally be accessed via uuconf_callout. If it is "*", + uuconf_callout will look it up in the call out file. This may be + NULL, in which case the login script may not use \P. */ + char *uuconf_zcall_password; + /* The login name this system must use when calling in. This may be + different for different alternates. This should only be examined + if uuconf_fcalled is TRUE. If this is NULL or "ANY" then + uuconf_validate must be called to make sure that whatever login + name was used is permitted for this machine. */ + char *uuconf_zcalled_login; + /* If non-zero, then when this system calls in the call should not + be allowed to proceed and the system should be called back. */ + int uuconf_fcallback; + /* If non-zero, then conversation sequence numbers should be used + with this system. */ + int uuconf_fsequence; + /* A list of protocols to use with this system. Each protocol has a + single character name. May be NULL, in which case any known + protocol may be used. */ + char *uuconf_zprotocols; + /* Array of protocol parameters. Ends in an entry with a + uuconf_bproto field of '\0'. May be NULL. */ + struct uuconf_proto_param *uuconf_qproto_params; + /* Chat script to run when called by this system. */ + struct uuconf_chat uuconf_scalled_chat; + /* Debugging level to set during a conversation. May be NULL. */ + char *uuconf_zdebug; + /* Maximum remote debugging level this system may request. May be + NULL. */ + char *uuconf_zmax_remote_debug; + /* Non-zero if the remote system may request us to send files from + the local system to the remote. */ + int uuconf_fsend_request; + /* Non-zero if the remote system may request us to receive files + from the remote system to the local. */ + int uuconf_frec_request; + /* Non-zero if local requests are permitted when calling this + system. */ + int uuconf_fcall_transfer; + /* Non-zero if local requests are permitted when this system calls + in. */ + int uuconf_fcalled_transfer; + /* NULL terminated list of directories from which files may be sent + by local request. */ + char **uuconf_pzlocal_send; + /* NULL terminated list of directories from which files may be sent + by remote request. */ + char **uuconf_pzremote_send; + /* NULL terminated list of directories into which files may be + received by local request. */ + char **uuconf_pzlocal_receive; + /* NULL terminated list of directories into which files may be + received by remote request. */ + char **uuconf_pzremote_receive; + /* Path to use for command execution. This is a NULL terminated + list of directories. */ + char **uuconf_pzpath; + /* NULL terminated List of commands that may be executed. */ + char **uuconf_pzcmds; + /* Amount of free space to leave when accepting a file from this + system, in bytes. */ + long uuconf_cfree_space; + /* NULL terminated list of systems that this system may forward + from. May be NULL if there are no systems from which files may + be forwarded. The list may include "ANY". */ + char **uuconf_pzforward_from; + /* NULL terminated list of systems that this system may forward to. + May be NULL if there are no systems to which files may be + forwarded. The list may include "ANY". */ + char **uuconf_pzforward_to; + /* The public directory to use for this sytem. */ + const char *uuconf_zpubdir; + /* The local name to use for this remote system. May be NULL if the + usual local name should be used. */ + char *uuconf_zlocalname; + /* Memory allocation block for the system. */ + UUCONF_POINTER uuconf_palloc; +}; + +/* Types of ports. */ + +enum uuconf_porttype +{ + /* Unknown port type. A port of this type should never be returned + by the uuconf functions. */ + UUCONF_PORTTYPE_UNKNOWN, + /* Read from standard input and write to standard output. Not + normally used. */ + UUCONF_PORTTYPE_STDIN, + /* A modem port. */ + UUCONF_PORTTYPE_MODEM, + /* A direct connect port. */ + UUCONF_PORTTYPE_DIRECT, + /* A TCP port. Not supported on all systems. */ + UUCONF_PORTTYPE_TCP, + /* A TLI port. Not supported on all systems. */ + UUCONF_PORTTYPE_TLI +}; + +/* Additional information for a stdin port (there is none). */ + +struct uuconf_stdin_port +{ + int uuconf_idummy; +}; + +/* Additional information for a modem port. */ + +struct uuconf_modem_port +{ + /* The device name. May be NULL, in which case the port name is + used instead. */ + char *uuconf_zdevice; + /* The device name to send the dialer chat script to. May be NULL, + in which case the chat script is sent to the usual device. */ + char *uuconf_zdial_device; + /* The default baud rate (speed). If zero, there is no default. */ + long uuconf_ibaud; + /* The low baud rate, if a range is used. If zero, a range is not + used and ihighbaud should be ignored. */ + long uuconf_ilowbaud; + /* The high baud rate, if ilowbaud is non-zero. */ + long uuconf_ihighbaud; + /* Non-zero if the port supports carrier detect. */ + int uuconf_fcarrier; + /* A NULL terminated sequence of dialer/token pairs (element 0 is a + dialer name, element 1 is a token, etc.) May be NULL, in which + case qdialer should not be NULL. */ + char **uuconf_pzdialer; + /* Specific dialer information. Only used if pzdialer is NULL. */ + struct uuconf_dialer *uuconf_qdialer; +}; + +/* Additional information for a direct connect port. */ + +struct uuconf_direct_port +{ + /* The device name. May be NULL, in which case the port name is + used instead. */ + char *uuconf_zdevice; + /* The baud rate (speed). */ + long uuconf_ibaud; +}; + +/* Additional information for a TCP port. */ + +struct uuconf_tcp_port +{ + /* The TCP port number to use. May be a name or a number. May be + NULL, in which case "uucp" is looked up using getservbyname. */ + char *uuconf_zport; +}; + +/* Additional information for a TLI port. */ + +struct uuconf_tli_port +{ + /* Device name to open. May be NULL, in which case the port name is + used. */ + char *uuconf_zdevice; + /* Whether this port should be turned into a stream, permitting the + read and write calls instead of the t_rcv and t_send calls. */ + int uuconf_fstream; + /* A NULL terminated list of modules to push after making the + connection. May be NULL, in which case if fstream is non-zero, + then "tirdwr" is pushed onto the stream, and otherwise nothing is + pushed. */ + char **uuconf_pzpush; + /* A NULL terminated sequence of dialer/token pairs (element 0 is a + dialer name, element 1 is a token, etc.) May be NULL. If + element 0 is TLI or TLIS, element 1 is used as the address to + connect to; otherwise uuconf_zphone from the system information + is used. */ + char **uuconf_pzdialer; + /* Address to use when operating as a server. This may contain + escape sequences. */ + char *uuconf_zservaddr; +}; + +/* Information kept for a port. */ + +struct uuconf_port +{ + /* The name of the port. */ + char *uuconf_zname; + /* The type of the port. */ + enum uuconf_porttype uuconf_ttype; + /* The list of protocols supported by the port. The name of each + protocol is a single character. May be NULL, in which case any + protocol is permitted. */ + char *uuconf_zprotocols; + /* Array of protocol parameters. Ends in an entry with a + uuconf_bproto field of '\0'. May be NULL. */ + struct uuconf_proto_param *uuconf_qproto_params; + /* The set of reliability bits. */ + int uuconf_ireliable; + /* The lock file name to use. */ + char *uuconf_zlockname; + /* Memory allocation block for the port. */ + UUCONF_POINTER uuconf_palloc; + /* The type specific information. */ + union + { + struct uuconf_stdin_port uuconf_sstdin; + struct uuconf_modem_port uuconf_smodem; + struct uuconf_direct_port uuconf_sdirect; + struct uuconf_tcp_port uuconf_stcp; + struct uuconf_tli_port uuconf_stli; + } uuconf_u; +}; + +/* Information kept about a dialer. */ + +struct uuconf_dialer +{ + /* The name of the dialer. */ + char *uuconf_zname; + /* The chat script to use when dialing out. */ + struct uuconf_chat uuconf_schat; + /* The string to send when a `=' appears in the phone number. */ + char *uuconf_zdialtone; + /* The string to send when a `-' appears in the phone number. */ + char *uuconf_zpause; + /* Non-zero if the dialer supports carrier detect. */ + int uuconf_fcarrier; + /* The number of seconds to wait for carrier after the chat script + is complete. Only used if fcarrier is non-zero. Only supported + on some systems. */ + int uuconf_ccarrier_wait; + /* If non-zero, DTR should be toggled before dialing. Only + supported on some systems. */ + int uuconf_fdtr_toggle; + /* If non-zero, sleep for 1 second after toggling DTR. Ignored if + fdtr_toggle is zero. */ + int uuconf_fdtr_toggle_wait; + /* The chat script to use when a call is complete. */ + struct uuconf_chat uuconf_scomplete; + /* The chat script to use when a call is aborted. */ + struct uuconf_chat uuconf_sabort; + /* Array of protocol parameters. Ends in an entry with a + uuconf_bproto field of '\0'. May be NULL. */ + struct uuconf_proto_param *uuconf_qproto_params; + /* The set of reliability bits. */ + int uuconf_ireliable; + /* Memory allocation block for the dialer. */ + UUCONF_POINTER uuconf_palloc; +}; + +/* Reliability bits for the ireliable field of ports and dialers. + These bits are used to decide which protocol to run. A given + protocol will have a set of these bits, and each of them must be + turned on for the port before we will permit that protocol to be + used. This will be overridden by the zprotocols field. */ + +/* Whether a set of reliability bits is given. If this bit is not + set, then there is no reliability information. */ +#define UUCONF_RELIABLE_SPECIFIED (01) + +/* Set if the connection is eight bit transparent. */ +#define UUCONF_RELIABLE_EIGHT (02) + +/* Set if the connection is error-free. */ +#define UUCONF_RELIABLE_RELIABLE (04) + +/* Set if the connection is end-to-end reliable (e.g. TCP). */ +#define UUCONF_RELIABLE_ENDTOEND (010) + +/* Set if the connection is full-duplex; that is, no time consuming + line turnaround is required before sending data in the reverse + direction. If the connection is truly half-duplex, in the sense + that communication can only flow in one direction, UUCP can not be + used. */ +#define UUCONF_RELIABLE_FULLDUPLEX (020) + +/* UUCP grades range from 0 to 9, A to Z, a to z in order from highest + to lowest (work of higher grades is done before work of lower + grades). */ + +/* The highest grade. */ +#define UUCONF_GRADE_HIGH ('0') + +/* The lowest grade. */ +#define UUCONF_GRADE_LOW ('z') + +/* Whether a character is a legal grade (requires <ctype.h>). */ +#define UUCONF_GRADE_LEGAL(b) (isalnum ((unsigned) (b))) + +/* Return < 0 if the first grade should be done before the second + grade, == 0 if they are the same, or > 0 if the first grade should + be done after the second grade. On an ASCII system, this can just + be b1 - b2. */ +#define UUCONF_GRADE_CMP(b1, b2) (uuconf_grade_cmp ((b1), (b2))) + +/* Most of the uuconf functions returns an error code. A value of + zero (UUCONF_SUCCESS) indicates success. */ + +/* If this bit is set in the returned error code, then the + uuconf_errno function may be used to obtain the errno value as set + by the function which caused the failure. */ +#define UUCONF_ERROR_ERRNO (0x100) + +/* If this bit is set in the returned error code, then the + uuconf_filename function may be used to get the name of a file + associated with the error. */ +#define UUCONF_ERROR_FILENAME (0x200) + +/* If this bit is set in the returned error code, then the + uuconf_lineno function may be used to get a line number associated + with the error; normally if this is set UUCONF_ERROR_FILENAME will + also be set. */ +#define UUCONF_ERROR_LINENO (0x400) + +/* There are two UUCONF_CMDTABRET bits that may be set in the return + value of uuconf_cmd_line or uuconf_cmd_args, described below. They + do not indicate an error, but instead give instructions to the + calling function, often uuconf_cmd_file. They may also be set in + the return value of a user function listed in a uuconf_cmdtab + table, in which case they will be honored by uuconf_cmd_file. */ + +/* This bit means that the memory occupied by the arguments passed to + the function should be preserved, and not overwritten or freed. It + refers only to the contents of the arguments; the contents of the + argv array itself may always be destroyed. If this bit is set in + the return value of uuconf_cmd_line or uuconf_cmd_args, it must be + honored. It will be honored by uuconf_cmd_file. This may be + combined with an error code or with UUCONF_CMDTABRET_EXIT, although + neither uuconf_cmd_file or uuconf_cmd_line will do so. */ +#define UUCONF_CMDTABRET_KEEP (0x800) + +/* This bit means that uuconf_cmd_file should exit, rather than go on + to read and process the next line. If uuconf_cmd_line or + uuconf_cmd_args encounter an error, the return value will have this + bit set along with the error code. A user function may set this + bit with or without an error; the return value of the user function + will be returned by uuconf_cmd_file, except that the + UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT bits will be + cleared. */ +#define UUCONF_CMDTABRET_EXIT (0x1000) + +/* This macro may be used to extract the specific error value. */ +#define UUCONF_ERROR_VALUE(i) ((i) & 0xff) + +/* UUCONF_ERROR_VALUE will return one of the following values. */ + +/* Function succeeded. */ +#define UUCONF_SUCCESS (0) +/* Named item not found. */ +#define UUCONF_NOT_FOUND (1) +/* A call to fopen failed. */ +#define UUCONF_FOPEN_FAILED (2) +/* A call to fseek failed. */ +#define UUCONF_FSEEK_FAILED (3) +/* A call to malloc or realloc failed. */ +#define UUCONF_MALLOC_FAILED (4) +/* Syntax error in file. */ +#define UUCONF_SYNTAX_ERROR (5) +/* Unknown command. */ +#define UUCONF_UNKNOWN_COMMAND (6) + +#if UUCONF_ANSI_C + +/* For each type of configuration file (Taylor, V2, HDB), there are + separate routines to read various sorts of information. There are + also generic routines, which call on the appropriate type specific + routines. The library can be compiled to read any desired + combination of the configuration file types. This affects only the + generic routines, as it determines which type specific routines + they call. Thus, on a system which, for example, does not have any + V2 configuration files, there is no need to include the overhead of + the code to parse the files and the time to look for them. + However, a program which specifically wants to be able to parse + them can call the V2 specific routines. + + The uuconf functions all take as an argument a pointer to uuconf + global information. This must be initialized by any the + initialization routines (the generic one and the three file type + specific ones) before any of the other uuconf functions may be + called. */ + +/* Initialize the configuration file reading routines. The ppglobal + argument should point to a generic pointer (a void *, or, on older + compilers, a char *) which will be initialized and may then be + passed to the other uuconf routines. The zprogram argument is the + name of the program for which files should be read. A NULL is + taken as "uucp", and reads the standard UUCP configuration files. + The only other common argument is "cu", but any string is + permitted. The zname argument is the name of the Taylor UUCP + config file; if it is NULL, the default config file will be read. + If not reading Taylor UUCP configuration information, the argument + is ignored. This function must be called before any of the other + uuconf functions. + + Note that if the zname argument is obtained from the user running + the program, the program should be careful to revoke any special + privileges it may have (e.g. on Unix call setuid (getuid ()) and + setgid (getgid ())). Otherwise various sorts of spoofing become + possible. */ +extern int uuconf_init (void **uuconf_ppglobal, + const char *uuconf_zprogram, + const char *uuconf_zname); + +/* Adjust the configuration file global pointer for a new thread. The + library is fully reentrant (with the exception of the function + uuconf_error_string, which calls strerror, which on some systems is + not reentrant), provided that each new thread that wishes to call + the library calls this function and uses the new global pointer + value. The ppglobal argument should be set to the address of the + global pointer set by any of the init functions; it will be + modified to become a new global pointer. */ +extern int uuconf_init_thread (void **uuconf_ppglobal); + +/* Get the names of all known systems. This sets sets *ppzsystems to + point to an array of system names. The list of names is NULL + terminated. The array is allocated using malloc, as is each + element of the array, and they may all be passed to free when they + are no longer needed. If the falias argument is 0, the list will + not include any aliases; otherwise, it will. */ +extern int uuconf_system_names (void *uuconf_pglobal, + char ***uuconf_ppzsystems, + int uuconf_falias); + +/* Get the information for the system zsystem. This sets the fields + in *qsys. This will work whether zsystem is the official name of + the system or merely an alias. */ +extern int uuconf_system_info (void *uuconf_pglobal, + const char *uuconf_zsystem, + struct uuconf_system *uuconf_qsys); + +/* Get information for an unknown (anonymous) system. The + uuconf_zname field of the returned system information will be NULL. + If no information is available for unknown systems, this will + return UUCONF_NOT_FOUND. This does not run the HDB remote.unknown + shell script. */ +extern int uuconf_system_unknown (void *uuconf_pglobal, + struct uuconf_system *uuconf_qsys); + +/* Get information for the local system. Normally the local system + name should first be looked up using uuconf_system_info. If that + returns UUCONF_NOT_FOUND, this function may be used to get an + appropriate set of defaults. The uuconf_zname field of the + returned system information may be NULL. */ +extern int uuconf_system_local (void *uuconf_pglobal, + struct uuconf_system *uuconf_qsys); + +/* Free the memory occupied by system information returned by + uuconf_system_info, uuconf_system_unknown, uuconf_system_local, or + any of the configuration file type specific routines described + below. After this is called, the contents of the structure shall + not be referred to. */ +extern int uuconf_system_free (void *uuconf_pglobal, + struct uuconf_system *uuconf_qsys); + +#ifdef __OPTIMIZE__ +#define uuconf_system_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#endif + +/* Find a matching port. This will consider each port in turn. + + If the zname argument is not NULL, the port's uuconf_zname field + must match it. + + If the ibaud argument is not zero and the ihighbaud argument is + zero, the port's baud rate, if defined, must be the same (if the + port has a range of baud rates, ibaud must be within the range). + If ibaud and ihighbaud are both not zero, the port's baud rate, if + defined, must be between ibaud and ihighbaud inclusive (if the port + has a range of baud rates, the ranges must intersect). If the port + has no baud rate, either because it is a type of port for which + baud rate is not defined (e.g. a TCP port) or because the + uuconf_ibaud field is 0, the ibaud and ihighbaud arguments are + ignored. + + If the pifn argument is not NULL, the port is passed to pifn, along + with the pinfo argument (which is otherwise ignored). If pifn + returns UUCONF_SUCCESS, the port matches. If pifn returns + UUCONF_NOT_FOUND, a new port is sought. Otherwise the return value + of pifn is returned from uuconf_find_port. The pifn function may + be used to further restrict the port, such as by modem class or + device name. It may also be used to lock the port, if appropriate; + in this case, if the lock fails, pifn may return UUCONF_NOT_FOUND + to force uuconf_find_port to continue searching for a port. + + If the port matches, the information is set into uuconf_qport, and + uuconf_find_port returns UUCONF_SUCCESS. */ +extern int uuconf_find_port (void *uuconf_pglobal, + const char *uuconf_zname, + long uuconf_ibaud, + long uuconf_ihighbaud, + int (*uuconf_pifn) (struct uuconf_port *, + void *uuconf_pinfo), + void *uuconf_pinfo, + struct uuconf_port *uuconf_qport); + +/* Free the memory occupied by system information returned by + uuconf_find_port (or any of the configuration file specific + routines described below). After this is called, the contents of + the structure shall not be referred to. */ +extern int uuconf_port_free (void *uuconf_pglobal, + struct uuconf_port *uuconf_qport); + +#ifdef __OPTIMIZE__ +#define uuconf_port_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#endif + +/* Get the names of all known dialers. This sets sets *ppzdialers to + point to an array of dialer names. The list of names is NULL + terminated. The array is allocated using malloc, as is each + element of the array, and they may all be passed to free when they + are no longer needed. */ +extern int uuconf_dialer_names (void *uuconf_pglobal, + char ***uuconf_ppzdialers); + +/* Get the information for the dialer zdialer. This sets the fields + in *qdialer. */ +extern int uuconf_dialer_info (void *uuconf_pglobal, + const char *uuconf_zdialer, + struct uuconf_dialer *uuconf_qdialer); + +/* Free the memory occupied by system information returned by + uuconf_dialer_info (or any of the configuration file specific + routines described below). After this is called, the contents of + the structure shall not be referred to. */ +extern int uuconf_dialer_free (void *uuconf_pglobal, + struct uuconf_dialer *uuconf_qsys); + +#ifdef __OPTIMIZE__ +#define uuconf_dialer_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#endif + +/* Get the local node name. If the node name is not specified + (because no ``nodename'' command appeared in the config file) this + will return UUCONF_NOT_FOUND, and some system dependent function + must be used to determine the node name. Otherwise it will return + a pointer to a constant string, which should not be freed. */ +extern int uuconf_localname (void *uuconf_pglobal, + const char **pzname); + +/* Get the local node name that should be used, given a login name. + This function will check for any special local name that may be + associated with the login name zlogin (as set by the ``myname'' + command in a Taylor configuration file, or the MYNAME field in a + Permissions entry). This will set *pzname to the node name. If no + node name can be determined, *pzname will be set to NULL and the + function will return UUCONF_NOT_FOUND; in this case some system + dependent function must be used to determine the node name. If the + function returns UUCONF_SUCCESS, *pzname will be point to an + malloced buffer. */ +extern int uuconf_login_localname (void *uuconf_pglobal, + const char *uuconf_zlogin, + char **pzname); + +/* Get the name of the UUCP spool directory. This will set *pzspool + to a constant string, which should not be freed. */ +extern int uuconf_spooldir (void *uuconf_pglobal, + const char **uuconf_pzspool); + +/* Get the name of the default UUCP public directory. This will set + *pzpub to a constant string, which should not be freed. Note that + particular systems may use a different public directory. */ +extern int uuconf_pubdir (void *uuconf_pglobal, + const char **uuconf_pzpub); + +/* Get the name of the UUCP lock directory. This will set *pzlock to + a constant string, which should not be freed. */ +extern int uuconf_lockdir (void *uuconf_pglobal, + const char **uuconf_pzlock); + +/* Get the name of the UUCP log file. This will set *pzlog to a + constant string, which should not be freed. */ +extern int uuconf_logfile (void *uuconf_pglobal, + const char **uuconf_pzlog); + +/* Get the name of the UUCP statistics file. This will set *pzstats + to a constant string, which should not be freed. */ +extern int uuconf_statsfile (void *uuconf_pglobal, + const char **uuconf_pzstats); + +/* Get the name of the UUCP debugging file. This will set *pzdebug to + a constant string, which should not be freed. */ +extern int uuconf_debugfile (void *uuconf_pglobal, + const char **uuconf_pzdebug); + +/* Get the default debugging level to use. This basically gets the + argument of the ``debug'' command from the Taylor UUCP config file. + It will set *pzdebug to a constant string, which should not be + freed. */ +extern int uuconf_debuglevel (void *uuconf_pglobal, + const char **uuconf_pzdebug); + +/* Get the maximum number of simultaneous uuxqt executions. This will + set *pcmaxuuxqt to the number. Zero indicates no maximum. */ +extern int uuconf_maxuuxqts (void *uuconf_pglobal, + int *uuconf_pcmaxuuxqt); + +/* Check a login name and password. This checks the Taylor UUCP + password file (not /etc/passwd). It will work even if + uuconf_taylor_init was not called. If the login name exists and + the password is correct, this returns UUCONF_SUCCESS. If the login + does not exist, or the password is wrong, this returns + UUCONF_NOT_FOUND. Other errors are also possible. */ +extern int uuconf_callin (void *uuconf_pglobal, + const char *uuconf_zlogin, + const char *uuconf_zpassword); + +/* Get the callout login name and password for a system. This will + set both *pzlog and *pzpass to a string allocated by malloc, or to + NULL if the value is not found. If neither value is found, the + function will return UUCONF_NOT_FOUND. */ +extern int uuconf_callout (void *uuconf_pglobal, + const struct uuconf_system *uuconf_qsys, + char **uuconf_pzlog, + char **uuconf_pzpass); + +/* See if a login name is permitted for a system. This will return + UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is + invalid. This simply calls uuconf_taylor_validate or returns + UUCONF_SUCCESS, depending on the value of HAVE_TAYLOR_CONFIG. */ +extern int uuconf_validate (void *uuconf_pglobal, + const struct uuconf_system *uuconf_qsys, + const char *uuconf_zlogin); + +/* Get the name of the HDB remote.unknown shell script, if using + HAVE_HDB_CONFIG. This does not actually run the shell script. If + the function returns UUCONF_SUCCESS, the name will be in *pzname, + which will point to an malloced buffer. If it returns + UUCONF_NOT_FOUND, then there is no script to run. */ +extern int uuconf_remote_unknown (void *uuconf_pglobal, + char **pzname); + +/* Translate a dial code. This sets *pznum to an malloced string. + This will look up the entire zdial string in the dialcode file, so + for normal use the alphabetic prefix should be separated. */ +extern int uuconf_dialcode (void *uuconf_pglobal, + const char *uuconf_zdial, + char **uuconf_pznum); + +/* Compare two grades, returning < 0 if b1 should be executed before + b2, == 0 if they are the same, or > 0 if b1 should be executed + after b2. This can not fail, and does not return a standard uuconf + error code; it is normally called via the macro UUCONF_GRADE_CMP, + defined above. */ +extern int uuconf_grade_cmp (int uuconf_b1, int uuconf_b2); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_init (); +extern int uuconf_init_thread (); +extern int uuconf_system_names (); +extern int uuconf_system_info (); +extern int uuconf_system_unknown (); +extern int uuconf_system_local (); +extern int uuconf_system_free (); +extern int uuconf_find_port (); +extern int uuconf_port_free (); +extern int uuconf_dialer_names (); +extern int uuconf_dialer_info (); +extern int uuconf_dialer_free (); +extern int uuconf_localname (); +extern int uuconf_login_localname (); +extern int uuconf_spooldir (); +extern int uuconf_lockdir (); +extern int uuconf_pubdir (); +extern int uuconf_logfile (); +extern int uuconf_statsfile (); +extern int uuconf_debugfile (); +extern int uuconf_debuglevel (); +extern int uuconf_maxuuxqts (); +extern int uuconf_callin (); +extern int uuconf_callout (); +extern int uuconf_remote_unknown (); +extern int uuconf_validate (); +extern int uuconf_grade_cmp (); + +#ifdef __OPTIMIZE__ +#define uuconf_system_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#define uuconf_port_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#define uuconf_dialer_free(qglob, q) \ + (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) +#endif + +#endif /* ! UUCONF_ANSI_C */ + +#if UUCONF_ANSI_C + +/* Initialize the Taylor UUCP configuration file reading routines. + This must be called before calling any of the Taylor UUCP + configuration file specific routines. The ppglobal argument should + point to a generic pointer. Moreover, before calling this function + the pointer either must be set to NULL, or must have been passed to + one of the other uuconf init routines. The zprogram argument is + the name of the program for which files should be read. If NULL, + it is taken as "uucp", which means to read the standard UUCP files. + The zname argument is the name of the config file. If it is NULL, + the default config file will be used. + + Note that if the zname argument is obtained from the user running + the program, the program should be careful to revoke any special + privileges it may have (e.g. on Unix call setuid (getuid ()) and + setgid (getgid ())). Otherwise various sorts of spoofing become + possible. */ +extern int uuconf_taylor_init (void **uuconf_pglobal, + const char *uuconf_zprogram, + const char *uuconf_zname); + +/* Get the names of all systems listed in the Taylor UUCP + configuration files. This sets *ppzsystems to point to an array of + system names. The list of names is NULL terminated. The array is + allocated using malloc, as is each element of the array. If the + falias argument is 0, the list will not include any aliases; + otherwise, it will. */ +extern int uuconf_taylor_system_names (void *uuconf_pglobal, + char ***uuconf_ppzsystems, + int uuconf_falias); + +/* Get the information for system zsystem from the Taylor UUCP + configuration files. This will set *qsys. */ +extern int uuconf_taylor_system_info (void *uuconf_pglobal, + const char *uuconf_zsystem, + struct uuconf_system *uuconf_qsys); + +/* Get information for an unknown (anonymous) system. This returns + the values set by the ``unknown'' command in the main configuration + file. If the ``unknown'' command was not used, this will return + UUCONF_NOT_FOUND. */ +extern int uuconf_taylor_system_unknown (void *uuconf_pglobal, + struct uuconf_system *uuconf_qsys); + +/* Find a port from the Taylor UUCP configuration files. The + arguments and return values are identical to those of + uuconf_find_port. */ +extern int uuconf_taylor_find_port (void *uuconf_pglobal, + const char *uuconf_zname, + long uuconf_ibaud, + long uuconf_ihighbaud, + int (*uuconf_pifn) (struct uuconf_port *, + void *uuconf_pinfo), + void *uuconf_pinfo, + struct uuconf_port *uuconf_qport); + +/* Get the names of all dialers listed in the Taylor UUCP + configuration files. This sets *ppzdialers to point to an array of + dialer names. The list of names is NULL terminated. The array is + allocated using malloc, as is each element of the array. */ +extern int uuconf_taylor_dialer_names (void *uuconf_pglobal, + char ***uuconf_ppzdialers); + +/* Get the information for the dialer zdialer from the Taylor UUCP + configuration files. This sets the fields in *qdialer. */ +extern int uuconf_taylor_dialer_info (void *uuconf_pglobal, + const char *uuconf_zdialer, + struct uuconf_dialer *uuconf_qdialer); + +/* Get the local node name that should be used, given a login name, + considering only the ``myname'' command in the Taylor UUCP + configuration files. If the function returns UUCONF_SUCCESS, + *pzname will point to an malloced buffer. */ +extern int uuconf_taylor_login_localname (void *uuconf_pglobal, + const char *uuconf_zlogin, + char **pzname); + +/* Get the callout login name and password for a system from the + Taylor UUCP configuration files. This will set both *pzlog and + *pzpass to a string allocated by malloc, or to NULL if the value is + not found. If neither value is found, the function will return + UUCONF_NOT_FOUND. */ +extern int uuconf_taylor_callout (void *uuconf_pglobal, + const struct uuconf_system *uuconf_qsys, + char **uuconf_pzlog, + char **uuconf_pzpass); + +/* See if a login name is permitted for a system. This will return + UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is + invalid. This checks whether the login name appears in a + called-login command with a list of system which does not include + the system qsys. */ +extern int uuconf_taylor_validate (void *uuconf_pglobal, + const struct uuconf_system *uuconf_qsys, + const char *uuconf_zlogin); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_taylor_init (); +extern int uuconf_taylor_system_names (); +extern int uuconf_taylor_system_info (); +extern int uuconf_taylor_system_unknown (); +extern int uuconf_taylor_find_port (); +extern int uuconf_taylor_dialer_names (); +extern int uuconf_taylor_dialer_info (); +extern int uuconf_taylor_login_localname (); +extern int uuconf_taylor_callout (); +extern int uuconf_taylor_validate (); + +#endif /* ! UUCONF_ANSI_C */ + +#if UUCONF_ANSI_C + +/* Initialize the V2 configuration file reading routines. This must + be called before any of the other V2 routines are called. The + ppglobal argument should point to a generic pointer. Moreover, + before calling this function the pointer either must be set to + NULL, or must have been passed to one of the other uuconf init + routines. */ +extern int uuconf_v2_init (void **uuconf_ppglobal); + +/* Get the names of all systems listed in the V2 configuration files. + This sets *ppzsystems to point to an array of system names. The + list of names is NULL terminated. The array is allocated using + malloc, as is each element of the array. If the falias argument is + 0, the list will not include any aliases; otherwise, it will. */ +extern int uuconf_v2_system_names (void *uuconf_pglobal, + char ***uuconf_ppzsystems, + int uuconf_falias); + +/* Get the information for system zsystem from the V2 configuration + files. This will set *qsys. */ +extern int uuconf_v2_system_info (void *uuconf_pglobal, + const char *uuconf_zsystem, + struct uuconf_system *uuconf_qsys); + +/* Find a port from the V2 configuration files. The arguments and + return values are identical to those of uuconf_find_port. */ +extern int uuconf_v2_find_port (void *uuconf_pglobal, + const char *uuconf_zname, + long uuconf_ibaud, + long uuconf_ihighbaud, + int (*uuconf_pifn) (struct uuconf_port *, + void *uuconf_pinfo), + void *uuconf_pinfo, + struct uuconf_port *uuconf_qport); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_v2_init (); +extern int uuconf_v2_system_names (); +extern int uuconf_v2_system_info (); +extern int uuconf_v2_find_port (); + +#endif /* ! UUCONF_ANSI_C */ + +#if UUCONF_ANSI_C + +/* Initialize the HDB configuration file reading routines. This + should be called before any of the other HDB routines are called. + The ppglobal argument should point to a generic pointer. Moreover, + before calling this function the pointer either must be set to + NULL, or must have been passed to one of the other uuconf init + routines. The zprogram argument is used to match against a + "services" string in Sysfiles. A NULL or "uucp" argument is taken + as "uucico". */ +extern int uuconf_hdb_init (void **uuconf_ppglobal, + const char *uuconf_zprogram); + +/* Get the names of all systems listed in the HDB configuration files. + This sets *ppzsystems to point to an array of system names. The + list of names is NULL terminated. The array is allocated using + malloc, as is each element of the array. If the falias argument is + 0, the list will not include any aliases; otherwise, it will (an + alias is created by using the ALIAS= keyword in the Permissions + file). */ +extern int uuconf_hdb_system_names (void *uuconf_pglobal, + char ***uuconf_ppzsystems, + int uuconf_falias); + +/* Get the information for system zsystem from the HDB configuration + files. This will set *qsys. */ +extern int uuconf_hdb_system_info (void *uuconf_pglobal, + const char *uuconf_zsystem, + struct uuconf_system *uuconf_qsys); + + +/* Get information for an unknown (anonymous) system. If no + information is available for unknown systems, this will return + UUCONF_NOT_FOUND. This does not run the remote.unknown shell + script. */ +extern int uuconf_hdb_system_unknown (void *uuconf_pglobal, + struct uuconf_system *uuconf_qsys); + +/* Find a port from the HDB configuration files. The arguments and + return values are identical to those of uuconf_find_port. */ +extern int uuconf_hdb_find_port (void *uuconf_pglobal, + const char *uuconf_zname, + long uuconf_ibaud, + long uuconf_ihighbaud, + int (*uuconf_pifn) (struct uuconf_port *, + void *uuconf_pinfo), + void *uuconf_pinfo, + struct uuconf_port *uuconf_qport); + +/* Get the names of all dialers listed in the HDB configuration files. + This sets *ppzdialers to point to an array of dialer names. The + list of names is NULL terminated. The array is allocated using + malloc, as is each element of the array. */ +extern int uuconf_hdb_dialer_names (void *uuconf_pglobal, + char ***uuconf_ppzdialers); + +/* Get the information for the dialer zdialer from the HDB + configuration files. This sets the fields in *qdialer. */ +extern int uuconf_hdb_dialer_info (void *uuconf_pglobal, + const char *uuconf_zdialer, + struct uuconf_dialer *uuconf_qdialer); + +/* Get the local node name that should be used, given a login name, + considering only the MYNAME field in the HDB Permissions file. If + the function returns UUCONF_SUCCESS, *pzname will point to an + malloced buffer. */ +extern int uuconf_hdb_login_localname (void *uuconf_pglobal, + const char *uuconf_zlogin, + char **pzname); + +/* Get the name of the HDB remote.unknown shell script. This does not + actually run the shell script. If the function returns + UUCONF_SUCCESS, the name will be in *pzname, which will point to an + malloced buffer. */ +extern int uuconf_hdb_remote_unknown (void *uuconf_pglobal, + char **pzname); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_hdb_init (); +extern int uuconf_hdb_system_names (); +extern int uuconf_hdb_system_info (); +extern int uuconf_hdb_system_unknown (); +extern int uuconf_hdb_find_port (); +extern int uuconf_hdb_dialer_names (); +extern int uuconf_hdb_dialer_info (); +extern int uuconf_hdb_localname (); +extern int uuconf_hdb_remote_unknown (); + +#endif /* ! UUCONF_ANSI_C */ + +#if UUCONF_ANSI_C + +/* This function will set an appropriate error message into the buffer + zbuf, given a uuconf error code. The buffer will always be null + terminated, and will never be accessed beyond the length cbuf. + This function will return the number of characters needed for the + complete message, including the null byte. If this is less than + the cbytes argument, the buffer holds a truncated string. */ +extern int uuconf_error_string (void *uuconf_pglobal, int ierror, + char *zbuf, UUCONF_SIZE_T cbuf); + +/* If UUCONF_ERROR_ERRNO is set in a return value, this function may + be used to retrieve the errno value. This will be the value of + errno as set by the system function which failed. However, some + system functions, notably some stdio routines, may not set errno, + in which case the value will be meaningless. This function does + not return a uuconf error code, and it cannot fail. */ +extern int uuconf_error_errno (void *uuconf_pglobal); + +/* If UUCONF_ERROR_FILENAME is set in a return value, this function + may be used to retrieve the file name. This function does not + return a uuconf error code, and it cannot fail. The string that it + returns a pointer to is not guaranteed to remain allocated across + the next call to a uuconf function (other than one of the three + error retrieving functions). */ +extern const char *uuconf_error_filename (void *uuconf_pglobal); + +/* If UUCONF_ERROR_LINENO is set in a return value, this function may + be used to retrieve the line number. This function does not return + a uuconf error code, and it cannot fail. */ +extern int uuconf_error_lineno (void *uuconf_pglobal); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_error_string (); +extern int uuconf_error_errno (); +extern UUCONF_CONST char *uuconf_error_filename (); +extern int uuconf_error_lineno (); + +#endif /* ! UUCONF_ANSI_C */ + +/* The uuconf package also provides a few functions which can accept + commands and parcel them out according to a table. These are + publically visible, partially in the hopes that they will be + useful, but mostly because the rest of the Taylor UUCP package uses + them. */ + +/* The types of entries allowed in a command table (struct + uuconf_cmdtab). Each type defines how a particular command is + interpreted. Each type will either assign a value to a variable or + call a function. In all cases, a line of input is parsed into + separate fields, separated by whitespace; comments beginning with + '#' are discarded, except that a '#' preceeded by a backslash is + retained. The first field is taken as the command to execute, and + the remaining fields are its arguments. */ + +/* A boolean value. Used for a command which accepts a single + argument, which must begin with 'y', 'Y', 't', or 'T' for true (1) + or 'n', 'N', 'f', or 'F' for false (0). The corresponding variable + must be an int. */ +#define UUCONF_CMDTABTYPE_BOOLEAN (0x12) + +/* An integer value. Used for a command which accepts a single + argument, which must be an integer. The corresponding variable + must be an int. */ +#define UUCONF_CMDTABTYPE_INT (0x22) + +/* A long value. Used for a command which accepts a single value, + which must be an integer. The corresponding variable must be a + long. */ +#define UUCONF_CMDTABTYPE_LONG (0x32) + +/* A string value. Used for a command which accepts a string + argument. If there is no argument, the variable will be set to + point to a zero byte. Otherwise the variable will be set to point + to the string. The corresponding variable must be a char *. The + memory pointed to by the variable after it is set must not be + modified. */ +#define UUCONF_CMDTABTYPE_STRING (0x40) + +/* A full string value. Used for a command which accepts a series of + string arguments separated by whitespace. The corresponding + variable must be a char **. It will be set to an NULL terminated + array of the arguments. The memory occupied by the array itself, + and by the strings within it, must not be modified. */ +#define UUCONF_CMDTABTYPE_FULLSTRING (0x50) + +/* A function. If this command is encountered, the command and its + arguments are passed to the corresponding function. They are + passed as an array of strings, in which the first string is the + command itself, along with a count of strings. This value may be + or'red with a specific number of required arguments; + UUCONF_CMDTABTYPE_FN | 1 accepts no additional arguments besides + the command itself, UUCONF_CMDTABTYPE_FN | 2 accepts 1 argument, + etc. UUCONF_CMDTABTYPE_FN | 0, accepts any number of additional + arguments. */ +#define UUCONF_CMDTABTYPE_FN (0x60) + +/* A prefix function. The string in the table is a prefix; if a + command is encountered with the same prefix, the corresponding + function will be called as for UUCONF_CMDTABTYPE_FN. The number of + arguments may be or'red in as with UUCONF_CMDTABTYPE_FN. */ +#define UUCONF_CMDTABTYPE_PREFIX (0x70) + +/* This macro will return the particular type of a CMDTABTYPE. */ +#define UUCONF_TTYPE_CMDTABTYPE(i) ((i) & 0x70) + +/* This macro will return the required number of arguments of a + CMDTABTYPE. If it is zero, there is no restriction. */ +#define UUCONF_CARGS_CMDTABTYPE(i) ((i) & 0x0f) + +/* When a function is called via UUCONF_CMDTABTYPE_FN or + UUCONF_CMDTABTYPE_PREFIX, it may return any uuconf error code (see + above). However, it will normally return one of the following: + + UUCONF_CMDTABRET_CONTINUE: Take no special action. In particular, + the arguments passed to the function may be overwritten or freed. + + UUCONF_CMDTABRET_KEEP: The memory occupied by the arguments passed + to the function must be preserved. Continue processing commands. + + UUCONF_CMDTABRET_EXIT: If reading commands from a file, stop + processing. The arguments passed to the function may be + overwritten or freed. + + UUCONF_CMDTABRET_KEEP_AND_EXIT: Stop processing any file. The + memory occupied by the arguments passed to the function must be + preserved. + + These values are interpreted by uuconf_cmd_file. The + uuconf_cmd_line and uuconf_cmd_args functions may return + UUCONF_CMDTABRET_KEEP. It they get an error, they will return an + error code with UUCONF_CMDTABRET_EXIT set. Also, of course, they + may return any value that is returned by one of the user functions + in the uuconf_cmdtab table. */ + +/* UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT are defined above, + with the error codes. */ + +#define UUCONF_CMDTABRET_CONTINUE UUCONF_SUCCESS +#define UUCONF_CMDTABRET_KEEP_AND_EXIT \ + (UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT) + +/* When a function is called via CMDTABTYPE_FN or CMDTABTYPE_PREFIX, + it is passed five arguments. This is the type of a pointer to such + a function. The uuconf global information structure is passed in + for convenience in calling another uuconf function. The arguments + to the command are passed in (the command itself is the first + argument) along with a count and the value of the pvar field from + the uuconf_cmdtab structure in which the function pointer was + found. The pinfo argument to the function is taken from the + argument to uuconf_cmd_*. */ + +#if UUCONF_ANSI_C +typedef int (*uuconf_cmdtabfn) (void *uuconf_pglobal, + int uuconf_argc, + char **uuconf_argv, + void *uuconf_pvar, + void *uuconf_pinfo); +#else +typedef int (*uuconf_cmdtabfn) (); +#endif + +/* A table of commands is an array of the following structures. The + final element of the table should have uuconf_zcmd == NULL. */ + +struct uuconf_cmdtab +{ + /* Command name. */ + UUCONF_CONST char *uuconf_zcmd; + /* Command type (one of CMDTABTYPE_*). */ + int uuconf_itype; + /* If not CMDTABTYPE_FN or CMDTABTYPE_PREFIX, the address of the + associated variable. Otherwise, a pointer value to pass to the + function pifn. */ + UUCONF_POINTER uuconf_pvar; + /* The function to call if CMDTABTYPE_FN or CMDTABTYPE_PREFIX. */ + uuconf_cmdtabfn uuconf_pifn; +}; + +/* Bit flags to pass to uuconf_processcmds. */ + +/* If set, case is significant when checking commands. Normally case + is ignored. */ +#define UUCONF_CMDTABFLAG_CASE (0x1) + +/* If set, a backslash at the end of a line may be used to include the + next physical line in the logical line. */ +#define UUCONF_CMDTABFLAG_BACKSLASH (0x2) + +#if UUCONF_ANSI_C + +/* Read commands from a file, look them up in a table, and take the + appropriate action. This continues reading lines from the file + until EOF, or until a function returns with UUCONF_CMDTABRET_EXIT + set, or until an error occurs. The qtab argument must point to a + table of struct uuconf_cmdtab; the last element in the table should + have uuconf_zcmd == NULL. When a UUCONF_CMDTABTYPE_FN or + UUCONF_CMDTABTYPE_PREFIX command is found, the pinfo argument will + be passed to the called function. If an a command is found that is + not in the table, then if pfiunknownfn is NULL the unknown command + is ignored; otherwise it is passed to pfiunknownfn, which should + return a uuconf return code which is handled as for any other + function (the pvar argument to pfiunknownfn will always be NULL). + The iflags argument is any combination of the above + UUCONF_CMDTABFLAG bits. The pblock argument may also be a memory + block, as returned by uuconf_malloc_block (described below), in + which case all memory preserved because of UUCONF_CMDTABRET_KEEP + will be added to the block so that it may be freed later; it may + also be NULL, in which case any such memory is permanently lost. + + This function initially sets the internal line number to 0, and + then increments it as each line is read. It is permitted for any + called function to use the uuconf_lineno function to obtain it. If + this function is called when not at the start of a file, the value + returned by uuconf_lineno (which is, in any case, only valid if an + error code with UUCONF_ERROR_LINENO set is returned) must be + adjusted by the caller. + + This returns a normal uuconf return value, as described above. */ +extern int uuconf_cmd_file (void *uuconf_pglobal, + FILE *uuconf_e, + const struct uuconf_cmdtab *uuconf_qtab, + void *uuconf_pinfo, + uuconf_cmdtabfn uuconf_pfiunknownfn, + int uuconf_iflags, + void *pblock); + +/* This utility function is just like uuconf_cmd_file, except that it + only operates on a single string. If a function is called via + qtab, its return value will be the return value of this function. + UUCONF_CMDTABFLAG_BACKSLASH is ignored in iflags. The string z is + modified in place. The return value may include the + UUCONF_CMDTABRET_KEEP and, on error, the UUCONF_CMDTABRET_EXIT + bits, which should be honored by the calling code. */ +extern int uuconf_cmd_line (void *uuconf_pglobal, + char *uuconf_z, + const struct uuconf_cmdtab *uuconf_qtab, + void *uuconf_pinfo, + uuconf_cmdtabfn uuconf_pfiunknownfn, + int uuconf_iflags, + void *pblock); + +/* This utility function is just like uuconf_cmd_line, except it is + given a list of already parsed arguments. */ +extern int uuconf_cmd_args (void *uuconf_pglobal, + int uuconf_cargs, + char **uuconf_pzargs, + const struct uuconf_cmdtab *uuconf_qtab, + void *uuconf_pinfo, + uuconf_cmdtabfn uuconf_pfiunknownfn, + int uuconf_iflags, + void *pblock); + +#else /* ! UUCONF_ANSI_C */ + +extern int uuconf_cmd_file (); +extern int uuconf_cmd_line (); +extern int uuconf_cmd_args (); + +#endif /* ! UUCONF_ANSI_C */ + +#if UUCONF_ANSI_C + +/* The uuconf_cmd_file function may allocate memory permanently, as + for setting a UUCONF_CMDTABTYPE_STRING value, in ways which are + difficult to free up. A memory block may be used to record all + allocated memory, so that it can all be freed up at once at some + later time. These functions do not take a uuconf global pointer, + and are independent of the rest of the uuconf library. */ + +/* Allocate a block of memory. If this returns NULL, then malloc + returned NULL, and errno is whatever malloc set it to. */ +extern void *uuconf_malloc_block (void); + +/* Allocate memory within a memory block. If this returns NULL, then + malloc returned NULL, and errno is whatever malloc set it to. */ +extern void *uuconf_malloc (void *uuconf_pblock, + UUCONF_SIZE_T uuconf_cbytes); + +/* Add a block returned by the generic malloc routine to a memory + block. This returns zero on success, non-zero on failure. If this + fails (returns non-zero), then malloc returned NULL, and errno is + whatever malloc set it to. */ +extern int uuconf_add_block (void *uuconf_pblock, void *uuconf_padd); + +/* Free a value returned by uuconf_malloc from a memory block. In the + current implementation, this will normally not do anything, but it + doesn't hurt. No errors can occur. */ +extern void uuconf_free (void *uuconf_pblock, void *uuconf_pfree); + +/* Free an entire memory block, including all values returned by + uuconf_malloc from it and all values added to it with + uuconf_add_block. No errors can occur. */ +extern void uuconf_free_block (void *uuconf_pblock); + +#else /* ! UUCONF_ANSI_C */ + +extern UUCONF_POINTER uuconf_malloc_block (); +extern UUCONF_POINTER uuconf_malloc (); +extern int uuconf_add_block (); +extern /* void */ uuconf_free (); +extern /* void */ uuconf_free_block (); + +#endif /* ! UUCONF_ANSI_C */ + +#endif /* ! defined (UUCONF_H) */ diff --git a/gnu/libexec/uucp/common_sources/uucp.h b/gnu/libexec/uucp/common_sources/uucp.h new file mode 100644 index 00000000000..8df3ec4c3e7 --- /dev/null +++ b/gnu/libexec/uucp/common_sources/uucp.h @@ -0,0 +1,367 @@ +/* uucp.h + Header file for the UUCP package. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* Get the system configuration parameters. */ +#include "conf.h" +#include "policy.h" + +/* Get a definition for ANSI_C if we weren't given one. */ +#ifndef ANSI_C +#ifdef __STDC__ +#define ANSI_C 1 +#else /* ! defined (__STDC__) */ +#define ANSI_C 0 +#endif /* ! defined (__STDC__) */ +#endif /* ! defined (ANSI_C) */ + +/* Pass this definition into uuconf.h. */ +#define UUCONF_ANSI_C ANSI_C + +/* We always include some standard header files. We need <signal.h> + to define sig_atomic_t. */ +#if HAVE_STDDEF_H +#include <stddef.h> +#endif +#include <stdio.h> +#include <signal.h> + +/* On some systems we need <sys/types.h> to get sig_atomic_t or + size_t or time_t. */ +#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && HAVE_SIG_ATOMIC_T_IN_TYPES_H +#define USE_TYPES_H 1 +#else +#if ! HAVE_SIZE_T_IN_STDDEF_H && HAVE_SIZE_T_IN_TYPES_H +#define USE_TYPES_H 1 +#else +#if ! HAVE_TIME_T_IN_TIME_H && HAVE_TIME_T_IN_TYPES_H +#define USE_TYPES_H 1 +#endif +#endif +#endif + +#ifndef USE_TYPES_H +#define USE_TYPES_H 0 +#endif + +#if USE_TYPES_H +#include <sys/types.h> +#endif + +/* Make sure we have sig_atomic_t. */ +#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H +#ifndef SIG_ATOMIC_T +/* There is no portable definition for sig_atomic_t. */ +#define SIG_ATOMIC_T char +#endif /* ! defined (SIG_ATOMIC_T) */ +typedef SIG_ATOMIC_T sig_atomic_t; +#endif /* ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H */ + +/* Make sure we have size_t. We use int as the default because the + main use of this type is to provide an argument to malloc and + realloc. On a system which does not define size_t, int is + certainly the correct type to use. */ +#if ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H +#ifndef SIZE_T +#define SIZE_T unsigned +#endif /* ! defined (SIZE_T) */ +typedef SIZE_T size_t; +#endif /* ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H */ + +/* Make sure we have time_t. We use long as the default. We don't + bother to let conf.h override this, since on a system which doesn't + define time_t long must be correct. */ +#if ! HAVE_TIME_T_IN_TIME_H && ! HAVE_TIME_T_IN_TYPES_H +typedef long time_t; +#endif + +/* Set up some definitions for both ANSI C and Classic C. + + P() -- for function prototypes (e.g. extern int foo P((int)) ). + pointer -- for a generic pointer (i.e. void *). + constpointer -- for a generic pointer to constant data. + BUCHAR -- to convert a character to unsigned. */ +#if ANSI_C +#if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR + #error ANSI C compiler without void or unsigned char +#endif +#define P(x) x +typedef void *pointer; +typedef const void *constpointer; +#define BUCHAR(b) ((unsigned char) (b)) +#else /* ! ANSI_C */ +/* Handle uses of const, volatile and void in Classic C. */ +#define const +#define volatile +#if ! HAVE_VOID +#define void int +#endif +#define P(x) () +typedef char *pointer; +typedef const char *constpointer; +#if HAVE_UNSIGNED_CHAR +#define BUCHAR(b) ((unsigned char) (b)) +#else /* ! HAVE_UNSIGNED_CHAR */ +/* This should work on most systems, but not necessarily all. */ +#define BUCHAR(b) ((b) & 0xff) +#endif /* ! HAVE_UNSIGNED_CHAR */ +#endif /* ! ANSI_C */ + +/* Make sure we have a definition for offsetof. */ +#ifndef offsetof +#define offsetof(type, field) \ + ((size_t) ((char *) &(((type *) 0)->field) - (char *) (type *) 0)) +#endif + +/* Only use inline with gcc. */ +#ifndef __GNUC__ +#define __inline__ +#endif + +/* Get the string functions, which are used throughout the code. */ +#if HAVE_MEMORY_H +#include <memory.h> +#else +/* We really need a definition for memchr, and this should not + conflict with anything in <string.h>. I hope. */ +extern pointer memchr (); +#endif + +#if HAVE_STRING_H +#include <string.h> +#else /* ! HAVE_STRING_H */ +#if HAVE_STRINGS_H +#include <strings.h> +#else /* ! HAVE_STRINGS_H */ +extern char *strcpy (), *strncpy (), *strchr (), *strrchr (), *strtok (); +extern char *strcat (), *strerror (), *strstr (); +extern size_t strlen (), strspn (), strcspn (); +#if ! HAVE_MEMORY_H +extern pointer memcpy (), memchr (); +#endif /* ! HAVE_MEMORY_H */ +#endif /* ! HAVE_STRINGS_H */ +#endif /* ! HAVE_STRING_H */ + +/* Get what we need from <stdlib.h>. */ +#if HAVE_STDLIB_H +#include <stdlib.h> +#else /* ! HAVE_STDLIB_H */ +extern pointer malloc (), realloc (), bsearch (); +extern long strtol (); +extern char *getenv (); +#endif /* ! HAVE_STDLIB_H */ + +/* NeXT uses <libc.h> to declare a bunch of functions. */ +#if HAVE_LIBC_H +#include <libc.h> +#endif + +/* Make sure we have the EXIT_ macros. */ +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS (0) +#endif +#ifndef EXIT_FAILURE +#define EXIT_FAILURE (1) +#endif + +/* If we need to declare errno, do so. I don't want to always do + this, because some system might theoretically have a different + declaration for errno. On a POSIX system this is sure to work. */ +#if ! HAVE_ERRNO_DECLARATION +extern int errno; +#endif + +/* If the system has the socket call, guess that we can compile the + TCP code. */ +#define HAVE_TCP HAVE_SOCKET + +/* If the system has the t_open call, guess that we can compile the + TLI code. */ +#define HAVE_TLI HAVE_T_OPEN + +/* The boolean type holds boolean values. */ +typedef int boolean; +#undef TRUE +#undef FALSE +#define TRUE (1) +#define FALSE (0) + +/* The openfile_t type holds an open file. This depends on whether we + are using stdio or not. */ +#if USE_STDIO + +typedef FILE *openfile_t; +#define EFILECLOSED ((FILE *) NULL) +#define ffileisopen(e) ((e) != NULL) +#define ffileeof(e) feof (e) +#define cfileread(e, z, c) fread ((z), 1, (c), (e)) +#define ffilereaderror(e, c) ferror (e) +#define cfilewrite(e, z, c) fwrite ((z), 1, (c), (e)) +#ifdef SEEK_SET +#define ffileseek(e, i) (fseek ((e), (long) (i), SEEK_SET) == 0) +#define ffilerewind(e) (fseek ((e), (long) 0, SEEK_SET) == 0) +#else +#define ffileseek(e, i) (fseek ((e), (long) (i), 0) == 0) +#define ffilerewind(e) (fseek ((e), (long) 0, 0) == 0) +#endif +#define ffileclose(e) (fclose (e) == 0) + +#else /* ! USE_STDIO */ + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +typedef int openfile_t; +#define EFILECLOSED (-1) +#define ffileisopen(e) ((e) >= 0) +#define ffileeof(e) (FALSE) +#define cfileread(e, z, c) read ((e), (z), (c)) +#define ffilereaderror(e, c) ((c) < 0) +#define cfilewrite(e, z, c) write ((e), (z), (c)) +#ifdef SEEK_SET +#define ffileseek(e, i) (lseek ((e), (long) i, SEEK_SET) >= 0) +#define ffilerewind(e) (lseek ((e), (long) 0, SEEK_SET) >= 0) +#else +#define ffileseek(e, i) (lseek ((e), (long) i, 0) >= 0) +#define ffilerewind(e) (lseek ((e), (long) 0, 0) >= 0) +#endif +#define ffileclose(e) (close (e) >= 0) + +#endif /* ! USE_STDIO */ + +/* A prototype for main to avoid warnings from gcc 2.0 + -Wmissing-prototype option. */ +extern int main P((int argc, char **argv)); + +/* Some standard routines which we only define if they are not present + on the system we are compiling on. */ + +#if ! HAVE_GETLINE +/* Read a line from a file. */ +extern int getline P((char **pz, size_t *pc, FILE *e)); +#endif + +#if ! HAVE_REMOVE +/* Erase a file. */ +#undef remove +extern int remove P((const char *zfile)); +#endif + +#if ! HAVE_STRDUP +/* Copy a string into memory. */ +extern char *strdup P((const char *z)); +#endif + +#if ! HAVE_STRSTR +/* Look for one string within another. */ +extern char *strstr P((const char *zouter, const char *zinner)); +#endif + +#if ! HAVE_STRCASECMP +#if HAVE_STRICMP +#define strcasecmp stricmp +#else /* ! HAVE_STRICMP */ +/* Rename strcasecmp to avoid ANSI C name space. */ +#define strcasecmp xstrcasecmp +extern int strcasecmp P((const char *z1, const char *z2)); +#endif /* ! HAVE_STRICMP */ +#endif /* ! HAVE_STRCASECMP */ + +#if ! HAVE_STRNCASECMP +#if HAVE_STRNICMP +#define strncasecmp strnicmp +#else /* ! HAVE_STRNICMP */ +/* Rename strncasecmp to avoid ANSI C name space. */ +#define strncasecmp xstrncasecmp +extern int strncasecmp P((const char *z1, const char *z2, size_t clen)); +#endif /* ! HAVE_STRNICMP */ +#endif /* ! HAVE_STRNCASECMP */ + +#if ! HAVE_STRERROR +/* Get a string corresponding to an error message. */ +#undef strerror +extern char *strerror P((int ierr)); +#endif + +/* Get the appropriate definitions for memcmp, memcpy, memchr and + bzero. */ +#if ! HAVE_MEMCMP +#if HAVE_BCMP +#define memcmp(p1, p2, c) bcmp ((p1), (p2), (c)) +#else /* ! HAVE_BCMP */ +extern int memcmp P((constpointer p1, constpointer p2, size_t c)); +#endif /* ! HAVE_BCMP */ +#endif /* ! HAVE_MEMCMP */ + +#if ! HAVE_MEMCPY +#if HAVE_BCOPY +#define memcpy(pto, pfrom, c) bcopy ((pfrom), (pto), (c)) +#else /* ! HAVE_BCOPY */ +extern pointer memcpy P((pointer pto, constpointer pfrom, size_t c)); +#endif /* ! HAVE_BCOPY */ +#endif /* ! HAVE_MEMCPY */ + +#if ! HAVE_MEMCHR +extern pointer memchr P((constpointer p, int b, size_t c)); +#endif + +#if ! HAVE_BZERO +#if HAVE_MEMSET +#define bzero(p, c) memset ((p), 0, (c)) +#else /* ! HAVE_MEMSET */ +extern void bzero P((pointer p, int c)); +#endif /* ! HAVE_MEMSET */ +#endif /* ! HAVE_BZERO */ + +/* Look up a character in a string. */ +#if ! HAVE_STRCHR +#if HAVE_INDEX +#define strchr index +extern char *index (); +#else /* ! HAVE_INDEX */ +extern char *strchr P((const char *z, int b)); +#endif /* ! HAVE_INDEX */ +#endif /* ! HAVE_STRCHR */ + +#if ! HAVE_STRRCHR +#if HAVE_RINDEX +#define strrchr rindex +extern char *rindex (); +#else /* ! HAVE_RINDEX */ +extern char *strrchr P((const char *z, int b)); +#endif /* ! HAVE_RINDEX */ +#endif /* ! HAVE_STRRCHR */ + +/* Turn a string into a long integer. */ +#if ! HAVE_STRTOL +extern long strtol P((const char *, char **, int)); +#endif + +/* Lookup a key in a sorted array. */ +#if ! HAVE_BSEARCH +extern pointer bsearch P((constpointer pkey, constpointer parray, + size_t celes, size_t cbytes, + int (*pficmp) P((constpointer, constpointer)))); +#endif diff --git a/gnu/libexec/uucp/common_sources/uudefs.h b/gnu/libexec/uucp/common_sources/uudefs.h new file mode 100644 index 00000000000..47d2c89896e --- /dev/null +++ b/gnu/libexec/uucp/common_sources/uudefs.h @@ -0,0 +1,445 @@ +/* uudefs.h + Miscellaneous definitions for the UUCP package. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#if ANSI_C +/* These structures are used in prototypes but are not defined in this + header file. */ +struct uuconf_system; +struct uuconf_timespan; +#endif + +/* The tlog enumeration holds the different types of logging. */ +enum tlog +{ + /* Normal log entry. */ + LOG_NORMAL, + /* Error log entry. */ + LOG_ERROR, + /* Fatal log entry. */ + LOG_FATAL +#if DEBUG > 1 + , + /* Debugging log entry. */ + LOG_DEBUG, + /* Start debugging log entry. */ + LOG_DEBUG_START, + /* Continue debugging log entry. */ + LOG_DEBUG_CONTINUE, + /* End debugging log entry. */ + LOG_DEBUG_END +#endif +}; + +/* The tstatus_type enumeration holds the kinds of status information + we put in the status file. The order of entries here corresponds + to the order of entries in the azStatus array. */ +enum tstatus_type +{ + /* Conversation complete. */ + STATUS_COMPLETE, + /* Port unavailable. */ + STATUS_PORT_FAILED, + /* Dial failed. */ + STATUS_DIAL_FAILED, + /* Login failed. */ + STATUS_LOGIN_FAILED, + /* Handshake failed. */ + STATUS_HANDSHAKE_FAILED, + /* Failed after logging in. */ + STATUS_FAILED, + /* Talking to remote system. */ + STATUS_TALKING, + /* Wrong time to call. */ + STATUS_WRONG_TIME, + /* Number of status values. */ + STATUS_VALUES +}; + +/* An array to convert status entries to strings. If more status entries + are added, this array must be extended. */ +extern const char *azStatus[]; + +/* The sstatus structure holds the contents of a system status file. */ +struct sstatus +{ + /* Current status of conversation. */ + enum tstatus_type ttype; + /* Number of failed retries. */ + int cretries; + /* Time of last call in seconds since epoch (determined by + ixsysdep_time). */ + long ilast; + /* Number of seconds until a retry is permitted. */ + int cwait; +}; + +/* How long we have to wait for the next call, given the number of retries + we have already made. This should probably be configurable. */ +#define CRETRY_WAIT(c) ((c) * 10 * 60) + +/* The scmd structure holds a complete UUCP command. */ +struct scmd +{ + /* Command ('S' for send, 'R' for receive, 'X' for execute, 'E' for + simple execution, 'H' for hangup, 'Y' for hangup confirm, 'N' for + hangup deny). */ + char bcmd; + /* At least one compiler needs an explicit padding byte here. */ + char bdummy; + /* Sequence handle for fsysdep_did_work. */ + pointer pseq; + /* File name to transfer from. */ + const char *zfrom; + /* File name to transfer to. */ + const char *zto; + /* User who requested transfer. */ + const char *zuser; + /* Options. */ + const char *zoptions; + /* Temporary file name ('S' and 'E'). */ + const char *ztemp; + /* Mode to give newly created file ('S' and 'E'). */ + unsigned int imode; + /* User to notify on remote system (optional; 'S' and 'E'). */ + const char *znotify; + /* File size (-1 if not supplied) ('S', 'E' and 'R'). */ + long cbytes; + /* Command to execute ('E'). */ + const char *zcmd; + /* Position to restart from ('R'). */ + long ipos; +}; + +#if DEBUG > 1 + +/* We allow independent control over several different types of + debugging output, using a bit string with individual bits dedicated + to particular debugging types. */ + +/* The bit string is stored in iDebug. */ +extern int iDebug; + +/* Debug abnormal events. */ +#define DEBUG_ABNORMAL (01) +/* Debug chat scripts. */ +#define DEBUG_CHAT (02) +/* Debug initial handshake. */ +#define DEBUG_HANDSHAKE (04) +/* Debug UUCP protocol. */ +#define DEBUG_UUCP_PROTO (010) +/* Debug protocols. */ +#define DEBUG_PROTO (020) +/* Debug port actions. */ +#define DEBUG_PORT (040) +/* Debug configuration files. */ +#define DEBUG_CONFIG (0100) +/* Debug spool directory actions. */ +#define DEBUG_SPOOLDIR (0200) +/* Debug executions. */ +#define DEBUG_EXECUTE (0400) +/* Debug incoming data. */ +#define DEBUG_INCOMING (01000) +/* Debug outgoing data. */ +#define DEBUG_OUTGOING (02000) + +/* Maximum possible value for iDebug. */ +#define DEBUG_MAX (03777) + +/* Intializer for array of debug names. The index of the name in the + array is the corresponding bit position in iDebug. We only check + for prefixes, so these names only need to be long enough to + distinguish each name from every other. The last entry must be + NULL. The string "all" is also recognized to turn on all + debugging. */ +#define DEBUG_NAMES \ + { "a", "ch", "h", "u", "pr", "po", "co", "s", "e", "i", "o", NULL } + +/* The prefix to use to turn off all debugging. */ +#define DEBUG_NONE "n" + +/* Check whether a particular type of debugging is being done. */ +#define FDEBUGGING(i) ((iDebug & (i)) != 0) + +/* These macros are used to output debugging information. I use + several different macros depending on the number of arguments + because no macro can take a variable number of arguments and I + don't want to use double parentheses. */ +#define DEBUG_MESSAGE0(i, z) \ + do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z)); } while (0) +#define DEBUG_MESSAGE1(i, z, a1) \ + do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z), (a1)); } while (0) +#define DEBUG_MESSAGE2(i, z, a1, a2) \ + do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z), (a1), (a2)); } while (0) +#define DEBUG_MESSAGE3(i, z, a1, a2, a3) \ + do \ + { \ + if (FDEBUGGING (i)) \ + ulog (LOG_DEBUG, (z), (a1), (a2), (a3)); \ + } \ + while (0) +#define DEBUG_MESSAGE4(i, z, a1, a2, a3, a4) \ + do \ + { \ + if (FDEBUGGING (i)) \ + ulog (LOG_DEBUG, (z), (a1), (a2), (a3), (a4)); \ + } \ + while (0) + +#else /* DEBUG <= 1 */ + +/* If debugging information is not being compiled, provide versions of + the debugging macros which just disappear. */ +#define DEBUG_MESSAGE0(i, z) +#define DEBUG_MESSAGE1(i, z, a1) +#define DEBUG_MESSAGE2(i, z, a1, a2) +#define DEBUG_MESSAGE3(i, z, a1, a2, a3) +#define DEBUG_MESSAGE4(i, z, a1, a2, a3, a4) + +#endif /* DEBUG <= 1 */ + +/* Functions. */ + +/* Given an unknown system name, return information for an unknown + system. If unknown systems are not permitted, this returns FALSE. + Otherwise, it translates the name as necessary for the spool + directory, and fills in *qsys. */ +extern boolean funknown_system P((pointer puuconf, const char *zsystem, + struct uuconf_system *qsys)); + +/* See whether a file belongs in the spool directory. */ +extern boolean fspool_file P((const char *zfile)); + +/* See if the current time matches a time span. If not, return FALSE. + Otherwise, return TRUE and set *pival and *pcretry to the values + from the matching element of the span. */ +extern boolean ftimespan_match P((const struct uuconf_timespan *qspan, + long *pival, int *pcretry)); + +/* Determine the maximum size that may ever be transferred, given a + timesize span. If there are any time gaps larger than 1 hour not + described by the timesize span, this returns -1. Otherwise it + returns the largest size that may be transferred at some time. */ +extern long cmax_size_ever P((const struct uuconf_timespan *qtimesize)); + +/* Send mail about a file transfer. */ +extern boolean fmail_transfer P((boolean fok, const char *zuser, + const char *zmail, const char *zwhy, + const char *zfrom, const char *zfromsys, + const char *zto, const char *ztosys, + const char *zsaved)); + +/* See whether a file is in one of a list of directories. The zpubdir + argument is used to pass the directory names to zsysdep_local_file. + If fcheck is FALSE, this does not check accessibility. Otherwise, + if freadable is TRUE, the user zuser must have read access to the + file and all appropriate directories; if freadable is FALSE zuser + must have write access to the appropriate directories. The zuser + argument may be NULL, in which case all users must have the + appropriate access (this is used for a remote request). */ +extern boolean fin_directory_list P((const char *zfile, + char **pzdirs, + const char *zpubdir, + boolean fcheck, + boolean freadable, + const char *zuser)); + +/* Parse a command string. */ +extern boolean fparse_cmd P((char *zcmd, struct scmd *qcmd)); + +/* Make a log entry. */ +#ifdef __GNUC__ +#define GNUC_VERSION __GNUC__ +#else +#define GNUC_VERSION 0 +#endif + +#if ANSI_C && HAVE_VFPRINTF +extern void ulog P((enum tlog ttype, const char *zfmt, ...)) +#if GNUC_VERSION > 1 + __attribute__ ((format (printf, 2, 3))) +#endif + ; +#else +extern void ulog (); +#endif + +#undef GNUC_VERSION + +/* Report an error returned by one of the uuconf routines. */ +extern void ulog_uuconf P((enum tlog ttype, pointer puuconf, + int iuuconf)); + +/* Set the function to call if a fatal error occurs. */ +extern void ulog_fatal_fn P((void (*pfn) P((void)))); + +/* If ffile is TRUE, send log entries to the log file rather than to + stderr. */ +extern void ulog_to_file P((pointer puuconf, boolean ffile)); + +/* Set the ID number used by the logging functions. */ +extern void ulog_id P((int iid)); + +/* Set the system name used by the logging functions. */ +extern void ulog_system P((const char *zsystem)); + +/* Set the system and user name used by the logging functions. */ +extern void ulog_user P((const char *zuser)); + +/* Set the device name used by the logging functions. */ +extern void ulog_device P((const char *zdevice)); + +/* Close the log file. */ +extern void ulog_close P((void)); + +/* Make an entry in the statistics file. */ +extern void ustats P((boolean fsucceeded, const char *zuser, + const char *zsystem, boolean fsent, + long cbytes, long csecs, long cmicros, + boolean fmaster)); + +/* Close the statistics file. */ +extern void ustats_close P((void)); + +#if DEBUG > 1 +/* A debugging routine to output a buffer. This outputs zhdr, the + buffer length clen, and the contents of the buffer in quotation + marks. */ +extern void udebug_buffer P((const char *zhdr, const char *zbuf, + size_t clen)); + +/* A debugging routine to make a readable version of a character. + This takes a buffer at least 5 bytes long, and returns the length + of the string it put into it (not counting the null byte). */ +extern size_t cdebug_char P((char *z, int ichar)); + +/* Parse a debugging option string. This can either be a number or a + comma separated list of debugging names. This returns a value for + iDebug. */ +extern int idebug_parse P((const char *)); + +#endif /* DEBUG <= 1 */ + +/* Copy one file to another. */ +extern boolean fcopy_file P((const char *zfrom, const char *zto, + boolean fpublic, boolean fmkdirs)); + +/* Copy an open file to another. */ +extern boolean fcopy_open_file P((openfile_t efrom, const char *zto, + boolean fpublic, boolean fmkdirs)); + +/* Translate escape sequences in a buffer, leaving the result in the + same buffer and returning the length. */ +extern size_t cescape P((char *zbuf)); + +/* Get a buffer to hold a string of a given size. The buffer should + be freed with ubuffree. */ +extern char *zbufalc P((size_t csize)); + +/* Call zbufalc to allocate a buffer and copy a string into it. */ +extern char *zbufcpy P((const char *z)); + +/* Free up a buffer returned by zbufalc or zbufcpy. */ +extern void ubuffree P((char *z)); + +/* Allocate memory without fail. */ +extern pointer xmalloc P((size_t)); + +/* Realloc memory without fail. */ +extern pointer xrealloc P((pointer, size_t)); + +/* Free memory (accepts NULL pointers, which some libraries erroneously + do not). */ +extern void xfree P((pointer)); + +/* Global variables. */ + +/* The name of the program being run. This is statically initialized, + although it should perhaps be set from argv[0]. */ +extern char abProgram[]; + +/* When a signal occurs, the signal handlers sets the appropriate + element of the arrays afSignal and afLog_signal to TRUE. The + afSignal array is used to check whether a signal occurred. The + afLog_signal array tells ulog to log the signal; ulog will clear + the element after logging it, which means that if a signal comes in + at just the right moment it will not be logged. It will always be + recorded in afSignal, though. At the moment we handle 5 signals: + SIGHUP, SIGINT, SIGQUIT, SIGTERM and SIGPIPE (the Unix code also + handles SIGALRM). If we want to handle more, the afSignal array + must be extended; I see little point to handling any of the other + ANSI C or POSIX signals, as they are either unlikely to occur + (SIGABRT, SIGUSR1) or nearly impossible to handle cleanly (SIGILL, + SIGSEGV). SIGHUP is only logged if fLog_sighup is TRUE. */ +#define INDEXSIG_SIGHUP (0) +#define INDEXSIG_SIGINT (1) +#define INDEXSIG_SIGQUIT (2) +#define INDEXSIG_SIGTERM (3) +#define INDEXSIG_SIGPIPE (4) +#define INDEXSIG_COUNT (5) + +extern volatile sig_atomic_t afSignal[INDEXSIG_COUNT]; +extern volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT]; +extern boolean fLog_sighup; + +/* The names of the signals to use in error messages, as an + initializer for an array. */ +#define INDEXSIG_NAMES \ + { "hangup", "interrupt", "quit", "termination", "SIGPIPE" } + +/* Check to see whether we've received a signal. It would be nice if + we could use a single variable for this, but we sometimes want to + clear our knowledge of a signal and that would cause race + conditions (clearing a single element of the array is not a race + assuming that we don't care about a particular signal, even if it + occurs after we've examined the array). */ +#define FGOT_SIGNAL() \ + (afSignal[INDEXSIG_SIGHUP] || afSignal[INDEXSIG_SIGINT] \ + || afSignal[INDEXSIG_SIGQUIT] || afSignal[INDEXSIG_SIGTERM] \ + || afSignal[INDEXSIG_SIGPIPE]) + +/* If we get a SIGINT in uucico, we continue the current communication + session but don't start any new ones. This macros checks for any + signal other than SIGINT, which means we should get out + immediately. */ +#define FGOT_QUIT_SIGNAL() \ + (afSignal[INDEXSIG_SIGHUP] || afSignal[INDEXSIG_SIGQUIT] \ + || afSignal[INDEXSIG_SIGTERM] || afSignal[INDEXSIG_SIGPIPE]) + +/* File being sent. */ +extern openfile_t eSendfile; + +/* File being received. */ +extern openfile_t eRecfile; + +/* Device name to log. This is set by fconn_open. It may be NULL. */ +extern char *zLdevice; + +/* If not NULL, ulog calls this function before outputting anything. + This is used to support cu. */ +extern void (*pfLstart) P((void)); + +/* If not NULL, ulog calls this function after outputting everything. + This is used to support cu. */ +extern void (*pfLend) P((void)); diff --git a/gnu/libexec/uucp/contrib/Dial.Hayes b/gnu/libexec/uucp/contrib/Dial.Hayes new file mode 100644 index 00000000000..32eef82d347 --- /dev/null +++ b/gnu/libexec/uucp/contrib/Dial.Hayes @@ -0,0 +1,108 @@ +#!xchat +# @(#) dial.hayes V1.1 Tue Sep 1 13:59:58 1992 (Bob Denny) +# +# xchat script for dialing a vanilla Hayes modem +# +# Usage: +# xchat dial.hayes telno +# +# where telno is the telephone number, subject to pause and wait +# character modification. +# +# Uncomment the first two lines after "start:" to get debugging +# in file "Dial.Log" +# +# Flush input, zero counter, set telephone number if supplied, +# else fail if no telephone number given. +# +start: +### dbgfile Dial.Log +### dbgset 15 + zero + flush + ifnstr notelno 0 + telno 0 + goto initmodem +# +# Missing telephone number. +# +notelno: + logerr No telephone number given + failed +# +# Reset the modem to nonvolatile profile. +# Allow 3 sec. for response, as some modems are slow to reset. +# +initmodem: + count + ifgtr cantinit 4 + send ATZ\r + timeout initmodem 3000 + expect setupmodem OK +# +# No response from modem +# +cantinit: + logerr Can't wake modem + failed +# +# Send the stuff needed to initialize the modem to the modes +# needed for the particular modem flavor. The string below +# is provided as a vanilla example. Allow 2 sec. for the +# modem to respond to this command. +# +setupmodem: + sleep 1000 + send ATM0S7=90S11=120\r + timeout setupfail 2000 + expect setupfail ERROR + expect dialnumber OK +# +# Modem barfed or died on setup command. +# +setupfail: + logerr Error in modem setup string + failed +# +# Dial the supplied number. Handle the various errors that +# can come back from the modem by logging the error. +# +dialnumber: + sleep 1000 + send ATDT + dial + send \r + flush + timeout timeout 90000 + expect connected CONNECT + expect busy BUSY + expect nocarrier NO CARRIER + expect noanswer NO ANSWER + expect nodialtone NO DIALTONE +# +# Success! +# +connected: + success +# +# Handle modem dial failures +# +timeout: + logerr Modem or carrier timeout. + failed +busy: + logerr BUSY + failed +nocarrier: + logerr NO CARRIER + failed +noanswer: + logerr NO ANSWER + failed +nodialtone: + logerr NO DIALTONE + failed +# +# end +# + diff --git a/gnu/libexec/uucp/contrib/Hangup.Hayes b/gnu/libexec/uucp/contrib/Hangup.Hayes new file mode 100644 index 00000000000..c111c00fcae --- /dev/null +++ b/gnu/libexec/uucp/contrib/Hangup.Hayes @@ -0,0 +1,57 @@ +#!xchat +# @(#) Hangup.Hayes V1.1 Tue Sep 1 14:04:25 1992 (Bob Denny) +# +# xchat script for hanging up a Hayes-type modem. When used with Taylor +# UUCP, this script should be run as the dialer-complete and dialer-abort +# script with xchat. +# +# Usage: +# xchat Hangup.Hayes [ x ] +# +# where 'x' is any string. If it is present, this script will log the +# modem reset as an ABORT reset, otherwise it will not log anything. +# +# Uncomment the lines starting with '###' to get debugging log. +# +start: +### dbgfile Hangup.Log +### dbgset 15 + zero + sleep 2000 # Wait for trailing garbage + flush # Toss it out + ifnstr wakemodem 0 # No abort indicator + log Hangup on abort +# +# Get modem's attention via Hayes 'escape' protocol. +# +wakemodem: + sleep 4000 + send +++ + sleep 4000 + send \r + timeout reset 2000 + expect reset OK +# +# We're (probably) in command mode. Use ATZ (reset) to hang up +# as some modems don't behave well with ATH0 command. +# +reset: + send ATZ\r + timeout silent 5000 + expect done OK +# +# Finished, modem is back in initial state. +# +done: + success +# +# No response to escape protocol. Log the error and force DTR low +# in an attempt to get control of the modem. Then send ATZ just to +# make sure. +# +silent: + logerr Hangup: no response from modem + hangup # Force DTR low as last gasp + send ATZ\r + sleep 5000 + failed diff --git a/gnu/libexec/uucp/contrib/Login.LAT b/gnu/libexec/uucp/contrib/Login.LAT new file mode 100644 index 00000000000..d557f97e219 --- /dev/null +++ b/gnu/libexec/uucp/contrib/Login.LAT @@ -0,0 +1,137 @@ +#!xchat +# @(#) login.LAT V1.2 Tue Sep 1 13:25:28 1992 +# +# xchat script for logging into a VMS system through a LAT +# terminal server port. If no VMS password parameter supplied, +# skips password phase of VMS login. If LAT-password supplied, +# will log into LAT server using that password. NOTE: does not +# handle the situation where a LAT password is needed but no +# VMS password is needed. +# +# Usage: +# xchat login.LAT sysname username [ password [ LAT-password ] ] +# +# History: +# rbd Fri Aug 14 13:37:06 1992 +# Changes for Lantronix ETS-16. It says "type help at the Local> +# prompt..." then it gives the prompt for real! Prompt may need +# to be something other than "Local>". We match the real Local> +# prompt by matching the leading newline! +# +# rbd Tue Sep 1 13:04:32 1992 +# Remove absolute path name from log file. Now defaults per config. +# +start: + dbgfile Login.Log + dbgset 15 + sleep 2000 # Wait 2 seconds + flush # Flush typeahead + ifnstr svrstart 3 # Skip server password if not given +# +# Starting point if server password supplied. Handle situation +# where the server line may have been left waiting for username +# or at local> prompt. +# +getsvrpwp: + zero +l0: + count # Get server's password prompt + ifgtr deadmux 5 # die if 5 cr's don't do it + send \r + timeout l0 1000 # Wait and try again + expect dosvrpw ssword> + expect svrlogin ername> + expect connect \nLocal> +# +# Send server's password. Fail if don't get Username +# or Local> prompt. +# +dosvrpw: + zero +l2: + sendstr 3 + send \r + timeout badsvrpw 5000 # Die if invalid + expect svrlogin ername> + expect connect \nLocal> +# +# Starting point if NO server password supplied. Handle situation +# where the server line may have been left at local> prompt. +# +svrstart: + zero +l1: + count # Get username> or local> prompt + ifgtr deadmux 5 # Die if 5 cr's don't do it + send \r + timeout l1 1000 # Wait and try again + expect svrlogin ername> + expect connect \nLocal> +# +# Server asked for a username. Just give 'uucp'. +# +svrlogin: + send uucp\r + timeout deadmux 2000 + expect connect \nLocal> +# +# At this point, we have the Local> prompt. Send the connect +# command for the specified LAT host service name, and wait for +# VMS "Username:" prompt. Die after 10 seconds. +# +connect: + send c\s + sendstr 0 + send \r + timeout nologin 10000 + expect gotlogin ername: +# +# Got VMS "Username:" prompt. Send the username. If a password +# was given, wait for the "Password:" prompt. Die after 10 seconds. +# if no password was given, we're done! +# +gotlogin: + sendstr 1 + send \r + ifnstr done 2 + timeout nopasswd 10000 + expect gotpasswd ssword: +# +# Got VMS "Password:" prompt. Send the password and we're done! +# +gotpasswd: + sendstr 2 + send \r +# +# Success! +# +done: + success +# +# ERROR HANDLERS +# +# +# LAT server appears dead. Fail. +# +deadmux: + logerr No response from LAT server + failed +# +# The server password was bad. Fail. +# +badsvrpw: + logerr Invalid LAT server password + failed +# +# VMS system appears to be dead. Fail. +# +nologin: + logerr No VMS Username: prompt + failed +# +# Failed to get "Password:" prompt. Fail. +# +nopasswd: + logerr No VMS Password: prompt. Invalid password? + failed + diff --git a/gnu/libexec/uucp/contrib/Login.PortSel b/gnu/libexec/uucp/contrib/Login.PortSel new file mode 100644 index 00000000000..d8c3a6643a6 --- /dev/null +++ b/gnu/libexec/uucp/contrib/Login.PortSel @@ -0,0 +1,133 @@ +#!xchat +# @(#) Login.PortSelUnix V1.0 Tue Sep 1 14:57:05 1992 (Bob Denny) +# +# NOTE: Untested with xchat V1.1. Taken from DECUS UUCP. +# +# From: "Kent C. Brodie" <moocow!brodie@CSD4.MILW.WISC.EDU> +# uucp: {uunet!marque,csd4.milw.wisc.edu}!moocow!brodie +# special script for "uwmcsd4", have to go through a port selector (and then +# log in via standard Unix procedures). +# +# Also included is the ability to wait in the port selector queue. +# Be forwarned that the debug log can get pretty big depending on +# how many times you "wait" in the queue. +# (C) 1989 Kent C. Brodie - Medical College of Wisconsin + +# P0 is systemname , P1 is username, P2 is password. + + zero + +# send a CR to get the selector's attention. Sleep a little bit +# due to large login text of selector. It sends "Which System?" +# when it's ready. + +getprtslct: + count + ifgtr noprtslct 6 + break + send \r + sleep 2000 + flush + expect prtslctok ystem? + timeout getprtslct 15000 + +noprtslct: + logerr Sent cr, no "Which System?" from port selector + failed + +# Send the system name. We either get "OK" (connected), or we +# get "No ports available, would you like to wait?" (wait in queue) + +prtslctok: + zero + sendstr 0 + send \r + expect connected OK + expect prtslctwait wait? + timeout noconnect 10000 + +# Usually we get "nn Your place in queue" messages. JUST in case we +# get a free port right away, check for 'Are you ready?' as well. + +prtslctwait: + zero + send Y\r + expect prtslctque queue + expect prtslctrdy ready? + timeout prtwaitbad 70000 + +prtwaitbad: + logerr Sent "Y" to wait in queue, did not get valid response. + failed + +# Here's where we wait in the queue. The port selector sends us a status +# message about once a minute. We either get "nn Your place in queue" +# or we get "System Available. Are you Ready?". +# If something goes wrong, we time out waiting for either response. +# The reason we don't sleep for 40-50 seconds is because as SOON as the +# port is ready, it informs us. If we wait too long, it drops us. +# This setup is laid out for a maximum of 20 "tries" which is ABOUT +# 20 minutes. Note: This constant retrying can make log files +# kind of big.... + +prtslctque: + count + ifgtr prtslcttry 20 + expect prtslctque queue + expect prtslctrdy ready? + timeout noportwait 70000 + +prtslcttry: + logerr Too many (20) wait/retries -- queue too busy. + failed + +prtslctrdy: + send Y\r + expect connected OK + timeout noconnect 20000 + + +noportwait: + logerr Timed out awaiting place in port queue + failed + +noconnect: + logerr Sent system name, no "OK" from selector + failed + +# standard Unix login stuff. Send cr, expect "ogin:", if no, send a break +# (which tells Unix to try the next bit rate) and try again. + +connected: + send \r + zero + goto waitlogin + +sendbreak: + count + ifgtr nolgi 6 + flush + break + +waitlogin: + expect gotlogin ogin: + timeout sendbreak 5000 + +nolgi: + logerr No login: prompt + failed + +gotlogin: + sendstr 1 + send \r + expect gotword word: + timeout nopwd 10000 + +nopwd: + logerr No password: prompt + failed + +gotword: + sendstr 2 + send \r + success diff --git a/gnu/libexec/uucp/contrib/Login.VMS b/gnu/libexec/uucp/contrib/Login.VMS new file mode 100644 index 00000000000..d6196cb2aa6 --- /dev/null +++ b/gnu/libexec/uucp/contrib/Login.VMS @@ -0,0 +1,96 @@ +#!xchat +# @(#) Login.VMS V1.1 Tue Sep 1 13:24:54 1992 (Bob Denny) +# +# +# xchat script for logging into a VMS system. If no VMS password +# parameter supplied, skips password phase of VMS login. If syspass +# parameter given, will go through steps needed to log into a VMS +# system where a "system password" was set on the port. +# +# Cannot handle situation where system password is required but +# no password needed. +# +# +# Usage: +# xchat Login.VMS username [ password [ syspass ] ] +# +# Uncomment the lines starting with "###" to get debug logging. +# +start: +### dbgfile Login.Log +### dbgset 15 + sleep 2000 # Wait 2 seconds + zero + flush # Flush typeahead + ifnstr login 2 # Skip sys passwd if not given +# +# Need system password. Send <CR> to get bell. +# Try 5 times at 2 sec. intervals. Skip to do +# username if we see "Username:". +# +syspass: + count + ifgtr nobell 5 # Fail after 5 tries + send \r + timeout syspass 2000 # Wait 2 sec. and try again + expect gotbell \007 + expect gotlogin Username: +# +# Got the bell. Send the system password. Repeat 5 times +# at 2 sec. intervals. Fail if we don't get Username: +# +gotbell: + zero + sleep 2000 +l1: + count + ifgtr nologin 5 # Fail after 5 tries + sendstr 2 + send \r + timeout l1 2000 # Wait 2 sec. and try again + expect gotlogin Username: +# +# Start here if no system password supplied. +# Send <CR> until we get Username: Try 5 times at 2 sec. intervals. +# +login: + count + ifgtr nologin 5 # Fail after 5 tries + send \r + timeout login 2000 # Wait 2 sec. and try again + expect gotlogin Username: +# +# Got VMS "Username:" prompt. Send the username. If a password +# was given, wait for the "Password:" prompt. Die after 10 seconds. +# if no password was given, we're done! +# +gotlogin: + sendstr 0 + send \r + ifnstr done 1 + timeout nopasswd 10000 + expect gotpasswd Password: +# +# Got VMS "Password:" prompt. Send the password and we're done! +# +gotpasswd: + sendstr 1 + send \r +# +# Success! +# +done: + success +# +# ERROR HANDLERS +# +nobell: + logerr No VMS system password prompt (bell) + failed +nologin: + logerr No VMS Username: prompt + failed +nopasswd: + logerr No VMS Password: prompt. + failed + diff --git a/gnu/libexec/uucp/contrib/Makefile.uurt b/gnu/libexec/uucp/contrib/Makefile.uurt new file mode 100644 index 00000000000..235fcca889f --- /dev/null +++ b/gnu/libexec/uucp/contrib/Makefile.uurt @@ -0,0 +1,30 @@ +# +# Makefile for uurate 1.0 +# + +# Where uurate is installed +BIN=/usr/local/bin + +# Flags to use when compiling uurate +CFLAGS=-I.. + +CC=cc +SHELL=/bin/sh +PROGS=uurate + +#----------- + +all: $(PROGS) + +install: $(PROGS) + @for i in $(PROGS) ; do \ + echo "Install $$i into $(BIN)..." ; \ + cp $$i $(BIN) ; \ + echo "Set ownership and protection..." ; \ + /bin/chmod 0555 $(BIN)/$$i ; \ + /bin/chown bin $(BIN)/$$i ; \ + /bin/chgrp bin $(BIN)/$$i ; \ + done + +clean: + rm -f $(PROGS) core diff --git a/gnu/libexec/uucp/contrib/Makefile.xchat b/gnu/libexec/uucp/contrib/Makefile.xchat new file mode 100644 index 00000000000..5e9aaa8ffed --- /dev/null +++ b/gnu/libexec/uucp/contrib/Makefile.xchat @@ -0,0 +1,31 @@ +# +# Makefile for xchat 1.1 +# +# Bob Denny - Tue Sep 1 15:58:22 1992 +# +CC=cc +SHELL=/bin/sh +BIN=/usr/local/lib/uucp +PROGS=xchat + +#----------- + +all: $(PROGS) + +install: $(PROGS) + @for i in $(PROGS) ; do \ + echo "Install $$i into $(BIN)..." ; \ + cp $$i $(BIN) ; \ + echo "Set ownership and protection..." ; \ + /bin/chmod 0555 $(BIN)/$$i ; \ + /bin/chown bin $(BIN)/$$i ; \ + /bin/chgrp bin $(BIN)/$$i ; \ + done + +clean: + rm -f $(PROGS) core + + + + + diff --git a/gnu/libexec/uucp/contrib/README b/gnu/libexec/uucp/contrib/README new file mode 100644 index 00000000000..c4105ed0386 --- /dev/null +++ b/gnu/libexec/uucp/contrib/README @@ -0,0 +1,46 @@ +This is the README file for the Taylor UUCP contrib directory. + +This directory contains contributed shell scripts and programs that +you may find useful. + +xchat.c, xchat.man, README-XCHAT, xc-conf.h-dist, Makefile.xchat: + A program by Bob Denny that may be invoked by the ``chat-program'' + command for any of the various types of chat scripts. It is + driven by scripts which are written in its own little language. + It is a powerful program that can add a lot of flexibility to your + chat scripts. + +Dial.Hayes, Hangup.Hayes, Login.LAT, Login.PortSel, Login.VMS: + Sample scripts for xchat. + +uurate.c, uurate.man, README-UURATE, Makefile.uurt: + A nifty little program by Bob Denny which analyzes the Log and + Stats file and prints various sorts of reports. + +uutraf: + Another program to produce neat reports from your log files, this + one a perl script by Johan Vromans. + +savelog.sh, savelog.man: + A handy shell script to rename a log file and cycle old versions + through a set of names, throwing away the oldest one. It will + also optionally compress the old log files. I believe that this + is originally from smail. It was written by Ronald S. Karr and + Landon Curt Noll, and was given to me by Bob Denny. + +uureroute: + A perl script reroute all mail queued up for one host to another. + Written by Bill Campbell and contributed by Francois Pinard. + +stats.sh: + A gawk script by Zacharias Beckman which reads the Stats file and + prints the last 80 lines as a nicely formatted table. + +uuq.sh: + A uuq workalike shell script by Zacharias Beckman. + +tstout.c: + A program to remove a user from utmp and wtmp, essentially logging + them out. I put this together from BSD code. I need it to use + tstuu with the system UUCP on Ultrix 4.0, for reasons that escape + me. Most people will have little use for this. diff --git a/gnu/libexec/uucp/contrib/README-UURATE b/gnu/libexec/uucp/contrib/README-UURATE new file mode 100644 index 00000000000..2cc361ce26f --- /dev/null +++ b/gnu/libexec/uucp/contrib/README-UURATE @@ -0,0 +1,20 @@ +uurate V1.2 - Gather and display Taylor UUCP traffic statistics + +Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992 + +See the man page for documentation. + +Installation: +------------ + +(1) Copy Makefile.uurt to Makefile. + +(2) Edit Makefile: set BIN where you want uurate to be installed, and + set CFLAGS to point to the directory containing the UUCP sources + (this is .. by default). + +(3) Type ``make'' to compile the program. + +(4) Type ``make install'' to install the program. + +(5) Install the man page if you want. I didn't put that into the Makefile. diff --git a/gnu/libexec/uucp/contrib/README-XCHAT b/gnu/libexec/uucp/contrib/README-XCHAT new file mode 100644 index 00000000000..5f93a284bda --- /dev/null +++ b/gnu/libexec/uucp/contrib/README-XCHAT @@ -0,0 +1,42 @@ +This is xchat V1.1 (Tue Sep 1 15:50:56 1992) + +Introduction: +------------ + +Xchat is a general-purpose dialing and login program designed for use +with Taylor UUCP as a "chat-program", taking the place (or augmenting) +the built-in chat scripting facility. It provides the ability to +closely control timeouts, multiple simultaneous expect strings with +separate actions, extended terminal control, modem command character +pacing, and more. + +When used in conjunction with Taylor UUCP's configuration features, +xchat can provide you the ability to manage the most intricate login, +dial and hangup needs. The scripts are written in a shell-like (well, +sort-of) style with labels, commands, and parameters, easing the task +of writing procedures for complex terminal communications situations. + +Installation: +------------ + +(1) Copy xc-conf.h-dist to xc-conf.h, then edit xc-conf.h to reflect + your condifuration. A description of the settings is in that file. + +(2) Copy Makefile.xchat to Makefile and edit it to set BIN to where + you want xchat installed. + +(2) Do a 'make' to build xchat. + +(3) Do a 'make install' to install it. + +(4) Format and print xchat.8, and install it if you want. + +(5) Print out copies of the scripts in the ./scripts subdirectory. + +(6) Read xchat.8 and the scripts together. + + +Author: +------ + +Robert B. Denny (denny@alisa.com) diff --git a/gnu/libexec/uucp/contrib/savelog.man b/gnu/libexec/uucp/contrib/savelog.man new file mode 100644 index 00000000000..919b94f4ec1 --- /dev/null +++ b/gnu/libexec/uucp/contrib/savelog.man @@ -0,0 +1,130 @@ +.\" @(#)man/man8/savelog.an 1.2 24 Oct 1990 05:18:46 +.de pP +.if n .sp 1 +.if t .sp .4 +.. +.de tP +.pP +.ta \\n(pDu +.ti -\\n(pDu +.. +.TH SAVELOG X_MAN8_EXT_X "31 January 1988" "Local" +.SH NAME +savelog \- cycle and truncate log files +.SH SYNOPSIS +.na +.B X_UTIL_BIN_DIR_X/savelog +[ +.B \-m +.I mode +] [ +.B \-u +.I user +] [ +.B \-g +.I group +] [ +.B \-c +.I cycle +] [ +.B \-t +] [ +.B \-l +] +.I logfile +.br +.ad +.SH DESCRIPTION +The +.I savelog +command renames and optionally compresses a log file and cycles it +through a set of names based on the original log file, removing the +last name in the cycle. +.SH OPTIONS +The +.I savelog +command accepts the following options: +.TP +\fB\-m\fP \fImode\fP +Change the permissions mode for renamed log files to +.IR mode . +By default the mode is unchanged. +.TP +\fB\-u\fP \fIuser\fP +Change the owner for renamed log files to +.IR user . +By default the owner is unchanged. +.TP +\fB\-g\fP \fIgroup\fP +Change the group for renamed log files to +.IR group . +By default the group is unchanged. +.TP +\fB\-c\fP \fIcycle\fP +Save +.I cycle +versions of the logfile, where +.I cycle +is a decimal number. The default value is 7. +.TP +.B \-l +Do not compress log files. By default, a compression program is used, +if one is available. +.TP +.B \-t +Ensure that a new logfile exists when the savelog operation is +complete. Use of +.BR \-m , +.BR \-u +or +.BR \-g +imply this, ensuring that the logfile will have the designated mode. +.SH "OPERATION" +The given logfile is cycled through files named: +.RS + +OLD/\fIfile\fP.\fInumber\fP + +.RE +where +.I file +is the basename for the logfile and where +.I number +ranges from 0 to one less then the +.I cycle +count specified for the command. +The +.I OLD +dirctory is created, as necessary, and is under the same directory as +the logfile itself. +.PP +This cycle operation is accomplished by renaming the file numbered +.IR cycle -2 +to a file numbered +.IR cycle -1 +and so on until the file numbered 0 is renamed to the file numbered 1. +If compression is being used, the first cycle file is compressed after +being renamed to cycle 1. After the cycle files are moved through the +various names, the filefile itself is moved to the cycle 0 file. +This cycle normally occurs once every time +.I savelog +is executed. +If the log file does not exist, savelog ignores it and does +not cycle the OLD files. +.PP +If compression is being used, then compressed log files will have an +additional suffix appropriate for the compression program that is +used. +.SH "SEE ALSO" +.IR smail (X_MAN5_EXT_X) +and +.IR smail (X_MAN8_EXT_X). +.SH COPYRIGHT +Copyright(C)1987, 1988 Ronald S. Karr and Landon Curt Noll +.br +See a file COPYING, +distributed with the source code, +or type +.I "smail \-bc" +for distribution rights and restrictions +associated with this software. diff --git a/gnu/libexec/uucp/contrib/savelog.sh b/gnu/libexec/uucp/contrib/savelog.sh new file mode 100755 index 00000000000..64c989f292b --- /dev/null +++ b/gnu/libexec/uucp/contrib/savelog.sh @@ -0,0 +1,247 @@ +#! /bin/sh +# @(#)util/savelog.sh 1.4 26 Oct 1991 22:49:39 +# +# savelog - save a log file +# +# Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll +# +# See the file COPYING, distributed with smail, for restriction +# and warranty information. +# +# usage: savelog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-l] file... +# +# -m mode - chmod log files to mode +# -u user - chown log files to user +# -g group - chgrp log files to group +# -c cycle - save cycle versions of the logfile (default: 7) +# -t - touch file +# -l - don't compress any log files (default: compress) +# file - log file names +# +# The savelog command saves and optionally compresses old copies of files +# into an 'dir'/OLD sub-directory. The 'dir' directory is determined from +# the directory of each 'file'. +# +# Older version of 'file' are named: +# +# OLD/'file'.<number><compress_suffix> +# +# where <number> is the version number, 0 being the newest. By default, +# version numbers > 0 are compressed (unless -l prevents it). The +# version number 0 is never compressed on the off chance that a process +# still has 'file' opened for I/O. +# +# If the 'file' does not exist or if it is zero length, no further processing +# is performed. However if -t was also given, it will be created. +# +# For files that do exist and have lengths greater than zero, the following +# actions are performed. +# +# 1) Version numered files are cycled. That is version 6 is moved to +# version 7, version is moved to becomes version 6, ... and finally +# version 0 is moved to version 1. Both compressed names and +# uncompressed names are cycled, regardless of -t. Missing version +# files are ignored. +# +# 2) The new OLD/file.1 is compressed and is changed subject to +# the -m, -u and -g flags. This step is skipped if the -t flag +# was given. +# +# 3) The main file is moved to OLD/file.0. +# +# 4) If the -m, -u, -g or -t flags are given, then file is created +# (as an empty file) subject to the given flags. +# +# 5) The new OLD/file.0 is chanegd subject to the -m, -u and -g flags. +# +# Note: If the OLD sub-directory does not exist, it will be created +# with mode 0755. +# +# Note: If no -m, -u or -g flag is given, then the primary log file is +# not created. +# +# Note: Since the version numbers start with 0, version number <cycle> +# is never formed. The <cycle> count must be at least 2. +# +# Bugs: If a process is still writing to the file.0 and savelog +# moved it to file.1 and compresses it, data could be lost. +# Smail does not have this problem in general because it +# restats files often. + +# common location +PATH="X_UTIL_PATH_X:X_SECURE_PATH_X"; export PATH +COMPRESS="X_COMPRESS_X" +COMP_FLAG="X_COMP_FLAG_X" +DOT_Z="X_DOT_Z_X" +CHOWN="X_CHOWN_X" +GETOPT="X_UTIL_BIN_DIR_X/getopt" + +# parse args +exitcode=0 # no problems to far +prog=$0 +mode= +user= +group= +touch= +count=7 +set -- `$GETOPT m:u:g:c:lt $*` +if [ $# -eq 0 -o $? -ne 0 ]; then + echo "usage: $prog [-m mode][-u user][-g group][-t][-c cycle][-l] file ..." 1>&2 + exit 1 +fi +for i in $*; do + case $i in + -m) mode=$2; shift 2;; + -u) user=$2; shift 2;; + -g) group=$2; shift 2;; + -c) count=$2; shift 2;; + -t) touch=1; shift;; + -l) COMPRESS=""; shift;; + --) shift; break;; + esac +done +if [ "$count" -lt 2 ]; then + echo "$prog: count must be at least 2" 1>&2 + exit 2 +fi + +# cycle thru filenames +while [ $# -gt 0 ]; do + + # get the filename + filename=$1 + shift + + # catch bogus files + if [ -b "$filename" -o -c "$filename" -o -d "$filename" ]; then + echo "$prog: $filename is not a regular file" 1>&2 + exitcode=3 + continue + fi + + # if not a file or empty, do nothing major + if [ ! -s $filename ]; then + # if -t was given and it does not exist, create it + if [ ! -z "$touch" -a ! -f $filename ]; then + touch $filename + if [ "$?" -ne 0 ]; then + echo "$prog: could not touch $filename" 1>&2 + exitcode=4 + continue + fi + if [ ! -z "$user" ]; then + $CHOWN $user $filename + fi + if [ ! -z "$group" ]; then + chgrp $group $filename + fi + if [ ! -z "$mode" ]; then + chmod $mode $filename + fi + fi + continue + fi + + # be sure that the savedir exists and is writable + savedir=`expr "$filename" : '\(.*\)/'` + if [ -z "$savedir" ]; then + savedir=./OLD + else + savedir=$savedir/OLD + fi + if [ ! -s $savedir ]; then + mkdir $savedir + if [ "$?" -ne 0 ]; then + echo "$prog: could not mkdir $savedir" 1>&2 + exitcode=5 + continue + fi + chmod 0755 $savedir + fi + if [ ! -d $savedir ]; then + echo "$prog: $savedir is not a directory" 1>&2 + exitcode=6 + continue + fi + if [ ! -w $savedir ]; then + echo "$prog: directory $savedir is not writable" 1>&2 + exitcode=7 + continue + fi + + # deterine our uncompressed file names + newname=`expr "$filename" : '.*/\(.*\)'` + if [ -z "$newname" ]; then + newname=$savedir/$filename + else + newname=$savedir/$newname + fi + + # cycle the old compressed log files + cycle=`expr $count - 1` + rm -f $newname.$cycle $newname.$cycle$DOT_Z + while [ "$cycle" -gt 1 ]; do + # --cycle + oldcycle=$cycle + cycle=`expr $cycle - 1` + # cycle log + if [ -f $newname.$cycle$DOT_Z ]; then + mv -f $newname.$cycle$DOT_Z $newname.$oldcycle$DOT_Z + fi + if [ -f $newname.$cycle ]; then + # file was not compressed for some reason move it anyway + mv -f $newname.$cycle $newname.$oldcycle + fi + done + + # compress the old uncompressed log if needed + if [ -f $newname.0 ]; then + if [ -z "$COMPRESS" ]; then + newfile=$newname.1 + mv $newname.0 $newfile + else + newfile=$newname.1$DOT_Z + $COMPRESS $COMP_FLAG < $newname.0 > $newfile + rm -f $newname.0 + fi + if [ ! -z "$user" ]; then + $CHOWN $user $newfile + fi + if [ ! -z "$group" ]; then + chgrp $group $newfile + fi + if [ ! -z "$mode" ]; then + chmod $mode $newfile + fi + fi + + # move the file into the file.0 holding place + mv -f $filename $newname.0 + + # replace file if needed + if [ ! -z "$touch" -o ! -z "$user" -o \ + ! -z "$group" -o ! -z "$mode" ]; then + touch $filename + fi + if [ ! -z "$user" ]; then + $CHOWN $user $filename + fi + if [ ! -z "$group" ]; then + chgrp $group $filename + fi + if [ ! -z "$mode" ]; then + chmod $mode $filename + fi + + # fix the permissions on the holding place file.0 file + if [ ! -z "$user" ]; then + $CHOWN $user $newname.0 + fi + if [ ! -z "$group" ]; then + chgrp $group $newname.0 + fi + if [ ! -z "$mode" ]; then + chmod $mode $newname.0 + fi +done +exit $exitcode diff --git a/gnu/libexec/uucp/contrib/stats.sh b/gnu/libexec/uucp/contrib/stats.sh new file mode 100755 index 00000000000..ac1d0f556ee --- /dev/null +++ b/gnu/libexec/uucp/contrib/stats.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# +# uuspeed - a script to parse a Taylor UUCP Stats file into pretty results. +# Zacharias J. Beckman. + +grep bytes /usr/spool/uucp/Stats | grep -v 'bytes 0.00 secs' | grep -v 'failed after' | tail -80 | \ +gawk ' + BEGIN { + printf(" UUCP transmission history:\n"); + format=" %8d bytes %8s(%8s) in %7.2f sec = %5.0f baud, %4.1fK / min\n"; + average=0.01; + samples=0; + } + + { + if ($6 > 100) { + printf (format, $6, $5, $2, $9, $6/$9*10, ($6/$9*60)/1000); + + average += ($6/$9*10); + samples += 1; + } + } + + END { + printf (" average speed %d baud\n", average/samples); + } +' diff --git a/gnu/libexec/uucp/contrib/tstout.c b/gnu/libexec/uucp/contrib/tstout.c new file mode 100644 index 00000000000..dd82633c7a0 --- /dev/null +++ b/gnu/libexec/uucp/contrib/tstout.c @@ -0,0 +1,158 @@ +/* tstout.c + Put together by Ian Lance Taylor <ian@airs.com> + + This program is used to logout a program run by the tstuu program. + I needed this because on Ultrix 4.0 I can't get the uucp program + to run without invoking it via /bin/login and having it start up + as a shell. If I don't do it this way, it gets a SIGSEGV trap + for some reason. Most systems probably don't need to do things + this way. It will only work on BSD systems anyhow, I suspect. + + The code for this comes from "UNIX Network Programming" by W. + Richard Stevens, Prentice-Hall 1990. Most of it is from 4.3BSD, as + noted in the comments. + + This program must run suid to root. + */ + +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <utmp.h> + +static int logout P((const char *zdev)); +static void logwtmp P((const char *zdev, const char *zname, + const char *zhost)); + +int +main (argc, argv) + int argc; + char **argv; +{ + char *z; + + if (argc != 2 + || strncmp (argv[1], "/dev/", sizeof "/dev/" - 1) != 0) + { + fprintf (stderr, "Usage: tstout device\n"); + exit (EXIT_FAILURE); + } + + z = argv[1] + 5; + + if (logout (z)) + logwtmp (z, "", ""); + + chmod (argv[1], 0666); + chown (argv[1], 0, 0); + + *z = 'p'; + chmod (argv[1], 0666); + chown (argv[1], 0, 0); + + exit (EXIT_SUCCESS); +} + +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)logout.c 5.2 (Berkeley) 2/17/89"; +#endif /* LIBC_SCCS and not lint */ + +#define UTMPFILE "/etc/utmp" + +/* 0 on failure, 1 on success */ + +static int +logout(line) + register const char *line; +{ + register FILE *fp; + struct utmp ut; + int rval; + time_t time(); + + if (!(fp = fopen(UTMPFILE, "r+"))) + return(0); + rval = 0; + while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) { + if (!ut.ut_name[0] || + strncmp(ut.ut_line, line, sizeof(ut.ut_line))) + continue; + bzero(ut.ut_name, sizeof(ut.ut_name)); + bzero(ut.ut_host, sizeof(ut.ut_host)); + (void)time((time_t *)&ut.ut_time); + (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR); + (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp); + (void)fseek(fp, (long)0, L_INCR); + rval = 1; + } + (void)fclose(fp); + return(rval); +} + +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88"; +#endif /* LIBC_SCCS and not lint */ + +#define WTMPFILE "/usr/adm/wtmp" + +static void +logwtmp(line, name, host) + const char *line, *name, *host; +{ + struct utmp ut; + struct stat buf; + int fd; + time_t time(); + char *strncpy(); + + if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (!fstat(fd, &buf)) { + (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); + (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); + (void)time((time_t *)&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void)ftruncate(fd, buf.st_size); + } + (void)close(fd); +} diff --git a/gnu/libexec/uucp/contrib/uuclean b/gnu/libexec/uucp/contrib/uuclean new file mode 100644 index 00000000000..e9c631c86c3 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uuclean @@ -0,0 +1,23 @@ +# This is a sample uuclean shell script +# Copyright (C) 1992 Ian Lance Taylor +# Do whatever you like with this script. +# +# Set some variables +bindir=/usr/local/bin +spooldir=/usr/spool/uucp +# +# Warn about all mail over two days old +$(bindir)/uustat -c rmail -o 48 -N -Q -W"Unable to deliver; will try up to one week" +# Return all mail over a week old +$(bindir)/uustat -c rmail -o 168 -K -M -N -Q -W"Could not be delivered for over one week" +# Throw away other requests over a week old +$(bindir)/uustat -o 168 -K -M -N -Q -W"Over one week old" +# Throw away any executions over three days old +$(bindir)/uustat -o 72 -M -N -Q -W"Unable to execute for three days" +# +# Now delete any old spool files +find $(spooldir) -ctime +8 -name '[CDX].*' -print -exec rm -f \{\} \; +# Delete any old temporary files +find $(spooldir) -atime +1 -ctime +1 -name 'TM.*' -print -exec rm -f \{\} \; +# Delete any old preserved files +find $(spooldir)/.Preserve -atime +14 -ctime +14 -print -exec rm -f \{\} \; diff --git a/gnu/libexec/uucp/contrib/uuq.sh b/gnu/libexec/uucp/contrib/uuq.sh new file mode 100755 index 00000000000..a5d88e95223 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uuq.sh @@ -0,0 +1,125 @@ +#!/bin/sh +# +# uuq - a script to examine and display the Taylor spool directory contents. +# note - uses the uuname script or similar functionality. +# Zacharias Beckman + +SPOOLDIR="/usr/spool/uucp" +SYSTEMS=`uuname` +TMPFILE="/tmp/uuq.tmp" +FORSYSTEM="" +DELETE="" +LONG=0 +SINGLE=0 + +while [ "$1" != "" ] +do + case $1 in + -l) LONG=1 + shift + ;; + -s) shift + SYSTEMS=$argv[1] + SINGLE=1 + shift + ;; + -d) shift + DELETE=$argv[1] + shift + ;; + -h) echo "uuq: usage uuq [options]" + echo " -l long listing (may take a while)" + echo " -s n run uuq only for system n" + echo " -d n delete item n from the queue (required -s)" + exit 1 + ;; + *) echo "uuq: invalid option" + exit 1 + ;; + esac +done + +if [ "${DELETE}" != "" ] && [ ${SINGLE} != 1 ] ; then + echo "uuq: you must specify a system to delete the job from:" + echo " uuq -s wizard -d D.0004" + exit 1 +fi + +cd ${SPOOLDIR} + +# if we are deleting a job, then do that first and exit without showing +# any other queue information + +if [ "${DELETE}" != "" ] ; then + if [ -d ${SYSTEMS}/D. ] ; then + cd ${SYSTEMS}/C. + PACKET=${DELETE} + if [ -f ${PACKET} ] ; then + EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}` + DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}` + echo "deleting job ${PACKET}" + rm ${PACKET} + rm ${EXFILE} + rm ${DFILE} + else + echo "uuq: job ${PACKET} not found" + exit 1 + fi + else + echo "uuq: system ${SYSTEMS} not found" + fi + + exit 1 +fi + +# use the 'uuname' script to obtain a list of systems for the 'sys' file, +# then step through each directory looking for appropriate information. + +if [ ${LONG} -gt 0 ] ; then + echo "system" + echo -n "job# act size command" +fi + +for DESTSYSTEM in ${SYSTEMS} ; do + # if there is an existing directory for the named system, cd into it and + # "do the right thing." + + if [ -d ${DESTSYSTEM} ] ; then + cd ${DESTSYSTEM}/C. + + PACKET=`ls` + + if [ "${PACKET}" != "" ] ; then + # if a long listing has been required, extra information is printed + + echo "" + echo "${DESTSYSTEM}:" + + # now each packet must be examined and appropriate information is + # printed for this system + + if [ ${LONG} -gt 0 ] ; then + for PACKET in * ; do + EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}` + DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}` + echo -n "${PACKET} " > ${TMPFILE} + gawk '{if (NR == 2) printf(" %s ", $1);}' ${PACKET} >> ${TMPFILE} + ls -l ${DFILE}|awk '{printf("%-10d ", $4)}' >> ${TMPFILE} + if [ -f ${EXFILE} ] ; then + gawk '/U / {printf("(%s)", $2);}\ + /C / {print substr($0,2,length($0));}' ${EXFILE} >> ${TMPFILE} + else + echo "---" >> ${TMPFILE} + fi + + cat ${TMPFILE} + done + cat ${SPOOLDIR}/.Status/${DESTSYSTEM} + else + ls + fi + fi + fi + + cd ${SPOOLDIR} +done diff --git a/gnu/libexec/uucp/contrib/uurate.c b/gnu/libexec/uucp/contrib/uurate.c new file mode 100644 index 00000000000..ceab41c53bf --- /dev/null +++ b/gnu/libexec/uucp/contrib/uurate.c @@ -0,0 +1,657 @@ +/* + * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992 + * + * This program digests log and stats files in the "Taylor" format + * and outputs various statistical data to standard out. + * + * Author: + * Bob Denny (denny@alisa.com) + * Fri Feb 7 13:38:36 1992 + * + * Original author: + * Mark Pizzolato mark@infopiz.UUCP + * + * Edits: + * Bob Denny - Fri Feb 7 15:04:54 1992 + * Heavy rework for Taylor UUCP. This was the (very old) uurate from + * DECUS UUCP, which had a single logfile for activity and stats. + * Personally, I would have done things differently, with tables + * and case statements, but in the interest of time, I preserved + * Mark Pizzolato's techniques and style. + * + * Bob Denny - Sun Aug 30 14:18:50 1992 + * Changes to report format suggested by Francois Pinard and others. + * Add summary report, format from uutraf.pl (perl script), again + * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP. + */ + +char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2"; + +#include <ctype.h> /* Character Classification */ +#include <string.h> +#include <math.h> + +#include "uucp.h" + + +#define _DEBUG_ 0 + +/* + * Direction of Calling and Data Transmission + */ +#define IN 0 /* Inbound */ +#define OUT 1 /* Outbound */ + +/* + * Data structures used to collect information + */ +struct File_Stats + { + int files; /* Files Transferred */ + unsigned long bytes; /* Data Size Transferred*/ + double time; /* Transmission Time */ + }; + +struct Phone_Call + { + int calls; /* Call Count */ + int succs; /* Successful calls */ + double connect_time; /* Connect Time Spent */ + struct File_Stats flow[2]; /* Rcvd & Sent Data */ + }; + +struct Execution_Command + { + struct Execution_Command *next; + char Commandname[64]; + int count; + }; + +struct Host_entry + { + struct Host_entry *next; + char Hostname[32]; + struct Execution_Command *cmds; /* Local Activities */ + struct Phone_Call call[2]; /* In & Out Activities */ + }; + +/* + * Stuff for getopt() + */ +extern int optind; /* GETOPT : Option Index */ +extern char *optarg; /* GETOPT : Option Value */ +extern void *calloc(); + +static void fmtime(); +static void fmbytes(); + +/* + * Default files to read. Taken from Taylor compile-time configuration. + * Must look like an argvec, hence the dummy argv[0]. + */ +static char *(def_logs[3]) = { "", LOGFILE, STATFILE }; + +/* + * Misc. strings for reports + */ +static char *(file_hdr[2]) = { "\nReceived file statistics:\n", + "\nSent file statistics\n" }; + +/* + * BEGIN EXECUTION + */ +main(argc, argv) +int argc; +char *argv[]; +{ + char c; + char *p, *s; + struct Host_entry *hosts = NULL; + struct Host_entry *cur = NULL; + struct Host_entry *e; + struct Execution_Command *cmd; + struct Execution_Command *ec; + char Hostname[64]; + FILE *Log = NULL; + char logline[1024]; + char *logmsg; + int sent; + int called; + int show_files = 0; /* I prefer boolean, but... */ + int show_calls = 0; + int show_commands = 0; + int show_efficiency = 0; + int show_summary = 0; + int have_files = 0; + int have_calls = 0; + int have_commands = 0; + int use_stdin = 0; + Hostname[0] = '\0'; + + /* + * I wish the compiler had the #error directive! + */ +#if !HAVE_TAYLOR_LOGGING + fprintf(stderr, "uurate cannot be used with your configuration of\n"); + fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n"); + fprintf(stderr, "TAYLOR_LOGGING configuration.\n"); + exit(1); +#endif + + /* + * Process the command line arguments + */ + while((c = getopt(argc, argv, "h:cfexai")) != EOF) + { + switch(c) + { + case 'h': + strcpy(Hostname, optarg); + break; + case 'c': + show_calls = 1; + break; + case 'f': + show_files = 1; + break; + case 'x': + show_commands = 1; + break; + case 'e': + show_efficiency = 1; + break; + case 'a': + show_calls = show_files = show_commands = show_efficiency = 1; + break; + case 'i': + use_stdin = 1; + break; + default : + goto usage; + } + } + + /* + * If no report switches given, show summary report. + */ + if (show_calls == 0 && show_files == 0 + && show_efficiency == 0 && show_commands == 0) + show_summary = 1; + + /* + * Adjust argv and argc to account for the args processed above. + */ + argc -= (optind - 1); + argv += (optind - 1); + + /* + * If further args present, Assume rest are logfiles for us to process, + * otherwise, take input from Log and Stat files provided in the + * compilation environment of Taylor UUCP. If -i was given, Log already + * points to stdin and no file args are accepted. + */ + if(argc == 1) /* No file arguments */ + { + if (use_stdin) /* If -i, read from stdin */ + { + argc = 2; + Log = stdin; + } + else /* Read from current logs */ + { + argc = 3; /* Bash argvec to default log/stat files */ + argv = &def_logs[0]; + } + } + else if (use_stdin) /* File args with -i is an error */ + { + fprintf(stderr, "uurate (error): file args given with '-i'\n"); + goto usage; + } + +#if _DEBUG_ + printf("\n"); +#endif + + /* + * MAIN LOGFILE PROCESSING LOOP + */ + while (argc > 1) + { + + if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + return; + } + +#if _DEBUG_ + printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1])); +#endif + + /* + * Read each line of the logfile and collect information + */ + while (fgets(logline, sizeof(logline), Log)) + { + /* + * The host name of the other end of the connection is + * always the second field of the log line, whether we + * are reading a Log file or a Stats file. Set 'p' to + * point to the second field, null-terminated. Skip + * the line if something is funny. + */ + if (NULL == (p = strchr(logline, ' '))) + continue; + ++p; + if (NULL != (s = strchr(p, ' '))) + *s = '\0'; + for (s = p; *s; ++s) + if (isupper(*s)) + *s = tolower(*s); + /* + * Skip this line if we got -h <host> and + * this line does not contain that host name. + */ + if (Hostname[0] != '\0') + if (0 != strcmp(p, Hostname)) + continue; + /* + * We are within a call block now. If this line is a file + * transfer record, determine the direction. If not then + * skip the line if it is not interesting. + */ + if ((s = strchr(++s, ')')) == NULL) + continue; + logmsg = s + 2; /* Message is 2 characters after ')' */ + if (0 == strncmp(logmsg, "sent", 4)) + sent = OUT; + else + if (0 == strncmp(logmsg, "received", 8)) + sent = IN; + else + if ((0 != strncmp(logmsg, "Call complete", 13)) && + (0 != strncmp(logmsg, "Calling system", 14)) && + (0 != strncmp(logmsg, "Incoming call", 13)) && + (0 != strncmp(logmsg, "Executing", 9))) + continue; + /* + * Find the Host_entry for this host, or create a new + * one and link it on to the list. + */ + if ((cur == NULL) || (0 != strcmp(p, cur->Hostname))) + { + for (cur = hosts; cur != NULL ; cur = cur->next) + if (0 == strcmp(cur->Hostname, p)) + break; + if (cur == NULL) + { + cur = (struct Host_entry *)calloc(1, sizeof(*hosts)); + strcpy(cur->Hostname, p); + if (hosts == NULL) + hosts = cur; + else + { + for (e = hosts; e->next != NULL; e = e->next); + e->next = cur; + } + } + } + /* + * OK, if this is a uuxqt record, find the Execution_Command + * structure for the command being executed, or create a new + * one. Then count an execution of this command. + */ + if (0 == strncmp(logmsg, "Executing", 9)) + { + if (NULL == (p = strchr(logmsg, '('))) + continue; + if ((s = strpbrk(++p, " )")) == NULL) + continue; + *s = '\0'; + for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) + if (0 == strcmp(cmd->Commandname, p)) + break; + if (cmd == NULL) + { + cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd)); + strcpy(cmd->Commandname, p); + if (cur->cmds == NULL) + cur->cmds = cmd; + else + { + for (ec = cur->cmds; ec->next != NULL; ec = ec->next); + ec->next = cmd; + } + } + ++cmd->count; + have_commands = 1; + continue; + } + /* + * Count start of outgoing call. + */ + if (0 == strncmp(logmsg, "Calling system", 14)) + { + called = OUT; + cur->call[called].calls += 1; + have_calls = 1; + continue; + } + /* + * Count start of incoming call. + */ + if (0 == strncmp(logmsg, "Incoming call", 13)) + { + called = IN; + cur->call[called].calls += 1; + have_calls = 1; + continue; + } + /* + * Handle end of call. Pick up the connect time. + */ + if (0 == strncmp(logmsg, "Call complete", 13)) + { + cur->call[called].succs += 1; + if (NULL == (s = strchr(logmsg, '('))) + continue; + cur->call[called].connect_time += atof(s+1); + continue; + } + /* + * If we reached here, this must have been a file transfer + * record. Count it in the field corresponding to the + * direction of the transfer. Count bytes transferred and + * the time to transfer as well. + */ + have_files = 1; + cur->call[called].flow[sent].files += 1; + if (NULL == (s = strchr(logmsg, ' '))) + continue; + cur->call[called].flow[sent].bytes += atol(++s); + if (NULL == (s = strchr(s, ' '))) + continue; + if (NULL == (s = strpbrk(s, "0123456789"))) + continue; + cur->call[called].flow[sent].time += atof(s); + } + argc -= 1; + argv += 1; + if(Log != stdin) + fclose(Log); + } + + /* + * *********** + * * REPORTS * + * *********** + */ + + /* + * Truncate the Hostnames to 8 characters at most. + */ + for (cur = hosts; cur != NULL; cur = cur->next) + cur->Hostname[8] = '\0'; + +#if _DEBUG_ + printf("\n"); +#endif + + /* + * Summary report + * + * I know, this code could be tightened (rbd)... + */ + if(show_summary) + { + char t1[32], t2[32], t3[32], t4[32], t5[32]; + long ib, ob, b, rf, sf; + long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0; + double it, ot, ir, or; + double t_it=0.0, t_ot=0.0; + int nhosts = 0; + + printf("\n\ + Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n"); + printf("\ + Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n"); + printf("\ +-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + ib = (cur->call[IN].flow[IN].bytes + + cur->call[OUT].flow[IN].bytes); + fmbytes(ib, t1); + t_ib += ib; + + ob = (cur->call[IN].flow[OUT].bytes + + cur->call[OUT].flow[OUT].bytes); + fmbytes(ob, t2); + t_ob += ob; + + b = ib + ob; + fmbytes(b, t3); + t_b += b; + + it = cur->call[IN].flow[IN].time + + cur->call[OUT].flow[IN].time; + fmtime(it, t4); + t_it += it; + + ot = cur->call[IN].flow[OUT].time + + cur->call[OUT].flow[OUT].time; + fmtime(ot, t5); + t_ot += ot; + + rf = cur->call[IN].flow[IN].files + + cur->call[OUT].flow[IN].files; + t_rf += rf; + + sf = cur->call[IN].flow[OUT].files + + cur->call[OUT].flow[OUT].files; + t_sf += sf; + + ir = (it == 0.0) ? 0.0 : (ib / it); + or = (ot == 0.0) ? 0.0 : (ob / ot); + + printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", + cur->Hostname, + t1, t2, t3, t4, t5, + ir, or, rf, sf); + } + + if(nhosts > 1) + { + fmbytes(t_ib, t1); + fmbytes(t_ob, t2); + fmbytes(t_b, t3); + fmtime(t_it, t4); + fmtime(t_ot, t5); + ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it); + or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot); + + printf("\ +-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); + printf("\ +Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", + t1, t2, t3, t4, t5, + ir, or, t_rf, t_sf); + } + } + + + /* + * Call statistics report + */ + if(show_calls && have_calls) + { + char t1[32], t2[32]; + + printf("\nCall statistics:\n"); + printf("\ + sysname callto failto totime callfm failfm fmtime\n"); + printf("\ + -------- ------ ------ -------- ------ ------ --------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + fmtime(cur->call[OUT].connect_time, t1); + fmtime(cur->call[IN].connect_time, t2), + printf(" %-8s %6d %6d %8s %6d %6d %8s\n", + cur->Hostname, + cur->call[OUT].calls, + cur->call[OUT].calls - cur->call[OUT].succs, + t1, + cur->call[IN].calls, + cur->call[IN].calls - cur->call[IN].succs, + t2); + } + } + + /* + * File statistics report + */ + if(show_files && have_files) + { + char t1[32], t2[32]; + + for (sent = IN; sent <= OUT; ++sent) + { + printf(file_hdr[sent]); + printf(" sysname files bytes xfr time byte/s\n"); + printf(" -------- ------ -------- -------- ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + double rate; + double time; + + time = cur->call[IN].flow[sent].time + + cur->call[OUT].flow[sent].time; + if (time == 0.0) + continue; + rate = (cur->call[IN].flow[sent].bytes + + cur->call[OUT].flow[sent].bytes) / time; + fmbytes((cur->call[IN].flow[sent].bytes + + cur->call[OUT].flow[sent].bytes), t1); + fmtime((cur->call[IN].flow[sent].time + + cur->call[OUT].flow[sent].time), t2); + printf(" %-8s %6d %8s %8s %6.1f\n", + cur->Hostname, + cur->call[IN].flow[sent].files + + cur->call[OUT].flow[sent].files, + t1, t2, rate); + } + } + } + + /* + * Efficiency report + */ + if (show_efficiency && have_files) + { + char t1[32], t2[32], t3[32]; + double total, flow; + + printf("\nEfficiency:\n"); + printf(" sysname conntime flowtime ovhdtime eff. %%\n"); + printf(" -------- -------- -------- -------- ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + total = cur->call[IN].connect_time + cur->call[OUT].connect_time; + flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time + + cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time; + fmtime(total, t1); + fmtime(flow, t2); + fmtime((total-flow), t3); + printf(" %-8s %8s %8s %8s %5.1f%%\n", + cur->Hostname, t1, t2, t3, ((flow / total) * 100.0)); + } + } + + /* + * Command execution report + */ + if (show_commands & have_commands) + { + printf("\nCommand executions:\n"); + printf(" sysname rmail rnews other\n"); + printf(" -------- ------ ------ ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + int rmail, rnews, other; + + if (cur->cmds == NULL) + continue; + rmail = rnews = other = 0; + for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) + { + if (strcmp(cmd->Commandname, "rmail") == 0) + rmail += cmd->count; + else if (strcmp(cmd->Commandname, "rnews") == 0) + rnews += cmd->count; + else + other += cmd->count; + } + printf(" %-8s %6d %6d %6d\n", cur->Hostname, + rmail, rnews, other); + } + } + return; + + usage: + fprintf(stderr, + "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n"); + fprintf(stderr,"where:\t-c\tReport call statistics\n"); + fprintf(stderr, "\t-f\tReport file transfer statistics\n"); + fprintf(stderr, "\t-e\tReport efficiency statistics\n"); + fprintf(stderr, "\t-x\tReport command execution statistics\n"); + fprintf(stderr, "\t-a\tAll of the above reports\n"); + fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n"); + fprintf(stderr, "\t-i\tRead log info from standard input\n"); + fprintf(stderr, + "If no report options given, a compact summary report is given.\n"); + fprintf(stderr, + "If neither -i nor logfiles given, defaults to reading from\n"); + fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE); +} + +/* + * fmtime() - Format time in hours & minutes; + */ +static void fmtime(dsec, buf) + double dsec; + char *buf; +{ + long hrs, min, lsec; + + lsec = dsec; + hrs = lsec / 3600L; + min = (lsec - (hrs * 3600L)) / 60L; + + sprintf(buf, "%02ld:%02ld", hrs, min); +} + +/* + * fmbytes - Format size in bytes + */ +static void fmbytes(n, buf) + unsigned long n; + char *buf; +{ + char t; + double s = n; + + if(s >= 10239897.6) /* More than 9999.9K ? */ + { + s = (double)n / 1048576.0; /* Yes, display in Megabytes */ + t = 'M'; + } + else + { + s = (double)n / 1024.0; /* Display in Kilobytes */ + t = 'K'; + } + + sprintf(buf, "%.1f%c", s, t); +} + diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man new file mode 100644 index 00000000000..9f33ef30386 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uurate.man @@ -0,0 +1,217 @@ +.TH uurate 1 +.SH NAME +uurate \- Report Taylor UUCP statistics +.SH SYNOPSIS +.BR uurate " [ " "\-cfexai" " ] [ " "\-h " +.I host +.RI " ] [ " "logfile..." " ] " +.PP +or simply, +.PP +.B uurate +.PP +for a traffic summary report. +.SH DESCRIPTION +The +.I uurate +command provides tabular summary reports on the operation of the +Taylor UUCP system. Data is taken from the currently active log +files, standard input, or from a list of log files given on the +command line. Output is in the form of tabular reports summarizing +call, file transfer, and command execution +.RI "(" "uuxqt" ")" +activity. +.PP +The log files given to +.I uurate +must be in the ``Taylor'' format. Also, note that call and file +transfer activities are logged in separate files, nominally called +.I Log +and +.I Stats, +respectively. For reports to be meaningful, the +.I Log +and +.I Stats +files should be given to +.I uurate +together, and cover the same time period. +.PP +If neither the +.B \-i +option nor any +.I logfile +options are given, +.I uurate +defaults to taking its input from the current Taylor +.I Log +and +.I Stats +files, as defined at compilation time. +This is the normal mode of operation. +.PP +The reporting options described below can be used to select +the set of reports desired. If no options are given, the +.B call +and +.B file +reports are displayed. If there is no relevant data for a particular +report or host, that report or host will be supressed. +.SH OPTIONS +The following options may be given to +.I uurate: +.TP 5 +.B \-c +Report on call statistics. Requires data from a +.I Log +file. +.TP 5 +.B \-f +Report on file transfer statistics. Requires data from a +.I Stats +file. +.TP 5 +.B \-e +Report on efficiency (total connect time versus time spent transferring +files). Requires data from both a +.I Log +and a +.I Stats +file, and they must span the same time period. +.TP 5 +.B \-x +Report on remote execution requests (e.g., +.IR rmail ")." +Requires data from a +.I Log +file. +.TP 5 +.B \-a +All reports. Identical to +.B \-cfex. +.TP 5 +.BI "\-h " "host" +Restrict report output to +.I host. +.SH "DESCRIPTION OF REPORTS" +There are four reports available: the call, file transfer, efficiency, +and remote execution reports. Each may be selected by a command line +option. All reports may be selected via the option +.B \-a. +If no report selection options are given, +.I uurate +displays a compact traffic summary report (see below). +.SS "Summary report" +If no report options are given, +.I uurate +displays a traffic summary report. This is particularly useful in daily +.I cron +jobs which report on errors and the like. Traffic statistics for each +active system is reported on a single line. If more than one system was +active, a 'totals' line is included at the end of the report. +.SS "Call report" +The call report gives statistics on inbound and outbound calls for +each active host system. The fields are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "callto " "Outbound calls attempted to that system" +.BR "failto " "Failed outbound calls to that system" +.BR "totime " "Connect time (sec.) on outbound calls" +.BR "callfm " "Inbound calls attempted by that system" +.BR "failfm " "Failed inbound calls from that system" +.BR "fmtime " "Connect time (sec.) on inbound calls" +.in -.5 +.SS "File transfer reports" +The file transfer reports give statistics on inbound and +outbound file transfers (regardless of which end initiated the transfer) +for each active host system. There are two reports, one for files +sent to the remote system and one for files received from the remote +system. The fields in each report are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "files " "Number of files transferred" +.BR "bytes " "Total size (bytes) of files transferred" +.BR "seconds " "Total time (sec.) to transfer files" +.BR "byte/sec " "Average transfer rate (bytes/sec)" +.in -.5 +.SS "Efficiency report" +The efficiency report describes the utilization of the links +to each active remote system, giving the ratio of total connect time +to the time spent actually transferring files. +The fields are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "conntime " "Total connect time for that system" +.BR "flowtime " "Total file transfer time for that system" +.BR "ovhdtime " "Connect time not used to transfer files" +.BR "effcy (%) " "Ratio of connect time to transfer time" +.in -.5 +.SS "Remote execution report" +The remote execution report describes remotely +requested command executions from each active host system. +Executions of +.I rmail +and +.I rnews +are the most common, and are detailed separately. The fields +are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "rmail " "Number of rmail requests from that system" +.BR "rnews " "Number of rnews requests from that system" +.BR "other " "Number of other requests from that system" +.in -.5i +.SS FILES +The file names below may be changed at compilation time or by the +configuration file, so these are only approximations. +.br +.nf +.in +.5in +.ta 2.0i +.IR "/usr/spool/uucp/Log " "Taylor format call/execution log" +.IR "/usr/spool/uucp/Stats " "Taylor format file transfer log" +.SS "SEE ALSO" +.IR uucico "(8)" +.SS BUGS +Does not understand older (V2, BNU) logging formats. Anyone care to +volunteer to add this? I don't use the stuff myself. +.PP +The entries that Taylor UUCP makes in the log file for incoming calls +don't have a host name. This confuses +.I uurate +into thinking that the calls came in for system "-". This may require +a change to Taylor logging. +.PP +Should check the configuration file to locate the currently active +.I Log +and +.I Stats +files when using them for default inputs. Instead, it uses the +compile-time settings only. +.PP +Should report packet protocol error statistics by host and +protocol type. +.SS AUTHOR +Robert B. Denny (denny@alisa.com) +.br +Loosely based on the DECUS UUCP program +.I uurate +by Mark Pizzolato. + + + + + + diff --git a/gnu/libexec/uucp/contrib/uureroute b/gnu/libexec/uucp/contrib/uureroute new file mode 100644 index 00000000000..3eeb654e1e2 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uureroute @@ -0,0 +1,91 @@ +#!/usr/local/bin/perl +eval ' exec /usr/local/bin/perl $0 "$@" ' + if $running_under_some_shell; + +# From a script by <Bill.Campbell@celestial.com> +# Newsgroups: comp.sources.misc +# Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01 +# Date: 26 Feb 92 02:28:37 GMT +# +# This is a Honey DanBer specific routine written in perl to reroute all +# mail queued up for a specific host. It needs to be run as "root" since +# uucp will not allow itself to remove others requests. +# +# Revision *** 92/21/09: Francois Pinard <pinard@iro.umontreal.ca> +# 1. adapted for Taylor UUCP +# +# Revision 1.3 91/10/08 09:01:21 src +# 1. Rewritten in perl +# 2. Add -v option for debugging. +# +# Revision 1.2 91/10/07 23:57:42 root +# 1. Fix mail program path. +# 2. Truncate directory name to 7 characters + +($progname = $0) =~ s!.*/!!; # save this very early + +$USAGE = " +# Reroute uucp mail +# +# Usage: $progname [-v] host [host...] +# +# Options Argument Description +# -v Verbose (doesn't execute /bin/sh) +# +"; + +$UUSTAT = "/usr/local/bin/uustat"; +$SHELL = "/bin/sh"; +$SMAIL = "/bin/smail"; + +sub usage +{ + die join ("\n", @_) . "\n$USAGE\n"; +} + +do "getopts.pl"; + +&usage ("Invalid Option") unless do Getopts ("vV"); + +$verbose = ($opt_v ? '-v' : ()); +$suffix = ($verbose ? '' : $$); + +&usage ("No system specified") if $#ARGV < 0; + +if (!$verbose) +{ + open (SHELL, "| $SHELL"); + select SHELL; +} + +while ($system = shift) +{ + $sysprefix = substr ($system, 0, 7); + $directory = "/usr/spool/uucp/$sysprefix"; + open (UUSTAT, "$UUSTAT -s $system -c rmail |"); + print "set -ex\n"; + while (<UUSTAT>) + { + ($jobid, ) = split; + ($cfile) = substr ($jobid, length ($jobid) - 5); + $cfilename = "$directory/C./C.$cfile"; + open (CFILE, $cfilename) || die "Cannot open $cfilename\n"; + $_ = <CFILE>; + close CFILE; + if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/) + { + $datafile = "$directory/D./D.$1"; + $address = $2; + } + else + { + print STDERR; + die "Cannot parse previous line from $cfilename\n"; + } + print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n"; + } + close UUSTAT; +} +close SHELL unless $verbose; + +exit 0; diff --git a/gnu/libexec/uucp/contrib/uusnap.c b/gnu/libexec/uucp/contrib/uusnap.c new file mode 100644 index 00000000000..0f878c1e054 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uusnap.c @@ -0,0 +1,321 @@ +/* uusnap.c + (c) 1992 Heiko W.Rupp hwr@pilhuhn.ka.sub.org + uusnap is a tool to display the activities of the connected + systems. + + Put a file uusnap.systems in NEWCONFIGDIR (see Makefile), in which + the systems, you want to monitor are listed, one on a single line. + The sequence of the files there determine the sequence of the + listing. + + At the moment it only works with taylor config and taylor dirs + + compile it form the Makefile or: + cc -c -g -pipe -O -I. -I. -DNEWCONFIGLIB=\"/usr/local/lib/uucp\" uusnap.c + cc -o uusnap uusnap.o + For this, uusnap.[ch] must be in the same directory as uucp.h and so. + + uusnap must have read access to SPOOLDIR/.Status in order to work. +*/ + +#define MAXSYS 30 /* maximum number of systems */ +#define WAIT_NORMAL 10 /* wait period if noone is talking */ +#define WAIT_TALKING 2 /* refresh display every second if */ + /* someone is talking with us */ + +#include "uucp.h" +#if USE_RCS_ID +char uusnap_rcsid[] = "$Id: uusnap.c,v 1.1 1993/08/04 19:31:43 jtc Exp $"; +#endif + +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/dir.h> + +extern char *ctime(time_t*); + +struct sysInfo { + char sysname[10]; /* name of the system to watch */ + char *statfile; /* name of its status file */ + char *spooldir; /* root of its spooldir */ + int in; /* number of unprocessed in-files */ + int out; /* number of files to send them */ + time_t last; /* last poll time */ + time_t next; /* time of next poll */ + time_t lastidir; /* time of last in-spooldir access */ + time_t lastodir; /* time of last outgoing spd acc */ + time_t laststat; /* time of last status file access */ + int status; /* status of the system */ + int num_retries; /* number of retries */ +}; + +struct sysInfo Systems[MAXSYS]; + + +/* I have extend the system status. If time for the specified system + is Never, I say so. To get this to work, one also should extend + uucico.c. It is not important to do this. With the normal uucico, + one only gets no status. +*/ + +const char *azStatus[] = /* Status codes as defined by uucico */ +{ /* listing them here instead of */ + "Conversation complete", /* including the appropriate file */ + "Port unavailable", /* reduces the size of the executable */ + "Dial failed", + "Login failed", + "Handshake failed", + "Call failed", + "Talking", + "Wrong time to call", + "Time to call = Never !" +}; + +main() +{ + int i; + i=get_systems(); + display_info(i); + + exit(0); +} + +int +get_systems() +{ + char filename[1024]; + char fn[1024]; + char line[80]; + FILE *fp; + int i=0; + int j; + struct stat stbuf; + struct sysInfo sys; + + strcpy(filename,NEWCONFIGLIB); + strcat(filename,"/uusnap.systems"); + if ((fp=fopen(filename,"r"))!=NULL) { + while (fgets(line,80,fp)!=NULL) { + *(rindex(line,'\n'))='\0'; + strcpy(sys.sysname,line); /* get the name of the system */ + strcpy(fn,SPOOLDIR); /* get the name of the statusfile */ + strcat(fn,"/.Status/"); + strcat(fn,line); + sys.statfile=malloc(strlen(fn)+1); + strcpy(sys.statfile,fn); + strcpy(fn,SPOOLDIR); /* get the name of the spooldir */ + strcat(fn,"/"); + strcat(fn,line); + sys.spooldir=malloc(strlen(fn)+1); + strcpy(sys.spooldir,fn); + sys.laststat=0; + sys.lastidir=sys.lastodir=0; + Systems[i]=sys; /* get_stat_for_system needs it */ + get_stat_for_system(i); /* now get the system status */ + get_inq_num(i,TRUE); /* number of unprocessed files */ + get_outq_num(i,TRUE); /* number of files to send */ + i++; + } + fclose(fp); + } + else { + fprintf(stderr,"Can't open %s \n",filename); + exit(1); + } + return i; +} + + + +display_info(int numSys) +{ + char *filename; + int sysnum; + FILE *fp; + char contentline[80]; + char isTalking=FALSE; + struct stat stbuf; + struct sysInfo sys; + time_t time; + + filename = (char*)malloc(1024); + if (filename == NULL) { + fprintf(stderr, "Can't malloc 1024 bytes"); + exit(1); + } + + while(TRUE) { + display_headline(); + for (sysnum=0;sysnum<numSys;sysnum++) { + sys = Systems[sysnum]; + stat(sys.statfile,&stbuf); + if ((time=stbuf.st_atime) > sys.laststat) { + get_stat_for_system(sysnum); + } + if(display_status_line(sysnum)==1) + isTalking=TRUE; + } + if (isTalking) { + sleep(WAIT_TALKING); + isTalking = FALSE; + } + else + sleep(WAIT_NORMAL); /* wait a bit */ + } + return 0; +} + +int +display_status_line(int sn) +{ + char *time_s; + + int sys_stat,num_retries,wait; + int i; + time_t last_time; + time_t next_time; + + struct sysInfo sys; + + sys = Systems[sn]; + + printf("%10s ",sys.sysname); + get_inq_num(sn); + if (sys.in==0) + printf(" "); + else + printf("%3d ",sys.in); + get_outq_num(sn); + if (sys.out==0) + printf(" "); + else + printf("%3d ",sys.out); + time_s = ctime(&sys.last); + time_s = time_s + 11; + *(time_s+8)='\0'; + printf("%8s ",time_s); /* time of last poll */ + time_s = ctime(&sys.next); + time_s = time_s + 11; + *(time_s+8)='\0'; + if (sys.last == sys.next) + printf(" "); + else + printf("%8s ",time_s); /* time of next poll */ + if (sys.num_retries==0) + printf(" "); + else + printf("%2d ",sys.num_retries); + if (sys_stat==6) /* system is talking */ + printf("\E[7m"); /* reverse video on */ + printf("%s",azStatus[sys.status]); + if (sys.status==6) { + printf("\E[m\n"); /* reverse video off */ + return 1; + } + else { + printf("\n"); + return 0; + } +} + + +display_headline() +{ + printf("\E[;H\E[2J"); /* clear screen */ + printf("\E[7muusnap (press CTRL-C to escape)\E[m \n\n"); + printf(" System #in #out last next #ret Status\n"); + return 0; +} + +get_inq_num(int num,char firstTime) +{ + int i=0; + char filename[1024]; + struct stat stbuf; + DIR *dirp; + + strcpy(filename,Systems[num].spooldir); + strcat(filename,"/X./."); + stat(filename,&stbuf); + if ((stbuf.st_mtime > Systems[num].lastidir) || (firstTime)) { + if ((dirp=opendir(filename))!=NULL) { + while(readdir(dirp)) + i++; + closedir(dirp); + stat(filename,&stbuf); + Systems[num].lastidir=stbuf.st_mtime; + } + else { + fprintf(stderr,"Can't open %s \n",filename); + exit(1); + } + if (i>=2) + i-=2; /* correct . and .. */ + Systems[num].in=i; + } + return 0; +} + +get_outq_num(int sys,char firstTime) +{ + int i=0; + char filename[1024]; + struct stat stbuf; + DIR *dirp; + + strcpy(filename,Systems[sys].spooldir); + strcat(filename,"/C./."); + stat(filename,&stbuf); + if ((stbuf.st_mtime > Systems[sys].lastodir) || (firstTime)) { + if ((dirp=opendir(filename))!=NULL) { + while(readdir(dirp)) + i++; + closedir(dirp); + stat(filename,&stbuf); + Systems[sys].lastodir=stbuf.st_mtime; + } + else { + fprintf(stderr,"Can't open %s \n",filename); + exit(1); + } + if (i>=2) + i-=2; /* correct . and .. */ + Systems[sys].out=i; + } + return 0; +} + +get_stat_for_system(int i) +{ + char fn[80]; + struct sysInfo sys; + struct stat stbuf; + FILE *fp; + time_t wait; + + sys = Systems[i]; + stat(sys.statfile,&stbuf); + if (stbuf.st_atime > sys.laststat) { + if ((fp=fopen(sys.statfile,"r"))!=NULL) { + fgets(fn,80,fp); + fclose(fp); + sscanf(fn,"%d %d %ld %d", + &sys.status, + &sys.num_retries, + &sys.last, + &wait); + sys.next=sys.last+wait; + } + else { + sys.status=0; + sys.num_retries=0; + sys.last=0; + sys.next=0; + } + stat(sys.statfile,&stbuf); + sys.laststat=stbuf.st_atime; + } + Systems[i] = sys; + return 0; +} diff --git a/gnu/libexec/uucp/contrib/uutraf b/gnu/libexec/uucp/contrib/uutraf new file mode 100644 index 00000000000..8b56d0f6b4f --- /dev/null +++ b/gnu/libexec/uucp/contrib/uutraf @@ -0,0 +1,203 @@ +#!/usr/local/bin/perl +# uutraf.pl -- UUCP Traffic Analyzer +# SCCS Status : @(#)@ uutraf 1.7 +# Author : Johan Vromans +# Created On : *** +# Last Modified By: Johan Vromans +# Last Modified On: Wed Feb 26 08:52:56 1992 +# Update Count : 4 +# Status : OK +# Requires: : Perl V4 or later + +# Reads UUCP syslog, and generates a report from it. +# +# Created by Johan Vromans <jv@mh.nl> +# Loosely based on an idea by Greg Hackney (hack@texbell.swbt.com) + +# Usage: uutraf [-taylor|-hdb|-bnu|-bsd] [syslog] + +# Logfile formats: +# +# BSD: +# +# jv mhres (2/23-5:18) (698818735) received 135 b 2 secs +# root mhres (2/23-5:19) (698818742) sent 2365 b 3 secs, Pk: 38, Rxmt: 0 +# +# HDB: +# +# uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, \ +# 474 bytes/sec +# +# Taylor: +# +# jv mhres (1992-02-24 20:49:04.06) sent 16234 bytes in 148.780 seconds \ +# (109 bytes/sec) +# jv mhres (1992-02-24 21:04:05.76) received 449 bytes in 6.550 seconds \ +# (68 bytes/sec) + +$uucp_type = "gnu"; + +%hosts = (); # hosts seen +%bytes_in = (); # of bytes received from host +%bytes_out = (); # of bytes sent to host +%secs_in = (); # of seconds connect for recving +%secs_out = (); # of seconds connect for sending +%files_in = (); # of input requests +%files_out = (); # of output requests + +# read info, break the lines and tally + +if ( $ARGV[0] =~ /^-/ ) { + ($uucp_type = substr (shift (@ARGV), 1)) =~ tr/A-Z/a-z/; +} + +if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) { + @ARGV = ("/usr/spool/uucp/Stats") unless $#ARGV >= 0; + $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " . + "(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds"; + $uucp_type = 0; + $recv = "received"; +} +elsif ( $uucp_type eq "hdb" || $uucp_type eq "bnu" ) { + @ARGV = ("/usr/spool/uucp/.Admin/xferstats") unless $#ARGV >= 0; + $pat = "^([^!]+)![^(]+\\(([-0-9:\\/]+)\\).+([<>])-? " . + "(\\d+) \\/ (\\d+)\\.(\\d+) secs"; + $uucp_type = 1; + $recv = "<"; +} +elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) { + @ARGV = ("/usr/spool/uucp/SYSLOG") unless $#ARGV >= 0; + $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/]+)\\) \\([^)]+\\) " . + "(sent|received) (\\d+) b (\\d+) secs"; + $uucp_type = 2; + $recv = "received"; +} +else { + die ("Unknown UUCP type: $uucp_type\n"); +} + +$garbage = 0; + +while ( <> ) { + unless ( /$pat/o ) { + print STDERR "Possible garbage: $_"; + if ( $garbage++ > 10 ) { + die ("Too much garbage; wrong UUCP type?\n"); + } + next; + } + + # gather timestamps + $last_date = $2; + $first_date = $last_date unless defined $first_date; + + # initialize new hosts + unless ( defined $hosts{$1} ) { + $hosts{$1} = $files_in{$1} = $files_out{$1} = + $bytes_in{$1} = $bytes_out{$1} = + $secs_in{$1} = $secs_out{$1} = 0; + } + + # Taylor and HDB have milliseconds, BSD has not. + $secs = ($uucp_type == 2) ? ($5 + ($5 == 0 ? 0.5 : 0)) : ($5 + $6/1000); + + # tally + if ( $3 eq $recv ) { # recv + $bytes_in{$1} += $4; + $files_in{$1}++; + $secs_in{$1} += $secs; + } + else { # xmit + $bytes_out{$1} += $4; + $files_out{$1}++; + $secs_out{$1} += $secs; + } + $garbage = 0; +} + +@hosts = keys (%hosts); +die ("No info found, stopped\n") if $#hosts < 0; + +################ report section ################ + +$thishost = &gethostname(); +$thishost = (defined $thishost) ? "on node $thishost" : "report"; + +if ( $uucp_type eq 0 ) { # Taylor UUCP + substr ($first_date, 16) = ""; + substr ($last_date, 16) = ""; +} + +format std_head = +@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +"UUCP traffic $thishost from $first_date to $last_date" + +Remote -----------K-Bytes----------- ----Hours---- --Avg CPS-- --Files-- + Host Recv Sent Total Recv Sent Recv Sent Recv Sent +. +format std_out = +@<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>> @>>>>> @>>>> @>>>> @>>> @>>> +$Zhost, $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs, $Zi_acps, $Zo_acps, $Zi_count, $Zo_count +. + +$^ = "std_head"; +$~ = "std_out"; + +&print_dashes (); + +reset "T"; # reset totals + +foreach $host (@hosts) { + &print_line ($host, $bytes_in{$host}, $bytes_out{$host}, + $secs_in{$host}, $secs_out{$host}, + $files_in{$host}, $files_out{$host}); + +} + +&print_dashes (); +&print_line ("Total", $Ti_bytes, $To_bytes, + $Ti_secs, $To_secs, $Ti_count, $To_count); + +################ that's it ################ + +sub print_line { + reset "Z"; # reset print fields + local ($Zhost, + $Zi_bytes, $Zo_bytes, + $Zi_secs, $Zo_secs, + $Zi_count, $Zo_count) = @_; + $Ti_bytes += $Zi_bytes; + $To_bytes += $Zo_bytes; + $Zt_bytes = $Zi_bytes + $Zo_bytes; + $Tt_bytes += $Zt_bytes; + $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) : "0"; + $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) : "0"; + $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000); + $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000); + $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000); + $Zi_hrs = sprintf ("%.1f", $Zi_secs/3600); + $Zo_hrs = sprintf ("%.1f", $Zo_secs/3600); + $Ti_secs += $Zi_secs; + $To_secs += $Zo_secs; + $Ti_count += $Zi_count; + $To_count += $Zo_count; + write; +} + +sub print_dashes { + $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes = + $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count = + "------------"; + write; + # easy, isn't it? +} + +################ missing ################ + +sub gethostname { + $ENV{"SHELL"} = "/bin/sh"; + $try = `uuname -l 2>/dev/null`; + chop $try; + return $+ if $try =~ /^[-.\w]+$/; + return undef; +} diff --git a/gnu/libexec/uucp/contrib/uutry b/gnu/libexec/uucp/contrib/uutry new file mode 100644 index 00000000000..bc0cf299e99 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uutry @@ -0,0 +1,43 @@ +#!/bin/sh +# +# This script was hacked together by Marc Evans (marc@Synergytics.Com) +# I claim no copyright to it and don't really care what people do +# with it, hence, it is public domain. I take no responsibility for +# for happens if you use this script, providing no warentee. This +# section of the comments may be removed if you so desire. +# +# Usage: +# uutry [-x#] systemname +# where '-x#' has the value [0-9], higher values providing more detail + +# +# The following variables should be gropped from the configuration +# files rather then being hard coded here. +# +Spool=/usr/spool/uucp +Lib=/usr/lib/uucp +Status=$Spool/.Status +Debug=$Spool/Debug +Uucico=$lib/uucico +# +# Default option values +# +x="-x5" +s="" + +for i in $* ; do + case $i in + -x*) x="$i" ;; + *) s="$i" ;; + esac +done + +if [ $s != "" ]; then + rm -f $Status/$s + $Uucico -r1 $x -s$s & + >$Debug + tail -f $Debug +else + echo "Usage: uutry systemname" + exit 1 +fi diff --git a/gnu/libexec/uucp/contrib/xc-conf.h-dist b/gnu/libexec/uucp/contrib/xc-conf.h-dist new file mode 100644 index 00000000000..8810dd78d92 --- /dev/null +++ b/gnu/libexec/uucp/contrib/xc-conf.h-dist @@ -0,0 +1,38 @@ +/* + * ************* + * * XC-CONF.H * + * ************* + * + * Configuration file for xchat 1.1. Edit this file prior to make-ing + * xchat. + * + * History: + * Bob Denny - Tue Sep 1 11:42:54 1992 + */ + +/* + * Edit this to reflect the relative location of xchat sources to + * the main Taylor UUCP source directory. As distributed, xchat + * is in the ./contrib sub-directory under the main Taylor UUCP + * directory. Therefore, Taylor's conf.h is in our parent directory. + */ +#include "../conf.h" + +/* + * The following definition establishes the default path to the + * scripts used by xchat. You may lleave this blank (""), but + * the command line given to xchat (e.g., in the 'sys' file entry) + * must specify a full (absolute) path name to the script to be + * executed. Normally, this is the same place you put your config + * and system files for UUCP. + */ +#define SCRIPT_DIR "/usr/local/conf/uucp/" /* MUST HAVE TRAILING "/" */ + +/* + * The following definition establishes the default path to the + * log files that are produced by the 'dbgfile' statement. Normally + * this is the same location you configured Taylor UUCP to put its + * log files. + */ +#define LOG_DIR "/usr/spool/uucp/" /* MUST HAVE TRAILING "/" */ + diff --git a/gnu/libexec/uucp/contrib/xchat.c b/gnu/libexec/uucp/contrib/xchat.c new file mode 100644 index 00000000000..cfb4d359662 --- /dev/null +++ b/gnu/libexec/uucp/contrib/xchat.c @@ -0,0 +1,1444 @@ +/* + * *********** + * * XCHAT.C * + * *********** + * + * Extended chat processor for Taylor UUCP. See accompanying documentation. + * + * Written by: + * Bob Denny (denny@alisa.com) + * Based on code in DECUS UUCP (for VAX/VMS) + * + * History: + * Version 1.0 shipped with Taylor 1.03. No configuration info inside. + * + * Bob Denny - Sun Aug 30 18:41:30 1992 + * V1.1 - long overdue changes for other systems. Rip out interval + * timer code, use timer code from Taylor UUCP, use select() + * for timed reads. Use Taylor UUCP "conf.h" file to set + * configuration for this program. Add defaulting of script + * and log file paths. + * + * Bugs: + * Does not support BSD terminal I/O. Anyone care to add it? + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <time.h> +#include <sys/ioctl.h> +#include <sys/termio.h> + +#include "xc-conf.h" + +/* + * Pick a timing routine to use, as done in Taylor UUCP. + */ +#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL +#define USE_SELECT_TIMER 0 +#else +#define USE_SELECT_TIMER HAVE_SELECT +#if USE_SELECT_TIMER +#include <sys/time.h> +#endif +#endif + +#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS +#undef HAVE_POLL +#define HAVE_POLL 0 +#endif + +#if HAVE_USLEEP || HAVE_NAP +#undef HAVE_NAPMS +#define HAVE_NAPMS 0 +#endif + +#if HAVE_USLEEP +#undef HAVE_NAP +#define HAVE_NAP 0 +#endif + +static int ttblind(); +static int ttcd(); + +/* script entry -- "compiled" form of dial, hangup, or login script */ + +struct script { + struct script *next; /* pointer to next entry, or null */ + int opcode; /* numeric opcode */ + char *strprm; /* pointer to string param */ + long intprm; /* integer parameter */ + char *newstate; /* new state name */ +}; + +/* opcode definition array element -- one for each possible opcode */ + +struct script_opdef { + char *opname; + int opcode; /* numeric opcode -- same as array index */ + int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */ + int newstate; /* one of SC_NONE, SC_NWST */ +}; + + /* values for opcode */ + +#define SC_LABEL 0 /* "label" (state name) */ +#define SC_CDLY 1 /* set char output delay in msec */ +#define SC_PCHR 2 /* pause char for dial string (from P in input) */ +#define SC_PTIM 3 /* seconds to allow for pause char */ +#define SC_WCHR 4 /* wait char for dial string (from W in input) */ +#define SC_WTIM 5 /* seconds to allow for wait char */ +#define SC_ZERO 6 /* zero counter */ +#define SC_INCR 7 /* increment counter */ +#define SC_IFGT 8 /* change state if counter > int param */ +#define SC_WAIT 9 /* wait for int param seconds */ +#define SC_GOTO 10 /* unconditional change to new state */ +#define SC_SEND 11 /* send strparam (after sprintf substitutions) */ +#define SC_BRK 12 /* send a break */ +#define SC_HANG 13 /* drop DTR */ +#define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */ +#define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */ + /* default = 100 (one tenth second) */ +#define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */ + /* default = 45 seconds */ +#define SC_EXIT 17 /* script done, success */ +#define SC_FAIL 18 /* script done, failure */ +#define SC_LOG 19 /* write strparam to uucp.log */ +#define SC_LOGE 20 /* write strparam to uucp.log w/error ind */ +#define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */ +#define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */ +#define SC_DBST 23 /* 'or' intparam into debug mask */ +#define SC_DBCL 24 /* 'bicl' intparam into debug mask */ +#define SC_TIMO 25 /* newstate if no match in intparam secs */ + /* (uses calculated dial time if intparam is 0) */ +#define SC_XPCT 26 /* wait for strparam, goto _newstate if found */ +#define SC_CARR 27 /* goto _newstate if carrier detected */ +#define SC_FLSH 28 /* flush typeahead buffer */ +#define SC_IFBL 29 /* change state if controller is blind w/o CD */ +#define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */ +#define SC_SNDP 31 /* send parameter n */ +#define SC_IF1P 32 /* if parameter n present */ +#define SC_IF0P 33 /* if parameter n absent */ +#define SC_DBOF 34 /* open debugging file */ +#define SC_TELN 35 /* Set telno from parameter n */ +#define SC_7BIT 36 /* Set port to 7-bit stripping */ +#define SC_8BIT 37 /* Set port for 8-bit characters */ +#define SC_PNON 38 /* Set port for 8-bit, no parity */ +#define SC_PEVN 39 /* Set port for 7-bit, even parity */ +#define SC_PODD 40 /* Set port for 7-bit, odd parity */ +#define SC_HUPS 41 /* Change state on HUP signal */ +#define SC_END 42 /* end of array */ + + /* values for prmtype, prm2type */ + +#define SC_NONE 0 /* no parameter */ +#define SC_STR 1 /* simple string */ +#define SC_INT 2 /* integer */ +#define SC_NWST 3 /* new state name */ +#define SC_XSTR 4 /* translated string */ + +/* opcode definition table for dial/login/hangup scripts */ + +static struct script_opdef sc_opdef[] = + { + {"label", SC_LABEL, SC_NONE, SC_NONE}, + {"chrdly", SC_CDLY, SC_INT, SC_NONE}, + {"pchar", SC_PCHR, SC_STR, SC_NONE}, + {"ptime", SC_PTIM, SC_INT, SC_NONE}, + {"wchar", SC_WCHR, SC_STR, SC_NONE}, + {"wtime", SC_WTIM, SC_INT, SC_NONE}, + {"zero", SC_ZERO, SC_NONE, SC_NONE}, + {"count", SC_INCR, SC_NONE, SC_NONE}, + {"ifgtr", SC_IFGT, SC_INT, SC_NWST}, + {"sleep", SC_WAIT, SC_INT, SC_NONE}, + {"goto", SC_GOTO, SC_NONE, SC_NWST}, + {"send", SC_SEND, SC_XSTR, SC_NONE}, + {"break", SC_BRK, SC_NONE, SC_NONE}, + {"hangup", SC_HANG, SC_NONE, SC_NONE}, + {"7bit", SC_7BIT, SC_NONE, SC_NONE}, + {"8bit", SC_8BIT, SC_NONE, SC_NONE}, + {"nopar", SC_PNON, SC_NONE, SC_NONE}, + {"evenpar", SC_PEVN, SC_NONE, SC_NONE}, + {"oddpar", SC_PODD, SC_NONE, SC_NONE}, + {"telno", SC_TELN, SC_INT, SC_NONE}, + {"dial", SC_DIAL, SC_NONE, SC_NONE}, + {"dgttime", SC_DTIM, SC_INT, SC_NONE}, + {"ctime", SC_CTIM, SC_INT, SC_NONE}, + {"success", SC_EXIT, SC_NONE, SC_NONE}, + {"failed", SC_FAIL, SC_NONE, SC_NONE}, + {"log", SC_LOG, SC_XSTR, SC_NONE}, + {"logerr", SC_LOGE, SC_XSTR, SC_NONE}, + {"debug", SC_DBG, SC_XSTR, SC_NONE}, + {"debuge", SC_DBGE, SC_XSTR, SC_NONE}, + {"dbgset", SC_DBST, SC_INT, SC_NONE}, + {"dbgclr", SC_DBCL, SC_INT, SC_NONE}, + {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE}, + {"timeout", SC_TIMO, SC_INT, SC_NWST}, + {"expect", SC_XPCT, SC_XSTR, SC_NWST}, + {"ifcarr", SC_CARR, SC_NONE, SC_NWST}, + {"ifhang", SC_HUPS, SC_NONE, SC_NWST}, + {"flush", SC_FLSH, SC_NONE, SC_NONE}, + {"ifblind", SC_IFBL, SC_NONE, SC_NWST}, + {"ifblgtr", SC_IFBG, SC_INT, SC_NWST}, + {"sendstr", SC_SNDP, SC_INT, SC_NONE}, + {"ifstr", SC_IF1P, SC_INT, SC_NWST}, + {"ifnstr", SC_IF0P, SC_INT, SC_NWST}, + {"table end", SC_END, SC_NONE, SC_NONE} + }; + +#define SUCCESS 0 +#define FAIL 1 +#define ERROR -1 +#define MAX_SCLINE 255 /* max length of a line in a script file */ +#define MAX_EXPCT 127 /* max length of an expect string */ +#define CTL_DELIM " \t\n\r" /* Delimiters for tokens */ +#define SAME 0 /* if (strcmp(a,b) == SAME) ... */ +#define SLOP 10 /* Slop space on arrays */ +#define MAX_STRING 200 /* Max length string to send/expect */ + +#define DEBUG_LEVEL(level) \ + (Debug & (1 << level)) + +#define DB_LOG 0 /* error messages and a copy of the LOGFILE output */ +#define DB_LGIE 1 /* dial,login,init trace -- errors only */ +#define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */ +#define DB_LGII 3 /* script processing internals */ + +#define TRUE 1 +#define FALSE 0 + +#define NONE 0 +#define EVEN 1 +#define ODD 2 + +#define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1) + +static char **paramv; /* Parameter vector */ +static int paramc; /* Parameter count */ +static char telno[64]; /* Telephone number w/meta-chars */ +static int Debug; +static int fShangup = FALSE; /* TRUE if HUP signal received */ +static FILE *dbf = NULL; +static struct termio old, new; + +extern int usignal(); +extern int uhup(); + +static struct siglist +{ + int signal; + int (*o_catcher) (); + int (*n_catcher) (); +} sigtbl[] = { + { SIGHUP, NULL, uhup }, + { SIGINT, NULL, usignal }, + { SIGIOT, NULL, usignal }, + { SIGQUIT, NULL, usignal }, + { SIGTERM, NULL, usignal }, + { SIGALRM, NULL, usignal }, + { 0, NULL, NULL } /* Table end */ + }; + +extern struct script *read_script(); +extern void msleep(); +extern char xgetc(); +extern void charlog(); +extern void setup_tty(); +extern void restore_tty(); +extern void ttoslow(); +extern void ttflui(); +extern void tthang(); +extern void ttbreak(); +extern void tt7bit(); +extern void ttpar(); +extern void DEBUG(); + +extern void *malloc(); + + +/* + * ********************************** + * * BEGIN EXECUTION - MAIN PROGRAM * + * ********************************** + * + * This program is called by Taylor UUCP with a list of + * arguments in argc/argv, and stdin/stdout mapped to the + * tty device, and stderr mapped to the Taylor logfile, where + * anything written to stdout will be logged as an error. + * + */ +int main(argc, argv) +int argc; +char *argv[]; +{ + int i, stat; + FILE *sf; + char sfname[256]; + struct script *script; + struct siglist *sigs; + + /* + * The following is needed because my cpp does not have the + * #error directive... + */ +#if ! HAVE_SELECT + no_select_sorry(); /* Sad way to fail make */ +#endif + + paramv = &argv[2]; /* Parameters start at 2nd arg */ + paramc = argc - 2; /* Number of live parameters */ + + telno[0] = '\0'; + + if (argc < 2) + { + fprintf(stderr, "%s: no script file supplied\n", argv[0]); + exit(FAIL); + } + + /* + * If the script file argument begins with '/', then we assume + * it is an absolute pathname, otherwise, we prepend the + * SCRIPT_DIR path. + */ + *sfname = '\0'; /* Empty name string */ + if(argv[1][0] != '/') /* If relative path */ + strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */ + strcat(sfname, argv[1]); /* Add the script file name */ + + /* + * Now open the script file. + */ + if ((sf = fopen(sfname, "r")) == NULL) + { + fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname); + perror(" "); + exit(FAIL); + } + + /* + * COMPILE SCRIPT + */ + if ((script = read_script(sf)) == NULL) + { + fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]); + exit(FAIL); + } + + /* + * Set up a signal catcher so the line can be returned to + * it's current state if something nasty happens. + */ + sigs = &sigtbl[0]; + while(sigs->signal) + { + sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher); + sigs += 1; + } + + /* + * Save current tty settings, then set up raw, single + * character input processing, with 7-bit stripping. + */ + setup_tty(); + + /* + * EXECUTE SCRIPT + */ + if ((stat = do_script(script)) != SUCCESS) + fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]); + + /* + * Clean up and exit. + */ + restore_tty(); +#ifdef FIXSIGS + sigs = &sigtbl[0]; + while(sigs->signal) + if(sigs->o_catcher != -1) + signal(sigs->signal, sigs->o_catcher); +#endif + exit(stat); +} + +/* + * deal_script - deallocate a script and all strings it points to + */ +int deal_script(loc) +struct script *loc; +{ + /* + * If pointer is null, just exit + */ + if (loc == (struct script *)NULL) + return SUCCESS; + + /* + * Deallocate the rest of the script + */ + deal_script(loc->next); + + /* + * Deallocate the string parameter, if any + */ + if (loc->strprm != (char *)NULL) + free(loc->strprm); + + /* + * Deallocate the new state name parameter, if any + */ + if (loc->newstate != (char *)NULL) + free(loc->newstate); + + /* + * Deallocate this entry + */ + free(loc); + + return SUCCESS; +} + + +/* + * read_script + * + * Read & compile a script, return pointer to first entry, or null if bad + */ +struct script *read_script(fd) + FILE *fd; +{ + struct script *this = NULL; + struct script *prev = NULL; + struct script *first = NULL; + long len, i; + char inpline[MAX_SCLINE]; + char inpcopy[MAX_SCLINE]; + char *c, *cln, *opc, *cp; + + /* + * MAIN COMPILATION LOOP + */ + while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL) + { + /* + * Skip comments and blank lines + */ + if (*c == '#' || *c == '\n') + continue; + + /* + * Get rid of the trailing newline, and copy the string + */ + inpline[strlen(inpline)-1] = '\0'; + strcpy(inpcopy, inpline); + + /* + * Look for text starting in the first col (a label) + */ + if ((!isspace(inpline[0])) && + (cln = strchr (inpline, ':')) != (char *)NULL) { + this = (struct script *)malloc (sizeof (struct script)); + if (prev != (struct script *)NULL) + prev->next = this; + prev = this; + if (first == (struct script *)NULL) + first = this; + this->next = (struct script *)NULL; + this->opcode = SC_LABEL; + len = cln - c; + this->strprm = (char *)malloc(len+1); + strncpy(this->strprm, c, len); + (this->strprm)[len] = '\0'; + this->intprm = 0; + this->newstate = (char *)NULL; + c = cln + 1; + } + + /* + * Now handle the opcode. Fold it to lower case. + */ + opc = strtok(c, CTL_DELIM); + if (opc == (char *)NULL) /* If no opcode... */ + continue; /* ...read the next line */ + cp = opc; + while(*cp) + tolower(*cp++); + + /* + * If we have an opcode but we haven't seen anything + * else (like a label) yet, i.e., this is the first + * entry, and there was no label. We need to + * cobble up a label so that read_script is happy + */ + if (first == (struct script *)NULL) + { + this = (struct script *)malloc (sizeof (struct script)); + prev = this; + first = this; + this->next = (struct script *)NULL; + this->opcode = SC_LABEL; + this->strprm = (char *)malloc(2); + strcpy(this->strprm, ":"); + this->intprm = 0; + this->newstate = (char *)NULL; + } + + /* + * Find opcode - ndex through the opcode definition table + */ + for (i=1; sc_opdef[i].opcode != SC_END; i++) + if (strcmp(opc, sc_opdef[i].opname) == SAME) + break; + if ((sc_opdef[i].opcode) == SC_END) + { + logit ("Bad opcode in script", opc); + deal_script(first); + return (struct script *)NULL; + } + + /* + * Found opcode. Allocate a new command node and initialize + */ + this = (struct script *)malloc(sizeof (struct script)); + prev->next = this; + prev = this; + this->next = (struct script *)NULL; + this->opcode = sc_opdef[i].opcode; + this->strprm = (char *)NULL; + this->intprm = 0; + this->newstate = (char *)NULL; + + /* + * Pick up new state parameter, if any + */ + if (sc_opdef[i].newstate == SC_NWST) + { + c = strtok((char *)NULL, CTL_DELIM); + if (c == (char *)NULL) + { + logit("Missing new state", opc); + deal_script(first); + return (struct script *)NULL; + } + else + { + this->newstate = (char *)malloc(strlen(c)+1); + strcpy(this->newstate, c); + } + } + + /* + * Pick up the string or integer parameter. Handle missing + * parameter gracefully. + */ + switch (sc_opdef[i].prmtype) + { + /* + * INT parameter - convert and store in node + */ + case SC_INT: + c = strtok((char *)NULL, CTL_DELIM); + if (c == (char *)NULL) + { + logit("Missing script param", opc); + deal_script(first); + return (struct script *)NULL; + } + /* + * If this is the parameter to DBST or DBCL, force + * base-10 conversion, else convert per parameter. + */ + if (sc_opdef[i].opcode == SC_DBST || + sc_opdef[i].opcode == SC_DBCL) + this->intprm = strtol(c, (char **)NULL, 0); + else + this->intprm = strtol(c, (char **)NULL, 10); + break; + + /* + * STR/XSTR strings. + */ + case SC_STR: + case SC_XSTR: + c = strtok((char *)NULL, CTL_DELIM); + if (c == (char *)NULL) + { + logit("Missing script param", opc); + deal_script(first); + return (struct script *)NULL; + } + /* + * For XSTR opcode, use c to find out where + * the string param begins in the copy of the + * input line, and pick up all that's left of + * the line (to allow imbedded blanks, etc.). + */ + if (sc_opdef[i].prmtype == SC_XSTR) + c = &inpcopy[0] + (c - &inpline[0]); + + /* + * Allocate a buffer for the string parameter + */ + this->strprm = (char *)malloc(strlen(c)+1); + + /* + * For XSTR, Translate the string and store its + * length. Note that, after escape sequences are + * compressed, the resulting string may well be a + * few bytes shorter than the input string (whose + * length was the basis for the malloc above), + * but it will never be longer. + */ + if (sc_opdef[i].prmtype == SC_XSTR) + { + this->intprm = xlat_str(this->strprm, c); + this->strprm[this->intprm] = '\0'; + } + else + strcpy(this->strprm, c); + break; + + } + } + + /* + * EOF + */ + return first; +} + + +/* + * xlat_str + * + * Translate embedded escape characters in a "send" or "expect" string. + * + * Called by read_script(), above. + * + * Returns the actual length of the resulting string. Note that imbedded + * nulls (specified by \000 in the input) ARE allowed in the result. + */ +xlat_str(out, in) + char *out, *in; +{ + register int i = 0, j = 0; + int byte, k; + + while (in[i]) + { + if (in[i] != '\\') + { + out[j++] = in[i++]; + } + else + { + switch (in[++i]) + { + case 'd': /* EOT */ + out[j++] = 0x04; + break; + case 'N': /* null */ + out[j++] = 0x00; + break; + case 'n': /* line feed */ + out[j++] = 0x0a; + break; + case 'r': /* carriage return */ + out[j++] = 0x0d; + break; + case 's': /* space */ + out[j++] = ' '; + break; + case 't': /* tab */ + out[j++] = '\t'; + break; + case '-': /* hyphen */ + out[j++] = '-'; + break; + case '\\': /* back slash */ + out[j++] = '\\'; + break; + case '0': /* '\nnn' format */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + byte = in[i] - '0'; + k = 0; + + while (3 > ++k) + if ((in[i+1] < '0') || (in[i+1] > '7')) + break; + else + { + byte = (byte<<3) + in[i+1] - '0'; + ++i; + } + out[j++] = byte; + break; + default: /* don't know so skip it */ + break; + } + ++i; + } + } + return j; +} + + +/* find a state within a script */ + +struct script * + find_state(begin, newstate) +struct script *begin; +char *newstate; +{ + struct script *here; + + for (here=begin; here != (struct script *)NULL; here=here->next) { + if (here->opcode == SC_LABEL && + strcmp(here->strprm, newstate) == SAME) + return here; + } + return (struct script *)NULL; +} + + +/* + * do_script() - execute a script + */ +int do_script(begin) + struct script *begin; +{ + struct script *curstate, *newstate, *curscr; + int dbgsave; + char tempstr[MAX_SCLINE]; + char dfname[256]; + char *c, chr; + int prmlen; + int dbfd; + + time_t sc_carrtime = 45000; /* time to wf carr after dial */ + time_t sc_chrdly = 100; /* delay time for ttoslow */ + time_t sc_ptime = 2000; /* time to allow for pause char */ + time_t sc_wtime = 10000; /* time to allow for wait char */ + time_t sc_dtime = 100; /* time to allow for each digit */ + time_t sc_dtmo; /* total time to dial number */ + int sc_counter; /* random counter */ + char sc_pchar = ','; /* modem pause character */ + char sc_wchar = 'W'; /* modem wait-for-dialtone character */ + time_t sc_begwait; /* time at beg of wait */ + time_t sc_secs; /* timeout period */ + + int expcnt; + int expin; + static char expbuf[MAX_EXPCT]; + + dbgsave = Debug; + curstate = begin; + + if (curstate == (struct script *)NULL) + return SUCCESS; + + _newstate: + /* + * do all of curstate's actions. Enter with curstate pointing + * to a label entry + */ + expin = 0; + + for (curscr = curstate->next; /* point to 1st scr after label */ + (curscr != (struct script *)NULL) && /* do until end of scr */ + (curscr->opcode != SC_LABEL); /* or next label */ + curscr = curscr->next) + { + expcnt = 0; + switch (curscr->opcode) + { + case SC_LABEL: + logit("Script proc err", curstate->strprm); + return FAIL; + + case SC_FLSH: + DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0); + ttflui(); + break; + + case SC_CDLY: + sc_chrdly = curscr->intprm; + DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly); + break; + + case SC_PCHR: + sc_pchar = *(curscr->strprm); + DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar); + break; + + case SC_PTIM: + sc_ptime = curscr->intprm; + DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime); + break; + + case SC_WCHR: + sc_wchar = *(curscr->strprm); + DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar); + break; + + case SC_WTIM: + sc_wtime = curscr->intprm; + DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime); + break; + + case SC_ZERO: + sc_counter = 0; + DEBUG(DB_LGII, "Set counter to %d\n", sc_counter); + break; + + case SC_INCR: + sc_counter++; + DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter); + break; + + case SC_WAIT: + DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm); + msleep(curscr->intprm); + break; + + case SC_DTIM: + sc_dtime = curscr->intprm; + DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime); + break; + + case SC_CTIM: + sc_carrtime = curscr->intprm; + DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime); + break; + + case SC_EXIT: + Debug = dbgsave; + DEBUG(DB_LGI, "Script ended successfully\n", 0); + return SUCCESS; + + case SC_FAIL: + Debug = dbgsave; + if (DEBUG_LEVEL(DB_LGI) && dbf != NULL) + fprintf(dbf, "Script failed\n"); + else if (expin) + charlog(expbuf, expin, DB_LOG, + "Script failed. Last received data"); + return FAIL; + + case SC_LOG: + logit(curscr->strprm, ""); + break; + + case SC_LOGE: + logit("ERROR: ", curscr->strprm); + break; + + case SC_DBOF: + /* + * If the debug file name does not begin with "/", then + * we prepend the LOG_DIR to the string. Then CREATE the + * file. This WIPES OUT previous logs. + */ + *dfname = '\0'; /* Zero name string */ + if(curscr->strprm[0] != '/') + strcat(dfname, LOG_DIR); /* Prepend default directory */ + strcat(dfname, curscr->strprm); /* Add given string */ + DEBUG(DB_LGII, "Open debug file %s\n", dfname); + if ((dbfd = creat (dfname, 0600)) <= 0) + { + logit("Failed to create debug log %s", dfname); + perror(""); + return FAIL; + } + if ((dbf = fdopen(dbfd, "w")) == NULL) + { + logit("Failed to open debug log fildes.", ""); + perror(""); + return FAIL; + } + break; + + case SC_DBG: + DEBUG(DB_LGI, "<%s>\n", curscr->strprm); + break; + + case SC_DBGE: + DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm); + break; + + case SC_DBST: + Debug |= curscr->intprm; + DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); + break; + + case SC_DBCL: + Debug &= ~(curscr->intprm); + DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); + break; + + case SC_BRK: + DEBUG(DB_LGI, "Sending break\n", 0); + ttbreak(); + break; + + case SC_HANG: + DEBUG(DB_LGI, "Dropping DTR\n", 0); + tthang(); + break; + + case SC_7BIT: + DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0); + tt7bit(TRUE); + break; + + case SC_8BIT: + DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0); + tt7bit(FALSE); + break; + + case SC_PNON: + DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0); + ttpar(NONE); + break; + + case SC_PEVN: + DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0); + ttpar(EVEN); + break; + + case SC_PODD: + DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0); + ttpar(ODD); + break; + + case SC_IFBL: + if (ttblind()) + { + DEBUG(DB_LGI, "Blind mux,\n", 0); + goto _chgstate; + } + break; + + case SC_IFBG: + if (ttblind() && sc_counter > curscr->intprm) + { + DEBUG(DB_LGI, "Blind mux & ctr > %d\n", + curscr->intprm); + goto _chgstate; + } + break; + + case SC_IFGT: + if (sc_counter > curscr->intprm) + { + DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm); + goto _chgstate; + } + break; + + case SC_GOTO: + _chgstate: + DEBUG(DB_LGI, "Changing to state %s\n", + curscr->newstate); + curstate = find_state(begin, curscr->newstate); + if (curstate == NULL) + { + logit("New state not found", + curscr->newstate); + return FAIL; + } + goto _newstate; + + case SC_SEND: + ttoslow(curscr->strprm, curscr->intprm, sc_chrdly); + break; + + case SC_TELN: + if (curscr->intprm > paramc - 1) + { + sprintf(tempstr, "telno - param #%d", curscr->intprm); + logit(tempstr, " not present"); + return FAIL; + } + strcpy(telno, paramv[curscr->intprm]); + DEBUG(DB_LGII, "telno set to %s\n", telno); + break; + + case SC_SNDP: + if (curscr->intprm > paramc - 1) + { + sprintf(tempstr, "sendstr - param #%d", curscr->intprm); + logit(tempstr, " not present"); + return FAIL; + } + prmlen = xlat_str(tempstr, paramv[curscr->intprm]); + ttoslow(tempstr, prmlen, sc_chrdly); + break; + + case SC_IF1P: + if (curscr->intprm < paramc) + goto _chgstate; + break; + + case SC_IF0P: + if (curscr->intprm >= paramc) + goto _chgstate; + break; + + case SC_DIAL: + if(telno[0] == '\0') + { + logit("telno not set", ""); + return(FAIL); + } + /* + * Compute and set a default timeout for the 'timeout' + * command. Some parameters in this computation may be + * changed by the script. See the man page xchat(8) for + * details. + */ + sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno) + + sc_carrtime; + c=strcpy(tempstr, telno); + for (; *c!='\0'; c++) + { + if (*c == 'W') + { + *c = sc_wchar; + sc_dtmo += sc_wtime; + } + else if (*c == 'P') + { + *c = sc_pchar; + sc_dtmo += sc_ptime; + } + } + DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo); + ttoslow(tempstr, 0, sc_chrdly); + break; + + case SC_TIMO: /* these are "expects", don't bother */ + case SC_XPCT: /* with them yet, other than noting that */ + case SC_CARR: /* they exist */ + expcnt++; + break; + } + + } + + /* we've done the current state's actions, now do its expects, if any */ + + if (expcnt == 0) + { + if (curscr != (struct script *)NULL && + (curscr->opcode == SC_LABEL)) + { + curstate = curscr; + DEBUG(DB_LGI, "Fell through to state %s\n", + curstate->strprm); + goto _newstate; + } + else + { + logit("No way out of state", curstate->strprm); + return FAIL; + } + } + + time(&sc_begwait); /* log time at beg of expect */ + DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm); + charlog((char *)NULL, 0, DB_LGI, "Received"); + + while (1) + { + chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */ + + charlog(&chr, 1, DB_LGI, (char *)NULL); + + if (chr != EOF) + { + if (expin < MAX_EXPCT) + { + expbuf[expin++] = chr & 0x7f; + } + else + { + strncpy(expbuf, &expbuf[1], MAX_EXPCT-1); + expbuf[MAX_EXPCT-1] = chr & 0x7f; + } + } + + /* for each entry in the current state... */ + + for (curscr = curstate->next; + (curscr != (struct script *)NULL) && + (curscr->opcode != SC_LABEL); + curscr = curscr->next) + { + + switch (curscr->opcode) + { + case SC_TIMO: + sc_secs = curscr->intprm; + if (sc_secs == 0) + sc_secs = sc_dtmo; + sc_secs /= 1000; + if (time(NULL)-sc_begwait > sc_secs) + { + DEBUG(DB_LGI, + "\nTimed out (%d secs)\n", sc_secs); + goto _chgstate; + } + break; + + case SC_CARR: + if (ttcd()) + { + DEBUG(DB_LGI, "\nGot carrier\n", 0); + goto _chgstate; + } + break; + + case SC_HUPS: + if (fShangup) + { + DEBUG(DB_LGI, "\nGot data set hangup\n", 0); + goto _chgstate; + } + break; + + case SC_XPCT: + if ((expin >= curscr->intprm) && + (strncmp(curscr->strprm, + &expbuf[expin - curscr->intprm], + curscr->intprm) == SAME)) + { + charlog(curscr->strprm, curscr->intprm, + DB_LGI, "Matched"); + goto _chgstate; + } + break; + + } + } + } +} + +/* + * SIGNAL HANDLERS + */ + +/* + * usignal - generic signal catcher + */ +static int usignal(isig) + int isig; +{ + DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig); + restore_tty(); + exit(FAIL); +} + +/* + * uhup - HUP catcher + */ +static int uhup(isig) + int isig; +{ + DEBUG(DB_LOG, "Data set hangup.\n"); + fShangup = TRUE; +} + +/* + * TERMINAL I/O ROUTINES + */ + +/* + * xgetc - get a character with timeout + * + * Assumes that stdin is opened on a terminal or TCP socket + * with O_NONBLOCK. + */ +static char xgetc(tmo) +int tmo; /* Timeout, seconds */ +{ + char c; + struct timeval s; + int f = 1; /* Select on stdin */ + int result; + + if(read(0, &c, 1) <= 0) /* If no data available */ + { + s.tv_sec = (long)tmo; + s.tv_usec = 0L; + if(select (1, &f, (int *) NULL, &f, &s) == 1) + read(0, &c, 1); + else + c = '\377'; + } + + return(c); +} + +/* + * Pause for an interval in milliseconds + */ +void msleep(msec) +long msec; +{ + +#if HAVE_USLEEP + if(msec == 0) /* Skip all of this if delay = 0 */ + return; + usleep (msec * (long)1000); +#endif /* HAVE_USLEEP */ + +#if HAVE_NAPMS + if(msec == 0) /* Skip all of this if delay = 0 */ + return; + napms (msec); +#endif /* HAVE_NAPMS */ + +#if HAVE_NAP + if(msec == 0) /* Skip all of this if delay = 0 */ + return; + nap (msec); +#endif /* HAVE_NAP */ + +#if HAVE_POLL + struct pollfd sdummy; + + if(msec == 0) + return; + /* + * We need to pass an unused pollfd structure because poll checks + * the address before checking the number of elements. + */ + poll (&sdummy, 0, msec); +#endif /* HAVE_POLL */ + +#if USE_SELECT_TIMER + struct timeval s; + + if(msec == 0) + return; + s.tv_sec = msec / 1000L; + s.tv_usec = (msec % 1000L) * 1000L; + select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s); +#endif /* USE_SELECT_TIMER */ + +#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \ + ! HAVE_POLL && ! USE_SELECT_TIMER + if(msec == 0) + return; + sleep (1); /* Sleep for a whole second (UGH!) */ +#endif /* HAVE_ and USE_ nothing */ +} + +/* + * Debugging output + */ +static void DEBUG(level, msg1, msg2) +int level; +char *msg1, *msg2; +{ + if ((dbf != NULL) && DEBUG_LEVEL(level)) + fprintf(dbf, msg1, msg2); +} + +/* + * charlog - log a string of characters + * + * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged + * when read does its 1 sec. timeout. Log "<1 sec.>" + * so user can see elapsed time + */ +static void charlog(buf, len, mask, msg) +char *buf; +int len, mask; +char *msg; +{ + char tbuf[256]; + + if (DEBUG_LEVEL(mask) && dbf != NULL) + { + if(msg == (char *)NULL) + msg = ""; + strncpy(tbuf, buf, len); + tbuf[len] = '\0'; + if(len == 1 && tbuf[0] == '\377') + strcpy(tbuf, "<1 sec.>"); + fprintf(dbf, "%s %s\n", msg, tbuf); + } +} + +/* + * setup_tty() + * + * Save current tty settings, then set up raw, single + * character input processing, with 7-bit stripping. + */ +static void setup_tty() +{ + register int i; + + ioctl(0, TCGETA, &old); + + new = old; + + for(i = 0; i < 7; i++) + new.c_cc[i] = '\0'; + new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */ + new.c_cc[VTIME] = 10; /* TIME = 1 sec. */ + new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */ + new.c_lflag = 0; /* No special line discipline */ + + ioctl(0, TCSETA, &new); +} + +/* + * restore_tty() - restore signal handlers and tty modes on exit. + */ +static void restore_tty(sig) +int sig; +{ + ioctl(0, TCSETA, &old); + return; +} + +/* + * ttoslow() - Send characters with pacing delays + */ +static void ttoslow(s, len, delay) + char *s; + int len; + time_t delay; +{ + int i; + + if (len == 0) + len = strlen(s); + + charlog (s, len, DB_LGI, "Sending slowly"); + + for (i = 0; i < len; i++, s++) + { + write(1, s, 1); + msleep(delay); + } +} + +/* + * ttflui - flush input buffer + */ +static void ttflui() +{ + if(isatty(0)) + (void) ioctl ( 0, TCFLSH, 0); +} + +/* + * ttcd - Test if carrier is present + * + * NOT IMPLEMENTED. I don't know how!!! + */ +static int ttcd() +{ + return TRUE; +} + +/* + * tthang - Force DTR low for 1-2 sec. + */ +static void tthang() +{ + if(!isatty()) + return; + +#ifdef TCCLRDTR + (void) ioctl (1, TCCLRDTR, 0); + sleep (2); + (void) ioctl (1, TCSETDTR, 0); +#endif + + return; +} + +/* + * ttbreak - Send a "break" on the line + */ +static void ttbreak() +{ + (void) ioctl (1, TCSBRK, 0); +} + +/* + * ttblind - return TRUE if tty is "blind" + * + * NOT IMPLEMENTED - Don't know how!!! + */ +static int ttblind() +{ + return FALSE; +} + +/* + * tt7bit - enable/disable 7-bit stripping on line + */ +static void tt7bit(enable) + int enable; +{ + if(enable) + new.c_iflag |= ISTRIP; + else + new.c_iflag &= ~ISTRIP; + + ioctl(0, TCSETA, &new); +} + +/* + * ttpar - Set parity mode on line. Ignore parity errors on input. + */ +static void ttpar(mode) + int mode; +{ + switch(mode) + { + case NONE: + new.c_iflag &= ~(INPCK | IGNPAR); + new.c_cflag &= ~(CSIZE | PARENB | PARODD); + new.c_cflag |= CS8; + break; + + case EVEN: + new.c_iflag |= (INPCK | IGNPAR); + new.c_cflag &= ~(CSIZE | PARODD); + new.c_cflag |= (CS7 | PARENB); + + break; + + case ODD: + new.c_iflag |= (INPCK | IGNPAR); + new.c_cflag &= ~(CSIZE); + new.c_cflag |= (CS7 | PARENB | PARODD); + break; + } + + ioctl(0, TCSETA, &new); +} + + + + + + + diff --git a/gnu/libexec/uucp/contrib/xchat.man b/gnu/libexec/uucp/contrib/xchat.man new file mode 100644 index 00000000000..c980e202fcb --- /dev/null +++ b/gnu/libexec/uucp/contrib/xchat.man @@ -0,0 +1,614 @@ +.TH xchat 8 +.SH NAME +xchat - Extended chat processor +.SH SYNOPSIS +.BI "xchat " "scriptfile" +.RI " [ " parameter... " ] " +.PP +where +.I scriptfile +is the name of a file containing an +.I xchat +script. If +.I scriptfile +begins with ``/'', then it is assumed to be a full path name for the +script file. If not, a configuration-dependent default directory path +(usually +.B "/usr/local/conf/uucp/" +) is prepended to the script file name. Normally, the default path +is the same as that for the Taylor UUCP configuration files. +.SH DESCRIPTION +.I Xchat +is a general-purpose dialing and login program designed for use +with Taylor UUCP as a ``chat-program'', taking the place (or +augmenting) the built-in chat scripting facility. It provides the +ability to closely control timeouts, multiple simultaneous ``expect'' +strings with separate actions, extended terminal control, modem +command character pacing, and more. +.PP +When used in conjunction with Taylor UUCP's +configuration features, +.I xchat +can provide you the ability to manage the most intricate login, +dial and hangup needs. The scripts are written in a shell-like (well, +sort-of) style with labels, commands, and parameters, easing the task +of writing procedures for complex terminal communications situations. +.PP +Because +.I xchat +assumes that it is connected to the terminal device via stdin/stdout, +you can easily debug scripts by invoking it from the shell and +responding to the script from the keyboard. A debug logging facility +is included, with the debug output going to a separate user-specified +file. This makes it easy to debug connection problems without wading +through large +.I uucico +log and debug files. +.PP +Formally, a script describes a state machine; +.I xchat +interprets the script and does what the state machine +tells it to. This section will be much easier to understand +if you obtain listings of the script files supplied with +.I xchat. +.SH "SCRIPT FILE FORMAT" +Script files are ordinary text files containing comments, labels, +and statements. Blank lines are ignored. +Comments are denoted by leading ``#'' +characters. Some statements (those which do not end with an +``extended string'' argument; see below) can also have trailing +comments. +.PP +.I Labels +begin in column one and are ended by colons (:). A label +specifies a state name. All lines between a pair of labels are +the statements for a single state. +.PP +Processing always begins at the head of the script (no leading +state name is necessary). +.PP +.I Statements +are divided into two categories, ``action'' and ``expect''. +When a state is entered, all of its actions are performed in the +order in which they appear in the file. +.PP +A +.I transition +to another state may occur for any of three reasons: +.IP (1) 5 +One of the actions may cause a transition to +another state, in which case the rest of the +current state's actions are skipped. +Processing resumes with the first action +statement of the new state. +.IP (2) 5 +If none of the actions cause a state +transition, and there are no expects in the +state, processing ``falls through'' to the next +state in the file. +.IP (3) 5 +If none of the actions cause a state +transition, but there are expects in the +state, the state machine pauses until one of +the expects is ``satisfied''. It then transitions +to the state named in the expect +statement. +.PP +Finally, there are two action statements which, when executed, +cause the script to exit. +.SH "SCRIPT FILE STATEMENTS" +This section describes all of the statements that may appear in script +files, except for a few special action statements. Those are described +in a later section, ``Overriding Defaults''. +.PP +Some statements accept one or two arguments, referred to in the +following descriptions as +.IR int ", " ns ", " str ", or " +.IR xstr ", to" +indicate whether the argument is an integer, a new state name, a +string, or an ``extended string'' (described in a later section). +.PP +For all statements that accept two arguments, the first is the +name of a new state, and the second specifies a condition or +reason for changing to the new state. +.SS "Termination And Informational Statements" +These statements are used to place entries into the Taylor UUCP +.I Log +file, and to cause +.I xchat +to exit with successful or failure status. It is also possible to open a +separate +.I debug +log file and control the level of tracing and error reporting that will go +into that log file. This is very useful in debugging +.I xchat +scripts. +.br +.ta 1.0i 1.5i 2.0i +.TP 2.0i +.B failed +Exit script with ``failed'' status. This causes +.I xchat +to exit with status 0. +.TP 2.0i +.B success +Exit script with ``success'' status. This causes +.I xchat +to exit with status 1. +.TP 2.0i +.BI "log " xstr +Send informational message +.I xstr +to standard error. When used with Taylor UUCP, this is the +.I Log +file for the +.I uucico +program. +.TP 2.0i +.BI "logerr " xstr +Send message +.I xstr +to standard error, with ``ERROR:'' indicator. When used +with Taylor UUCP, this is the +.I Log +file for the +.I uucico +program. +.TP 2.0i +.BI "dbgfile " xstr +Open script debugging file +.I xstr. +If +.I xstr +begins with ``/'', it is assumed to be an absolute path name for the +debugging file. If not, then a configuration-dependent default directory +path (usually +.B "/usr/spool/uucp" +) is prepended to +.I xstr. +Normally the default path is that of the directory where Taylor UUCP +puts its log files. +The debugging file is used to capture a detailed log of the data sent +and received, errors encountered, and a trace of script execution. +The various types of logging are controlled by the +.I "debug mask," +described next. +.B Note: +A new log file is created each time +.I xchat +runs. Use the +.B log +and +.B loge +commands to log +continuous information onto standard out, which is connected +to the Taylor UUCP +.I Log +file when +.I xchat +is run by the Taylor +.I uucico. +.TP 2.0i +.BI "dbgset " int +Set the bits specified in +.I int +in the debugging mask. The value in +.I int +is ``or''ed into the mask. Set bit 0 (value \= 1) for error messages, +bit 1 (value \= 2) for dial, login and init errors, bit 2 (value \= 4) +for dial, login and init trace with character I/O, and bit 3 (value \= 8) +for script processing internals. Normally, you will just turn it all on +with a value of 15. +.TP 2.0i +.BI "dbgclr " int +Clear the bits specified in +.I int +from the debugging mask. +.TP 2.0i +.BI "debug " xstr +Write +.I +xstr +into the debug log. The entry will be enclosed in angle brackets. +.TP 2.0i +.BI "debuge " xstr +Write +.I xstr +into the debug log with ``ERROR: '' prepended. The entry will be enclosed +in angle brackets. +.SS "Sending Data" +These statements are used to transmit data to standard out (the tty or TCP +port when used with Taylor UUCP). +.I +No implied carriage returns are sent. +You must include a \\r if you want a carriage return in the string +sent by the +.B send +command. If you want a return sent after +.B dial +or +.B sendstr, +you must send it with a separate +.B send +command. +.TP 2.0i +.B dial +Send the string previously set by the +.B telno +command to the serial port. +.B W +and +.B P +characters in the phone number are +converted as described under +.B +Dial Strings, +below. This statement also sets a default +timeout value, as described under the +.B timeout +statement. +.TP 2.0i +.BI "send " xstr +Send the string +.I xstr +to the serial port. +.TP 2.0i +.BI "sendstr " int +The argument of this statement is a digit from 0 +through 7. Send the corresponding string +parameter as passed to +.I xchat +following the script file name. The parameter is interpreted +as an extended string. +.SS "Special Terminal Control Statements" +These statements are used to cause the terminal port to perform some special action, or to change the mode of the port. +.I +The modes of the port are restored to their original settings +.I +by xchat before it exits. +.TP 2.0i +.B flush +Flush the terminal port's input buffer. +.TP 2.0i +.B break +Send a break signal. +.TP 2.0i +.B hangup +Momentarily drop Data Terminal Ready (DTR) on the +serial port, causing the modem to hang up. (Not +usually needed, since +.I uucico +does this at the end of each call.) +.TP 2.0i +.B 7bit +Change the port to strip incoming characters to 7 bits. +.I +This is the default mode. +This mode +is implied when the port has parity enabled, since parity characters +are 7-bits wide. +.TP 2.0i +.B 8bit +Change the port to allow incoming 8-bit characters to be passed +to the script processor. This mode has no effect if parity is +enabled, since parity characters are 7-bits wide. +.TP 2.0i +.B nopar +Change the port to 8-bits, no parity. +.I +This is the default mode. +.TP 2.0i +.B evenpar +Change the port to 7-bits, even parity. +.I +Incoming characters with parity errors are discarded. +.TP 2.0i +.B oddpar +Change the port to 7-bits, odd parity. +.I +Incoming characters with parity errors are discarded. +.SS "Counting, Branching, Timing and Testing Statements" +These statements are used to control the flow of the +.I xchat +script itself, including branching, delays, and counter manipulation. +.TP 2.0i +.BI "sleep " int +Delay for +.I int +milliseconds. +.TP 2.0i +.B zero +Clear the counter. +.TP 2.0i +.B count +Add one to the counter. +.TP 2.0i +.BI "ifgtr " "ns int" +Go to state +.I ns +if counter greater than +.I int. +.TP 2.0i +.BI "goto " ns +Go to state +.I ns +unconditionally. +.TP 2.0i +.BI "ifstr " "ns int" +Go to state +.I ns +if string parameter +.I int +is nonempty. +.TP 2.0i +.BI "ifnstr " "ns int" +Go to state +.I ns +if string parameter +.I int +is empty. +.TP 2.0i +.BI "ifblind " ns +Change to state +.I ns +if the port is ``blind'' without carrier (CD) asserted. +.I +This is not yet implemented, the test always fails. +.TP 2.0i +.BI "ifblgtr " "ns int" +Change to state +.I ns +if the port is ``blind'' without carrier (CD) asserted, and counter +is greater then +.I int. +.I +This is not yet implemented, the test always fails. +.SS "Expect Statements" +Expect statements are usually the last statements that appear in a +given state, though in fact they can appear anywhere within the +state. Even if they appear at the beginning, the script processor +always does all of the action statements first. As a practical +matter, the order of these statements is not significant; they are +all interpreted ``in parallel''. +.TP 2.0i +.BI "expect " "ns xstr" +Change to state +.I ns +if the string specified by +.I xstr +is received from standard input (usually the serial port). +Case is significant, but high-order bits are not +checked. +.TP 2.0i +.BI "ifcarr " ns +Change to state +.I ns +if Carrier Detect (CD) is true. +.I +Not currently implemented. Always changes state. +.TP 2.0i +.BI "ifhang " ns +Change to state +.I ns +if a data set hangup occurs (SIGHUP signal received). +.TP 2.0i +.BI "timeout " "ns int" +Change to state +.I ns +if the time (in milliseconds) +given by +.I int +has elapsed without satisfying any +expects. If the time specified is 0, a default +timeout value (calculated from the length and +other characteristics of the most recent dial +string) is used. +.SH "SCRIPT PROCESSING DETAILS" +.SS "Extended Strings" +In the statements that accept string arguments, the strings are +interpreted as +.I +extended strings. +Extended strings begin with +the first nonblank character and continue, including all imbedded +and trailing blanks and other whitespace, until (but not +including) the end of the line in the script file. (There is no +provision for line continuation.) No trailing spaces should be +present between the last ``desired'' character of the string and the +end of the line, as they will be included in the stored string and +sent or expected, just as they appear in the script file. And, +obviously, no trailing comments are permitted! They will just be +stored as part of the string. +.PP +Within an extended string, the following ``escape sequences'' will +be converted as indicated before being sent or expected: +.br +.nf +.in +0.5i +\fB\\d\fR EOT character (control-D) +\fB\\N\fR null character +\fB\\n\fR line feed +\fB\\r\fR carriage return +\fB\\s\fR space +\fB\\t\fR tab +\fB\\\-\fR hyphen +\fB\\\\\fR backslash +\fB\\ooo\fR character with value ooo (in octal) +.in -0.5i +.fi +.PP +Since extended strings in scripts can include embedded spaces, +tabs, etc., these escape sequences are only required in strings +appearing in systems entries, though they may be used in script +files to improve readability. +.PP +The octal-character specification (\\ooo) may have from one to +three octal digits; it is terminated either after the third digit +or when a non-octal character is encountered. But if you want to +specify one of these followed by something that happens to be a +valid octal character (for example, a control-A followed by a 7) +make sure to include all three digits after the \\ . So \\0017 +would become a control-A followed by the Ascii character ``7'', but +\\17 or \\017 would become a control-Y (decimal value 25). \\1S +would convert to a control-A followed by an ``S''. +.PP +Extended strings are stored without a trailing carriage return +unless one is explicitly present in the string (via \\r). +.SS "String Parameters" +The +.B sendstr +statement sends (after conversion from extended string +format) one of the parameters given on the +.I xchat +command line following the script file name. +The parameter is selected by the integer +argument of the statement. +.PP +This allows ``generic'' script files to serve +for many different systems; the string parameters +provide the phone number, username, password, etc. Character +substitutions described under ``extended strings'' above are +performed on these strings. +.PP +The ifstr and ifnstr statements allow further generality in script +files, by testing whether a particular parameter is present in the +systems entry. For example, a single script can be +used both for those systems that require a password and +those that do not. The password is specified as the last argument +in the +.xchat +command; the script can test for this +parameter's existence and skip the password sequence if +the parameter is empty. +.SS "``Wait'' And ``Pause'' Characters In Dial Strings" +An additional conversion is performed on dial strings. Dial strings +are interpreted as extended strings. Then the characters +.B W +and +.B P +within a dial string are interpreted as ``wait for dial +tone'' and ``pause'', and may be converted to other characters. By +default, +.B W +is left alone, and +.B P +is converted to a comma (,); +these are appropriate for Hayes-type modems. The script may +specify other substitutions (see below). +.PP +.B NOTE: +The Taylor UUCP documentation states that the ``wait'' and ``pause'' +characters are ``='' and ``-'', respectively. These are actual characters +understood by some modems. When using +.I xchat +you should put +.B W +and +.B P +in the dial strings you specify in the Taylor configuration files. +This way, the +.I xchat +processor can make the substitution appropriate for the particular +modem in use. Make a separate +.I xchat +script for each modem type, e.g., +.I "dial.hayes" +and specify the translation there. This way, the phone number strings +in the Taylor configuration files can be used with a variety of modems. +.SS "Default Timeouts For Dial Strings" +When a +.B dial +statement is executed, a default timeout value is set. +This is the timeout value used by a subsequent timeout statement +if the statement specifies a timeout value of 0. +.PP +The default timeout is given by: +.br +.nf +.in +2 +\fIctime\fR + (\fIndigits\fR * \fIdgttime\fR) + (\fInwchar\fR * \fIwtime\fR) + (\fInpchar\fR * \fI ptime\fR) +.in -2 +.fi +.PP +where +.I +ndigits, nwchar, +and +.I npchar +are the number of digits, wait characters, and pause characters in +the dial string, and +.I ctime, dgttime, wtime, +and +.I ptime +are 45 seconds, 0.1 seconds, 10 seconds, and 2 seconds, +respectively. +All of these times may be changed as specified below under +``Overriding Defaults.'' +.SS "Trailing Carriage Returns Not Assumed" +In the +.B dial +and +.B sendstr +statements, the dial string or +parameter is sent with no trailing carriage return; +if a carriage return must be sent after one of these, a separate +send statement must provide it. +.SH "OVERRIDING DEFAULTS" +The script processor sets several default values. The following +statements, which override these defaults, may be useful in +certain circumstances. +.TP 2.0i +.BI "chrdly " int +Since many modems cannot accept dialing commands +at full ``computer speed'', the script processor +sends all strings with a brief inter-character +delay. This statement specifies the delay time, +in milliseconds. The default is 100 (0.1 second). +.TP 2.0i +.BI "pchar " str +Specifies the character to which +.BR P s +in the +dial string should be converted. Default is +``,'', for use with Hayes-type modems. +.TP 2.0i +.BI "ptime " int +Specifies the time, in milliseconds, to allow in +the default timeout for each pause character in +the dial string. Default is 2000 (2 seconds). +.TP 2.0i +.BI "wchar " str +Specifies the character to which +.BR W s +in the +dial string should be converted. Default is +``W'', for Hayes modems. +.TP 2.0i +.BI "wtime " int +Specifies the time, in milliseconds, to allow in +the default timeout for each wait-for-dialtone +character in the dial string. Default is 10000 +(10 seconds). +.TP 2.0i +.BI "dgttime " int +Specifies the time, in milliseconds, to allow in +the default timeout for each digit character in +the dial string. Default is 100 (0.1 second). +.TP 2.0i +.BI "ctime " int +Specifies the time, in milliseconds, to allow in +the default timeout for carrier to appear after +the dial string is sent. Default is 45000 (45 +seconds). +.SH "SEE ALSO" +uucico(8) for Taylor UUCP, and documentation for Taylor UUCP. +.SH AUTHOR +Robert B. Denny (denny@alisa.com) +.SH HISTORY +This program is an adaptation of the dial/login script processing +code that is a part of DECUS UUCP for VAX/VMS, written by Jamie +Hanrahan, et. al. +.SH BUGS +This version (1.1) does not support BSD terminal facilities. Anyone +volunteer to add this? + diff --git a/gnu/libexec/uucp/cu/Makefile b/gnu/libexec/uucp/cu/Makefile new file mode 100644 index 00000000000..be03d0ba8e4 --- /dev/null +++ b/gnu/libexec/uucp/cu/Makefile @@ -0,0 +1,15 @@ +# Makefile for cu + +BINDIR= $(bindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= cu +SRCS= cu.c prot.c log.c chat.c conn.c tcp.c tli.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +.include <bsd.prog.mk> +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/cu/cu.1 b/gnu/libexec/uucp/cu/cu.1 new file mode 100644 index 00000000000..56409a00427 --- /dev/null +++ b/gnu/libexec/uucp/cu/cu.1 @@ -0,0 +1,286 @@ +''' $Id: cu.1,v 1.1 1993/08/04 19:31:53 jtc Exp $ +.TH cu 1 "Taylor UUCP 1.04" +.SH NAME +cu \- Call up another system +.SH SYNOPSIS +.B cu +[ options ] [ system | phone | "dir" ] +.SH DESCRIPTION +The +.I cu +command is used to call up another system and act as a dial in +terminal. It can also do simple file transfers with no error +checking. + +.I cu +takes a single argument, besides the options. If the argument is the +string "dir" cu will make a direct connection to the port. This may +only be used by users with write access to the port, as it permits +reprogramming the modem. + +Otherwise, if the argument begins with a digit, it is taken to be a +phone number to call. Otherwise, it is taken to be the name of a +system to call. The +.B \-z +option may be used to name a system beginning with a digit, and the +.B \-c +option may be used to name a phone number that does not begin with a +digit. + +.I cu +locates a port to use in the UUCP configuration files. If a simple +system name is given, it will select a port appropriate for that +system. The +.B \-p, \-l +and +.B \-s +options may be used to control the port selection. + +When a connection is made to the remote system, +.I cu +forks into two processes. One reads from the port and writes to the +terminal, while the other reads from the terminal and writes to the +port. + +.I cu +provides several commands that may be used during the conversation. +The commands all begin with an escape character, initially +.B ~ +(tilde). The escape character is only recognized at the beginning of +a line. To send an escape character to the remote system at the start +of a line, it must be entered twice. All commands are either a single +character or a word beginning with +.B % +(percent sign). + +.I cu +recognizes the following commands: + +.TP 5 +.B ~. +Terminate the conversation. +.TP 5 +.B ~! command +Run command in a shell. If command is empty, starts up a shell. +.TP 5 +.B ~$ command +Run command, sending the standard output to the remote system. +.TP 5 +.B ~| command +Run command, taking the standard input from the remote system. +.TP 5 +.B ~+ command +Run command, taking the standard input from the remote system and +sending the standard output to the remote system. +.TP 5 +.B ~#, ~%break +Send a break signal, if possible. +.TP 5 +.B ~c directory, ~%cd directory +Change the local directory. +.TP 5 +.B ~> file +Send a file to the remote system. This just dumps the file over the +communication line. It is assumed that the remote system is expecting +it. +.TP 5 +.B ~< +Receive a file from the remote system. This prompts for the local +file name and for the remote command to execute to begin the file +transfer. It continues accepting data until the contents of the +.B eofread +variable are seen. +.TP 5 +.B ~p from to, ~%put from to +Send a file to a remote Unix system. This runs the appropriate +commands on the remote system. +.TP 5 +.B ~t from to, ~%take from to +Retrieve a file from a remote Unix system. This runs the appropriate +commands on the remote system. +.TP 5 +.B ~s variable value +Set a +.I cu +variable to the given value. If value is not given, the variable is +set to +.B true. +.TP 5 +.B ~! variable +Set a +.I cu +variable to +.B false. +.TP 5 +.B ~z +Suspend the cu session. This is only supported on some systems. On +systems for which ^Z may be used to suspend a job, +.B ~^Z +will also suspend the session. +.TP 5 +.B ~%nostop +Turn off XON/XOFF handling. +.TP 5 +.B ~%stop +Turn on XON/XOFF handling. +.TP 5 +.B ~v +List all the variables and their values. +.TP 5 +.B ~? +List all commands. + +.I cu +also supports several variables. They may be listed with the +.B ~v +command, and set with the +.B ~s +or +.B ~! +commands. + +.TP 5 +.B escape +The escape character. Initially +.B ~ +(tilde). +.TP 5 +.B delay +If this variable is true, +.I cu +will delay for a second after recognizing the escape character before +printing the name of the local system. The default is true. +.TP 5 +.B eol +The list of characters which are considered to finish a line. The +escape character is only recognized after one of these is seen. The +default is carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R. +.TP 5 +.B binary +Whether to transfer binary data when sending a file. If this is +false, then newlines in the file being sent are converted to carriage +returns. The default is false. +.TP 5 +.B binary-prefix +A string used before sending a binary character in a file transfer, if +the +.B binary +variable is true. The default is ^Z. +.TP 5 +.B echo-check +Whether to check file transfers by examining what the remote system +echoes back. This probably doesn't work very well. The default is +false. +.TP 5 +.B echonl +The character to look for after sending each line in a file. The +default is carriage return. +.TP 5 +.B timeout +The timeout to use, in seconds, when looking for a character, either +when doing echo checking or when looking for the +.B echonl +character. The default is 30. +.TP 5 +.B kill +The character to use delete a line if the echo check fails. The +default is ^U. +.TP 5 +.B resend +The number of times to resend a line if the echo check continues to +fail. The default is 10. +.TP 5 +.B eofwrite +The string to write after sending a file with the +.B ~> +command. The default is ^D. +.TP 5 +.B eofread +The string to look for when receiving a file with the +.B ~< +command. The default is $, which is intended to be a typical shell +prompt. +.TP 5 +.B verbose +Whether to print accumulated information during a file transfer. The +default is true. +.SH OPTIONS +The following options may be given to +.I cu. +.TP 5 +.B \-e +Use even parity. +.TP 5 +.B \-o +Use odd parity. If both +.B \-e +and +.B \-o +are used, no parity is used. Otherwise the default parity of the line +is used. +.TP 5 +.B \-h +Echo characters locally (half-duplex mode). +.TP 5 +.B \-z system +The system to call. +.TP 5 +.B \-c phone-number +The phone number to call. +.TP 5 +.B \-p port +Name the port to use. +.TP 5 +.B \-a port +Equivalent to +.B \-p port. +.TP 5 +.B \-l line +Name the line to use by giving a device name. This may be used to +dial out on ports that are not listed in the UUCP configuration files. +Write access to the device is required. +.TP 5 +.B \-s speed +The speed (baud rate) to use. +.TP 5 +.B \-# +Where # is a number, equivalent to +.B \-s #. +.TP 5 +.B \-n +Prompt for the phone number to use. +.TP 5 +.B \-d +Enter debugging mode. Equivalent to +.B \-x all. +.TP 5 +.B \-x type +Turn on particular debugging types. The following types are +recognized: abnormal, chat, handshake, uucp-proto, proto, port, +config, spooldir, execute, incoming, outgoing. Only abnormal, chat, +handshake, port, config, incoming and outgoing are meaningful for +.I cu. + +Multiple types may be given, separated by commas, and the +.B \-x +option may appear multiple times. A number may also be given, which +will turn on that many types from the foregoing list; for example, +.B \-x 2 +is equivalent to +.B \-x abnormal,chat. +.B \-x all +may be used to turn on all debugging options. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I cu +was compiled. +.SH BUGS +This program does not work very well. +.SH FILES +The file name may be changed at compilation time, so this is only an +approximation. + +.br +/usr/lib/uucp/config - Configuration file. diff --git a/gnu/libexec/uucp/cu/cu.c b/gnu/libexec/uucp/cu/cu.c new file mode 100644 index 00000000000..72d60a62ecc --- /dev/null +++ b/gnu/libexec/uucp/cu/cu.c @@ -0,0 +1,2068 @@ +/* cu.c + Call up a remote system. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char cu_rcsid[] = "$Id: cu.c,v 1.1 1993/08/04 19:31:54 jtc Exp $"; +#endif + +#include "cu.h" +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "prot.h" +#include "system.h" +#include "sysdep.h" +#include "getopt.h" + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> + +/* Here are the user settable variables. The user is permitted to + change these while running the program, using ~s. */ + +/* The escape character used to introduce a special command. The + escape character is the first character of this string. */ +const char *zCuvar_escape = "~"; + +/* Whether to delay for a second before printing the host name after + seeing an escape character. */ +boolean fCuvar_delay = TRUE; + +/* The input characters which finish a line. The escape character is + only recognized following one of these characters. The default is + carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the + Ultrix /etc/remote file. */ +const char *zCuvar_eol = "\r\025\003\017\004\023\021\022"; + +/* Whether to transfer binary data (nonprintable characters other than + newline and tab) when sending a file. If this is FALSE, then + newline is changed to carriage return. */ +boolean fCuvar_binary = FALSE; + +/* A prefix string to use before sending a binary character from a + file; this is only used if fCuvar_binary is TRUE. The default is + ^Z. */ +const char *zCuvar_binary_prefix = "\026"; + +/* Whether to check for echoes of characters sent when sending a file. + This is ignored if fCuvar_binary is TRUE. */ +boolean fCuvar_echocheck = FALSE; + +/* A character to look for after each newline is sent when sending a + file. The character is the first character in this string, except + that a '\0' means that no echo check is done. */ +const char *zCuvar_echonl = "\r"; + +/* The timeout to use when looking for an character. */ +int cCuvar_timeout = 30; + +/* The character to use to kill a line if an echo check fails. The + first character in this string is sent. The default is ^U. */ +const char *zCuvar_kill = "\025"; + +/* The number of times to try resending a line if the echo check keeps + failing. */ +int cCuvar_resend = 10; + +/* The string to send at the end of a file sent with ~>. The default + is ^D. */ +const char *zCuvar_eofwrite = "\004"; + +/* The string to look for to finish a file received with ~<. For tip + this is a collection of single characters, but I don't want to do + that because it means that there are characters which cannot be + received. The default is a guess at a typical shell prompt. */ +const char *zCuvar_eofread = "$"; + +/* Whether to provide verbose information when sending or receiving a + file. */ +boolean fCuvar_verbose = TRUE; + +/* The table used to give a value to a variable, and to print all the + variable values. */ + +static const struct uuconf_cmdtab asCuvars[] = +{ + { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL }, + { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL }, + { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL }, + { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL }, + { "binary-prefix", UUCONF_CMDTABTYPE_STRING, + (pointer) &zCuvar_binary_prefix, NULL }, + { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN, + (pointer) &fCuvar_echocheck, NULL }, + { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL }, + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL }, + { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL }, + { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL }, + { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL }, + { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL }, + { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL }, + { NULL, 0, NULL, NULL} +}; + +/* The program name. */ +char abProgram[] = "cu"; + +/* The string printed at the initial connect. */ +#if ANSI_C +#define ZCONNMSG "\aConnected." +#else +#define ZCONNMSG "Connected." +#endif + +/* The string printed when disconnecting. */ +#if ANSI_C +#define ZDISMSG "\aDisconnected." +#else +#define ZDISMSG "Disconnected." +#endif + +/* Local variables. */ + +/* The string we print when the user is once again connected to the + port after transferring a file or taking some other action. */ +static const char abCuconnected[] +#if ANSI_C + = "\a[connected]"; +#else + = "[connected]"; +#endif + +/* Global uuconf pointer. */ +static pointer pCuuuconf; + +/* Connection. */ +static struct sconnection *qCuconn; + +/* Whether to close the connection. */ +static boolean fCuclose_conn; + +/* Dialer used to dial out. */ +static struct uuconf_dialer *qCudialer; + +/* Whether we need to restore the terminal. */ +static boolean fCurestore_terminal; + +/* Whether we are doing local echoing. */ +static boolean fCulocalecho; + +/* Whether we need to call fsysdep_cu_finish. */ +static boolean fCustarted; + +/* A structure used to pass information to icuport_lock. */ +struct sconninfo +{ + boolean fmatched; + boolean flocked; + struct sconnection *qconn; + const char *zline; +}; + +/* Local functions. */ + +static void ucuusage P((void)); +static void ucuabort P((void)); +static void uculog_start P((void)); +static void uculog_end P((void)); +static int icuport_lock P((struct uuconf_port *qport, pointer pinfo)); +static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn, + int bcmd)); +static boolean fcuset_var P((pointer puuconf, char *zline)); +static int icuunrecogvar P((pointer puuconf, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int icuunrecogfn P((pointer puuconf, int argc, char **argv, + pointer pvar, pointer pinfo)); +static void uculist_vars P((void)); +static void uculist_fns P((const char *zescape)); +static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn, + char *zline)); +static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf, + size_t cbuf)); + +#define ucuputs(zline) \ + do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0) + +/* Long getopt options. */ +static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -c: phone number. */ + char *zphone = NULL; + /* -e: even parity. */ + boolean feven = FALSE; + /* -l: line. */ + char *zline = NULL; + /* -n: prompt for phone number. */ + boolean fprompt = FALSE; + /* -o: odd parity. */ + boolean fodd = FALSE; + /* -p: port name. */ + const char *zport = NULL; + /* -s: speed. */ + long ibaud = 0L; + /* -t: map cr to crlf. */ + boolean fmapcr = FALSE; + /* -z: system. */ + const char *zsystem = NULL; + /* -I: configuration file name. */ + const char *zconfig = NULL; + int iopt; + pointer puuconf; + int iuuconf; + const char *zlocalname; + int i; + struct uuconf_system ssys; + const struct uuconf_system *qsys = NULL; + boolean flooped; + struct uuconf_port sport; + struct sconnection sconn; + struct sconninfo sinfo; + long ihighbaud; + struct uuconf_dialer sdialer; + struct uuconf_dialer *qdialer; + char bcmd; + + /* We want to accept -# as a speed. It's easiest to look through + the arguments, replace -# with -s#, and let getopt handle it. */ + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-' + && isdigit (BUCHAR (argv[i][1]))) + { + size_t clen; + char *z; + + clen = strlen (argv[i]); + z = zbufalc (clen + 2); + z[0] = '-'; + z[1] = 's'; + memcpy (z + 2, argv[i] + 1, clen); + argv[i] = z; + } + } + + while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:", + asCulongopts, (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'c': + /* Phone number. */ + zphone = optarg; + break; + + case 'd': + /* Set debugging level to maximum. */ +#if DEBUG > 1 + iDebug = DEBUG_MAX; +#endif + break; + + case 'e': + /* Even parity. */ + feven = TRUE; + break; + + case 'h': + /* Local echo. */ + fCulocalecho = TRUE; + break; + + case 'n': + /* Prompt for phone number. */ + fprompt = TRUE; + break; + + case 'l': + /* Line name. */ + zline = optarg; + break; + + case 'o': + /* Odd parity. */ + fodd = TRUE; + break; + + case 'p': + case 'a': + /* Port name (-a is for compatibility). */ + zport = optarg; + break; + + case 's': + /* Speed. */ + ibaud = strtol (optarg, (char **) NULL, 10); + break; + + case 't': + /* Map cr to crlf. */ + fmapcr = TRUE; + break; + + case 'z': + /* System name. */ + zsystem = optarg; + break; + + case 'I': + /* Configuration file name. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'x': +#if DEBUG > 1 + /* Set debugging level. */ + iDebug |= idebug_parse (optarg); +#endif + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + ucuusage (); + break; + } + } + + /* There can be one more argument, which is either a system name, a + phone number, or "dir". We decide which it is based on the first + character. To call a UUCP system whose name begins with a digit, + or one which is named "dir", you must use -z. */ + if (optind != argc) + { + if (optind != argc - 1 + || zsystem != NULL + || zphone != NULL) + ucuusage (); + if (strcmp (argv[optind], "dir") != 0) + { + if (isdigit (BUCHAR (argv[optind][0]))) + zphone = argv[optind]; + else + zsystem = argv[optind]; + } + } + + /* If the user doesn't give a system, port, line or speed, then + there's no basis on which to select a port. */ + if (zsystem == NULL + && zport == NULL + && zline == NULL + && ibaud == 0L) + ucuusage (); + + if (fprompt) + { + size_t cphone; + + printf ("Phone number: "); + (void) fflush (stdout); + zphone = NULL; + cphone = 0; + if (getline (&zphone, &cphone, stdin) <= 0 + || *zphone == '\0') + { + fprintf (stderr, "%s: No phone number entered\n", abProgram); + exit (EXIT_FAILURE); + } + } + + iuuconf = uuconf_init (&puuconf, "cu", zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + pCuuuconf = puuconf; + +#if DEBUG > 1 + { + const char *zdebug; + + iuuconf = uuconf_debuglevel (puuconf, &zdebug); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + if (zdebug != NULL) + iDebug |= idebug_parse (zdebug); + } +#endif + + usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID); + + iuuconf = uuconf_localname (puuconf, &zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zlocalname = zsysdep_localname (); + if (zlocalname == NULL) + exit (EXIT_FAILURE); + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + ulog_fatal_fn (ucuabort); + pfLstart = uculog_start; + pfLend = uculog_end; + +#ifdef SIGINT + usysdep_signal (SIGINT); +#endif +#ifdef SIGHUP + usysdep_signal (SIGHUP); +#endif +#ifdef SIGQUIT + usysdep_signal (SIGQUIT); +#endif +#ifdef SIGTERM + usysdep_signal (SIGTERM); +#endif +#ifdef SIGPIPE + usysdep_signal (SIGPIPE); +#endif + + if (zsystem != NULL) + { + iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + ulog (LOG_FATAL, "%s: System not found", zsystem); + } + qsys = &ssys; + } + + /* This loop is used if a system is specified. It loops over the + various alternates until it finds one for which the dial + succeeds. This is an ugly spaghetti construction, and it should + be broken up into different functions someday. */ + flooped = FALSE; + while (TRUE) + { + enum tparitysetting tparity; + enum tstripsetting tstrip; + + /* The uuconf_find_port function only selects directly on a port + name and a speed. To select based on the line name, we use a + function. If we can't find any defined port, and the user + specified a line name but did not specify a port name or a + system or a phone number, then we fake a direct port with + that line name (we don't fake a port if a system or phone + number were given because if we fake a port we have no way to + place a call; perhaps we should automatically look up a + particular dialer). This permits users to say cu -lttyd0 + without having to put ttyd0 in the ports file, provided they + have read and write access to the port. */ + sinfo.fmatched = FALSE; + sinfo.flocked = FALSE; + sinfo.qconn = &sconn; + sinfo.zline = zline; + if (zport != NULL || zline != NULL || ibaud != 0L) + { + iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L, + icuport_lock, (pointer) &sinfo, + &sport); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + { + if (sinfo.flocked) + { + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + } + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + if (zline == NULL + || zport != NULL + || zphone != NULL + || qsys != NULL) + { + if (sinfo.fmatched) + ulog (LOG_FATAL, "All matching ports in use"); + else + ulog (LOG_FATAL, "No matching ports"); + } + + sport.uuconf_zname = zline; + sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT; + sport.uuconf_zprotocols = NULL; + sport.uuconf_qproto_params = NULL; + sport.uuconf_ireliable = 0; + sport.uuconf_zlockname = NULL; + sport.uuconf_palloc = NULL; + sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL; + sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud; + + if (! fsysdep_port_access (&sport)) + ulog (LOG_FATAL, "%s: Permission denied", zline); + + if (! fconn_init (&sport, &sconn)) + ucuabort (); + + if (! fconn_lock (&sconn, FALSE)) + ulog (LOG_FATAL, "%s: Line in use", zline); + + qCuconn = &sconn; + } + ihighbaud = 0L; + } + else + { + for (; qsys != NULL; qsys = qsys->uuconf_qalternate) + { + if (! qsys->uuconf_fcall) + continue; + if (qsys->uuconf_qport != NULL) + { + if (fconn_init (qsys->uuconf_qport, &sconn)) + { + if (fconn_lock (&sconn, FALSE)) + { + qCuconn = &sconn; + break; + } + uconn_free (&sconn); + } + } + else + { + sinfo.fmatched = FALSE; + sinfo.flocked = FALSE; + sinfo.qconn = &sconn; + iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport, + qsys->uuconf_ibaud, + qsys->uuconf_ihighbaud, + icuport_lock, + (pointer) &sinfo, + &sport); + if (iuuconf == UUCONF_SUCCESS) + break; + if (iuuconf != UUCONF_NOT_FOUND) + { + if (sinfo.flocked) + { + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + } + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + } + } + + if (qsys == NULL) + { + const char *zrem; + + if (flooped) + zrem = "remaining "; + else + zrem = ""; + if (sinfo.fmatched) + ulog (LOG_FATAL, "%s: All %smatching ports in use", + zsystem, zrem); + else + ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem); + } + + ibaud = qsys->uuconf_ibaud; + ihighbaud = qsys->uuconf_ihighbaud; + } + + /* Here we have locked a connection to use. */ + if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE)) + ucuabort (); + + fCuclose_conn = TRUE; + + if (FGOT_SIGNAL ()) + ucuabort (); + + /* Set up the connection. */ + if (fodd && feven) + { + tparity = PARITYSETTING_NONE; + tstrip = STRIPSETTING_SEVENBITS; + } + else if (fodd) + { + tparity = PARITYSETTING_ODD; + tstrip = STRIPSETTING_SEVENBITS; + } + else if (feven) + { + tparity = PARITYSETTING_EVEN; + tstrip = STRIPSETTING_SEVENBITS; + } + else + { + tparity = PARITYSETTING_DEFAULT; + tstrip = STRIPSETTING_DEFAULT; + } + + if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON)) + ucuabort (); + + if (qsys != NULL) + zphone = qsys->uuconf_zphone; + + if (qsys != NULL || zphone != NULL) + { + enum tdialerfound tdialer; + + if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer, + &tdialer)) + { + if (zport != NULL + || zline != NULL + || ibaud != 0L + || qsys == NULL) + ucuabort (); + + if (qsys->uuconf_qalternate == NULL) + ulog (LOG_FATAL, "%s: No remaining alternates", zsystem); + + fCuclose_conn = FALSE; + (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE); + qCuconn = NULL; + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + + /* Loop around and try another alternate. */ + flooped = TRUE; + continue; + } + if (tdialer == DIALERFOUND_FALSE) + qdialer = NULL; + else + qdialer = &sdialer; + } + else + { + /* If no system or phone number was specified, we connect + directly to the modem. We only permit this if the user + has access to the port, since it permits various + shenanigans such as reprogramming the automatic + callbacks. */ + if (! fsysdep_port_access (sconn.qport)) + ulog (LOG_FATAL, "Access to port denied"); + qdialer = NULL; + if (! fconn_carrier (&sconn, FALSE)) + ulog (LOG_FATAL, "Can't turn off carrier"); + } + + break; + } + + qCudialer = qdialer; + + if (FGOT_SIGNAL ()) + ucuabort (); + + /* Here we have connected, and can start the main cu protocol. The + program spends most of its time in system dependent code, and + only comes out when a special command is received from the + terminal. */ + printf ("%s\n", ZCONNMSG); + + if (! fsysdep_terminal_raw (fCulocalecho)) + ucuabort (); + + fCurestore_terminal = TRUE; + + if (! fsysdep_cu_init (&sconn)) + ucuabort (); + + fCustarted = TRUE; + + while (fsysdep_cu (&sconn, &bcmd, zlocalname)) + if (! fcudo_cmd (puuconf, &sconn, bcmd)) + break; + + fCustarted = FALSE; + if (! fsysdep_cu_finish ()) + ucuabort (); + + fCurestore_terminal = FALSE; + (void) fsysdep_terminal_restore (); + + (void) fconn_close (&sconn, puuconf, qdialer, TRUE); + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + + printf ("\n%s\n", ZDISMSG); + + ulog_close (); + + usysdep_exit (TRUE); + + /* Avoid errors about not returning a value. */ + return 0; +} + +/* Print a usage message and die. */ + +static void +ucuusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: cu [options] [system or phone-number]\n"); + fprintf (stderr, + " -a port, -p port: Use named port\n"); + fprintf (stderr, + " -l line: Use named device (e.g. tty0)\n"); + fprintf (stderr, + " -s speed, -#: Use given speed\n"); + fprintf (stderr, + " -c phone: Phone number to call\n"); + fprintf (stderr, + " -z system: System to call\n"); + fprintf (stderr, + " -e: Set even parity\n"); + fprintf (stderr, + " -o: Set odd parity\n"); + fprintf (stderr, + " -h: Echo locally\n"); + fprintf (stderr, + " -t: Map carriage return to carriage return/linefeed\n"); + fprintf (stderr, + " -n: Prompt for phone number\n"); + fprintf (stderr, + " -d: Set maximum debugging level\n"); + fprintf (stderr, + " -x debug: Set debugging type\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + + exit (EXIT_FAILURE); +} + +/* This function is called when a fatal error occurs. */ + +static void +ucuabort () +{ + if (fCustarted) + { + fCustarted = FALSE; + (void) fsysdep_cu_finish (); + } + + if (fCurestore_terminal) + { + fCurestore_terminal = FALSE; + (void) fsysdep_terminal_restore (); + } + + if (qCuconn != NULL) + { + struct sconnection *qconn; + + if (fCuclose_conn) + { + fCuclose_conn = FALSE; + (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE); + } + qconn = qCuconn; + qCuconn = NULL; + (void) fconn_unlock (qconn); + uconn_free (qconn); + } + + ulog_close (); + + printf ("\n%s\n", ZDISMSG); + + usysdep_exit (FALSE); +} + +/* This variable is just used to communicate between uculog_start and + uculog_end. */ +static boolean fCulog_restore; + +/* This function is called by ulog before it output anything. We use + it to restore the terminal, if necessary. ulog is only called for + errors or debugging in cu, so it's not too costly to do this. If + we didn't do it, then at least on Unix each line would leave the + cursor in the same column rather than wrapping back to the start, + since CRMOD will not be on. */ + +static void +uculog_start () +{ + if (! fCurestore_terminal) + fCulog_restore = FALSE; + else + { + fCulog_restore = TRUE; + fCurestore_terminal = FALSE; + if (! fsysdep_terminal_restore ()) + ucuabort (); + } +} + +/* This function is called by ulog after everything is output. It + sets the terminal back, if necessary. */ + +static void +uculog_end () +{ + if (fCulog_restore) + { + if (! fsysdep_terminal_raw (fCulocalecho)) + ucuabort (); + fCurestore_terminal = TRUE; + } +} + +/* Check to see if this port has the desired line, to handle the -l + option. If it does, or if no line was specified, set up a + connection and lock it. */ + +static int +icuport_lock (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + struct sconninfo *q = (struct sconninfo *) pinfo; + + if (q->zline != NULL + && ! fsysdep_port_is_line (qport, q->zline)) + return UUCONF_NOT_FOUND; + + q->fmatched = TRUE; + + if (! fconn_init (qport, q->qconn)) + return UUCONF_NOT_FOUND; + else if (! fconn_lock (q->qconn, FALSE)) + { + uconn_free (q->qconn); + return UUCONF_NOT_FOUND; + } + else + { + qCuconn = q->qconn; + q->flocked = TRUE; + return UUCONF_SUCCESS; + } +} + +/* Execute a cu escape command. Return TRUE if the connection should + continue, or FALSE if the connection should be terminated. */ + +static boolean +fcudo_cmd (puuconf, qconn, bcmd) + pointer puuconf; + struct sconnection *qconn; + int bcmd; +{ + char *zline; + char *z; + char abescape[5]; + boolean fret; + size_t clen; + char abbuf[100]; + + /* Some commands take a string up to the next newline character. */ + switch (bcmd) + { + default: + zline = NULL; + break; + case '!': + case '$': + case '|': + case '+': + case '%': + case 'c': + case '>': + case '<': + case 'p': + case 't': + case 's': + { + zline = zsysdep_terminal_line ((const char *) NULL); + if (zline == NULL) + ucuabort (); + zline[strcspn (zline, "\n")] = '\0'; + } + break; + } + + switch (bcmd) + { + default: + if (! isprint (*zCuvar_escape)) + sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); + else + { + abescape[0] = *zCuvar_escape; + abescape[1] = '\0'; + } + sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]", + abescape, abescape, abescape); + ucuputs (abbuf); + return TRUE; + + case '.': + /* Hangup. */ + return FALSE; + + case '!': + case '$': + case '|': + case '+': + /* Shell out. */ + if (! fsysdep_cu_copy (FALSE) + || ! fsysdep_terminal_restore ()) + ucuabort (); + fCurestore_terminal = FALSE; + { + enum tshell_cmd t; + + switch (bcmd) + { + default: + case '!': t = SHELL_NORMAL; break; + case '$': t = SHELL_STDOUT_TO_PORT; break; + case '|': t = SHELL_STDIN_FROM_PORT; break; + case '+': t = SHELL_STDIO_ON_PORT; break; + } + + (void) fsysdep_shell (qconn, zline, t); + } + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_raw (fCulocalecho)) + ucuabort (); + fCurestore_terminal = TRUE; + ubuffree (zline); + return TRUE; + + case '%': + fret = fcudo_subcmd (puuconf, qconn, zline); + ubuffree (zline); + return fret; + + case '#': + if (! fconn_break (qconn)) + ucuabort (); + return TRUE; + + case 'c': + (void) fsysdep_chdir (zline); + ubuffree (zline); + return TRUE; + + case '>': + case '<': + case 'p': + case 't': + clen = strlen (zline); + z = zbufalc (clen + 3); + z[0] = bcmd; + z[1] = ' '; + memcpy (z + 2, zline, clen + 1); + ubuffree (zline); + fret = fcudo_subcmd (puuconf, qconn, z); + ubuffree (z); + return fret; + + case 'z': + if (! fsysdep_cu_copy (FALSE) + || ! fsysdep_terminal_restore ()) + ucuabort (); + fCurestore_terminal = FALSE; + if (! fsysdep_suspend ()) + ucuabort (); + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_raw (fCulocalecho)) + ucuabort (); + fCurestore_terminal = TRUE; + return TRUE; + + case 's': + fret = fcuset_var (puuconf, zline); + ubuffree (zline); + return fret; + + case 'v': + uculist_vars (); + return TRUE; + + case '?': + if (! isprint (*zCuvar_escape)) + sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); + else + { + abescape[0] = *zCuvar_escape; + abescape[1] = '\0'; + } + ucuputs (""); + ucuputs ("[Escape sequences]"); + sprintf (abbuf, + "[%s. hangup] [%s!CMD run shell]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s$CMD stdout to remote] [%s|CMD stdin from remote]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s+CMD stdin and stdout to remote]", + abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s# send break] [%scDIR change directory]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s> send file] [%s< receive file]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%ssVAR VAL set variable] [%ssVAR set boolean]", + abescape, abescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%ss!VAR unset boolean] [%sv list variables]", + abescape, abescape); + ucuputs (abbuf); +#ifdef SIGTSTP + sprintf (abbuf, + "[%sz suspend]", + abescape); + ucuputs (abbuf); +#endif + uculist_fns (abescape); + return TRUE; + } +} + +/* List ~% functions. */ + +static void +uculist_fns (zescape) + const char *zescape; +{ + char abbuf[100]; + + sprintf (abbuf, + "[%s%%break send break] [%s%%cd DIR change directory]", + zescape, zescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]", + zescape, zescape); + ucuputs (abbuf); + sprintf (abbuf, + "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]", + zescape, zescape); + ucuputs (abbuf); +} + +/* Set a variable. */ + +static boolean +fcuset_var (puuconf, zline) + pointer puuconf; + char *zline; +{ + char *zvar, *zval; + char *azargs[2]; + char azbool[2]; + int iuuconf; + + zvar = strtok (zline, "= \t"); + if (zvar == NULL) + { + ucuputs (abCuconnected); + return TRUE; + } + + zval = strtok ((char *) NULL, " \t"); + + if (zval == NULL) + { + azargs[0] = zvar; + if (azargs[0][0] != '!') + azbool[0] = 't'; + else + { + ++azargs[0]; + azbool[0] = 'f'; + } + azbool[1] = '\0'; + azargs[1] = azbool; + } + else + { + azargs[0] = zvar; + azargs[1] = zval; + } + + iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars, + (pointer) NULL, icuunrecogvar, 0, + (pointer) NULL); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + + return TRUE; +} + +/* Warn about an unknown variable. */ + +/*ARGSUSED*/ +static int +icuunrecogvar (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + char abescape[5]; + + if (! isprint (*zCuvar_escape)) + sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); + else + { + abescape[0] = *zCuvar_escape; + abescape[1] = '\0'; + } + ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)", + argv[0], abescape); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* List all the variables with their values. */ + +static void +uculist_vars () +{ + const struct uuconf_cmdtab *q; + char abbuf[100]; + + ucuputs (""); + for (q = asCuvars; q->uuconf_zcmd != NULL; q++) + { + switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype)) + { + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN): + if (*(boolean *) q->uuconf_pvar) + sprintf (abbuf, "%s true", q->uuconf_zcmd); + else + sprintf (abbuf, "%s false", q->uuconf_zcmd); + break; + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT): + sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar); + break; + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG): + sprintf (abbuf, "%s %ld", q->uuconf_zcmd, + *(long *) q->uuconf_pvar); + break; + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING): + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING): + { + const char *z; + char abchar[5]; + size_t clen; + + sprintf (abbuf, "%s ", q->uuconf_zcmd); + clen = strlen (abbuf); + for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++) + { + int cchar; + + if (! isprint (*z)) + { + sprintf (abchar, "\\%03o", (unsigned int) *z); + cchar = 4; + } + else + { + abchar[0] = *z; + abchar[1] = '\0'; + cchar = 1; + } + if (clen + cchar < sizeof (abbuf)) + strcat (abbuf, abchar); + clen += cchar; + } + } + break; + + default: + sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd); + break; + } + + ucuputs (abbuf); + } +} + +/* Subcommands. These are commands that begin with ~%. */ + +/* This variable is only used so that we can pass a non-NULL address + in pvar. It is never assigned to or examined. */ + +static char bCutype; + +/* The command table for the subcommands. */ + +static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); + +static const struct uuconf_cmdtab asCucmds[] = +{ + { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak }, + { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak }, + { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir }, + { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug }, + { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput }, + { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake }, + { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop }, + { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop }, + { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput }, + { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake }, + { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput }, + { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake }, + { NULL, 0, NULL, NULL } +}; + +/* Do a subcommand. This is called by commands beginning with ~%. */ + +static boolean +fcudo_subcmd (puuconf, qconn, zline) + pointer puuconf; + struct sconnection *qconn; + char *zline; +{ + char *azargs[3]; + int iarg; + int iuuconf; + + for (iarg = 0; iarg < 3; iarg++) + { + azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n"); + if (azargs[iarg] == NULL) + break; + } + + if (iarg == 0) + { + ucuputs (abCuconnected); + return TRUE; + } + + iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds, + (pointer) qconn, icuunrecogfn, + 0, (pointer) NULL); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + + return TRUE; +} + +/* Warn about an unknown function. */ + +/*ARGSUSED*/ +static int +icuunrecogfn (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + char abescape[5]; + + if (! isprint (*zCuvar_escape)) + sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); + else + { + abescape[0] = *zCuvar_escape; + abescape[1] = '\0'; + } + if (argv[0][0] == '?') + uculist_fns (abescape); + else + ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)", + argv[0], abescape); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Send a break. */ + +/*ARGSUSED*/ +static int +icubreak (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sconnection *qconn = (struct sconnection *) pinfo; + + if (! fconn_break (qconn)) + ucuabort (); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Change directories. */ + +/*ARGSUSED*/ +static int +icuchdir (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + const char *zarg; + + if (argc <= 1) + zarg = NULL; + else + zarg = argv[1]; + (void) fsysdep_chdir (zarg); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Toggle debugging. */ + +/*ARGSUSED*/ +static int +icudebug (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ +#if DEBUG > 1 + if (iDebug != 0) + iDebug = 0; + else + iDebug = DEBUG_MAX; +#else + ucuputs ("[compiled without debugging]"); +#endif + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Control whether the port does xon/xoff handshaking. If pvar is not + NULL, this is "stop"; otherwise it is "nostop". */ + +/*ARGSUSED*/ +static int +icunostop (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sconnection *qconn = (struct sconnection *) pinfo; + + if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT, + pvar == NULL ? XONXOFF_OFF : XONXOFF_ON)) + ucuabort (); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Send a file to the remote system. The first argument is the file + to send. If that argument is not present, it is prompted for. The + second argument is to file name to use on the remote system. If + that argument is not present, the basename of the local filename is + used. If pvar is not NULL, then this is ~>, which is used to send + a command to a non-Unix system. We treat is the same as ~%put, + except that we assume the user has already entered the appropriate + command (for ~%put, we force ``cat >to'' to the other side). */ + +/*ARGSUSED*/ +static int +icuput (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sconnection *qconn = (struct sconnection *) pinfo; + char *zfrom; + char *zto = NULL; + char *zalc; + openfile_t e; + int cline; + char *zbuf; + size_t cbuf; + + if (argc > 1) + zfrom = zbufcpy (argv[1]); + else + { + zfrom = zsysdep_terminal_line ("File to send: "); + if (zfrom == NULL) + ucuabort (); + zfrom[strcspn (zfrom, " \t\n")] = '\0'; + + if (*zfrom == '\0') + { + ubuffree (zfrom); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + } + + if (pvar == NULL) + { + if (argc > 2) + zto = zbufcpy (argv[2]); + else + { + char *zbase; + char *zprompt; + + zbase = zsysdep_base_name (zfrom); + if (zbase == NULL) + ucuabort (); + + zprompt = zbufalc (sizeof "Remote file name []: " + + strlen (zbase)); + sprintf (zprompt, "Remote file name [%s]: ", zbase); + zto = zsysdep_terminal_line (zprompt); + ubuffree (zprompt); + if (zto == NULL) + ucuabort (); + + zto[strcspn (zto, " \t\n")] = '\0'; + if (*zto != '\0') + ubuffree (zbase); + else + { + ubuffree (zto); + zto = zbase; + } + } + } + + e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary); + if (! ffileisopen (e)) + { + const char *zerrstr; + + if (pvar == NULL) + ubuffree (zto); + zerrstr = strerror (errno); + zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr)); + sprintf (zalc, "%s: %s", zfrom, zerrstr); + ubuffree (zfrom); + ucuputs (zalc); + ubuffree (zalc); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + + ubuffree (zfrom); + + /* Tell the system dependent layer to stop copying data from the + port to the terminal. We want to read the echoes ourself. Also + permit the local user to generate signals. */ + if (! fsysdep_cu_copy (FALSE) + || ! fsysdep_terminal_signals (TRUE)) + ucuabort (); + + /* If pvar is NULL, then we are sending a file to a Unix system. We + send over the command "cat > TO" to prepare it to receive. If + pvar is not NULL, the user is assumed to have set up whatever + action was needed to receive the file. */ + if (pvar == NULL) + { + boolean fret; + + zalc = zbufalc (sizeof "cat > \n" + strlen (zto)); + sprintf (zalc, "cat > %s\n", zto); + ubuffree (zto); + fret = fcusend_buf (qconn, zalc, strlen (zalc)); + ubuffree (zalc); + if (! fret) + { + (void) ffileclose (e); + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_signals (FALSE)) + ucuabort (); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + } + + cline = 0; + + zbuf = NULL; + cbuf = 0; + + while (TRUE) + { + char abbuf[512]; + size_t c; + +#if USE_STDIO + if (fCuvar_binary) +#endif + { + if (ffileeof (e)) + break; + c = cfileread (e, abbuf, sizeof abbuf); + if (ffilereaderror (e, c)) + { + ucuputs ("[file read error]"); + break; + } + if (c == 0) + break; + zbuf = abbuf; + } +#if USE_STDIO + else + { + if (getline (&zbuf, &cbuf, e) <= 0) + { + xfree ((pointer) zbuf); + break; + } + c = strlen (zbuf); + } +#endif + + if (fCuvar_verbose) + { + ++cline; + printf ("%d ", cline); + (void) fflush (stdout); + } + + if (! fcusend_buf (qconn, zbuf, c)) + { + if (! fCuvar_binary) + xfree ((pointer) zbuf); + (void) fclose (e); + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_signals (FALSE)) + ucuabort (); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + } + + (void) ffileclose (e); + + if (pvar == NULL) + { + char beof; + + beof = '\004'; + if (! fconn_write (qconn, &beof, 1)) + ucuabort (); + } + else + { + if (*zCuvar_eofwrite != '\0') + { + if (! fconn_write (qconn, zCuvar_eofwrite, + strlen (zCuvar_eofwrite))) + ucuabort (); + } + } + + if (fCuvar_verbose) + ucuputs (""); + + ucuputs ("[file transfer complete]"); + + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_signals (FALSE)) + ucuabort (); + + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Get a file from the remote side. This is ~%take, or ~t, or ~<. + The first two are assumed to be taking the file from a Unix system, + so we force the command "cat FROM; echo */ + +/*ARGSUSED*/ +static int +icutake (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sconnection *qconn = (struct sconnection *) pinfo; + const char *zeof; + char *zfrom, *zto, *zcmd; + char *zalc; + openfile_t e; + char bcr; + size_t ceoflen; + char *zlook = NULL; + size_t ceofhave; + boolean ferr; + + if (argc > 1) + zfrom = zbufcpy (argv[1]); + else + { + zfrom = zsysdep_terminal_line ("Remote file to retreive: "); + if (zfrom == NULL) + ucuabort (); + zfrom[strcspn (zfrom, " \t\n")] = '\0'; + if (*zfrom == '\0') + { + ubuffree (zfrom); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + } + + if (argc > 2) + zto = zbufcpy (argv[2]); + else + { + char *zbase; + char *zprompt; + + zbase = zsysdep_base_name (zfrom); + if (zbase == NULL) + ucuabort (); + + zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase)); + sprintf (zprompt, "Local file name [%s]: ", zbase); + zto = zsysdep_terminal_line (zprompt); + ubuffree (zprompt); + if (zto == NULL) + ucuabort (); + + zto[strcspn (zto, " \t\n")] = '\0'; + if (*zto != '\0') + ubuffree (zbase); + else + { + ubuffree (zto); + zto = zbase; + } + } + + if (pvar != NULL) + { + zcmd = zsysdep_terminal_line ("Remote command to execute: "); + if (zcmd == NULL) + ucuabort (); + zcmd[strcspn (zcmd, "\n")] = '\0'; + zeof = zCuvar_eofread; + } + else + { + zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////" + + strlen (zfrom)); + sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom); + zeof = "\n////cuend////\n"; + } + + ubuffree (zfrom); + + e = esysdep_user_fopen (zto, FALSE, fCuvar_binary); + if (! ffileisopen (e)) + { + const char *zerrstr; + + ubuffree (zcmd); + zerrstr = strerror (errno); + zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr)); + sprintf (zalc, "%s: %s\n", zto, zerrstr); + ucuputs (zalc); + ubuffree (zalc); + ucuputs (abCuconnected); + ubuffree (zto); + return UUCONF_CMDTABRET_CONTINUE; + } + + ubuffree (zto); + + if (! fsysdep_cu_copy (FALSE) + || ! fsysdep_terminal_signals (TRUE)) + ucuabort (); + + if (! fconn_write (qconn, zcmd, strlen (zcmd))) + ucuabort (); + bcr = '\r'; + if (! fconn_write (qconn, &bcr, 1)) + ucuabort (); + + ubuffree (zcmd); + + /* Eliminated any previously echoed data to avoid confusion. */ + iPrecstart = 0; + iPrecend = 0; + + /* If we're dealing with a Unix system, we can reliably discard the + command. Otherwise, the command will probably wind up in the + file; too bad. */ + if (pvar == NULL) + { + int b; + + while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n') + { + if (b == -2) + ucuabort (); + if (b < 0) + { + ucuputs ("[timed out waiting for newline]"); + ucuputs (abCuconnected); + return UUCONF_CMDTABRET_CONTINUE; + } + } + } + + ceoflen = strlen (zeof); + zlook = zbufalc (ceoflen); + ceofhave = 0; + ferr = FALSE; + + while (TRUE) + { + int b; + + if (FGOT_SIGNAL ()) + { + /* Make sure the signal is logged. */ + ulog (LOG_ERROR, (const char *) NULL); + ucuputs ("[file receive aborted]"); + /* Reset the SIGINT flag so that it does not confuse us in + the future. */ + afSignal[INDEXSIG_SIGINT] = FALSE; + break; + } + + b = breceive_char (qconn, cCuvar_timeout, TRUE); + if (b == -2) + ucuabort (); + if (b < 0) + { + if (ceofhave > 0) + (void) fwrite (zlook, sizeof (char), ceofhave, e); + ucuputs ("[timed out]"); + break; + } + + if (ceoflen == 0) + { + if (cfilewrite (e, &b, 1) != 1) + { + ferr = TRUE; + break; + } + } + else + { + zlook[ceofhave] = b; + ++ceofhave; + if (ceofhave == ceoflen) + { + size_t cmove; + char *zmove; + + if (memcmp (zeof, zlook, ceoflen) == 0) + { + ucuputs ("[file transfer complete]"); + break; + } + + if (cfilewrite (e, zlook, 1) != 1) + { + ferr = TRUE; + break; + } + + zmove = zlook; + for (cmove = ceoflen - 1, zmove = zlook; + cmove > 0; + cmove--, zmove++) + zmove[0] = zmove[1]; + + --ceofhave; + } + } + } + + ubuffree (zlook); + + if (! ffileclose (e)) + ferr = TRUE; + if (ferr) + ucuputs ("[file write error]"); + + if (! fsysdep_cu_copy (TRUE) + || ! fsysdep_terminal_signals (FALSE)) + ucuabort (); + + ucuputs (abCuconnected); + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Send a buffer to the remote system. If fCuvar_binary is FALSE, + each buffer passed in will be a single line; in this case we can + check the echoed characters and kill the line if they do not match. + This returns FALSE if an echo check fails. If a port error + occurrs, it calls ucuabort. */ + +static boolean +fcusend_buf (qconn, zbufarg, cbufarg) + struct sconnection *qconn; + const char *zbufarg; + size_t cbufarg; +{ + const char *zbuf; + size_t cbuf; + int ctries; + size_t cbplen; + char *zsendbuf; + + zbuf = zbufarg; + cbuf = cbufarg; + ctries = 0; + + if (fCuvar_binary) + cbplen = strlen (zCuvar_binary_prefix); + else + cbplen = 1; + zsendbuf = zbufalc (64 * (cbplen + 1)); + + /* Loop while we still have characters to send. The value of cbuf + will be reset to cbufarg if an echo failure occurs while sending + a line in non-binary mode. */ + while (cbuf > 0) + { + int csend; + char *zput; + const char *zget; + boolean fnl; + int i; + + if (FGOT_SIGNAL ()) + { + /* Make sure the signal is logged. */ + ubuffree (zsendbuf); + ulog (LOG_ERROR, (const char *) NULL); + ucuputs ("[file send aborted]"); + /* Reset the SIGINT flag so that it does not confuse us in + the future. */ + afSignal[INDEXSIG_SIGINT] = FALSE; + return FALSE; + } + + /* Discard anything we've read from the port up to now, to avoid + confusing the echo checking. */ + iPrecstart = 0; + iPrecend = 0; + + /* Send all characters up to a newline before actually sending + the newline. This makes it easier to handle the special + newline echo checking. Send up to 64 characters at a time + before doing echo checking. */ + if (*zbuf == '\n') + csend = 1; + else + { + const char *znl; + + znl = memchr (zbuf, '\n', cbuf); + if (znl == NULL) + csend = cbuf; + else + csend = znl - zbuf; + if (csend > 64) + csend = 64; + } + + /* Translate this part of the buffer. If we are not in binary + mode, we translate \n to \r, and ignore any nonprintable + characters. */ + zput = zsendbuf; + fnl = FALSE; + for (i = 0, zget = zbuf; i < csend; i++, zget++) + { + if (isprint (*zget) + || *zget == '\t') + *zput++ = *zget; + else if (*zget == '\n') + { + if (fCuvar_binary) + *zput++ = '\n'; + else + *zput++ = '\r'; + fnl = TRUE; + } + else if (fCuvar_binary) + { + strcpy (zput, zCuvar_binary_prefix); + zput += cbplen; + *zput++ = *zget; + } + } + + zbuf += csend; + cbuf -= csend; + + if (zput == zsendbuf) + continue; + + /* Send the data over the port. */ + if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE)) + ucuabort (); + + /* We do echo checking if requested, unless we are in binary + mode. Echo checking of a newline is different from checking + of normal characters; when we send a newline we look for + *zCuvar_echonl. */ + if ((fCuvar_echocheck && ! fCuvar_binary) + || (fnl && *zCuvar_echonl != '\0')) + { + long iend; + + iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout; + for (zget = zsendbuf; zget < zput; zget++) + { + int bread; + int bwant; + + if (fCuvar_binary ? *zget == '\n' : *zget == '\r') + { + bwant = *zCuvar_echonl; + if (bwant == '\0') + continue; + } + else + { + if (! fCuvar_echocheck || ! isprint (*zget)) + continue; + bwant = *zget; + } + + do + { + if (FGOT_SIGNAL ()) + { + /* Make sure the signal is logged. */ + ubuffree (zsendbuf); + ulog (LOG_ERROR, (const char *) NULL); + ucuputs ("[file send aborted]"); + /* Reset the SIGINT flag so that it does not + confuse us in the future. */ + afSignal[INDEXSIG_SIGINT] = FALSE; + return FALSE; + } + + bread = breceive_char (qconn, + iend - ixsysdep_time ((long *) NULL), + TRUE); + if (bread < 0) + { + if (bread == -2) + ucuabort (); + + /* If we timed out, and we're not in binary + mode, we kill the line and try sending it + again from the beginning. */ + if (! fCuvar_binary && *zCuvar_kill != '\0') + { + ++ctries; + if (ctries < cCuvar_resend) + { + if (fCuvar_verbose) + { + printf ("R "); + (void) fflush (stdout); + } + if (! fsend_data (qconn, zCuvar_kill, 1, + TRUE)) + ucuabort (); + zbuf = zbufarg; + cbuf = cbufarg; + break; + } + } + ubuffree (zsendbuf); + ucuputs ("[timed out looking for echo]"); + return FALSE; + } + } + while (bread != *zget); + + if (bread < 0) + break; + } + } + } + + ubuffree (zsendbuf); + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/MANIFEST b/gnu/libexec/uucp/libunix/MANIFEST new file mode 100644 index 00000000000..d64e7992204 --- /dev/null +++ b/gnu/libexec/uucp/libunix/MANIFEST @@ -0,0 +1,76 @@ +Makefile.in +MANIFEST +access.c +addbas.c +app3.c +app4.c +basnam.c +bytfre.c +chmod.c +cohtty.c +cwd.c +cusub.c +detach.c +dirent.c +dup2.c +efopen.c +epopen.c +exists.c +filnam.c +fsusg.c +fsusg.h +ftw.c +getcwd.c +indir.c +init.c +isdir.c +isfork.c +iswait.c +jobid.c +lcksys.c +link.c +locfil.c +lock.c +loctim.c +mail.c +mkdir.c +mkdirs.c +mode.c +move.c +opensr.c +pause.c +picksb.c +portnm.c +proctm.c +recep.c +remove.c +rename.c +rmdir.c +run.c +seq.c +serial.c +signal.c +sindir.c +size.c +sleep.c +splcmd.c +splnam.c +spool.c +spawn.c +srmdir.c +statsb.c +status.c +strerr.c +time.c +tmpfil.c +trunc.c +uacces.c +ufopen.c +ultspl.c +unknwn.c +uuto.c +walk.c +wldcrd.c +work.c +xqtfil.c +xqtsub.c diff --git a/gnu/libexec/uucp/libunix/Makefile b/gnu/libexec/uucp/libunix/Makefile new file mode 100644 index 00000000000..a9401e66dc0 --- /dev/null +++ b/gnu/libexec/uucp/libunix/Makefile @@ -0,0 +1,21 @@ +# This subdirectory contains Unix specific support functions. + +LIB= unix +SRCS= access.c addbas.c app3.c app4.c basnam.c bytfre.c cwd.c \ + chmod.c cohtty.c cusub.c detach.c efopen.c epopen.c exists.c \ + filnam.c fsusg.c indir.c init.c isdir.c isfork.c iswait.c \ + jobid.c lcksys.c link.c locfil.c lock.c loctim.c mail.c \ + mkdirs.c mode.c move.c opensr.c pause.c picksb.c portnm.c \ + proctm.c recep.c run.c seq.c serial.c signal.c sindir.c size.c \ + sleep.c spawn.c splcmd.c splnam.c spool.c srmdir.c statsb.c \ + status.c time.c tmpfil.c trunc.c uacces.c ufopen.c ultspl.c \ + unknwn.c uuto.c walk.c wldcrd.c work.c xqtfil.c xqtsub.c ftw.c +CFLAGS+= -I$(.CURDIR)/../common_sources \ + -DOWNER=\"$(owner)\" -DSBINDIR=\"$(sbindir)\" + +NOMAN= noman +NOPROFILE= noprofile + +install: + +.include <bsd.lib.mk> diff --git a/gnu/libexec/uucp/libunix/access.c b/gnu/libexec/uucp/libunix/access.c new file mode 100644 index 00000000000..c2c0eef2108 --- /dev/null +++ b/gnu/libexec/uucp/libunix/access.c @@ -0,0 +1,83 @@ +/* access.c + Check access to files by the user and by the daemon. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* See if the user has access to a file, to prevent the setuid uucp + and uux programs handing out unauthorized access. */ + +boolean +fsysdep_access (zfile) + const char *zfile; +{ + if (access (zfile, R_OK) == 0) + return TRUE; + ulog (LOG_ERROR, "%s: %s", zfile, strerror (errno)); + return FALSE; +} + +/* See if the daemon has access to a file. This is called if a file + is not being transferred to the spool directory, since if the + daemon does not have access the later transfer will fail. We + assume that the daemon will have the same euid (or egid) as the one + we are running under. If our uid (gid) and euid (egid) are the + same, we assume that we have access. Note that is not important + for security, since the check will be (implicitly) done again when + the daemon tries to transfer the file. This routine should work + whether the UUCP programs are installed setuid or setgid. */ + +boolean +fsysdep_daemon_access (zfile) + const char *zfile; +{ + struct stat s; + uid_t ieuid, iuid, iegid, igid; + boolean fok; + + ieuid = geteuid (); + if (ieuid == 0) + return TRUE; + iuid = getuid (); + iegid = getegid (); + igid = getgid (); + + /* If our effective uid and gid are the same as our real uid and + gid, we assume the daemon will have access to the file. */ + if (ieuid == iuid && iegid == igid) + return TRUE; + + if (stat ((char *) zfile, &s) != 0) + { + ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); + return FALSE; + } + + /* If our euid is not our uid, but it is the file's uid, see if the + owner has read access. Otherwise, if our egid is not our gid, + but it is the file's gid, see if the group has read access. + Otherwise, see if the world has read access. We know from the + above check that at least one of our euid and egid are different, + so that is the only one we want to check. This check could fail + if the UUCP programs were both setuid and setgid, but why would + they be? */ + if (ieuid != iuid && ieuid == s.st_uid) + fok = (s.st_mode & S_IRUSR) != 0; + else if (iegid != igid && iegid == s.st_gid) + fok = (s.st_mode & S_IRGRP) != 0; + else + fok = (s.st_mode & S_IROTH) != 0; + + if (! fok) + { + ulog (LOG_ERROR, "%s: cannot be read by daemon", zfile); + return FALSE; + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/addbas.c b/gnu/libexec/uucp/libunix/addbas.c new file mode 100644 index 00000000000..8597918a3c9 --- /dev/null +++ b/gnu/libexec/uucp/libunix/addbas.c @@ -0,0 +1,50 @@ +/* addbas.c + If we have a directory, add in a base name. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* If we have a directory, add a base name. */ + +char * +zsysdep_add_base (zfile, zname) + const char *zfile; + const char *zname; +{ + size_t clen; + const char *zlook; + char *zfree; + char *zret; + +#if DEBUG > 0 + if (*zfile != '/') + ulog (LOG_FATAL, "zsysdep_add_base: %s: Can't happen", zfile); +#endif + + clen = strlen (zfile); + + if (zfile[clen - 1] != '/') + { + if (! fsysdep_directory (zfile)) + return zbufcpy (zfile); + zfree = NULL; + } + else + { + /* Trim out the trailing '/'. */ + zfree = zbufcpy (zfile); + zfree[clen - 1] = '\0'; + zfile = zfree; + } + + zlook = strrchr (zname, '/'); + if (zlook != NULL) + zname = zlook + 1; + + zret = zsysdep_in_dir (zfile, zname); + ubuffree (zfree); + return zret; +} diff --git a/gnu/libexec/uucp/libunix/app3.c b/gnu/libexec/uucp/libunix/app3.c new file mode 100644 index 00000000000..5c0b5893851 --- /dev/null +++ b/gnu/libexec/uucp/libunix/app3.c @@ -0,0 +1,29 @@ +/* app3.c + Stick two directories and a file name together. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +char * +zsappend3 (zdir1, zdir2, zfile) + const char *zdir1; + const char *zdir2; + const char *zfile; +{ + size_t cdir1, cdir2, cfile; + char *zret; + + cdir1 = strlen (zdir1); + cdir2 = strlen (zdir2); + cfile = strlen (zfile); + zret = zbufalc (cdir1 + cdir2 + cfile + 3); + memcpy (zret, zdir1, cdir1); + memcpy (zret + cdir1 + 1, zdir2, cdir2); + memcpy (zret + cdir1 + cdir2 + 2, zfile, cfile); + zret[cdir1] = '/'; + zret[cdir1 + cdir2 + 1] = '/'; + zret[cdir1 + cdir2 + cfile + 2] = '\0'; + return zret; +} diff --git a/gnu/libexec/uucp/libunix/app4.c b/gnu/libexec/uucp/libunix/app4.c new file mode 100644 index 00000000000..a3b3787f68f --- /dev/null +++ b/gnu/libexec/uucp/libunix/app4.c @@ -0,0 +1,33 @@ +/* app4.c + Stick three directories and a file name together. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +char * +zsappend4 (zdir1, zdir2, zdir3, zfile) + const char *zdir1; + const char *zdir2; + const char *zdir3; + const char *zfile; +{ + size_t cdir1, cdir2, cdir3, cfile; + char *zret; + + cdir1 = strlen (zdir1); + cdir2 = strlen (zdir2); + cdir3 = strlen (zdir3); + cfile = strlen (zfile); + zret = zbufalc (cdir1 + cdir2 + cdir3 + cfile + 4); + memcpy (zret, zdir1, cdir1); + memcpy (zret + cdir1 + 1, zdir2, cdir2); + memcpy (zret + cdir1 + cdir2 + 2, zdir3, cdir3); + memcpy (zret + cdir1 + cdir2 + cdir3 + 3, zfile, cfile); + zret[cdir1] = '/'; + zret[cdir1 + cdir2 + 1] = '/'; + zret[cdir1 + cdir2 + cdir3 + 2] = '/'; + zret[cdir1 + cdir2 + cdir3 + cfile + 3] = '\0'; + return zret; +} diff --git a/gnu/libexec/uucp/libunix/basnam.c b/gnu/libexec/uucp/libunix/basnam.c new file mode 100644 index 00000000000..c61fcaa8de6 --- /dev/null +++ b/gnu/libexec/uucp/libunix/basnam.c @@ -0,0 +1,22 @@ +/* basnam.c + Get the base name of a file. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* Get the base name of a file name. */ + +char * +zsysdep_base_name (zfile) + const char *zfile; +{ + const char *z; + + z = strrchr (zfile, '/'); + if (z != NULL) + return zbufcpy (z + 1); + return zbufcpy (zfile); +} diff --git a/gnu/libexec/uucp/libunix/bytfre.c b/gnu/libexec/uucp/libunix/bytfre.c new file mode 100644 index 00000000000..568eebe0307 --- /dev/null +++ b/gnu/libexec/uucp/libunix/bytfre.c @@ -0,0 +1,19 @@ +/* bytfre.c + Get the number of bytes free on a file system. */ + +#include "uucp.h" + +#include "system.h" +#include "sysdep.h" +#include "fsusg.h" + +long +csysdep_bytes_free (zfile) + const char *zfile; +{ + struct fs_usage s; + + if (get_fs_usage ((char *) zfile, (char *) NULL, &s) < 0) + return -1; + return s.fsu_bavail * (long) 512; +} diff --git a/gnu/libexec/uucp/libunix/chmod.c b/gnu/libexec/uucp/libunix/chmod.c new file mode 100644 index 00000000000..cf69f3eb014 --- /dev/null +++ b/gnu/libexec/uucp/libunix/chmod.c @@ -0,0 +1,25 @@ +/* chmod.c + Change the mode of a file. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* Change the mode of a file. */ + +boolean +fsysdep_change_mode (zfile, imode) + const char *zfile; + unsigned int imode; +{ + if (chmod ((char *) zfile, imode) < 0) + { + ulog (LOG_ERROR, "chmod (%s): %s", zfile, strerror (errno)); + return FALSE; + } + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/cohtty.c b/gnu/libexec/uucp/libunix/cohtty.c new file mode 100644 index 00000000000..a7aec1cae33 --- /dev/null +++ b/gnu/libexec/uucp/libunix/cohtty.c @@ -0,0 +1,244 @@ +/* Coherent tty locking support. This file was contributed by Bob + Hemedinger <bob@dalek.mwc.com> of Mark Williams Corporation and + lightly edited by Ian Lance Taylor. */ + +/* The bottom part of this file is lock.c. + * This is a hacked lock.c. A full lock.c can be found in the libmisc sources + * under /usr/src/misc.tar.Z. + * + * These are for checking for the existence of locks: + * lockexist(resource) + * lockttyexist(ttyname) + */ + +#include "uucp.h" + +#if HAVE_COHERENT_LOCKFILES + +/* cohtty.c: Given a serial device name, read /etc/ttys and determine if + * the device is already enabled. If it is, disable the + * device and return a string so that it can be re-enabled + * at the completion of the uucico session as part of the + * function that resets the serial device before uucico + * terminates. + * + */ + +#include "uudefs.h" +#include "sysdep.h" + +#include <ctype.h> +#include <access.h> + +/* fscoherent_disable_tty() is a COHERENT specific function. It takes the name + * of a serial device and then scans /etc/ttys for a match. If it finds one, + * it checks the first field of the entry. If it is a '1', then it will disable + * the port and set a flag. The flag will be checked later when uucico wants to + * reset the serial device to see if the device needs to be re-enabled. + */ + +boolean +fscoherent_disable_tty (zdevice, pzenable) + const char *zdevice; + char **pzenable; +{ + + +struct ttyentry{ /* this is an /etc/ttys entry */ + char enable_disable[1]; + char remote_local[1]; + char baud_rate[1]; + char tty_device[16]; +}; + +struct ttyentry sought_tty; + +int x,y,z; /* dummy */ +FILE * infp; /* this will point to /etc/ttys */ +char disable_command[66]; /* this will be the disable command + * passed to the system. + */ +char enable_device[16]; /* this will hold our device name + * to enable. + */ + + *pzenable = NULL; + + strcpy(enable_device,""); /* initialize our strings */ + strcpy(sought_tty.tty_device,""); + + if( (infp = fopen("/etc/ttys","r")) == NULL){ + ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n"); + return FALSE; + } + + while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){ + sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0'; + strcpy(enable_device,sought_tty.tty_device); + + /* we must strip away the suffix to the com port name or + * we will never find a match. For example, if we are passed + * /dev/com4l to call out with and the port is already enabled, + * 9/10 the port enabled will be com4r. After we strip away the + * suffix of the port found in /etc/ttys, then we can test + * if the base port name appears in the device name string + * passed to us. + */ + + for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){ + if(isdigit(sought_tty.tty_device[z])){ + break; + } + } + y = strlen(sought_tty.tty_device); + for(x = z+1 ; x <= y; x++){ + sought_tty.tty_device[x] = '\0'; + } + + +/* ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */ + if(strstr(zdevice, sought_tty.tty_device)){ + if(sought_tty.enable_disable[0] == '1'){ + ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n", + zdevice, sought_tty.tty_device); + sprintf(disable_command, "/etc/disable %s",enable_device); + { + pid_t ipid; + const char *azargs[3]; + int aidescs[3]; + + azargs[0] = "/etc/disable"; + azargs[1] = enable_device; + azargs[2] = NULL; + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + ipid = ixsspawn (azargs, aidescs, TRUE, + FALSE, + (const char *) NULL, TRUE, + TRUE, + (const char *) NULL, + (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + x = 1; + else + x = ixswait ((unsigned long) ipid, + (const char *) NULL); + } + *pzenable = zbufalc (sizeof "/dev/" + + strlen (enable_device)); + sprintf(*pzenable,"/dev/%s", enable_device); +/* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */ + return(x==0? TRUE : FALSE); /* disable either failed + or succeded */ + }else{ + return FALSE; /* device in tty entry not enabled */ + } + } + } + return FALSE; /* no ttys entry found */ +} + +/* The following is COHERENT 4.0 specific. It is used to test for any + * existing lockfiles on a port which would have been created by init + * when a user logs into a port. + */ + +#define LOCKSIG 9 /* Significant Chars of Lockable Resources. */ +#define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */ + +#define LOCKPRE "LCK.." +#define PIDLEN 6 /* Maximum length of string representing a pid. */ + +#ifndef LOCKDIR +#define LOCKDIR SPOOLDIR +#endif + +/* There is a special version of DEVMASK for the PE multiport driver + * because of the peculiar way it uses the minor device number. For + * all other drivers, the lower 5 bits describe the physical port-- + * the upper 3 bits give attributes for the port. + */ + +#define PE_DRIVER 21 /* Major device number for the PE driver. */ +#define PE_DEVMASK 0x3f /* PE driver minor device mask. */ +#define DEVMASK 0x1f /* Minor device mask. */ + +/* + * Generates a resource name for locking, based on the major number + * and the lower 4 bits of the minor number of the tty device. + * + * Builds the name in buff as two "." separated decimal numbers. + * Returns NULL on failure, buff on success. + */ +static char * +gen_res_name(path, buff) +char *path; +char *buff; +{ + struct stat sbuf; + int status; + + if (0 != (status = stat(path, &sbuf))) { + /* Can't stat the file. */ + return (NULL); + } + + if (PE_DRIVER == major(sbuf.st_rdev)) { + sprintf(buff, "%d.%d", major(sbuf.st_rdev), + PE_DEVMASK & minor(sbuf.st_rdev)); + } else { + sprintf(buff, "%d.%d", major(sbuf.st_rdev), + DEVMASK & minor(sbuf.st_rdev)); + } + + return(buff); +} /* gen_res_name */ + +/* + * lockexist(resource) char *resource; + * + * Test for existance of a lock on the given resource. + * + * Returns: (1) Resource is locked. + * (0) Resource is not locked. + */ + +static boolean +lockexist(resource) +const char *resource; +{ + char lockfn[LOKFLEN]; + + if ( resource == NULL ) + return(0); + sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource); + + return (!access(lockfn, AEXISTS)); +} /* lockexist() */ + +/* + * lockttyexist(ttyname) char *ttyname; + * + * Test for existance of a lock on the given tty. + * + * Returns: (1) Resource is locked. + * (0) Resource is not locked. + */ +boolean +lockttyexist(ttyn) +const char *ttyn; +{ + char resource[LOKFLEN]; + char filename[LOKFLEN]; + + sprintf(filename, "/dev/%s", ttyn); + if (NULL == gen_res_name(filename, resource)){ + return(0); /* Non-existent tty can not be locked :-) */ + } + + return(lockexist(resource)); +} /* lockttyexist() */ + +#endif /* HAVE_COHERENT_LOCKFILES */ diff --git a/gnu/libexec/uucp/libunix/cusub.c b/gnu/libexec/uucp/libunix/cusub.c new file mode 100644 index 00000000000..4cee888d716 --- /dev/null +++ b/gnu/libexec/uucp/libunix/cusub.c @@ -0,0 +1,1163 @@ +/* cusub.c + System dependent routines for cu. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/04 19:32:09 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" +#include "cu.h" +#include "conn.h" +#include "prot.h" + +#include <errno.h> + +/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ +#ifndef EAGAIN +#ifndef EWOULDBLOCK +#define EAGAIN (-1) +#define EWOULDBLOCK (-1) +#else /* defined (EWOULDBLOCK) */ +#define EAGAIN EWOULDBLOCK +#endif /* defined (EWOULDBLOCK) */ +#else /* defined (EAGAIN) */ +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif /* ! defined (EWOULDBLOCK) */ +#endif /* defined (EAGAIN) */ + +#ifndef ENODATA +#define ENODATA EAGAIN +#endif + +/* Local variables. */ + +/* The EOF character, as set by fsysdep_terminal_raw. */ +static char bSeof; + +/* The SUSP character, as set by fsysdep_terminal_raw. */ +static char bStstp; + +/* Local functions. */ + +static const char *zsport_line P((const struct uuconf_port *qport)); +static void uscu_child P((struct sconnection *qconn, int opipe)); +static RETSIGTYPE uscu_alarm P((int isig)); +static int cscu_escape P((char *pbcmd, const char *zlocalname)); +static RETSIGTYPE uscu_alarm_kill P((int isig)); + +/* Return the device name for a port, or NULL if none. */ + +static const char * +zsport_line (qport) + const struct uuconf_port *qport; +{ + const char *zline; + + if (qport == NULL) + return NULL; + + switch (qport->uuconf_ttype) + { + default: + case UUCONF_PORTTYPE_STDIN: + return NULL; + case UUCONF_PORTTYPE_MODEM: + zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice; + break; + case UUCONF_PORTTYPE_DIRECT: + zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice; + break; + case UUCONF_PORTTYPE_TCP: + case UUCONF_PORTTYPE_TLI: + return NULL; + } + + if (zline == NULL) + zline = qport->uuconf_zname; + return zline; +} + +/* Check whether the user has legitimate access to a port. */ + +boolean +fsysdep_port_access (qport) + struct uuconf_port *qport; +{ + const char *zline; + char *zfree; + boolean fret; + + zline = zsport_line (qport); + if (zline == NULL) + return TRUE; + + zfree = NULL; + if (*zline != '/') + { + zfree = zbufalc (sizeof "/dev/" + strlen (zline)); + sprintf (zfree, "/dev/%s", zline); + zline = zfree; + } + + fret = access (zline, R_OK | W_OK) == 0; + ubuffree (zfree); + return fret; +} + +/* Return whether the given port is named by the given line. */ + +boolean +fsysdep_port_is_line (qport, zline) + struct uuconf_port *qport; + const char *zline; +{ + const char *zpline; + char *zfree1, *zfree2; + boolean fret; + + zpline = zsport_line (qport); + if (zpline == NULL) + return FALSE; + + if (strcmp (zline, zpline) == 0) + return TRUE; + + zfree1 = NULL; + zfree2 = NULL; + if (*zline != '/') + { + zfree1 = zbufalc (sizeof "/dev/" + strlen (zline)); + sprintf (zfree1, "/dev/%s", zline); + zline = zfree1; + } + if (*zpline != '/') + { + zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline)); + sprintf (zfree2, "/dev/%s", zpline); + zpline = zfree2; + } + + fret = strcmp (zline, zpline) == 0; + ubuffree (zfree1); + ubuffree (zfree2); + return fret; +} + +/* The cu program wants the system dependent layer to handle the + details of copying data from the communications port to the + terminal. This copying need only be done while executing + fsysdep_cu. On Unix, however, we set up a subprocess to do it all + the time. This subprocess must be controllable via the + fsysdep_cu_copy function. + + We keep a pipe open to the subprocess. When we want it to stop we + send it a signal, and then wait for it to write a byte to us over + the pipe. */ + +/* The subprocess pid. */ +static volatile pid_t iSchild; + +/* The pipe from the subprocess. */ +static int oSpipe; + +/* When we tell the child to stop, it sends this. */ +#define CHILD_STOPPED ('S') + +/* When we tell the child to start, it sends this. */ +#define CHILD_STARTED ('G') + +/* Initialize the subprocess, and have it start copying data. */ + +boolean +fsysdep_cu_init (qconn) + struct sconnection *qconn; +{ + int ai[2]; + + /* Write out anything we may have buffered up during the chat + script. We do this before forking the child only to make it easy + to move the child into a separate executable. */ + while (iPrecend != iPrecstart) + { + char *z; + int c; + + z = abPrecbuf + iPrecstart; + if (iPrecend > iPrecstart) + c = iPrecend - iPrecstart; + else + c = CRECBUFLEN - iPrecstart; + + iPrecstart = (iPrecstart + c) % CRECBUFLEN; + + while (c > 0) + { + int cwrote; + + cwrote = write (1, z, c); + if (cwrote <= 0) + { + if (cwrote < 0) + ulog (LOG_ERROR, "write: %s", strerror (errno)); + else + ulog (LOG_ERROR, "Line disconnected"); + return FALSE; + } + c -= cwrote; + z += cwrote; + } + } + + if (pipe (ai) < 0) + { + ulog (LOG_ERROR, "pipe: %s", strerror (errno)); + return FALSE; + } + + iSchild = ixsfork (); + if (iSchild < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + return FALSE; + } + + if (iSchild == 0) + { + (void) close (ai[0]); + uscu_child (qconn, ai[1]); + /*NOTREACHED*/ + } + + (void) close (ai[1]); + + oSpipe = ai[0]; + + return TRUE; +} + +/* Copy all data from the terminal to the communications port. If we + see an escape character following a newline character, read the + next character and return it. */ + +boolean +fsysdep_cu (qconn, pbcmd, zlocalname) + struct sconnection *qconn; + char *pbcmd; + const char *zlocalname; +{ + boolean fstart; + char b; + int c; + + fstart = TRUE; + + while (TRUE) + { + if (fsysdep_catch ()) + usysdep_start_catch (); + else + { + ulog (LOG_ERROR, (const char *) NULL); + return FALSE; + } + + c = read (0, &b, 1); + + usysdep_end_catch (); + + if (c <= 0) + break; + + if (fstart && b == *zCuvar_escape) + { + c = cscu_escape (pbcmd, zlocalname); + if (c <= 0) + break; + if (*pbcmd != b) + { + write (1, pbcmd, 1); + + /* For Unix, we let the eof character be the same as + '.', and we let the suspend character (if any) be the + same as 'z'. */ + if (*pbcmd == bSeof) + *pbcmd = '.'; + if (*pbcmd == bStstp) + *pbcmd = 'z'; + return TRUE; + } + } + if (! fconn_write (qconn, &b, (size_t) 1)) + return FALSE; + fstart = strchr (zCuvar_eol, b) != NULL; + } + + if (c < 0) + { + if (errno != EINTR) + ulog (LOG_ERROR, "read: %s", strerror (errno)); + else + ulog (LOG_ERROR, (const char *) NULL); + return FALSE; + } + + /* I'm not sure what's best in this case. */ + ulog (LOG_ERROR, "End of file on terminal"); + return FALSE; +} + +/* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */ + +volatile sig_atomic_t fScu_alarm; + +static RETSIGTYPE +uscu_alarm (isig) + int isig; +{ +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET + (void) signal (isig, uscu_alarm); +#endif + + fScu_alarm = TRUE; + +#if HAVE_RESTARTABLE_SYSCALLS + if (fSjmp) + longjmp (sSjmp_buf, 1); +#endif +} + +/* We've just seen an escape character. We print the host name, + optionally after a 1 second delay. We read the next character from + the terminal and return it. The 1 second delay on the host name is + mostly to be fancy; it lets ~~ look smoother. */ + +static int +cscu_escape (pbcmd, zlocalname) + char *pbcmd; + const char *zlocalname; +{ + CATCH_PROTECT int c; + + write (1, zCuvar_escape, 1); + + fScu_alarm = FALSE; + usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL); + + if (fsysdep_catch ()) + { + usysdep_start_catch (); + alarm (1); + } + + c = 0; + + while (TRUE) + { + if (fScu_alarm) + { + char b; + + fScu_alarm = FALSE; + b = '['; + write (1, &b, 1); + write (1, zlocalname, strlen (zlocalname)); + b = ']'; + write (1, &b, 1); + } + + if (c <= 0) + c = read (0, pbcmd, 1); + if (c >= 0 || errno != EINTR) + { + usysdep_end_catch (); + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + return c; + } + } +} + +/* A SIGALRM handler which does nothing but send a signal to the child + process and schedule another alarm. POSIX.1 permits kill and alarm + from a signal handler. The reference to static data may or may not + be permissible. */ + +static volatile sig_atomic_t iSsend_sig; + +static RETSIGTYPE +uscu_alarm_kill (isig) + int isig; +{ +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET + (void) signal (isig, uscu_alarm_kill); +#endif + + (void) kill (iSchild, iSsend_sig); + + alarm (1); +} + +/* Start or stop copying data from the communications port to the + terminal. We send a signal to the child process to tell it what to + do. Unfortunately, there are race conditions in the child, so we + keep sending it a signal once a second until it responds. We send + SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */ + +boolean +fsysdep_cu_copy (fcopy) + boolean fcopy; +{ + int ierr; + int c; + + usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); + if (fcopy) + iSsend_sig = SIGUSR1; + else + iSsend_sig = SIGUSR2; + + uscu_alarm_kill (SIGALRM); + + alarm (1); + + while (TRUE) + { + char b; + + c = read (oSpipe, &b, 1); + +#if DEBUG > 1 + if (c > 0) + DEBUG_MESSAGE1 (DEBUG_INCOMING, + "fsysdep_cu_copy: Got '%d'", b); +#endif + + if ((c < 0 && errno != EINTR) + || c == 0 + || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED))) + break; + + /* If none of the above conditions were true, then we either got + an EINTR error, in which case we probably timed out and the + SIGALRM handler resent the signal, or we read the wrong + character, in which case we will just read again from the + pipe. */ + } + + ierr = errno; + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + + if (c > 0) + return TRUE; + + if (c == 0) + ulog (LOG_ERROR, "EOF on child pipe"); + else + ulog (LOG_ERROR, "read: %s", strerror (ierr)); + + return FALSE; +} + +/* Shut down cu by killing the child process. */ + +boolean +fsysdep_cu_finish () +{ + (void) close (oSpipe); + + /* We hit the child with SIGTERM, give it two seconds to die, and + then send a SIGKILL. */ + if (kill (iSchild, SIGTERM) < 0) + { + /* Don't give an error if the child has already died. */ + if (errno != ESRCH) + ulog (LOG_ERROR, "kill: %s", strerror (errno)); + } + + usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); + iSsend_sig = SIGKILL; + alarm (2); + + (void) ixswait ((unsigned long) iSchild, "child"); + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + + return TRUE; +} + +/* Code for the child process. */ + +/* This signal handler just records the signal. In this case we only + care about which signal we received most recently. */ + +static volatile sig_atomic_t iSchild_sig; + +static RETSIGTYPE +uscu_child_handler (isig) + int isig; +{ +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET + (void) signal (isig, uscu_child_handler); +#endif + + iSchild_sig = isig; + +#if HAVE_RESTARTABLE_SYSCALLS + if (fSjmp) + longjmp (sSjmp_buf, 1); +#endif /* HAVE_RESTARTABLE_SYSCALLS */ +} + +/* The child process. This copies the port to the terminal, except + when it is stopped by a signal. It would be reasonable to write a + separate program for this, probably passing it the port on stdin. + This would reduce the memory requirements, since we wouldn't need a + second process holding all the configuration stuff, and also let it + work reasonably on 680x0 versions of MINIX. */ + +static void +uscu_child (qconn, opipe) + struct sconnection *qconn; + int opipe; +{ + CATCH_PROTECT int oport; + CATCH_PROTECT boolean fstopped, fgot; + CATCH_PROTECT int cwrite; + CATCH_PROTECT char abbuf[1024]; + + /* It would be nice if we could just use fsserial_read, but that + will log signals that we don't want logged. There should be a + generic way to extract the file descriptor from the port. */ + if (qconn->qport == NULL) + oport = 0; + else + { + switch (qconn->qport->uuconf_ttype) + { +#if DEBUG > 0 + default: + ulog (LOG_FATAL, "uscu_child: Can't happen"); + oport = -1; + break; +#endif + case UUCONF_PORTTYPE_STDIN: + oport = 0; + break; + case UUCONF_PORTTYPE_MODEM: + case UUCONF_PORTTYPE_DIRECT: + case UUCONF_PORTTYPE_TCP: + case UUCONF_PORTTYPE_TLI: + oport = ((struct ssysdep_conn *) qconn->psysdep)->o; + break; + } + } + + usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL); + usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL); + usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL); + usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL); + usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL); + usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL); + + fstopped = FALSE; + fgot = FALSE; + iSchild_sig = 0; + cwrite = 0; + + if (fsysdep_catch ()) + usysdep_start_catch (); + + while (TRUE) + { + int isig; + int c; + + /* There is a race condition here between checking the signal + and receiving a new and possibly different one. This is + solved by having the parent resend the signal until it gets a + response. */ + isig = iSchild_sig; + iSchild_sig = 0; + if (isig != 0) + { + char b; + + if (isig == SIGTERM) + exit (EXIT_SUCCESS); + + if (isig == SIGUSR1) + { + fstopped = FALSE; + b = CHILD_STARTED; + } + else + { + fstopped = TRUE; + b = CHILD_STOPPED; + cwrite = 0; + } + + c = write (opipe, &b, 1); + + /* Apparently on some systems we can get EAGAIN here. */ + if (c < 0 && + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) + c = 0; + + if (c <= 0) + { + /* Should we give an error message here? */ + (void) kill (getppid (), SIGHUP); + exit (EXIT_FAILURE); + } + } + + if (fstopped) + pause (); + else if (cwrite > 0) + { + char *zbuf; + + zbuf = abbuf; + while (cwrite > 0) + { + c = write (1, zbuf, cwrite); + + /* Apparently on some systems we can get EAGAIN here. */ + if (c < 0 && + (errno == EAGAIN + || errno == EWOULDBLOCK + || errno == ENODATA)) + c = 0; + + if (c < 0 && errno == EINTR) + break; + if (c <= 0) + { + /* Should we give an error message here? */ + (void) kill (getppid (), SIGHUP); + exit (EXIT_FAILURE); + } + cwrite -= c; + zbuf += c; + } + } + else + { + /* On some systems apparently read will return 0 until + something has been written to the port. We therefore + accept a 0 return until after we have managed to read + something. Setting errno to 0 apparently avoids a + problem on Coherent. */ + errno = 0; + c = read (oport, abbuf, sizeof abbuf); + + /* Apparently on some systems we can get EAGAIN here. */ + if (c < 0 && + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) + c = 0; + + if ((c == 0 && fgot) + || (c < 0 && errno != EINTR)) + { + /* This can be a normal way to exit, depending on just + how the connection is dropped. */ + (void) kill (getppid (), SIGHUP); + exit (EXIT_SUCCESS); + } + if (c > 0) + { + fgot = TRUE; + cwrite = c; + } + } + } +} + +/* Terminal control routines. */ + +/* Whether file descriptor 0 is attached to a terminal or not. */ +static boolean fSterm; + +/* Whether we are doing local echoing. */ +static boolean fSlocalecho; + +/* The original state of the terminal. */ +static sterminal sSterm_orig; + +/* The new state of the terminal. */ +static sterminal sSterm_new; + +#if ! HAVE_BSD_TTY +#ifdef SIGTSTP +/* Whether SIGTSTP is being ignored. */ +static boolean fStstp_ignored; +#endif +#endif + +/* Set the terminal into raw mode. */ + +boolean +fsysdep_terminal_raw (flocalecho) + boolean flocalecho; +{ + fSlocalecho = flocalecho; + + /* This defaults may be overriden below. */ + bSeof = '\004'; + bStstp = '\032'; + + if (! fgetterminfo (0, &sSterm_orig)) + { + fSterm = FALSE; + return TRUE; + } + + fSterm = TRUE; + + sSterm_new = sSterm_orig; + +#if HAVE_BSD_TTY + + /* We use CBREAK mode rather than RAW mode, because RAW mode turns + off all output processing, which we don't want to do. This means + that we have to disable the interrupt characters, which we do by + setting them to -1. */ + bSeof = sSterm_orig.stchars.t_eofc; + + sSterm_new.stchars.t_intrc = -1; + sSterm_new.stchars.t_quitc = -1; + sSterm_new.stchars.t_startc = -1; + sSterm_new.stchars.t_stopc = -1; + sSterm_new.stchars.t_eofc = -1; + sSterm_new.stchars.t_brkc = -1; + + bStstp = sSterm_orig.sltchars.t_suspc; + + sSterm_new.sltchars.t_suspc = -1; + sSterm_new.sltchars.t_dsuspc = -1; + sSterm_new.sltchars.t_rprntc = -1; + sSterm_new.sltchars.t_flushc = -1; + sSterm_new.sltchars.t_werasc = -1; + sSterm_new.sltchars.t_lnextc = -1; + + if (! flocalecho) + { + sSterm_new.stty.sg_flags |= (CBREAK | ANYP); + sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM); + } + else + { + sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO); + sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM); + } + +#endif /* HAVE_BSD_TTY */ + +#if HAVE_SYSV_TERMIO + + bSeof = sSterm_new.c_cc[VEOF]; + if (! flocalecho) + sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL); + else + sSterm_new.c_lflag &=~ (ICANON | ISIG); + sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); + sSterm_new.c_oflag &=~ (OPOST); + sSterm_new.c_cc[VMIN] = 1; + sSterm_new.c_cc[VTIME] = 0; + +#endif /* HAVE_SYSV_TERMIO */ + +#if HAVE_POSIX_TERMIOS + + bSeof = sSterm_new.c_cc[VEOF]; + bStstp = sSterm_new.c_cc[VSUSP]; + if (! flocalecho) + sSterm_new.c_lflag &=~ + (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL); + else + sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG); + sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); + sSterm_new.c_oflag &=~ (OPOST); + sSterm_new.c_cc[VMIN] = 1; + sSterm_new.c_cc[VTIME] = 0; + +#endif /* HAVE_POSIX_TERMIOS */ + + if (! fsetterminfo (0, &sSterm_new)) + { + ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Restore the terminal to its original setting. */ + +boolean +fsysdep_terminal_restore () +{ + if (! fSterm) + return TRUE; + + if (! fsetterminfo (0, &sSterm_orig)) + { + ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno)); + return FALSE; + } + return TRUE; +} + +/* Read a line from the terminal. This will be called after + fsysdep_terminal_raw has been called. */ + +char * +zsysdep_terminal_line (zprompt) + const char *zprompt; +{ + CATCH_PROTECT size_t cbuf = 0; + CATCH_PROTECT char *zbuf = NULL; + CATCH_PROTECT size_t cgot = 0; + + if (zprompt != NULL && *zprompt != '\0') + (void) write (1, zprompt, strlen (zprompt)); + + /* Forgot about any previous SIGINT or SIGQUIT signals we may have + received. We don't worry about the race condition here, since we + can't get these signals from the terminal at the moment and it's + not too likely that somebody else will be sending them to us. */ + afSignal[INDEXSIG_SIGINT] = 0; + afSignal[INDEXSIG_SIGQUIT] = 0; + + if (! fsysdep_terminal_restore ()) + return NULL; + + if (fsysdep_catch ()) + { + usysdep_start_catch (); + cbuf = 0; + zbuf = NULL; + cgot = 0; + } + + while (TRUE) + { + char b; + int c; + + if (afSignal[INDEXSIG_SIGINT] + || afSignal[INDEXSIG_SIGQUIT]) + { + usysdep_end_catch (); + /* Make sure the signal is logged. */ + ulog (LOG_ERROR, (const char *) NULL); + /* Return an empty string. */ + cgot = 0; + break; + } + + /* There's a race here between checking the signals and calling + read. It just means that the user will have to hit ^C more + than once. */ + + c = read (0, &b, 1); + if (c < 0) + { + if (errno == EINTR) + continue; + usysdep_end_catch (); + ulog (LOG_ERROR, "read: %s", strerror (errno)); + (void) fsysdep_terminal_raw (fSlocalecho); + return NULL; + } + if (c == 0) + { + /* I'm not quite sure what to do here. */ + usysdep_end_catch (); + ulog (LOG_ERROR, "EOF on terminal"); + (void) fsysdep_terminal_raw (fSlocalecho); + return NULL; + } + + if (cgot >= cbuf) + { + char *znew; + + cbuf += 64; + znew = zbufalc (cbuf); + if (zbuf != NULL) + { + memcpy (znew, zbuf, cgot); + ubuffree (zbuf); + } + zbuf = znew; + } + + zbuf[cgot] = b; + + ++cgot; + + if (b == '\n') + { + usysdep_end_catch (); + break; + } + } + + if (cgot >= cbuf) + { + char *znew; + + ++cbuf; + znew = zbufalc (cbuf); + if (zbuf != NULL) + { + memcpy (znew, zbuf, cgot); + ubuffree (zbuf); + } + zbuf = znew; + } + + zbuf[cgot] = '\0'; + + if (! fsysdep_terminal_raw (fSlocalecho)) + return NULL; + + return zbuf; +} + +/* Write a line to the terminal with a trailing newline. */ + +boolean +fsysdep_terminal_puts (zline) + const char *zline; +{ + char *zalc, *zprint; + size_t clen; + + if (zline == NULL) + { + zalc = zbufalc (2); + clen = 0; + } + else + { + clen = strlen (zline); + zalc = zbufalc (clen + 2); + memcpy (zalc, zline, clen); + } + + if (fSterm) + { + zalc[clen] = '\r'; + ++clen; + } + zalc[clen] = '\n'; + ++clen; + + zprint = zalc; + while (clen > 0) + { + int c; + + c = write (1, zprint, clen); + if (c <= 0) + { + ubuffree (zalc); + ulog (LOG_ERROR, "write: %s", strerror (errno)); + return FALSE; + } + clen -= c; + zprint += c; + } + + ubuffree (zalc); + + return TRUE; +} + +/* Allow or disallow signals from the terminal. */ + +boolean +fsysdep_terminal_signals (faccept) + boolean faccept; +{ +#if HAVE_BSD_TTY + + if (faccept) + { + sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc; + sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc; + } + else + { + sSterm_new.stchars.t_intrc = -1; + sSterm_new.stchars.t_quitc = -1; + } + +#else /* ! HAVE_BSD_TTY */ + + if (faccept) + sSterm_new.c_lflag |= ISIG; + else + sSterm_new.c_lflag &=~ ISIG; + +#ifdef SIGTSTP + /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This + function will be called with faccept TRUE before it is called + with faccept FALSE, so fStstp_ignored will be correctly + initialized. */ + if (faccept) + usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored); + else if (! fStstp_ignored) + usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL); +#endif + +#endif /* ! HAVE_BSD_TTY */ + + if (! fsetterminfo (0, &sSterm_new)) + { + ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Start up a command, or possibly just a shell. Optionally attach + stdin or stdout to the port. We attach directly to the port, + rather than copying the data ourselves. */ + +boolean +fsysdep_shell (qconn, zcmd, tcmd) + struct sconnection *qconn; + const char *zcmd; + enum tshell_cmd tcmd; +{ + const char *azargs[4]; + int oread, owrite; + int aidescs[3]; + pid_t ipid; + + azargs[0] = "/bin/sh"; + if (zcmd == NULL || *zcmd == '\0') + azargs[1] = NULL; + else + { + azargs[1] = "-c"; + azargs[2] = zcmd; + azargs[3] = NULL; + } + + if (qconn->qport == NULL) + { + oread = 0; + owrite = 1; + } + else + { + switch (qconn->qport->uuconf_ttype) + { + default: + oread = owrite = -1; + break; + case UUCONF_PORTTYPE_STDIN: + oread = 0; + owrite = 1; + break; + case UUCONF_PORTTYPE_MODEM: + case UUCONF_PORTTYPE_DIRECT: + case UUCONF_PORTTYPE_TCP: + case UUCONF_PORTTYPE_TLI: + oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o; + break; + } + } + + aidescs[0] = 0; + aidescs[1] = 1; + aidescs[2] = 2; + + if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT) + aidescs[0] = oread; + if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT) + aidescs[1] = owrite; + + ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL, + FALSE, FALSE, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno)); + return FALSE; + } + + return ixswait ((unsigned long) ipid, "shell") == 0; +} + +/* Change directories. */ + +boolean +fsysdep_chdir (zdir) + const char *zdir; +{ + if (zdir == NULL || *zdir == '\0') + { + zdir = getenv ("HOME"); + if (zdir == NULL) + { + ulog (LOG_ERROR, "HOME not defined"); + return FALSE; + } + } + if (chdir (zdir) < 0) + { + ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno)); + return FALSE; + } + return TRUE; +} + +/* Suspend the current process. */ + +boolean +fsysdep_suspend () +{ +#ifndef SIGTSTP + return fsysdep_terminal_puts ("[process suspension not supported]"); +#else + return kill (getpid (), SIGTSTP) == 0; +#endif +} diff --git a/gnu/libexec/uucp/libunix/cwd.c b/gnu/libexec/uucp/libunix/cwd.c new file mode 100644 index 00000000000..433025db6c3 --- /dev/null +++ b/gnu/libexec/uucp/libunix/cwd.c @@ -0,0 +1,55 @@ +/* cwd.c + Routines dealing with the current working directory. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* See whether running this file through zsysdep_add_cwd would require + knowing the current working directory. This is used to avoid + determining the cwd if it will not be needed. */ + +boolean +fsysdep_needs_cwd (zfile) + const char *zfile; +{ + return *zfile != '/' && *zfile != '~'; +} + +/* Expand a local file, putting relative pathnames in the current + working directory. Note that ~/file is placed in the public + directory, rather than in the user's home directory. This is + consistent with other UUCP packages. */ + +char * +zsysdep_local_file_cwd (zfile, zpubdir) + const char *zfile; + const char *zpubdir; +{ + if (*zfile == '/') + return zbufcpy (zfile); + else if (*zfile == '~') + return zsysdep_local_file (zfile, zpubdir); + else + return zsysdep_add_cwd (zfile); +} + +/* Add the current working directory to a remote file name. */ + +char * +zsysdep_add_cwd (zfile) + const char *zfile; +{ + if (*zfile == '/' || *zfile == '~') + return zbufcpy (zfile); + + if (zScwd == NULL) + { + ulog (LOG_ERROR, "Can't determine current directory"); + return NULL; + } + + return zsysdep_in_dir (zScwd, zfile); +} diff --git a/gnu/libexec/uucp/libunix/detach.c b/gnu/libexec/uucp/libunix/detach.c new file mode 100644 index 00000000000..41e1969b5ef --- /dev/null +++ b/gnu/libexec/uucp/libunix/detach.c @@ -0,0 +1,186 @@ +/* detach.c + Detach from the controlling terminal. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "system.h" +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef TIOCNOTTY +#define HAVE_TIOCNOTTY 1 +#else +#define HAVE_TIOCNOTTY 0 +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +/* Detach from the controlling terminal. This is called by uucico if + it is calling out to another system, so that it can receive SIGHUP + signals from the port it calls out on. It is also called by uucico + just before it starts uuxqt, so that uuxqt is completely + independent of the terminal. */ + +void +usysdep_detach () +{ +#if ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY + + pid_t igrp; + + /* First make sure we are not a process group leader. If we have + TIOCNOTTY, this doesn't matter, since TIOCNOTTY sets our process + group to 0 anyhow. */ + +#if HAVE_BSD_PGRP + igrp = getpgrp (0); +#else + igrp = getpgrp (); +#endif + + if (igrp == getpid ()) + { + boolean fignored; + pid_t ipid; + + /* Ignore SIGHUP, since our process group leader is about to + die. */ + usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + /* We'll always wind up as a child of process number 1, right? + Right? We have to wait for our parent to die before + reenabling SIGHUP. */ + while (getppid () != 1) + sleep (1); + + ulog_id (getpid ()); + + /* Restore SIGHUP catcher if it wasn't being ignored. */ + if (! fignored) + usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL); + } + +#endif /* ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY */ + +#if HAVE_TIOCNOTTY + /* Lose the original controlling terminal. If standard input has + been reopened to /dev/null, this will do no harm. If another + port has been opened to become the controlling terminal, it + should have been detached when it was closed. */ + (void) ioctl (0, TIOCNOTTY, (char *) NULL); +#endif + + /* Close stdin, stdout and stderr and reopen them on /dev/null, to + make sure we have no connection at all to the terminal. */ + (void) close (0); + (void) close (1); + (void) close (2); + if (open ((char *) "/dev/null", O_RDONLY) != 0 + || open ((char *) "/dev/null", O_WRONLY) != 1 + || open ((char *) "/dev/null", O_WRONLY) != 2) + ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno)); + +#if HAVE_BSD_PGRP + + /* Make sure our process group ID is set to 0. On BSD TIOCNOTTY + should already have set it 0, so this will do no harm. On System + V we presumably did not execute the TIOCNOTTY call, but the + System V setpgrp will detach the controlling terminal anyhow. + This lets us use the same code on both BSD and System V, provided + it compiles correctly, which life easier for the configure + script. We don't output an error if we got EPERM because some + BSD variants don't permit this usage of setpgrp (which means they + don't provide any way to pick up a new controlling terminal). */ + + if (setpgrp (0, 0) < 0) + { + if (errno != EPERM) + ulog (LOG_ERROR, "setpgrp: %s", strerror (errno)); + } + +#else /* ! HAVE_BSD_PGRP */ + +#if HAVE_SETSID + + /* Under POSIX the setsid call creates a new session for which we + are the process group leader. It also detaches us from our + controlling terminal. I'm using the BSD setpgrp call first + because they should be equivalent for my purposes, but it turns + out that on Ultrix 4.0 setsid prevents us from ever acquiring + another controlling terminal (it does not change our process + group, and Ultrix 4.0 prevents us from setting our process group + to 0). */ + (void) setsid (); + +#else /* ! HAVE_SETSID */ + +#if HAVE_SETPGRP + + /* Now we assume we have the System V setpgrp, which takes no + arguments, and we couldn't compile the HAVE_BSD_PGRP code above + because there was a prototype somewhere in scope. On System V + setpgrp makes us the leader of a new process group and also + detaches the controlling terminal. */ + + if (setpgrp () < 0) + ulog (LOG_ERROR, "setpgrp: %s", strerror (errno)); + +#else /* ! HAVE_SETPGRP */ + + #error Must detach from controlling terminal + +#endif /* HAVE_SETPGRP */ +#endif /* ! HAVE_SETSID */ +#endif /* ! HAVE_BSD_PGRP */ + + /* At this point we have completely detached from our controlling + terminal. The next terminal device we open will probably become + our controlling terminal. */ +} diff --git a/gnu/libexec/uucp/libunix/dirent.c b/gnu/libexec/uucp/libunix/dirent.c new file mode 100644 index 00000000000..83db496cabb --- /dev/null +++ b/gnu/libexec/uucp/libunix/dirent.c @@ -0,0 +1,123 @@ +/* dirent.c + Replacements for opendir, readdir and closedir for the original + Unix filesystem only. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* Simple emulations of opendir/readdir/closedir for systems which + have the original format of Unix directories. It's probably better + to get Doug Gwyn's public domain set of emulation functions. */ + +DIR * +opendir (zdir) + const char *zdir; +{ + int o; + struct stat s; + DIR *qret; + + o = open ((char *) zdir, O_RDONLY | O_NOCTTY, 0); + if (o < 0) + return NULL; + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0 + || fstat (o, &s) < 0) + { + int isave; + + isave = errno; + (void) close (o); + errno = isave; + return NULL; + } + if (! S_ISDIR (s.st_mode)) + { + (void) close (o); + errno = ENOTDIR; + return NULL; + } + qret = (DIR *) xmalloc (sizeof (DIR)); + qret->o = o; + return qret; +} + +struct dirent * +readdir (q) + DIR *q; +{ + struct direct sdir; + int cgot; + + do + { + cgot = read (q->o, &sdir, sizeof (struct direct)); + if (cgot <= 0) + return NULL; + if (cgot != sizeof (struct direct)) + { + errno = ENOENT; + return NULL; + } + } + while (sdir.d_ino == 0); + + strncpy (q->s.d_name, sdir.d_name, DIRSIZ); + q->s.d_name[DIRSIZ] = '\0'; + return &q->s; +} + +int +closedir (q) + DIR *q; +{ + int o; + + o = q->o; + xfree (q); + return close (o); +} diff --git a/gnu/libexec/uucp/libunix/dup2.c b/gnu/libexec/uucp/libunix/dup2.c new file mode 100644 index 00000000000..6a7359fe92e --- /dev/null +++ b/gnu/libexec/uucp/libunix/dup2.c @@ -0,0 +1,69 @@ +/* dup2.c + The Unix dup2 function, for systems which only have dup. + + Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc. + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +/* I basically took this from the emacs 18.57 distribution, although I + cleaned it up a bit and made it POSIX compliant. */ + +int +dup2 (oold, onew) + int oold; + int onew; +{ + if (oold == onew) + return onew; + (void) close (onew); + +#ifdef F_DUPFD + return fcntl (oold, F_DUPFD, onew); +#else + { + int onext, oret, isave; + + onext = dup (oold); + if (onext == onew) + return onext; + if (onext < 0) + return -1; + oret = dup2 (oold, onew); + isave = errno; + (void) close (onext); + errno = isave; + return oret; + } +#endif +} diff --git a/gnu/libexec/uucp/libunix/efopen.c b/gnu/libexec/uucp/libunix/efopen.c new file mode 100644 index 00000000000..7e360b61687 --- /dev/null +++ b/gnu/libexec/uucp/libunix/efopen.c @@ -0,0 +1,132 @@ +/* efopen.c + Open a stdio file with appropriate permissions. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_APPEND +#ifdef FAPPEND +#define O_APPEND FAPPEND +#endif +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +FILE * +esysdep_fopen (zfile, fpublic, fappend, fmkdirs) + const char *zfile; + boolean fpublic; + boolean fappend; + boolean fmkdirs; +{ + int imode; + int o; + FILE *e; + + if (fpublic) + imode = IPUBLIC_FILE_MODE; + else + imode = IPRIVATE_FILE_MODE; + + if (! fappend) + o = creat ((char *) zfile, imode); + else + { +#ifdef O_CREAT + o = open ((char *) zfile, + O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, + imode); +#else + o = open ((char *) zfile, O_WRONLY | O_NOCTTY); + if (o < 0 && errno == ENOENT) + o = creat ((char *) zfile, imode); +#endif /* ! defined (O_CREAT) */ + } + + if (o < 0) + { + if (errno == ENOENT && fmkdirs) + { + if (! fsysdep_make_dirs (zfile, fpublic)) + return NULL; + if (! fappend) + o = creat ((char *) zfile, imode); + else + { +#ifdef O_CREAT + o = open ((char *) zfile, + O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, + imode); +#else + o = creat ((char *) zfile, imode); +#endif + } + } + if (o < 0) + { + ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); + return NULL; + } + } + +#ifndef O_CREAT +#ifdef O_APPEND + if (fappend) + { + if (fcntl (o, F_SETFL, O_APPEND) < 0) + { + ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile, + strerror (errno)); + (void) close (o); + return NULL; + } + } +#endif /* defined (O_APPEND) */ +#endif /* ! defined (O_CREAT) */ + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile, + strerror (errno)); + (void) close (o); + return NULL; + } + + if (fappend) + e = fdopen (o, (char *) "a"); + else + e = fdopen (o, (char *) "w"); + + if (e == NULL) + { + ulog (LOG_ERROR, "fdopen: %s", strerror (errno)); + (void) close (o); + } + + return e; +} diff --git a/gnu/libexec/uucp/libunix/epopen.c b/gnu/libexec/uucp/libunix/epopen.c new file mode 100644 index 00000000000..dec1b3999d6 --- /dev/null +++ b/gnu/libexec/uucp/libunix/epopen.c @@ -0,0 +1,85 @@ +/* epopen.c + A version of popen that goes through ixsspawn. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +/* A version of popen that goes through ixsspawn. This actually takes + an array of arguments rather than a string, and takes a boolean + read/write value rather than a string. It sets *pipid to the + process ID of the child. */ + +FILE * +espopen (pazargs, frd, pipid) + const char **pazargs; + boolean frd; + pid_t *pipid; +{ + int aidescs[3]; + pid_t ipid; + FILE *eret; + + if (frd) + { + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_READ_PIPE; + } + else + { + aidescs[0] = SPAWN_WRITE_PIPE; + aidescs[1] = SPAWN_NULL; + } + aidescs[2] = SPAWN_NULL; + + ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, + (const char *) NULL, FALSE, TRUE, + (const char *) NULL, (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + return NULL; + + if (frd) + eret = fdopen (aidescs[1], (char *) "r"); + else + eret = fdopen (aidescs[0], (char *) "w"); + if (eret == NULL) + { + int ierr; + + ierr = errno; + (void) close (frd ? aidescs[1] : aidescs[0]); + (void) kill (ipid, SIGKILL); + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + errno = ierr; + return NULL; + } + + *pipid = ipid; + + return eret; +} diff --git a/gnu/libexec/uucp/libunix/exists.c b/gnu/libexec/uucp/libunix/exists.c new file mode 100644 index 00000000000..9473922f0d5 --- /dev/null +++ b/gnu/libexec/uucp/libunix/exists.c @@ -0,0 +1,16 @@ +/* exists.c + Check whether a file exists. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "system.h" + +boolean +fsysdep_file_exists (zfile) + const char *zfile; +{ + struct stat s; + + return stat ((char *) zfile, &s) == 0; +} diff --git a/gnu/libexec/uucp/libunix/filnam.c b/gnu/libexec/uucp/libunix/filnam.c new file mode 100644 index 00000000000..62054767b89 --- /dev/null +++ b/gnu/libexec/uucp/libunix/filnam.c @@ -0,0 +1,376 @@ +/* filnam.c + Get names to use for UUCP files. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +/* We need a definition for SEEK_SET. */ + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +/* External functions. */ +#ifndef lseek +extern off_t lseek (); +#endif + +#define ZCHARS \ + "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz" + +/* Local functions. */ + +static boolean fscmd_seq P((const char *zsystem, char *zseq)); +static char *zsfile_name P((int btype, const char *zsystem, + const char *zlocalname, int bgrade, + boolean fxqt, char *ztname, char *zdname, + char *zxname)); + +/* Get a new command sequence number (this is not a sequence number to + be used for communicating with another system, but a sequence + number to be used when generating the name of a command file). + The sequence number is placed into zseq, which should be five + characters long. */ + +static boolean +fscmd_seq (zsystem, zseq) + const char *zsystem; + char *zseq; +{ + boolean ferr; + char *zfree; + const char *zfile; + int o; + int i; + + /* Lock the sequence file. This may not be correct for all systems, + but it only matters if the system UUCP and this UUCP are running + at the same time. */ + while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr)) + { + if (ferr || FGOT_SIGNAL ()) + return FALSE; + sleep (5); + } + + zfree = NULL; + +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + zfile = "SEQF"; +#endif +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + zfree = zsysdep_in_dir (".Sequence", zsystem); + zfile = zfree; +#endif +#if SPOOLDIR_ULTRIX + if (! fsultrix_has_spool (zsystem)) + zfile = "sys/DEFAULT/.SEQF"; + else + { + zfree = zsappend3 ("sys", zsystem, ".SEQF"); + zfile = zfree; + } +#endif /* SPOOLDIR_ULTRIX */ +#if SPOOLDIR_TAYLOR + zfree = zsysdep_in_dir (zsystem, "SEQF"); + zfile = zfree; +#endif /* SPOOLDIR_TAYLOR */ + +#ifdef O_CREAT + o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE); +#else + o = open ((char *) zfile, O_RDWR | O_NOCTTY); + if (o < 0 && errno == ENOENT) + { + o = creat ((char *) zfile, IPUBLIC_FILE_MODE); + if (o >= 0) + { + (void) close (o); + o = open ((char *) zfile, O_RDWR | O_NOCTTY); + } + } +#endif + + if (o < 0) + { + if (errno == ENOENT) + { + if (! fsysdep_make_dirs (zfile, FALSE)) + { + (void) fsdo_unlock ("LCK..SEQ", TRUE); + return FALSE; + } +#ifdef O_CREAT + o = open ((char *) zfile, + O_RDWR | O_CREAT | O_NOCTTY, + IPUBLIC_FILE_MODE); +#else + o = creat ((char *) zfile, IPUBLIC_FILE_MODE); + if (o >= 0) + { + (void) close (o); + o = open ((char *) zfile, O_RDWR | O_NOCTTY); + } +#endif + } + if (o < 0) + { + ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); + (void) fsdo_unlock ("LCK..SEQ", TRUE); + return FALSE; + } + } + + if (read (o, zseq, CSEQLEN) != CSEQLEN) + strcpy (zseq, "0000"); + zseq[CSEQLEN] = '\0'; + + /* We must add one to the sequence number and return the new value. + On Ultrix, arbitrary characters are allowed in the sequence + number. On other systems, the sequence number apparently must be + in hex. */ +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_HDB || SPOOLDIR_SVR4 + i = (int) strtol (zseq, (char **) NULL, 16); + ++i; + if (i > 0xffff) + i = 0; + /* The sprintf argument has CSEQLEN built into it. */ + sprintf (zseq, "%04x", (unsigned int) i); +#endif +#if SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR + for (i = CSEQLEN - 1; i >= 0; i--) + { + const char *zdig; + + zdig = strchr (ZCHARS, zseq[i]); + if (zdig == NULL || zdig[0] == '\0' || zdig[1] == '\0') + zseq[i] = '0'; + else + { + zseq[i] = zdig[1]; + break; + } + } +#endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */ + + if (lseek (o, (off_t) 0, SEEK_SET) < 0 + || write (o, zseq, CSEQLEN) != CSEQLEN + || close (o) < 0) + { + ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno)); + (void) close (o); + (void) fsdo_unlock ("LCK..SEQ", TRUE); + return FALSE; + } + + (void) fsdo_unlock ("LCK..SEQ", TRUE); + + return TRUE; +} + +/* Get the name of a command or data file for a remote system. The + btype argument should be C for a command file or D for a data file. + If the grade of a data file is X, it is assumed that this is going + to become an execute file on some other system. The zsystem + argument is the system that the file will be transferred to. The + ztname argument will be set to a file name that could be passed to + zsysdep_spool_file_name. The zdname argument, if not NULL, will be + set to a data file name appropriate for the remote system. The + zxname argument, if not NULL, will be set to the name of an execute + file on the remote system. None of the names will be more than 14 + characters long. */ + +/*ARGSUSED*/ +static char * +zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname) + int btype; + const char *zsystem; + const char *zlocalname; + int bgrade; + boolean fxqt; + char *ztname; + char *zdname; + char *zxname; +{ + char abseq[CSEQLEN + 1]; + char absimple[11 + CSEQLEN]; + char *zname; + + if (zlocalname == NULL) + zlocalname = zSlocalname; + + while (TRUE) + { + if (! fscmd_seq (zsystem, abseq)) + return NULL; + + if (btype == 'C') + { +#if ! SPOOLDIR_TAYLOR + sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq); +#else + sprintf (absimple, "C.%c%s", bgrade, abseq); +#endif + } + else if (btype == 'D') + { + /* This name doesn't really matter that much; it's just the + name we use on the local system. The name we use on the + remote system, which we return in zdname, should contain + our system name so that remote UUCP's running SPOOLDIR_V2 + and the like can distinguish while files come from which + systems. */ +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq); +#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ +#if ! SPOOLDIR_TAYLOR + sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq); +#else /* SPOOLDIR_TAYLOR */ + if (fxqt) + sprintf (absimple, "D.X%s", abseq); + else + sprintf (absimple, "D.%s", abseq); +#endif /* SPOOLDIR_TAYLOR */ +#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ + } +#if DEBUG > 0 + else + ulog (LOG_FATAL, "zsfile_name: Can't happen"); +#endif + + zname = zsfind_file (absimple, zsystem, bgrade); + if (zname == NULL) + return NULL; + + if (! fsysdep_file_exists (zname)) + break; + + ubuffree (zname); + } + + if (ztname != NULL) + strcpy (ztname, absimple); + + if (zdname != NULL) + sprintf (zdname, "D.%.7s%c%s", zlocalname, bgrade, abseq); + + if (zxname != NULL) + sprintf (zxname, "X.%.7s%c%s", zlocalname, bgrade, abseq); + + return zname; +} + +/* Return a name to use for a data file to be copied to another + system. The name returned will be for a real file. The zlocalname + argument is the local name as seen by the remote system, the bgrade + argument is the file grade, and the fxqt argument is TRUE if this + file will become an execution file. The ztname argument, if not + NULL, will be set to a name that could be passed to + zsysdep_spool_file_name to get back the return value of this + function. The zdname argument, if not NULL, will be set to a name + that the file could be given on another system. The zxname + argument, if not NULL, will be set to a name for an execute file on + another system. */ + +char * +zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname, + zxname) + const struct uuconf_system *qsys; + const char *zlocalname; + int bgrade; + boolean fxqt; + char *ztname; + char *zdname; + char *zxname; +{ + return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt, + ztname, zdname, zxname); +} + +/* Get a command file name. */ + +char * +zscmd_file (qsys, bgrade) + const struct uuconf_system *qsys; + int bgrade; +{ + return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL, + bgrade, FALSE, (char *) NULL, (char *) NULL, + (char *) NULL); +} + +/* Return a name for an execute file to be created locally. This is + used by uux to execute a command locally with remote files. */ + +char * +zsysdep_xqt_file_name () +{ + char abseq[CSEQLEN + 1]; + char absx[11 + CSEQLEN]; + char *zname; + + while (TRUE) + { + if (! fscmd_seq (zSlocalname, abseq)) + return NULL; + + sprintf (absx, "X.%.7sX%s", zSlocalname, abseq); + + zname = zsfind_file (absx, zSlocalname, -1); + if (zname == NULL) + return NULL; + + if (! fsysdep_file_exists (zname)) + break; + + ubuffree (zname); + } + + return zname; +} diff --git a/gnu/libexec/uucp/libunix/fsusg.c b/gnu/libexec/uucp/libunix/fsusg.c new file mode 100644 index 00000000000..e2b40a8ad5a --- /dev/null +++ b/gnu/libexec/uucp/libunix/fsusg.c @@ -0,0 +1,231 @@ +/* fsusage.c -- return space usage of mounted filesystems + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file was modified slightly by Ian Lance Taylor, December 1992, + for use with Taylor UUCP. */ + +#include "uucp.h" +#include "sysdep.h" +#include "fsusg.h" + +int statfs (); + +#if STAT_STATFS2_BSIZE +#ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */ +#include <sys/vfs.h> +#endif +#endif + +#if STAT_STATFS2_FSIZE /* 4.4BSD. */ +#include <sys/mount.h> +#endif + +#if STAT_STATFS2_FS_DATA /* Ultrix. */ +#include <sys/param.h> +#include <sys/mount.h> +#endif + +#if STAT_USTAT /* SVR2 and others. */ +#include <ustat.h> +#endif + +#if STAT_STATFS4 /* SVR3, Dynix, Irix. */ +#include <sys/statfs.h> +#endif +#ifdef _AIX +#ifdef _IBMR2 /* AIX RS6000. */ +#include <sys/statfs.h> +#endif +#endif + +#ifdef _AIX +#ifdef _I386 /* AIX PS/2. */ +#include <sys/stat.h> +#include <sys/dustat.h> +#endif +#endif + +#if STAT_STATVFS /* SVR4. */ +#include <sys/statvfs.h> +int statvfs (); +#endif + +#define STAT_NONE 0 + +#if ! STAT_STATVFS +#if ! STAT_STATFS2_BSIZE +#if ! STAT_STATFS2_FSIZE +#if ! STAT_STATFS2_FS_DATA +#if ! STAT_STATFS4 +#if ! STAT_USTAT +#undef STAT_NONE +#define STAT_NONE 1 +#endif +#endif +#endif +#endif +#endif +#endif + +#if ! STAT_NONE + +/* Return the number of TOSIZE-byte blocks used by + BLOCKS FROMSIZE-byte blocks, rounding up. */ + +static long +adjust_blocks (blocks, fromsize, tosize) + long blocks; + int fromsize, tosize; +{ + if (fromsize == tosize) /* E.g., from 512 to 512. */ + return blocks; + else if (fromsize > tosize) /* E.g., from 2048 to 512. */ + return blocks * (fromsize / tosize); + else /* E.g., from 256 to 512. */ + return (blocks + 1) / (tosize / fromsize); +} + +#endif + +/* Fill in the fields of FSP with information about space usage for + the filesystem on which PATH resides. + DISK is the device on which PATH is mounted, for space-getting + methods that need to know it. + Return 0 if successful, -1 if not. */ + +int +get_fs_usage (path, disk, fsp) + char *path, *disk; + struct fs_usage *fsp; +{ +#if STAT_NONE + return -1; +#endif + +#if STAT_STATFS2_FS_DATA /* Ultrix. */ + struct fs_data fsd; + + if (statfs (path, &fsd) != 1) + return -1; +#define convert_blocks(b) adjust_blocks ((b), 1024, 512) + fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot); + fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree); + fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen); + fsp->fsu_files = fsd.fd_req.gtot; + fsp->fsu_ffree = fsd.fd_req.gfree; +#endif + +#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */ + struct statfs fsd; + + if (statfs (path, &fsd) < 0) + return -1; +#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512) +#endif + +#if STAT_STATFS2_FSIZE /* 4.4BSD. */ + struct statfs fsd; + + if (statfs (path, &fsd) < 0) + return -1; +#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512) +#endif + +#if STAT_STATFS4 /* SVR3, Dynix, Irix. */ + struct statfs fsd; + + if (statfs (path, &fsd, sizeof fsd, 0) < 0) + return -1; + /* Empirically, the block counts on most SVR3 and SVR3-derived + systems seem to always be in terms of 512-byte blocks, + no matter what value f_bsize has. */ +#define convert_blocks(b) (b) +#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */ +#define f_bavail f_bfree +#endif +#endif + +#if STAT_STATVFS /* SVR4. */ + struct statvfs fsd; + + if (statvfs (path, &fsd) < 0) + return -1; + /* f_frsize isn't guaranteed to be supported. */ +#define convert_blocks(b) \ + adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512) +#endif + +#if STAT_USTAT + { + struct stat sstat; + struct ustat s; + + if (stat (path, &sstat) < 0 + || ustat (sstat.st_dev, &s) < 0) + return -1; + fsp->fsu_blocks = -1; + fsp->fsu_bfree = f_tfree; + fsp->fsu_bavail = f_tfree; + fsp->fsu_files = -1; + fsp->fsu_ffree = -1; + } +#endif + +#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */ +#if ! STAT_USTAT +#if ! STAT_NONE + fsp->fsu_blocks = convert_blocks (fsd.f_blocks); + fsp->fsu_bfree = convert_blocks (fsd.f_bfree); + fsp->fsu_bavail = convert_blocks (fsd.f_bavail); + fsp->fsu_files = fsd.f_files; + fsp->fsu_ffree = fsd.f_ffree; +#endif +#endif +#endif + + return 0; +} + +#ifdef _AIX +#ifdef _I386 +/* AIX PS/2 does not supply statfs. */ + +int +statfs (path, fsb) + char *path; + struct statfs *fsb; +{ + struct stat stats; + struct dustat fsd; + + if (stat (path, &stats)) + return -1; + if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) + return -1; + fsb->f_type = 0; + fsb->f_bsize = fsd.du_bsize; + fsb->f_blocks = fsd.du_fsize - fsd.du_isize; + fsb->f_bfree = fsd.du_tfree; + fsb->f_bavail = fsd.du_tfree; + fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; + fsb->f_ffree = fsd.du_tinode; + fsb->f_fsid.val[0] = fsd.du_site; + fsb->f_fsid.val[1] = fsd.du_pckno; + return 0; +} +#endif +#endif /* _AIX && _I386 */ diff --git a/gnu/libexec/uucp/libunix/fsusg.h b/gnu/libexec/uucp/libunix/fsusg.h new file mode 100644 index 00000000000..8d4d054cb5a --- /dev/null +++ b/gnu/libexec/uucp/libunix/fsusg.h @@ -0,0 +1,31 @@ +/* fsusage.h -- declarations for filesystem space usage info + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + This files was modified slightly by Ian Lance Taylor for use with + Taylor UUCP. */ + +/* Space usage statistics for a filesystem. Blocks are 512-byte. */ +struct fs_usage +{ + long fsu_blocks; /* Total blocks. */ + long fsu_bfree; /* Free blocks available to superuser. */ + long fsu_bavail; /* Free blocks available to non-superuser. */ + long fsu_files; /* Total file nodes. */ + long fsu_ffree; /* Free file nodes. */ +}; + +extern int get_fs_usage P((char *path, char *disk, struct fs_usage *fsp)); diff --git a/gnu/libexec/uucp/libunix/ftw.c b/gnu/libexec/uucp/libunix/ftw.c new file mode 100644 index 00000000000..c3372b53ca4 --- /dev/null +++ b/gnu/libexec/uucp/libunix/ftw.c @@ -0,0 +1,250 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. +Contributed by Ian Lance Taylor (ian@airs.com). + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + +Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +#if HAVE_FTW_H +#include <ftw.h> +#endif + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +/* Traverse one level of a directory tree. */ + +static int +ftw_dir (dirs, level, descriptors, dir, len, func) + DIR **dirs; + int level; + int descriptors; + char *dir; + size_t len; + int (*func) P((const char *file, const struct stat *status, int flag)); +{ + int got; + struct dirent *entry; + + got = 0; + + errno = 0; + + while ((entry = readdir (dirs[level])) != NULL) + { + size_t namlen; + struct stat s; + int flag, ret, newlev; + + ++got; + + namlen = strlen (entry->d_name); + if (entry->d_name[0] == '.' + && (namlen == 1 || + (namlen == 2 && entry->d_name[1] == '.'))) + { + errno = 0; + continue; + } + + if (namlen + len + 1 > PATH_MAX) + { +#ifdef ENAMETOOLONG + errno = ENAMETOOLONG; +#else + errno = ENOMEM; +#endif + return -1; + } + + dir[len] = '/'; + memcpy ((dir + len + 1), entry->d_name, namlen + 1); + + if (stat (dir, &s) < 0) + { + if (errno != EACCES) + return -1; + flag = FTW_NS; + } + else if (S_ISDIR (s.st_mode)) + { + newlev = (level + 1) % descriptors; + + if (dirs[newlev] != NULL) + closedir (dirs[newlev]); + + dirs[newlev] = opendir (dir); + if (dirs[newlev] != NULL) + flag = FTW_D; + else + { + if (errno != EACCES) + return -1; + flag = FTW_DNR; + } + } + else + flag = FTW_F; + + ret = (*func) (dir, &s, flag); + + if (flag == FTW_D) + { + if (ret == 0) + ret = ftw_dir (dirs, newlev, descriptors, dir, + namlen + len + 1, func); + if (dirs[newlev] != NULL) + { + int save; + + save = errno; + closedir (dirs[newlev]); + errno = save; + dirs[newlev] = NULL; + } + } + + if (ret != 0) + return ret; + + if (dirs[level] == NULL) + { + int skip; + + dir[len] = '\0'; + dirs[level] = opendir (dir); + if (dirs[level] == NULL) + return -1; + skip = got; + while (skip-- != 0) + { + errno = 0; + if (readdir (dirs[level]) == NULL) + return errno == 0 ? 0 : -1; + } + } + + errno = 0; + } + + return errno == 0 ? 0 : -1; +} + +/* Call a function on every element in a directory tree. */ + +int +ftw (dir, func, descriptors) + const char *dir; + int (*func) P((const char *file, const struct stat *status, int flag)); + int descriptors; +{ + DIR **dirs; + int c; + DIR **p; + size_t len; + char buf[PATH_MAX + 1]; + struct stat s; + int flag, ret; + + if (descriptors <= 0) + descriptors = 1; + + dirs = (DIR **) malloc (descriptors * sizeof (DIR *)); + if (dirs == NULL) + return -1; + c = descriptors; + p = dirs; + while (c-- != 0) + *p++ = NULL; + + len = strlen (dir); + memcpy (buf, dir, len + 1); + + if (stat (dir, &s) < 0) + { + if (errno != EACCES) + { + free ((pointer) dirs); + return -1; + } + flag = FTW_NS; + } + else if (S_ISDIR (s.st_mode)) + { + dirs[0] = opendir (dir); + if (dirs[0] != NULL) + flag = FTW_D; + else + { + if (errno != EACCES) + { + free ((pointer) dirs); + return -1; + } + flag = FTW_DNR; + } + } + else + flag = FTW_F; + + ret = (*func) (buf, &s, flag); + + if (flag == FTW_D) + { + if (ret == 0) + ret = ftw_dir (dirs, 0, descriptors, buf, len, func); + if (dirs[0] != NULL) + { + int save; + + save = errno; + closedir (dirs[0]); + errno = save; + } + } + + free ((pointer) dirs); + return ret; +} diff --git a/gnu/libexec/uucp/libunix/getcwd.c b/gnu/libexec/uucp/libunix/getcwd.c new file mode 100644 index 00000000000..d3623bd2cd8 --- /dev/null +++ b/gnu/libexec/uucp/libunix/getcwd.c @@ -0,0 +1,59 @@ +/* getcwd.c + Replacement for the getcwd function that just calls /bin/pwd. */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +char * +getcwd (zbuf, cbuf) + char *zbuf; + size_t cbuf; +{ + const char *azargs[2]; + FILE *e; + pid_t ipid; + int cread; + int ierr; + + azargs[0] = PWD_PROGRAM; + azargs[1] = NULL; + e = espopen (azargs, TRUE, &ipid); + if (e == NULL) + return NULL; + + ierr = 0; + + cread = fread (zbuf, sizeof (char), cbuf, e); + if (cread == 0) + ierr = errno; + + (void) fclose (e); + + if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) + { + ierr = EACCES; + cread = 0; + } + + if (cread != 0) + { + if (zbuf[cread - 1] == '\n') + zbuf[cread - 1] = '\0'; + else + { + ierr = ERANGE; + cread = 0; + } + } + + if (cread == 0) + { + errno = ierr; + return NULL; + } + + return zbuf; +} diff --git a/gnu/libexec/uucp/libunix/indir.c b/gnu/libexec/uucp/libunix/indir.c new file mode 100644 index 00000000000..2484ec23f85 --- /dev/null +++ b/gnu/libexec/uucp/libunix/indir.c @@ -0,0 +1,133 @@ +/* indir.c + See if a file is in a directory. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* See whether a file is in a directory, and optionally check access. */ + +boolean +fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser) + const char *zfile; + const char *zdir; + boolean fcheck; + boolean freadable; + const char *zuser; +{ + size_t c; + char *zcopy, *zslash; + struct stat s; + + if (*zfile != '/') + return FALSE; + c = strlen (zdir); + if (c > 0 && zdir[c - 1] == '/') + c--; + if (strncmp (zfile, zdir, c) != 0 + || (zfile[c] != '/' && zfile[c] != '\0')) + return FALSE; + if (strstr (zfile + c, "/../") != NULL) + return FALSE; + + /* If we're not checking access, get out now. */ + if (! fcheck) + return TRUE; + + zcopy = zbufcpy (zfile); + + /* Start checking directories after zdir. Otherwise, we would + require that all directories down to /usr/spool/uucppublic be + publically searchable; they probably are but it should not be a + requirement. */ + zslash = zcopy + c; + do + { + char b; + struct stat shold; + + b = *zslash; + *zslash = '\0'; + + shold = s; + if (stat (zcopy, &s) != 0) + { + if (errno != ENOENT) + { + ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno)); + ubuffree (zcopy); + return FALSE; + } + + /* If this is the top directory, any problems will be caught + later when we try to open it. */ + if (zslash == zcopy + c) + { + ubuffree (zcopy); + return TRUE; + } + + /* Go back and check the last directory for read or write + access. */ + s = shold; + break; + } + + /* If this is not a directory, get out of the loop. */ + if (! S_ISDIR (s.st_mode)) + break; + + /* Make sure the directory is searchable. */ + if (! fsuser_access (&s, X_OK, zuser)) + { + ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); + ubuffree (zcopy); + return FALSE; + } + + /* If we've reached the end of the string, get out. */ + if (b == '\0') + break; + + *zslash = b; + } + while ((zslash = strchr (zslash + 1, '/')) != NULL); + + /* At this point s holds a stat on the last component of the path. + We must check it for readability or writeability. */ + if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser)) + { + ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); + ubuffree (zcopy); + return FALSE; + } + + ubuffree (zcopy); + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/init.c b/gnu/libexec/uucp/libunix/init.c new file mode 100644 index 00000000000..d4a13776281 --- /dev/null +++ b/gnu/libexec/uucp/libunix/init.c @@ -0,0 +1,394 @@ +/* init.c + Initialize the system dependent routines. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" + +#include <errno.h> +#include <pwd.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#if ! HAVE_GETHOSTNAME && HAVE_UNAME +#include <sys/utsname.h> +#endif + +/* Use getcwd in preference to getwd; if we have neither, we will be + using a getcwd replacement. */ +#if HAVE_GETCWD +#undef HAVE_GETWD +#define HAVE_GETWD 0 +#else /* ! HAVE_GETCWD */ +#if ! HAVE_GETWD +#undef HAVE_GETCWD +#define HAVE_GETCWD 1 +#endif /* ! HAVE_GETWD */ +#endif /* ! HAVE_GETCWD */ + +#if HAVE_GETWD +/* Get a value for MAXPATHLEN. */ +#if HAVE_SYS_PARAMS_H +#include <sys/params.h> +#endif + +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +#ifndef MAXPATHLEN +#ifdef PATH_MAX +#define MAXPATHLEN PATH_MAX +#else /* ! defined (PATH_MAX) */ +#define MAXPATHLEN 1024 +#endif /* ! defined (PATH_MAX) */ +#endif /* ! defined (MAXPATHLEN) */ +#endif /* HAVE_GETWD */ + +/* External functions. */ +#ifndef getlogin +extern char *getlogin (); +#endif +#if GETPWNAM_DECLARATION_OK +#ifndef getpwnam +extern struct passwd *getpwnam (); +#endif +#endif +#if GETPWUID_DECLARATION_OK +#ifndef getpwuid +extern struct passwd *getpwuid (); +#endif +#endif +#if HAVE_GETCWD +#ifndef getcwd +extern char *getcwd (); +#endif +#endif +#if HAVE_GETWD +#ifndef getwd +extern char *getwd (); +#endif +#endif +#if HAVE_SYSCONF +#ifndef sysconf +extern long sysconf (); +#endif +#endif + +/* Initialize the system dependent routines. We will probably be running + suid to uucp, so we make sure that nothing is obviously wrong. We + save the login name since we will be losing the real uid. */ +static char *zSlogin; + +/* The UUCP spool directory. */ +const char *zSspooldir; + +/* The UUCP lock directory. */ +const char *zSlockdir; + +/* The local UUCP name. */ +const char *zSlocalname; + +/* We save the current directory since we will do a chdir to the + spool directory. */ +char *zScwd; + +/* The maximum length of a system name is controlled by the type of spool + directory we use. */ +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX +size_t cSysdep_max_name_len = 7; +#endif +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 +size_t cSysdep_max_name_len = 14; +#endif +#if SPOOLDIR_TAYLOR +#if HAVE_LONG_FILE_NAMES +size_t cSysdep_max_name_len = 255; +#else /* ! HAVE_LONG_FILE_NAMES */ +size_t cSysdep_max_name_len = 14; +#endif /* ! HAVE_LONG_FILE_NAMES */ +#endif /* SPOOLDIR_TAYLOR */ + +/* Initialize the system dependent routines. */ + +void +usysdep_initialize (puuconf,iflags) + pointer puuconf; + int iflags; +{ + int cdescs; + int o; + int iuuconf; + char *z; + struct passwd *q; + + ulog_id (getpid ()); + + /* Close everything but stdin, stdout and stderr. */ +#if HAVE_GETDTABLESIZE + cdescs = getdtablesize (); +#else +#if HAVE_SYSCONF + cdescs = sysconf (_SC_OPEN_MAX); +#else +#ifdef OPEN_MAX + cdescs = OPEN_MAX; +#else +#ifdef NOFILE + cdescs = NOFILE; +#else + cdescs = 20; +#endif /* ! defined (NOFILE) */ +#endif /* ! defined (OPEN_MAX) */ +#endif /* ! HAVE_SYSCONF */ +#endif /* ! HAVE_GETDTABLESIZE */ + + for (o = 3; o < cdescs; o++) + (void) close (o); + + /* Make sure stdin, stdout and stderr are open. */ + if (fcntl (0, F_GETFD, 0) < 0 + && open ((char *) "/dev/null", O_RDONLY, 0) != 0) + exit (EXIT_FAILURE); + if (fcntl (1, F_GETFD, 0) < 0 + && open ((char *) "/dev/null", O_WRONLY, 0) != 1) + exit (EXIT_FAILURE); + if (fcntl (2, F_GETFD, 0) < 0 + && open ((char *) "/dev/null", O_WRONLY, 0) != 2) + exit (EXIT_FAILURE); + + iuuconf = uuconf_spooldir (puuconf, &zSspooldir); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + iuuconf = uuconf_lockdir (puuconf, &zSlockdir); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + iuuconf = uuconf_localname (puuconf, &zSlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { +#if HAVE_GETHOSTNAME + char ab[256]; + + if (gethostname (ab, sizeof ab - 1) < 0) + ulog (LOG_FATAL, "gethostname: %s", strerror (errno)); + ab[sizeof ab - 1] = '\0'; + ab[strcspn (ab, ".")] = '\0'; + zSlocalname = zbufcpy (ab); +#else /* ! HAVE_GETHOSTNAME */ +#if HAVE_UNAME + struct utsname s; + + if (uname (&s) < 0) + ulog (LOG_FATAL, "uname: %s", strerror (errno)); + zSlocalname = zbufcpy (s.nodename); +#else /* ! HAVE_UNAME */ + ulog (LOG_FATAL, "Don't know how to get local node name"); +#endif /* ! HAVE_UNAME */ +#endif /* ! HAVE_GETHOSTNAME */ + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + /* We always set our file modes to exactly what we want. */ + umask (0); + + /* Get the login name, making sure that it matches the uid. Many + systems truncate the getlogin return value to 8 characters, but + keep the full name in the password file, so we prefer the name in + the password file. */ + z = getenv ("LOGNAME"); + if (z == NULL) + z = getenv ("USER"); + if (z == NULL) + z = getlogin (); + if (z == NULL) + q = NULL; + else + { + q = getpwnam (z); + if (q != NULL) + z = q->pw_name; + } + if (q == NULL || q->pw_uid != getuid ()) + { + q = getpwuid (getuid ()); + if (q == NULL) + z = NULL; + else + z = q->pw_name; + } + if (z != NULL) + zSlogin = zbufcpy (z); + + /* On some old systems, an suid program run by root is started with + an euid of 0. If this happens, we look up the uid we should have + and set ourselves to it manually. This means that on such a + system root will not be able to uucp or uux files that are not + readable by uucp. */ + if ((iflags & INIT_SUID) != 0 + && geteuid () == 0) + { + q = getpwnam (OWNER); + if (q != NULL) + setuid (q->pw_uid); + } + + if ((iflags & INIT_GETCWD) != 0) + { + const char *zenv; + struct stat senv, sdot; + + /* Get the current working directory. We have to get it now, + since we're about to do a chdir. We use PWD if it's defined + and if it really names the working directory, since if it's + not the same as whatever getcwd returns it's probably more + appropriate. */ + zenv = getenv ("PWD"); + if (zenv != NULL + && stat ((char *) zenv, &senv) == 0 + && stat ((char *) ".", &sdot) == 0 + && senv.st_ino == sdot.st_ino + && senv.st_dev == sdot.st_dev) + zScwd = zbufcpy (zenv); + else + { + +#if HAVE_GETCWD + { + size_t c; + + c = 128; + while (TRUE) + { + zScwd = (char *) xmalloc (c); + if (getcwd (zScwd, c) != NULL) + break; + xfree ((pointer) zScwd); + zScwd = NULL; + if (errno != ERANGE) + break; + c <<= 1; + } + } +#endif /* HAVE_GETCWD */ + +#if HAVE_GETWD + zScwd = (char *) xmalloc (MAXPATHLEN); + if (getwd (zScwd) == NULL) + { + xfree ((pointer) zScwd); + zScwd = NULL; + } +#endif /* HAVE_GETWD */ + + if (zScwd != NULL) + zScwd = (char *) xrealloc ((pointer) zScwd, + strlen (zScwd) + 1); + } + } + + if ((iflags & INIT_NOCHDIR) == 0) + { + /* Connect to the spool directory, and create it if it doesn't + exist. */ + if (chdir (zSspooldir) < 0) + { + if (errno == ENOENT + && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0) + ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir, + strerror (errno)); + if (chdir (zSspooldir) < 0) + ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir, + strerror (errno)); + } + } +} + +/* Exit the program. */ + +void +usysdep_exit (fsuccess) + boolean fsuccess; +{ + exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* This is called when a non-standard configuration file is used, to + make sure the program doesn't hand out privileged file access. + This means that to test non-standard configuration files, you + should be logged in as uucp. This is called before + usysdep_initialize. It ensures that someone can't simply use an + alternate configuration file to steal UUCP transfers from other + systems. This will still permit people to set up their own + configuration file and pretend to be whatever system they choose. + The only real security is to use a high level of protection on the + modem ports. */ + +/*ARGSUSED*/ +boolean fsysdep_other_config (z) + const char *z; +{ + (void) setuid (getuid ()); + (void) setgid (getgid ()); + return TRUE; +} + +/* Get the node name to use if it was not specified in the configuration + file. */ + +const char * +zsysdep_localname () +{ + return zSlocalname; +} + +/* Get the login name. We actually get the login name in + usysdep_initialize, because after that we may switch away from the + real uid. */ + +const char * +zsysdep_login_name () +{ + if (zSlogin == NULL) + ulog (LOG_FATAL, "Can't get login name"); + return zSlogin; +} diff --git a/gnu/libexec/uucp/libunix/isdir.c b/gnu/libexec/uucp/libunix/isdir.c new file mode 100644 index 00000000000..fc95e5275a8 --- /dev/null +++ b/gnu/libexec/uucp/libunix/isdir.c @@ -0,0 +1,18 @@ +/* isdir.c + See whether a file exists and is a directory. */ + +#include "uucp.h" + +#include "system.h" +#include "sysdep.h" + +boolean +fsysdep_directory (z) + const char *z; +{ + struct stat s; + + if (stat ((char *) z, &s) < 0) + return FALSE; + return S_ISDIR (s.st_mode); +} diff --git a/gnu/libexec/uucp/libunix/isfork.c b/gnu/libexec/uucp/libunix/isfork.c new file mode 100644 index 00000000000..f067d07552c --- /dev/null +++ b/gnu/libexec/uucp/libunix/isfork.c @@ -0,0 +1,25 @@ +/* isfork.c + Retry fork several times before giving up. */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +pid_t +ixsfork () +{ + int i; + pid_t iret; + + for (i = 0; i < 10; i++) + { + iret = fork (); + if (iret >= 0 || errno != EAGAIN) + return iret; + sleep (5); + } + + return iret; +} diff --git a/gnu/libexec/uucp/libunix/iswait.c b/gnu/libexec/uucp/libunix/iswait.c new file mode 100644 index 00000000000..d2610aa1f8b --- /dev/null +++ b/gnu/libexec/uucp/libunix/iswait.c @@ -0,0 +1,159 @@ +/* iswait.c + Wait for a process to finish. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +/* We use a typedef wait_status for wait (waitpid, wait4) to put + results into. We define the POSIX examination functions we need if + they are not already defined (if they aren't defined, I assume that + we have a standard wait status). */ + +#if HAVE_UNION_WAIT +typedef union wait wait_status; +#ifndef WIFEXITED +#define WIFEXITED(u) ((u).w_termsig == 0) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(u) ((u).w_retcode) +#endif +#ifndef WTERMSIG +#define WTERMSIG(u) ((u).w_termsig) +#endif +#else /* ! HAVE_UNION_WAIT */ +typedef int wait_status; +#ifndef WIFEXITED +#define WIFEXITED(i) (((i) & 0xff) == 0) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(i) (((i) >> 8) & 0xff) +#endif +#ifndef WTERMSIG +#define WTERMSIG(i) ((i) & 0x7f) +#endif +#endif /* ! HAVE_UNION_WAIT */ + +/* Wait for a particular process to finish. The ipid argument should + be pid_t, but then we couldn't have a prototype. If the zreport + argument is not NULL, then a wait error will be logged, and if the + exit status is non-zero it will be logged with zreport as the + header of the log message. If the zreport argument is NULL, no + errors will be logged. This function returns the exit status if + the process exited normally, or -1 on error or if the process was + killed by a signal (I don't just always return the exit status + because then the calling code would have to prepared to handle + union wait status vs. int status, and none of the callers care + which signal killed the program anyhow). + + This functions keeps waiting until the process finished, even if it + is interrupted by a signal. I think this is right for all uses. + The controversial one would be when called from uuxqt to wait for a + requested process. Hitting uuxqt with SIGKILL will approximate the + actions taken if we return from here with an error anyhow. If we + do get a signal, we call ulog with a NULL argument to get it in the + log file at about the right time. */ + +int +ixswait (ipid, zreport) + unsigned long ipid; + const char *zreport; +{ + wait_status istat; + +#if HAVE_WAITPID + while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0) + { + if (errno != EINTR) + { + if (zreport != NULL) + ulog (LOG_ERROR, "waitpid: %s", strerror (errno)); + return -1; + } + ulog (LOG_ERROR, (const char *) NULL); + } +#else /* ! HAVE_WAITPID */ +#if HAVE_WAIT4 + while (wait4 ((pid_t) ipid, (pointer) &istat, 0, + (struct rusage *) NULL) < 0) + { + if (errno != EINTR) + { + if (zreport != NULL) + ulog (LOG_ERROR, "wait4: %s", strerror (errno)); + return -1; + } + ulog (LOG_ERROR, (const char *) NULL); + } +#else /* ! HAVE_WAIT4 */ + pid_t igot; + + /* We could theoretically get the wrong child here if we're in some + kind of weird pipeline, so we don't give any error messages for + it. */ + while ((igot = wait ((pointer) &istat)) != (pid_t) ipid) + { + if (igot < 0) + { + if (errno != EINTR) + { + if (zreport != NULL) + ulog (LOG_ERROR, "wait: %s", strerror (errno)); + return -1; + } + ulog (LOG_ERROR, (const char *) NULL); + } + } +#endif /* ! HAVE_WAIT4 */ +#endif /* ! HAVE_WAITPID */ + + DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d", + WIFEXITED (istat) ? "Exit status" : "Signal", + WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat)); + + if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0) + return 0; + + if (zreport != NULL) + { + if (! WIFEXITED (istat)) + ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat)); + else + ulog (LOG_ERROR, "%s: Exit status %d", zreport, + WEXITSTATUS (istat)); + } + + if (WIFEXITED (istat)) + return WEXITSTATUS (istat); + else + return -1; +} diff --git a/gnu/libexec/uucp/libunix/jobid.c b/gnu/libexec/uucp/libunix/jobid.c new file mode 100644 index 00000000000..7f22f1d37d7 --- /dev/null +++ b/gnu/libexec/uucp/libunix/jobid.c @@ -0,0 +1,101 @@ +/* jobid.c + Convert file names to jobids and vice versa. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uuconf.h" +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* Translate a file name and an associated system into a job id. + These job ids are used by uustat. We use the system name attached + to the grade and sequence number. This won't work correctly if the + file name was actually created by some other version of uucp that + uses a different length for the sequence number. Too bad. */ + +char * +zsfile_to_jobid (qsys, zfile, bgrade) + const struct uuconf_system *qsys; + const char *zfile; + int bgrade; +{ + size_t clen; + char *zret; + + clen = strlen (qsys->uuconf_zname); + zret = zbufalc (clen + CSEQLEN + 2); + memcpy (zret, qsys->uuconf_zname, clen); + zret[clen] = bgrade; + memcpy (zret + clen + 1, zfile + strlen (zfile) - CSEQLEN, CSEQLEN + 1); + return zret; +} + +/* Turn a job id back into a file name. */ + +char * +zsjobid_to_file (zid, pzsystem, pbgrade) + const char *zid; + char **pzsystem; + char *pbgrade; +{ + size_t clen; + const char *zend; + char *zsys; + char abname[CSEQLEN + 11]; + char *zret; + + clen = strlen (zid); + if (clen <= CSEQLEN) + { + ulog (LOG_ERROR, "%s: Bad job id", zid); + return NULL; + } + + zend = zid + clen - CSEQLEN - 1; + + zsys = zbufalc (clen - CSEQLEN); + memcpy (zsys, zid, clen - CSEQLEN - 1); + zsys[clen - CSEQLEN - 1] = '\0'; + + /* This must correspond to zsfile_name. */ +#if ! SPOOLDIR_TAYLOR + sprintf (abname, "C.%.7s%s", zsys, zend); +#else + sprintf (abname, "C.%s", zend); +#endif + + zret = zsfind_file (abname, zsys, *zend); + + if (zret != NULL && pzsystem != NULL) + *pzsystem = zsys; + else + ubuffree (zsys); + + if (pbgrade != NULL) + *pbgrade = *zend; + + return zret; +} diff --git a/gnu/libexec/uucp/libunix/lcksys.c b/gnu/libexec/uucp/libunix/lcksys.c new file mode 100644 index 00000000000..4ece16afe7b --- /dev/null +++ b/gnu/libexec/uucp/libunix/lcksys.c @@ -0,0 +1,41 @@ +/* lcksys.c + Lock and unlock a remote system. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +/* Lock a remote system. */ + +boolean +fsysdep_lock_system (qsys) + const struct uuconf_system *qsys; +{ + char *z; + boolean fret; + + z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK.."); + sprintf (z, "LCK..%.8s", qsys->uuconf_zname); + fret = fsdo_lock (z, FALSE, (boolean *) NULL); + ubuffree (z); + return fret; +} + +/* Unlock a remote system. */ + +boolean +fsysdep_unlock_system (qsys) + const struct uuconf_system *qsys; +{ + char *z; + boolean fret; + + z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK.."); + sprintf (z, "LCK..%.8s", qsys->uuconf_zname); + fret = fsdo_unlock (z, FALSE); + ubuffree (z); + return fret; +} diff --git a/gnu/libexec/uucp/libunix/link.c b/gnu/libexec/uucp/libunix/link.c new file mode 100644 index 00000000000..4550c76c94d --- /dev/null +++ b/gnu/libexec/uucp/libunix/link.c @@ -0,0 +1,38 @@ +/* link.c + Link two files. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +boolean +fsysdep_link (zfrom, zto, pfworked) + const char *zfrom; + const char *zto; + boolean *pfworked; +{ + *pfworked = FALSE; + if (link (zfrom, zto) == 0) + { + *pfworked = TRUE; + return TRUE; + } + if (errno == ENOENT) + { + if (! fsysdep_make_dirs (zto, TRUE)) + return FALSE; + if (link (zfrom, zto) == 0) + { + *pfworked = TRUE; + return TRUE; + } + } + if (errno == EXDEV) + return TRUE; + ulog (LOG_ERROR, "link (%s, %s): %s", zfrom, zto, strerror (errno)); + return FALSE; +} diff --git a/gnu/libexec/uucp/libunix/locfil.c b/gnu/libexec/uucp/libunix/locfil.c new file mode 100644 index 00000000000..0e05af9bcee --- /dev/null +++ b/gnu/libexec/uucp/libunix/locfil.c @@ -0,0 +1,95 @@ +/* locfil.c + Expand a file name on the local system. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <pwd.h> + +#if GETPWNAM_DECLARATION_OK +#ifndef getpwnam +extern struct passwd *getpwnam (); +#endif +#endif + +/* Turn a file name into an absolute path, by doing tilde expansion + and moving any other type of file into the public directory. */ + +char * +zsysdep_local_file (zfile, zpubdir) + const char *zfile; + const char *zpubdir; +{ + const char *zdir; + + if (*zfile == '/') + return zbufcpy (zfile); + + if (*zfile != '~') + zdir = zpubdir; + else + { + if (zfile[1] == '\0') + return zbufcpy (zpubdir); + + if (zfile[1] == '/') + { + zdir = zpubdir; + zfile += 2; + } + else + { + size_t cuserlen; + char *zcopy; + struct passwd *q; + + ++zfile; + cuserlen = strcspn ((char *) zfile, "/"); + zcopy = zbufalc (cuserlen + 1); + memcpy (zcopy, zfile, cuserlen); + zcopy[cuserlen] = '\0'; + + q = getpwnam (zcopy); + if (q == NULL) + { + ulog (LOG_ERROR, "User %s not found", zcopy); + ubuffree (zcopy); + return NULL; + } + ubuffree (zcopy); + + if (zfile[cuserlen] == '\0') + return zbufcpy (q->pw_dir); + + zdir = q->pw_dir; + zfile += cuserlen + 1; + } + } + + return zsysdep_in_dir (zdir, zfile); +} diff --git a/gnu/libexec/uucp/libunix/lock.c b/gnu/libexec/uucp/libunix/lock.c new file mode 100644 index 00000000000..c43e31dfd00 --- /dev/null +++ b/gnu/libexec/uucp/libunix/lock.c @@ -0,0 +1,477 @@ +/* lock.c + Lock and unlock a file name. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/04 19:32:33 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +/* Lock something. If the fspooldir argument is TRUE, the argument is + a file name relative to the spool directory; otherwise the argument + is a simple file name which should be created in the system lock + directory (under HDB this is /etc/locks). */ + +boolean +fsdo_lock (zlock, fspooldir, pferr) + const char *zlock; + boolean fspooldir; + boolean *pferr; +{ + char *zfree; + const char *zpath, *zslash; + size_t cslash; + pid_t ime; + char *ztempfile; + char abtempfile[sizeof "TMP1234567890"]; + int o; +#if HAVE_V2_LOCKFILES + int i; +#else + char ab[12]; +#endif + int cwrote; + const char *zerr; + boolean fret; + + if (pferr != NULL) + *pferr = TRUE; + + if (fspooldir) + { + zfree = NULL; + zpath = zlock; + } + else + { + zfree = zsysdep_in_dir (zSlockdir, zlock); + zpath = zfree; + } + + ime = getpid (); + + /* We do the actual lock by creating a file and then linking it to + the final file name we want. This avoids race conditions due to + one process checking the file before we have finished writing it, + and also works even if we are somehow running as root. + + First, create the file in the right directory (we must create the + file in the same directory since otherwise we might attempt a + cross-device link). */ + zslash = strrchr (zpath, '/'); + if (zslash == NULL) + cslash = 0; + else + cslash = zslash - zpath + 1; + + sprintf (abtempfile, "TMP%010lx", (unsigned long) ime); + ztempfile = zbufalc (cslash + sizeof abtempfile); + memcpy (ztempfile, zpath, cslash); + memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile); + + o = creat (ztempfile, IPUBLIC_FILE_MODE); + if (o < 0) + { + if (errno == ENOENT) + { + if (! fsysdep_make_dirs (ztempfile, FALSE)) + { + ubuffree (zfree); + ubuffree (ztempfile); + return FALSE; + } + o = creat (ztempfile, IPUBLIC_FILE_MODE); + } + if (o < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno)); + ubuffree (zfree); + ubuffree (ztempfile); + return FALSE; + } + } + +#if HAVE_V2_LOCKFILES + i = ime; + cwrote = write (o, &i, sizeof i); +#else + sprintf (ab, "%10d\n", (int) ime); + cwrote = write (o, ab, strlen (ab)); +#endif + + zerr = NULL; + if (cwrote < 0) + zerr = "write"; + if (close (o) < 0) + zerr = "close"; + if (zerr != NULL) + { + ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno)); + (void) remove (ztempfile); + ubuffree (zfree); + ubuffree (ztempfile); + return FALSE; + } + + /* Now try to link the file we just created to the lock file that we + want. If it fails, try reading the existing file to make sure + the process that created it still exists. We do this in a loop + to make it easy to retry if the old locking process no longer + exists. */ + fret = TRUE; + if (pferr != NULL) + *pferr = FALSE; + o = -1; + zerr = NULL; + + while (link (ztempfile, zpath) != 0) + { + int cgot; + int ipid; + boolean freadonly; + + fret = FALSE; + + if (errno != EEXIST) + { + ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath, + strerror (errno)); + if (pferr != NULL) + *pferr = TRUE; + break; + } + + freadonly = FALSE; + o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0); + if (o < 0) + { + if (errno == EACCES) + { + freadonly = TRUE; + o = open ((char *) zpath, O_RDONLY, 0); + } + if (o < 0) + { + if (errno == ENOENT) + { + /* The file was presumably removed between the link + and the open. Try the link again. */ + fret = TRUE; + continue; + } + zerr = "open"; + break; + } + } + + /* The race starts here. See below for a discussion. */ + +#if HAVE_V2_LOCKFILES + cgot = read (o, &i, sizeof i); +#else + cgot = read (o, ab, sizeof ab - 1); +#endif + + if (cgot < 0) + { + zerr = "read"; + break; + } + +#if HAVE_V2_LOCKFILES + ipid = i; +#else + ab[cgot] = '\0'; + ipid = strtol (ab, (char **) NULL, 10); +#endif + + /* On NFS, the link might have actually succeeded even though we + got a failure return. This can happen if the original + acknowledgement was lost or delayed and the operation was + retried. In this case the pid will be our own. This + introduces a rather improbable race condition: if a stale + lock was left with our process ID in it, and another process + just did the kill, below, but has not yet changed the lock + file to hold its own process ID, we could start up and make + it all the way to here and think we have the lock. I'm not + going to worry about this possibility. */ + if (ipid == ime) + { + fret = TRUE; + break; + } + + /* If the process still exists, we will get EPERM rather than + ESRCH. We then return FALSE to indicate that we cannot make + the lock. */ + if (kill (ipid, 0) == 0 || errno == EPERM) + break; + + ulog (LOG_ERROR, "Found stale lock %s held by process %d", + zpath, ipid); + + /* This is a stale lock, created by a process that no longer + exists. + + Now we could remove the file (and, if the file mode disallows + writing, that's what we have to do), but we try to avoid + doing so since it causes a race condition. If we remove the + file, and are interrupted any time after we do the read until + we do the remove, another process could get in, open the + file, find that it was a stale lock, remove the file and + create a new one. When we regained control we would remove + the file the other process just created. + + These files are being generated partially for the benefit of + cu, and it would be nice to avoid the race however cu avoids + it, so that the programs remain compatible. Unfortunately, + nobody seems to know how cu avoids the race, or even if it + tries to avoid it at all. + + There are a few ways to avoid the race. We could use kernel + locking primitives, but they may not be available. We could + link to a special file name, but if that file were left lying + around then no stale lock could ever be broken (Henry Spencer + would think this was a good thing). + + Instead I've implemented the following procedure: seek to the + start of the file, write our pid into it, sleep for five + seconds, and then make sure our pid is still there. Anybody + who checks the file while we're asleep will find our pid + there and fail the lock. The only race will come from + another process which has done the read by the time we do our + write. That process will then have five seconds to do its + own write. When we wake up, we'll notice that our pid is no + longer in the file, and retry the lock from the beginning. + + This relies on the atomicity of write(2). If it possible for + the writes of two processes to be interleaved, the two + processes could livelock. POSIX unfortunately leaves this + case explicitly undefined; however, given that the write is + of less than a disk block, it's difficult to imagine an + interleave occurring. + + Note that this is still a race. If it takes the second + process more than five seconds to do the kill, the lseek, and + the write, both processes will think they have the lock. + Perhaps the length of time to sleep should be configurable. + Even better, perhaps I should add a configuration option to + use a permanent lock file, which eliminates any race and + forces the installer to be aware of the existence of the + permanent lock file. + + We stat the file after the sleep, to make sure some other + program hasn't deleted it for us. */ + if (freadonly) + { + (void) close (o); + o = -1; + (void) remove (zpath); + continue; + } + + if (lseek (o, (off_t) 0, SEEK_SET) != 0) + { + zerr = "lseek"; + break; + } + +#if HAVE_V2_LOCKFILES + i = ime; + cwrote = write (o, &i, sizeof i); +#else + sprintf (ab, "%10d\n", (int) ime); + cwrote = write (o, ab, strlen (ab)); +#endif + + if (cwrote < 0) + { + zerr = "write"; + break; + } + + (void) sleep (5); + + if (lseek (o, (off_t) 0, SEEK_SET) != 0) + { + zerr = "lseek"; + break; + } + +#if HAVE_V2_LOCKFILES + cgot = read (o, &i, sizeof i); +#else + cgot = read (o, ab, sizeof ab - 1); +#endif + + if (cgot < 0) + { + zerr = "read"; + break; + } + +#if HAVE_V2_LOCKFILES + ipid = i; +#else + ab[cgot] = '\0'; + ipid = strtol (ab, (char **) NULL, 10); +#endif + + if (ipid == ime) + { + struct stat sfile, sdescriptor; + + /* It looks like we have the lock. Do the final stat + check. */ + if (stat ((char *) zpath, &sfile) < 0) + { + if (errno != ENOENT) + { + zerr = "stat"; + break; + } + /* Loop around and try again. */ + } + else + { + if (fstat (o, &sdescriptor) < 0) + { + zerr = "fstat"; + break; + } + + if (sfile.st_ino == sdescriptor.st_ino + && sfile.st_dev == sdescriptor.st_dev) + { + /* Close the file before assuming we've succeeded to + pick up any trailing errors. */ + if (close (o) < 0) + { + zerr = "close"; + break; + } + + o = -1; + + /* We have the lock. */ + fret = TRUE; + break; + } + } + } + + /* Loop around and try the lock again. We keep doing this until + the lock file holds a pid that exists. */ + (void) close (o); + o = -1; + fret = TRUE; + } + + if (zerr != NULL) + { + ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno)); + if (pferr != NULL) + *pferr = TRUE; + } + + if (o >= 0) + (void) close (o); + + ubuffree (zfree); + + /* It would be nice if we could leave the temporary file around for + future calls, but considering that we create lock files in + various different directories it's probably more trouble than + it's worth. */ + if (remove (ztempfile) != 0) + ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno)); + + ubuffree (ztempfile); + + return fret; +} + +/* Unlock something. The fspooldir argument is as in fsdo_lock. */ + +boolean +fsdo_unlock (zlock, fspooldir) + const char *zlock; + boolean fspooldir; +{ + char *zfree; + const char *zpath; + + if (fspooldir) + { + zfree = NULL; + zpath = zlock; + } + else + { + zfree = zsysdep_in_dir (zSlockdir, zlock); + zpath = zfree; + } + + if (remove (zpath) == 0 + || errno == ENOENT) + { + ubuffree (zfree); + return TRUE; + } + else + { + ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno)); + ubuffree (zfree); + return FALSE; + } +} diff --git a/gnu/libexec/uucp/libunix/loctim.c b/gnu/libexec/uucp/libunix/loctim.c new file mode 100644 index 00000000000..da5f32e2d27 --- /dev/null +++ b/gnu/libexec/uucp/libunix/loctim.c @@ -0,0 +1,25 @@ +/* loctim.c + Turn a time epoch into a struct tm. This is trivial on Unix. */ + +#include "uucp.h" + +#if HAVE_TIME_H +#include <time.h> +#endif + +#include "system.h" + +#ifndef localtime +extern struct tm *localtime (); +#endif + +void +usysdep_localtime (itime, q) + long itime; + struct tm *q; +{ + time_t i; + + i = (time_t) itime; + *q = *localtime (&i); +} diff --git a/gnu/libexec/uucp/libunix/mail.c b/gnu/libexec/uucp/libunix/mail.c new file mode 100644 index 00000000000..74c1aa95adc --- /dev/null +++ b/gnu/libexec/uucp/libunix/mail.c @@ -0,0 +1,85 @@ +/* mail.c + Send mail to a user. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_TIME_H +#include <time.h> +#endif + +#ifndef ctime +extern char *ctime (); +#endif + +/* Mail a message to a user. */ + +boolean +fsysdep_mail (zto, zsubject, cstrs, paz) + const char *zto; + const char *zsubject; + int cstrs; + const char **paz; +{ + const char *az[3]; + FILE *e; + pid_t ipid; + time_t itime; + int i; + + az[0] = MAIL_PROGRAM; + az[1] = zto; + az[2] = NULL; + + e = espopen (az, FALSE, &ipid); + if (e == NULL) + { + ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM, + strerror (errno)); + return FALSE; + } + + fprintf (e, "Subject: %s\n", zsubject); + fprintf (e, "To: %s\n", zto); + + fprintf (e, "\n"); + + (void) time (&itime); + /* Remember that ctime includes a \n, so this skips a line. */ + fprintf (e, "Message from UUCP on %s %s\n", zSlocalname, + ctime (&itime)); + + for (i = 0; i < cstrs; i++) + fputs (paz[i], e); + + (void) fclose (e); + + return ixswait ((unsigned long) ipid, MAIL_PROGRAM) == 0; +} diff --git a/gnu/libexec/uucp/libunix/mkdir.c b/gnu/libexec/uucp/libunix/mkdir.c new file mode 100644 index 00000000000..f59ad5dfd6e --- /dev/null +++ b/gnu/libexec/uucp/libunix/mkdir.c @@ -0,0 +1,58 @@ +/* mkdir.c + Create a directory. We must go through a subsidiary program to + force our real uid to be the uucp owner before invoking the setuid + /bin/mkdir program. */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +int +mkdir (zdir, imode) + const char *zdir; + int imode; +{ + struct stat s; + const char *azargs[3]; + int aidescs[3]; + pid_t ipid; + + /* Make sure the directory does not exist, since we will otherwise + get the wrong errno value. */ + if (stat (zdir, &s) == 0) + { + errno = EEXIST; + return -1; + } + + /* /bin/mkdir will create the directory with mode 777, so we set our + umask to get the mode we want. */ + (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO)); + + azargs[0] = UUDIR_PROGRAM; + azargs[1] = zdir; + azargs[2] = NULL; + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL, + TRUE, FALSE, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + + (void) umask (0); + + if (ipid < 0) + return -1; + + if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) + { + /* Make up an errno value. */ + errno = EACCES; + return -1; + } + + return 0; +} diff --git a/gnu/libexec/uucp/libunix/mkdirs.c b/gnu/libexec/uucp/libunix/mkdirs.c new file mode 100644 index 00000000000..a4e0b67bb8c --- /dev/null +++ b/gnu/libexec/uucp/libunix/mkdirs.c @@ -0,0 +1,49 @@ +/* mkdirs.c + Create any directories needed for a file name. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +boolean +fsysdep_make_dirs (zfile, fpublic) + const char *zfile; + boolean fpublic; +{ + char *zcopy, *z; + int imode; + + zcopy = zbufcpy (zfile); + + if (fpublic) + imode = IPUBLIC_DIRECTORY_MODE; + else + imode = IDIRECTORY_MODE; + + for (z = zcopy; *z != '\0'; z++) + { + if (*z == '/' && z != zcopy) + { + *z = '\0'; + if (! fsysdep_directory (zcopy)) + { + if (mkdir (zcopy, imode) != 0) + { + ulog (LOG_ERROR, "mkdir (%s): %s", zcopy, + strerror (errno)); + ubuffree (zcopy); + return FALSE; + } + } + *z = '/'; + } + } + + ubuffree (zcopy); + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/mode.c b/gnu/libexec/uucp/libunix/mode.c new file mode 100644 index 00000000000..53f74ec81c3 --- /dev/null +++ b/gnu/libexec/uucp/libunix/mode.c @@ -0,0 +1,33 @@ +/* mode.c + Get the Unix file mode of a file. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +unsigned int +ixsysdep_file_mode (zfile) + const char *zfile; +{ + struct stat s; + + if (stat ((char *) zfile, &s) != 0) + { + ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); + return 0; + } + +#if S_IRWXU != 0700 + #error Files modes need to be translated +#endif + + /* We can't return 0, since that indicate an error. */ + if ((s.st_mode & 0777) == 0) + return 0400; + + return s.st_mode & 0777; +} diff --git a/gnu/libexec/uucp/libunix/move.c b/gnu/libexec/uucp/libunix/move.c new file mode 100644 index 00000000000..ccfe6d4d728 --- /dev/null +++ b/gnu/libexec/uucp/libunix/move.c @@ -0,0 +1,176 @@ +/* move.c + Move a file. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +/* Move (rename) a file from one name to another. This routine will + optionally create necessary directories, and fpublic indicates + whether the new directories should be publically accessible or not. + If fcheck is true, it will try to determine whether the named user + has write access to the new file. */ + +boolean +fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser) + const char *zorig; + const char *zto; + boolean fmkdirs; + boolean fpublic; + boolean fcheck; + const char *zuser; +{ + struct stat s; + int o; + + DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, + "fsysdep_move_file: Moving %s to %s", zorig, zto); + + /* Optionally make sure that zuser has write access on the + directory. */ + if (fcheck) + { + char *zcopy; + char *zslash; + + zcopy = zbufcpy (zto); + zslash = strrchr (zcopy, '/'); + if (zslash == zcopy) + zslash[1] = '\0'; + else + *zslash = '\0'; + + if (stat (zcopy, &s) != 0) + { + ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno)); + (void) remove (zorig); + ubuffree (zcopy); + return FALSE; + } + if (! fsuser_access (&s, W_OK, zuser)) + { + ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); + (void) remove (zorig); + ubuffree (zcopy); + return FALSE; + } + ubuffree (zcopy); + + /* A malicious user now has a few milliseconds to change a + symbolic link to a directory uucp has write permission on but + the user does not (the obvious choice being /usr/lib/uucp). + The only certain method I can come up with to close this race + is to fork an suid process which takes on the users identity + and does the actual copy. This is sufficiently high overhead + that I'm not going to do it. */ + } + + /* We try to use rename to move the file. */ + + if (rename (zorig, zto) == 0) + return TRUE; + + if (fmkdirs && errno == ENOENT) + { + if (! fsysdep_make_dirs (zto, fpublic)) + { + (void) remove (zorig); + return FALSE; + } + if (rename (zorig, zto) == 0) + return TRUE; + } + +#if HAVE_RENAME + /* On some systems the system call rename seems to fail for + arbitrary reasons. To get around this, we always try to copy the + file by hand if the rename failed. */ + errno = EXDEV; +#endif + + /* If we can't link across devices, we must copy the file by hand. */ + if (errno != EXDEV) + { + ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto, + strerror (errno)); + (void) remove (zorig); + return FALSE; + } + + /* Copy the file. */ + if (stat ((char *) zorig, &s) < 0) + { + ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno)); + (void) remove (zorig); + return FALSE; + } + + /* Make sure the file gets the right mode by creating it before we + call fcopy_file. */ + (void) remove (zto); + o = creat ((char *) zto, s.st_mode); + if (o < 0) + { + if (fmkdirs && errno == ENOENT) + { + if (! fsysdep_make_dirs (zto, fpublic)) + { + (void) remove (zorig); + return FALSE; + } + o = creat ((char *) zto, s.st_mode); + } + if (o < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno)); + (void) remove (zorig); + return FALSE; + } + } + (void) close (o); + + if (! fcopy_file (zorig, zto, fpublic, fmkdirs)) + { + (void) remove (zorig); + return FALSE; + } + + if (remove (zorig) != 0) + ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno)); + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/opensr.c b/gnu/libexec/uucp/libunix/opensr.c new file mode 100644 index 00000000000..3a8ca7a8b8a --- /dev/null +++ b/gnu/libexec/uucp/libunix/opensr.c @@ -0,0 +1,244 @@ +/* opensr.c + Open files for sending and receiving. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_TIME_H +#include <time.h> +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#ifndef time +extern time_t time (); +#endif + +/* Open a file to send to another system, and return the mode and + the size. */ + +openfile_t +esysdep_open_send (qsys, zfile, fcheck, zuser) + const struct uuconf_system *qsys; + const char *zfile; + boolean fcheck; + const char *zuser; +{ + struct stat s; + openfile_t e; + int o; + + if (fsysdep_directory (zfile)) + { + ulog (LOG_ERROR, "%s: is a directory", zfile); + return EFILECLOSED; + } + +#if USE_STDIO + e = fopen (zfile, BINREAD); + if (e == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); + return NULL; + } + o = fileno (e); +#else + e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0); + if (e == -1) + { + ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); + return -1; + } + o = e; +#endif + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) ffileclose (e); + return EFILECLOSED; + } + + if (fstat (o, &s) == -1) + { + ulog (LOG_ERROR, "fstat: %s", strerror (errno)); + s.st_mode = 0666; + } + + /* We have to recheck the file permission, although we probably + checked it already, because otherwise there would be a window in + which somebody could change the contents of a symbolic link to + point to some file which was only readable by uucp. */ + if (fcheck) + { + if (! fsuser_access (&s, R_OK, zuser)) + { + ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES)); + (void) ffileclose (e); + return EFILECLOSED; + } + } + + return e; +} + +/* Get a temporary file name to receive into. We use the ztemp + argument to pick the file name, so that we relocate the file if the + transmission is aborted. */ + +char * +zsysdep_receive_temp (qsys, zto, ztemp) + const struct uuconf_system *qsys; + const char *zto; + const char *ztemp; +{ + if (ztemp != NULL + && *ztemp == 'D' + && strcmp (ztemp, "D.0") != 0) + return zsappend3 (".Temp", qsys->uuconf_zname, ztemp); + else + return zstemp_file (qsys); +} + +/* Open a temporary file to receive into. This should, perhaps, check + that we have write permission on the receiving directory, but it + doesn't. */ + +openfile_t +esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart) + const struct uuconf_system *qsys; + const char *zto; + const char *ztemp; + const char *zreceive; + long *pcrestart; +{ + int o; + openfile_t e; + + /* If we used the ztemp argument in zsysdep_receive_temp, above, + then we will have a name consistent across conversations. In + that case, we may have already received some portion of this + file. */ + o = -1; + *pcrestart = -1; + if (ztemp != NULL + && *ztemp == 'D' + && strcmp (ztemp, "D.0") != 0) + { + o = open ((char *) zreceive, O_WRONLY); + if (o >= 0) + { + struct stat s; + + /* For safety, we insist on the file being less than 1 week + old. This can still catch people, unfortunately. I + don't know of any good solution to the problem of old + files hanging around. If anybody has a file they want + restarted, and they know about this issue, they can touch + it to bring it up to date. */ + if (fstat (o, &s) < 0 + || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL)) + { + (void) close (o); + o = -1; + } + else + { + DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, + "esysdep_open_receive: Reusing %s", + zreceive); + *pcrestart = (long) s.st_size; + } + } + } + + if (o < 0) + o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); + + if (o < 0) + { + if (errno == ENOENT) + { + if (! fsysdep_make_dirs (zreceive, FALSE)) + return EFILECLOSED; + o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); + } + if (o < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", zreceive, strerror (errno)); + return EFILECLOSED; + } + } + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (o); + (void) remove (zreceive); + return EFILECLOSED; + } + +#if USE_STDIO + e = fdopen (o, (char *) BINWRITE); + + if (e == NULL) + { + ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno)); + (void) close (o); + (void) remove (zreceive); + return EFILECLOSED; + } +#else + e = o; +#endif + + return e; +} diff --git a/gnu/libexec/uucp/libunix/pause.c b/gnu/libexec/uucp/libunix/pause.c new file mode 100644 index 00000000000..e774e0897bf --- /dev/null +++ b/gnu/libexec/uucp/libunix/pause.c @@ -0,0 +1,96 @@ +/* pause.c + Pause for half a second. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "system.h" + +/* Pick a timing routine to use. I somewhat arbitrarily picked usleep + above nap above napms above poll above select. */ +#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL +#undef HAVE_SELECT +#define HAVE_SELECT 0 +#endif + +#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS +#undef HAVE_POLL +#define HAVE_POLL 0 +#endif + +#if HAVE_USLEEP || HAVE_NAP +#undef HAVE_NAPMS +#define HAVE_NAPMS 0 +#endif + +#if HAVE_USLEEP +#undef HAVE_NAP +#define HAVE_NAP 0 +#endif + +#if HAVE_SELECT +#include <sys/time.h> +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#endif + +#if HAVE_POLL +#if HAVE_STROPTS_H +#include <stropts.h> +#endif +#if HAVE_POLL_H +#include <poll.h> +#endif +#if ! HAVE_STROPTS_H && ! HAVE_POLL_H +/* We need a definition for struct pollfd, although it doesn't matter + what it contains. */ +struct pollfd +{ + int idummy; +}; +#endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */ +#endif /* HAVE_POLL */ + +#if HAVE_TIME_H +#if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER +#include <time.h> +#endif +#endif + +void +usysdep_pause () +{ +#if HAVE_NAPMS + napms (500); +#endif /* HAVE_NAPMS */ +#if HAVE_NAP +#if HAVE_HUNDREDTHS_NAP + nap (50L); +#else + nap (500L); +#endif /* ! HAVE_HUNDREDTHS_NAP */ +#endif /* HAVE_NAP */ +#if HAVE_USLEEP + usleep (500 * (long) 1000); +#endif /* HAVE_USLEEP */ +#if HAVE_POLL + struct pollfd sdummy; + + /* We need to pass an unused pollfd structure because poll checks + the address before checking the number of elements. */ + poll (&sdummy, 0, 500); +#endif /* HAVE_POLL */ +#if HAVE_SELECT + struct timeval s; + + s.tv_sec = 0; + s.tv_usec = 500 * (long) 1000; + select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s); +#endif /* USE_SELECT_TIMER */ +#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP +#if ! USE_SELECT_TIMER && ! HAVE_POLL + sleep (1); +#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */ +#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */ +} diff --git a/gnu/libexec/uucp/libunix/picksb.c b/gnu/libexec/uucp/libunix/picksb.c new file mode 100644 index 00000000000..3fe5c6f585f --- /dev/null +++ b/gnu/libexec/uucp/libunix/picksb.c @@ -0,0 +1,230 @@ +/* picksb.c + System dependent routines for uupick. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char picksb_rcsid[] = "$Id: picksb.c,v 1.1 1993/08/04 19:32:42 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "system.h" +#include "sysdep.h" + +#include <errno.h> +#include <pwd.h> + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +#if GETPWUID_DECLARATION_OK +#ifndef getpwuid +extern struct passwd *getpwuid (); +#endif +#endif + +/* Local variables. */ + +/* Directory of ~/receive/USER. */ +static DIR *qStopdir; + +/* Name of ~/receive/USER. */ +static char *zStopdir; + +/* Directory of ~/receive/USER/SYSTEM. */ +static DIR *qSsysdir; + +/* Name of system. */ +static char *zSsysdir; + +/* Prepare to get a list of all the file to uupick for this user. */ + +/*ARGSUSED*/ +boolean +fsysdep_uupick_init (zsystem, zpubdir) + const char *zsystem; + const char *zpubdir; +{ + const char *zuser; + + zuser = zsysdep_login_name (); + + zStopdir = (char *) xmalloc (strlen (zpubdir) + + sizeof "/receive/" + + strlen (zuser)); + sprintf (zStopdir, "%s/receive/%s", zpubdir, zuser); + + qStopdir = opendir (zStopdir); + if (qStopdir == NULL && errno != ENOENT) + { + ulog (LOG_ERROR, "opendir (%s): %s", zStopdir, + strerror (errno)); + return FALSE; + } + + qSsysdir = NULL; + + return TRUE; +} + +/* Return the next file from the uupick directories. */ + +/*ARGSUSED*/ +char * +zsysdep_uupick (zsysarg, zpubdir, pzfrom, pzfull) + const char *zsysarg; + const char *zpubdir; + char **pzfrom; + char **pzfull; +{ + struct dirent *qentry; + + while (TRUE) + { + while (qSsysdir == NULL) + { + const char *zsystem; + char *zdir; + + if (qStopdir == NULL) + return NULL; + + if (zsysarg != NULL) + { + closedir (qStopdir); + qStopdir = NULL; + zsystem = zsysarg; + } + else + { + do + { + qentry = readdir (qStopdir); + if (qentry == NULL) + { + closedir (qStopdir); + qStopdir = NULL; + return NULL; + } + } + while (strcmp (qentry->d_name, ".") == 0 + || strcmp (qentry->d_name, "..") == 0); + + zsystem = qentry->d_name; + } + + zdir = zbufalc (strlen (zStopdir) + strlen (zsystem) + sizeof "/"); + sprintf (zdir, "%s/%s", zStopdir, zsystem); + + qSsysdir = opendir (zdir); + if (qSsysdir == NULL) + { + if (errno != ENOENT && errno != ENOTDIR) + ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno)); + } + else + { + ubuffree (zSsysdir); + zSsysdir = zbufcpy (zsystem); + } + + ubuffree (zdir); + } + + qentry = readdir (qSsysdir); + if (qentry == NULL) + { + closedir (qSsysdir); + qSsysdir = NULL; + continue; + } + + if (strcmp (qentry->d_name, ".") == 0 + || strcmp (qentry->d_name, "..") == 0) + continue; + + *pzfrom = zbufcpy (zSsysdir); + *pzfull = zsappend3 (zStopdir, zSsysdir, qentry->d_name); + return zbufcpy (qentry->d_name); + } +} + +/*ARGSUSED*/ +boolean +fsysdep_uupick_free (zsystem, zpubdir) + const char *zsystem; + const char *zpubdir; +{ + xfree ((pointer) zStopdir); + if (qStopdir != NULL) + { + closedir (qStopdir); + qStopdir = NULL; + } + ubuffree (zSsysdir); + zSsysdir = NULL; + if (qSsysdir != NULL) + { + closedir (qSsysdir); + qSsysdir = NULL; + } + + return TRUE; +} + +/* Expand a local file name for uupick. */ + +char * +zsysdep_uupick_local_file (zfile) + const char *zfile; +{ + struct passwd *q; + + /* If this does not start with a simple ~, pass it to + zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd + only uses the zpubdir argument if the file starts with a simple + ~, so it doesn't really matter what we pass for zpubdir. */ + if (zfile[0] != '~' + || (zfile[1] != '/' && zfile[1] != '\0')) + return zsysdep_local_file_cwd (zfile, (const char *) NULL); + + q = getpwuid (getuid ()); + if (q == NULL) + { + ulog (LOG_ERROR, "Can't get home directory"); + return NULL; + } + + if (zfile[1] == '\0') + return zbufcpy (q->pw_dir); + + return zsysdep_in_dir (q->pw_dir, zfile + 2); +} diff --git a/gnu/libexec/uucp/libunix/portnm.c b/gnu/libexec/uucp/libunix/portnm.c new file mode 100644 index 00000000000..9eda4ab012b --- /dev/null +++ b/gnu/libexec/uucp/libunix/portnm.c @@ -0,0 +1,51 @@ +/* portnm.c + Get the port name of stdin. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "system.h" + +#if HAVE_TCP +#if HAVE_SYS_TYPES_TCP_H +#include <sys/types.tcp.h> +#endif +#include <sys/socket.h> +#endif + +#ifndef ttyname +extern char *ttyname (); +#endif + +/* Get the port name of standard input. I assume that Unix systems + generally support ttyname. If they don't, this function can just + return NULL. It uses getsockname to see whether standard input is + a TCP connection. */ + +const char * +zsysdep_port_name (ftcp_port) + boolean *ftcp_port; +{ + const char *z; + + *ftcp_port = FALSE; + +#if HAVE_TCP + { + size_t clen; + struct sockaddr s; + + clen = sizeof (struct sockaddr); + if (getsockname (0, &s, &clen) == 0) + *ftcp_port = TRUE; + } +#endif /* HAVE_TCP */ + + z = ttyname (0); + if (z == NULL) + return NULL; + if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0) + return z + sizeof "/dev/" - 1; + else + return z; +} diff --git a/gnu/libexec/uucp/libunix/proctm.c b/gnu/libexec/uucp/libunix/proctm.c new file mode 100644 index 00000000000..55cf96f0c97 --- /dev/null +++ b/gnu/libexec/uucp/libunix/proctm.c @@ -0,0 +1,197 @@ +/* proctm.c + Get the time spent in the process. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "sysdep.h" +#include "system.h" + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +/* Prefer gettimeofday to ftime to times. */ + +#if HAVE_GETTIMEOFDAY || HAVE_FTIME +#undef HAVE_TIMES +#define HAVE_TIMES 0 +#endif + +#if HAVE_GETTIMEOFDAY +#undef HAVE_FTIME +#define HAVE_FTIME 0 +#endif + +#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY) +#include <time.h> +#endif + +#if HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif + +#if HAVE_FTIME +#include <sys/timeb.h> +#endif + +#if HAVE_TIMES + +#if HAVE_SYS_TIMES_H +#include <sys/times.h> +#endif + +#if TIMES_DECLARATION_OK +/* We use a macro to protect this because times really returns clock_t + and on some systems, such as Ultrix 4.0, clock_t is int. We don't + leave it out entirely because on some systems, such as System III, + the declaration is necessary for correct compilation. */ +#ifndef times +extern long times (); +#endif +#endif /* TIMES_DECLARATION_OK */ + +#ifdef _SC_CLK_TCK +#define HAVE_SC_CLK_TCK 1 +#else +#define HAVE_SC_CLK_TCK 0 +#endif + +/* TIMES_TICK may have been set in policy.h, or we may be able to get + it using sysconf. If neither is the case, try to find a useful + definition from the system header files. */ +#if TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) +#ifdef CLK_TCK +#undef TIMES_TICK +#define TIMES_TICK CLK_TCK +#else /* ! defined (CLK_TCK) */ +#ifdef HZ +#undef TIMES_TICK +#define TIMES_TICK HZ +#endif /* defined (HZ) */ +#endif /* ! defined (CLK_TCK) */ +#endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */ + +#endif /* HAVE_TIMES */ + +#ifndef time +extern time_t time (); +#endif +#if HAVE_SYSCONF +#ifndef sysconf +extern long sysconf (); +#endif +#endif + +/* Get the time in seconds and microseconds; this need only work + within the process when called from the system independent code. + It is also called by ixsysdep_time. */ + +long +ixsysdep_process_time (pimicros) + long *pimicros; +{ +#if HAVE_GETTIMEOFDAY + struct timeval stime; + struct timezone stz; + + (void) gettimeofday (&stime, &stz); + if (pimicros != NULL) + *pimicros = (long) stime.tv_usec; + return (long) stime.tv_sec; +#endif /* HAVE_GETTIMEOFDAY */ + +#if HAVE_FTIME + static boolean fbad; + + if (! fbad) + { + struct timeb stime; + static struct timeb slast; + + (void) ftime (&stime); + + /* On some systems, such as SCO 3.2.2, ftime can go backwards in + time. If we detect this, we switch to using time. */ + if (slast.time != 0 + && (stime.time < slast.time + || (stime.time == slast.time && + stime.millitm < slast.millitm))) + fbad = TRUE; + else + { + slast = stime; + if (pimicros != NULL) + *pimicros = (long) stime.millitm * (long) 1000; + return (long) stime.time; + } + } + + if (pimicros != NULL) + *pimicros = 0; + return (long) time ((time_t *) NULL); +#endif /* HAVE_FTIME */ + +#if HAVE_TIMES + struct tms s; + long i; + static int itick; + + if (itick == 0) + { +#if TIMES_TICK == 0 +#if HAVE_SYSCONF && HAVE_SC_CLK_TCK + itick = (int) sysconf (_SC_CLK_TCK); +#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ + const char *z; + + z = getenv ("HZ"); + if (z != NULL) + itick = (int) strtol (z, (char **) NULL, 10); + + /* If we really couldn't get anything, just use 60. */ + if (itick == 0) + itick = 60; +#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ +#else /* TIMES_TICK != 0 */ + itick = TIMES_TICK; +#endif /* TIMES_TICK == 0 */ + } + + i = (long) times (&s); + if (pimicros != NULL) + *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick); + return i / (long) itick; +#endif /* HAVE_TIMES */ + +#if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES + if (pimicros != NULL) + *pimicros = 0; + return (long) time ((time_t *) NULL); +#endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */ +} diff --git a/gnu/libexec/uucp/libunix/recep.c b/gnu/libexec/uucp/libunix/recep.c new file mode 100644 index 00000000000..84a211a7a94 --- /dev/null +++ b/gnu/libexec/uucp/libunix/recep.c @@ -0,0 +1,197 @@ +/* recep.c + See whether a file has already been received. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_TIME_H +#include <time.h> +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +static char *zsreceived_name P((const struct uuconf_system *qsys, + const char *ztemp)); + +/* These routines are used to see whether we have already received a + file in a previous UUCP connection. It is possible for the + acknowledgement of a received file to be lost. The sending system + will then now know that the file was correctly received, and will + send it again. This can be a problem particularly with protocols + which support channels, since they may send several small files in + a single window, all of which may be received correctly although + the sending system never sees the acknowledgement. If these files + involve an execution, the execution will happen twice, which will + be bad. + + We use a simple system. For each file we want to remember, we + create an empty file names .Received/SYS/TEMP, where SYS is the + name of the system and TEMP is the name of the temporary file used + by the sender. If no temporary file is used by the sender, we + don't remember that we received the file. This is not perfect, but + execution files will always have a temporary file, so the most + important case is handled. Also, any file received from Taylor + UUCP 1.04 or greater will always have a temporary file. */ + +/* Return the name we are going use for the marker, or NULL if we have + no name. */ + +static char * +zsreceived_name (qsys, ztemp) + const struct uuconf_system *qsys; + const char *ztemp; +{ + if (ztemp != NULL + && *ztemp == 'D' + && strcmp (ztemp, "D.0") != 0) + return zsappend3 (".Received", qsys->uuconf_zname, ztemp); + else + return NULL; +} + +/* Remember that we have already received a file. */ + +/*ARGSUSED*/ +boolean +fsysdep_remember_reception (qsys, zto, ztemp) + const struct uuconf_system *qsys; + const char *zto; + const char *ztemp; +{ + char *zfile; + int o; + + zfile = zsreceived_name (qsys, ztemp); + if (zfile == NULL) + return TRUE; + o = creat (zfile, IPUBLIC_FILE_MODE); + if (o < 0) + { + if (errno == ENOENT) + { + if (fsysdep_make_dirs (zfile, TRUE)) + { + ubuffree (zfile); + return FALSE; + } + o = creat (zfile, IPUBLIC_FILE_MODE); + } + if (o < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", zfile, strerror (errno)); + ubuffree (zfile); + return FALSE; + } + } + + ubuffree (zfile); + + /* We don't have to actually put anything in the file; we just use + the name. This is more convenient than keeping a file with a + list of names. */ + if (close (o) < 0) + { + ulog (LOG_ERROR, "fsysdep_remember_reception: close: %s", + strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* See if we have already received a file. Note that don't delete the + marker file here, because we need to know that the sending system + has received our denial first. This function returns TRUE if the + file has already been received, FALSE if it has not. */ + +/*ARGSUSED*/ +boolean +fsysdep_already_received (qsys, zto, ztemp) + const struct uuconf_system *qsys; + const char *zto; + const char *ztemp; +{ + char *zfile; + struct stat s; + boolean fret; + + zfile = zsreceived_name (qsys, ztemp); + if (zfile == NULL) + return FALSE; + if (stat (zfile, &s) < 0) + { + if (errno != ENOENT) + ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); + ubuffree (zfile); + return FALSE; + } + + /* Ignore the file (return FALSE) if it is over one week old. */ + fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL); + + if (fret) + DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s", + zfile); + + ubuffree (zfile); + + return fret; +} + +/* Forget that we have received a file. */ + +/*ARGSUSED*/ +boolean +fsysdep_forget_reception (qsys, zto, ztemp) + const struct uuconf_system *qsys; + const char *zto; + const char *ztemp; +{ + char *zfile; + + zfile = zsreceived_name (qsys, ztemp); + if (zfile == NULL) + return TRUE; + if (remove (zfile) < 0 + && errno != ENOENT) + { + ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); + ubuffree (zfile); + return FALSE; + } + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/remove.c b/gnu/libexec/uucp/libunix/remove.c new file mode 100644 index 00000000000..b695888ffaa --- /dev/null +++ b/gnu/libexec/uucp/libunix/remove.c @@ -0,0 +1,13 @@ +/* remove.c + Remove a file (Unix specific implementation). */ + +#include "uucp.h" + +#include "sysdep.h" + +int +remove (z) + const char *z; +{ + return unlink (z); +} diff --git a/gnu/libexec/uucp/libunix/rename.c b/gnu/libexec/uucp/libunix/rename.c new file mode 100644 index 00000000000..0947ef5cfae --- /dev/null +++ b/gnu/libexec/uucp/libunix/rename.c @@ -0,0 +1,27 @@ +/* rename.c + Rename a file to a new name (Unix specific implementation). */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +/* This implementation will not work on directories, but fortunately + we never want to rename directories. */ + +int +rename (zfrom, zto) + const char *zfrom; + const char *zto; +{ + if (link (zfrom, zto) < 0) + { + if (errno != EEXIST) + return -1; + if (unlink (zto) < 0 + || link (zfrom, zto) < 0) + return -1; + } + return unlink (zfrom); +} diff --git a/gnu/libexec/uucp/libunix/rmdir.c b/gnu/libexec/uucp/libunix/rmdir.c new file mode 100644 index 00000000000..12a7b9e4507 --- /dev/null +++ b/gnu/libexec/uucp/libunix/rmdir.c @@ -0,0 +1,43 @@ +/* rmdir.c + Remove a directory on a system which doesn't have the rmdir system + call. This is only called by uupick, which is not setuid, so we + don't have to worry about the problems of invoking the setuid + /bin/rmdir program. */ + +#include "uucp.h" + +#include "sysdep.h" + +#include <errno.h> + +int +rmdir (zdir) + const char *zdir; +{ + const char *azargs[3]; + int aidescs[3]; + pid_t ipid; + + azargs[0] = RMDIR_PROGRAM; + azargs[1] = zdir; + azargs[2] = NULL; + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, + TRUE, TRUE, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + + if (ipid < 0) + return -1; + + if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) + { + /* Make up an errno value. */ + errno = EBUSY; + return -1; + } + + return 0; +} diff --git a/gnu/libexec/uucp/libunix/run.c b/gnu/libexec/uucp/libunix/run.c new file mode 100644 index 00000000000..e2191962837 --- /dev/null +++ b/gnu/libexec/uucp/libunix/run.c @@ -0,0 +1,75 @@ +/* run.c + Run a program. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* Start up a new program and end the current one. We don't have to + worry about SIGHUP because the current process is either not a + process group leader (uucp, uux) or it does not have a controlling + terminal (uucico). */ + +boolean +fsysdep_run (zprogram, zarg1, zarg2) + const char *zprogram; + const char *zarg1; + const char *zarg2; +{ + char *zlib; + const char *azargs[4]; + int aidescs[3]; + pid_t ipid; + + zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram)); + sprintf (zlib, "%s/%s", SBINDIR, zprogram); + + azargs[0] = zlib; + azargs[1] = zarg1; + azargs[2] = zarg2; + azargs[3] = NULL; + + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + /* We pass fsetuid and fshell as TRUE, which permits uucico and + uuxqt to be replaced by (non-setuid) shell scripts. */ + ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, + FALSE, TRUE, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + ubuffree (zlib); + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/seq.c b/gnu/libexec/uucp/libunix/seq.c new file mode 100644 index 00000000000..2e01233022a --- /dev/null +++ b/gnu/libexec/uucp/libunix/seq.c @@ -0,0 +1,126 @@ +/* seq.c + Get and increment the conversation sequence number for a system. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* Get the current conversation sequence number for a remote system, + and increment it for next time. The conversation sequence number + is kept in a file named for the system in the directory .Sequence + in the spool directory. This is not compatible with other versions + of UUCP, but it makes more sense to me. The sequence file is only + used if specified in the information for that system. */ + +long +ixsysdep_get_sequence (qsys) + const struct uuconf_system *qsys; +{ + FILE *e; + char *zname; + struct stat s; + long iseq; + + /* This will only be called when the system is locked anyhow, so there + is no need to use a separate lock for the conversation sequence + file. */ + zname = zsysdep_in_dir (".Sequence", qsys->uuconf_zname); + + iseq = 0; + if (stat (zname, &s) == 0) + { + boolean fok; + char *zline; + size_t cline; + + /* The file should only be readable and writable by uucp. */ + if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0) + { + ulog (LOG_ERROR, + "Bad file protection for conversation sequence file"); + ubuffree (zname); + return -1; + } + + e = fopen (zname, "r+"); + if (e == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); + ubuffree (zname); + return -1; + } + + ubuffree (zname); + + fok = TRUE; + zline = NULL; + cline = 0; + if (getline (&zline, &cline, e) <= 0) + fok = FALSE; + else + { + char *zend; + + iseq = strtol (zline, &zend, 10); + if (zend == zline) + fok = FALSE; + } + + xfree ((pointer) zline); + + if (! fok) + { + ulog (LOG_ERROR, "Bad format for conversation sequence file"); + (void) fclose (e); + return -1; + } + + rewind (e); + } + else + { + e = esysdep_fopen (zname, FALSE, FALSE, TRUE); + ubuffree (zname); + if (e == NULL) + return -1; + } + + ++iseq; + + fprintf (e, "%ld", iseq); + + if (fclose (e) != 0) + { + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + return -1; + } + + return iseq; +} diff --git a/gnu/libexec/uucp/libunix/serial.c b/gnu/libexec/uucp/libunix/serial.c new file mode 100644 index 00000000000..2b02cd5aaa5 --- /dev/null +++ b/gnu/libexec/uucp/libunix/serial.c @@ -0,0 +1,2977 @@ +/* serial.c + The serial port communication routines for Unix. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char serial_rcsid[] = "$Id: serial.c,v 1.1 1993/08/04 19:32:52 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "conn.h" +#include "sysdep.h" + +#include <errno.h> +#include <ctype.h> + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +#if HAVE_TLI +#if HAVE_TIUSER_H +#include <tiuser.h> +#else /* ! HAVE_TIUSER_H */ +#if HAVE_XTI_H +#include <xti.h> +#endif /* HAVE_XTI_H */ +#endif /* ! HAVE_TIUSER_H */ +#endif /* HAVE_TLI */ + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_BSD_TTY +#include <sys/time.h> +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#endif + +#if HAVE_TIME_H +#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY +#include <time.h> +#endif +#endif + +#if HAVE_STRIP_BUG && HAVE_BSD_TTY +#include <termio.h> +#endif + +#if HAVE_SVR4_LOCKFILES +/* Get the right definitions for major and minor. */ +#if MAJOR_IN_MKDEV +#include <sys/mkdev.h> +#endif /* MAJOR_IN_MKDEV */ +#if MAJOR_IN_SYSMACROS +#include <sys/sysmacros.h> +#endif /* MAJOR_IN_SYSMACROS */ +#if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS +#ifndef major +#define major(i) (((i) >> 8) & 0xff) +#endif +#ifndef minor +#define minor(i) ((i) & 0xff) +#endif +#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */ +#endif /* HAVE_SVR4_LOCKFILES */ + +/* Get definitions for both O_NONBLOCK and O_NDELAY. */ +#ifndef O_NDELAY +#ifdef FNDELAY +#define O_NDELAY FNDELAY +#else /* ! defined (FNDELAY) */ +#define O_NDELAY 0 +#endif /* ! defined (FNDELAY) */ +#endif /* ! defined (O_NDELAY) */ + +#ifndef O_NONBLOCK +#ifdef FNBLOCK +#define O_NONBLOCK FNBLOCK +#else /* ! defined (FNBLOCK) */ +#define O_NONBLOCK 0 +#endif /* ! defined (FNBLOCK) */ +#endif /* ! defined (O_NONBLOCK) */ + +#if O_NDELAY == 0 && O_NONBLOCK == 0 + #error No way to do nonblocking I/O +#endif + +/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ +#ifndef EAGAIN +#ifndef EWOULDBLOCK +#define EAGAIN (-1) +#define EWOULDBLOCK (-1) +#else /* defined (EWOULDBLOCK) */ +#define EAGAIN EWOULDBLOCK +#endif /* defined (EWOULDBLOCK) */ +#else /* defined (EAGAIN) */ +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif /* ! defined (EWOULDBLOCK) */ +#endif /* defined (EAGAIN) */ + +#ifndef ENODATA +#define ENODATA EAGAIN +#endif + +/* Make sure we have a definition for MAX_INPUT. */ +#ifndef MAX_INPUT +#define MAX_INPUT (256) +#endif + +/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal. + Otherwise, if we have the TIOCEXCL ioctl call, we have to open the + terminal before we know that it is unlocked. */ +#ifdef TIOCSINUSE +#define HAVE_TIOCSINUSE 1 +#else +#ifdef TIOCEXCL +#define HAVE_TIOCEXCL 1 +#endif +#endif + +#if HAVE_TLI +extern int t_errno; +extern char *t_errlist[]; +extern int t_nerr; +#endif + +/* Determine bits to clear for the various terminal control fields for + HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */ +#if HAVE_SYSV_TERMIO +#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \ + | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \ + | IXON | IXANY | IXOFF) +#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \ + | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \ + | VTDLY | FFDLY) +#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD) +#define ISET_CFLAG (CS8 | CREAD | HUPCL) +#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \ + | ECHONL | NOFLSH) +#endif +#if HAVE_POSIX_TERMIOS +#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \ + | INLCR | INPCK | ISTRIP | IXOFF | IXON \ + | PARMRK) +#define ICLEAR_OFLAG (OPOST) +#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD) +#define ISET_CFLAG (CS8 | CREAD | HUPCL) +#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \ + | ISIG | NOFLSH | TOSTOP) +#endif + +/* Local functions. */ + +static RETSIGTYPE usalarm P((int isig)); +static boolean fsserial_init P((struct sconnection *qconn, + const struct sconncmds *qcmds, + const char *zdevice)); +static void usserial_free P((struct sconnection *qconn)); +static boolean fsserial_lockfile P((boolean flok, + const struct sconnection *)); +static boolean fsserial_lock P((struct sconnection *qconn, + boolean fin)); +static boolean fsserial_unlock P((struct sconnection *qconn)); +static boolean fsserial_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean fsstdin_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean fsmodem_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean fsdirect_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean fsblock P((struct ssysdep_conn *q, boolean fblock)); +static boolean fsserial_close P((struct ssysdep_conn *q)); +static boolean fsstdin_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean fsmodem_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean fsdirect_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean fsserial_reset P((struct sconnection *qconn)); +static boolean fsstdin_reset P((struct sconnection *qconn)); +static boolean fsstdin_read P((struct sconnection *qconn, + char *zbuf, size_t *pclen, size_t cmin, + int ctimeout, boolean freport)); +static boolean fsstdin_write P((struct sconnection *qconn, + const char *zwrite, size_t cwrite)); +static boolean fsserial_break P((struct sconnection *qconn)); +static boolean fsstdin_break P((struct sconnection *qconn)); +static boolean fsserial_set P((struct sconnection *qconn, + enum tparitysetting tparity, + enum tstripsetting tstrip, + enum txonxoffsetting txonxoff)); +static boolean fsstdin_set P((struct sconnection *qconn, + enum tparitysetting tparity, + enum tstripsetting tstrip, + enum txonxoffsetting txonxoff)); +static boolean fsmodem_carrier P((struct sconnection *qconn, + boolean fcarrier)); +static boolean fsrun_chat P((int oread, int owrite, char **pzprog)); +static boolean fsstdin_chat P((struct sconnection *qconn, + char **pzprog)); +static long isserial_baud P((struct sconnection *qconn)); + +/* The command table for standard input ports. */ + +static const struct sconncmds sstdincmds = +{ + usserial_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + fsstdin_open, + fsstdin_close, + fsstdin_reset, + NULL, /* pfdial */ + fsstdin_read, + fsstdin_write, + fsysdep_conn_io, + fsstdin_break, + fsstdin_set, + NULL, /* pfcarrier */ + fsstdin_chat, + isserial_baud +}; + +/* The command table for modem ports. */ + +static const struct sconncmds smodemcmds = +{ + usserial_free, + fsserial_lock, + fsserial_unlock, + fsmodem_open, + fsmodem_close, + fsserial_reset, + fmodem_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + fsserial_break, + fsserial_set, + fsmodem_carrier, + fsysdep_conn_chat, + isserial_baud +}; + +/* The command table for direct ports. */ + +static const struct sconncmds sdirectcmds = +{ + usserial_free, + fsserial_lock, + fsserial_unlock, + fsdirect_open, + fsdirect_close, + fsserial_reset, + NULL, /* pfdial */ + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + fsserial_break, + fsserial_set, + NULL, /* pfcarrier */ + fsysdep_conn_chat, + isserial_baud +}; + +/* If the system will let us set both O_NDELAY and O_NONBLOCK, we do + so. This is because some ancient drivers on some systems appear to + look for one but not the other. Some other systems will give an + EINVAL error if we attempt to set both, so we use a static global + to hold the value we want to set. If we get EINVAL, we change the + global and try again (if some system gives an error other than + EINVAL, the code will have to be modified). */ +static int iSunblock = O_NDELAY | O_NONBLOCK; + +/* This code handles SIGALRM. See the discussion above + fsysdep_conn_read. Normally we ignore SIGALRM, but the handler + will temporarily be set to this function, which should set fSalarm + and then either longjmp or schedule another SIGALRM. fSalarm is + never referred to outside of this file, but we don't make it static + to try to fool compilers which don't understand volatile. */ + +volatile sig_atomic_t fSalarm; + +static RETSIGTYPE +usalarm (isig) + int isig; +{ +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET + (void) signal (isig, usalarm); +#endif + + fSalarm = TRUE; + +#if HAVE_RESTARTABLE_SYSCALLS + longjmp (sSjmp_buf, 1); +#else + alarm (1); +#endif +} + +/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and + SIGPIPE and another to restore the original state. When these + functions are called (in fsysdep_modem_close) SIGHUP is being + ignored. The routines are isblocksigs, which returns a value of + type HELD_SIG_MASK and usunblocksigs which takes a single argument + of type HELD_SIG_MASK. */ + +#if HAVE_SIGPROCMASK + +/* Use the POSIX sigprocmask call. */ + +#define HELD_SIG_MASK sigset_t + +static sigset_t isblocksigs P((void)); + +static sigset_t +isblocksigs () +{ + sigset_t sblock, sold; + + /* These expressions need an extra set of parentheses to avoid a bug + in SCO 3.2.2. */ + (void) (sigemptyset (&sblock)); + (void) (sigaddset (&sblock, SIGINT)); + (void) (sigaddset (&sblock, SIGQUIT)); + (void) (sigaddset (&sblock, SIGTERM)); + (void) (sigaddset (&sblock, SIGPIPE)); + + (void) sigprocmask (SIG_BLOCK, &sblock, &sold); + return sold; +} + +#define usunblocksigs(s) \ + ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL)) + +#else /* ! HAVE_SIGPROCMASK */ +#if HAVE_SIGBLOCK + +/* Use the BSD sigblock and sigsetmask calls. */ + +#define HELD_SIG_MASK int + +#ifndef sigmask +#define sigmask(i) (1 << ((i) - 1)) +#endif + +#define isblocksigs() \ + sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \ + | sigmask (SIGTERM) | sigmask (SIGPIPE)) + +#define usunblocksigs(i) ((void) sigsetmask (i)) + +#else /* ! HAVE_SIGBLOCK */ + +#if HAVE_SIGHOLD + +/* Use the SVR3 sighold and sigrelse calls. */ + +#define HELD_SIG_MASK int + +static int isblocksigs P((void)); + +static int +isblocksigs () +{ + sighold (SIGINT); + sighold (SIGQUIT); + sighold (SIGTERM); + sighold (SIGPIPE); + return 0; +} + +static void usunblocksigs P((int)); + +/*ARGSUSED*/ +static void +usunblocksigs (i) + int i; +{ + sigrelse (SIGINT); + sigrelse (SIGQUIT); + sigrelse (SIGTERM); + sigrelse (SIGPIPE); +} + +#else /* ! HAVE_SIGHOLD */ + +/* We have no way to block signals. This system will suffer from a + race condition in fsysdep_modem_close. */ + +#define HELD_SIG_MASK int + +#define isblocksigs() 0 + +#define usunblocksigs(i) + +#endif /* ! HAVE_SIGHOLD */ +#endif /* ! HAVE_SIGBLOCK */ +#endif /* ! HAVE_SIGPROCMASK */ + +/* Initialize a connection for use on a serial port. */ + +static boolean +fsserial_init (qconn, qcmds, zdevice) + struct sconnection *qconn; + const struct sconncmds *qcmds; + const char *zdevice; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + if (zdevice == NULL + && qconn->qport != NULL + && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) + zdevice = qconn->qport->uuconf_zname; + if (zdevice == NULL) + q->zdevice = NULL; + else if (*zdevice == '/') + q->zdevice = zbufcpy (zdevice); + else + { + size_t clen; + + clen = strlen (zdevice); + q->zdevice = zbufalc (sizeof "/dev/" + clen); + memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1); + memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen); + q->zdevice[sizeof "/dev/" + clen - 1] = '\0'; + } + q->o = -1; + q->ftli = FALSE; + qconn->psysdep = (pointer) q; + qconn->qcmds = qcmds; + return TRUE; +} + +/* Initialize a connection for use on standard input. */ + +boolean +fsysdep_stdin_init (qconn) + struct sconnection *qconn; +{ + return fsserial_init (qconn, &sstdincmds, (const char *) NULL); +} + +/* Initialize a connection for use on a modem port. */ + +boolean +fsysdep_modem_init (qconn) + struct sconnection *qconn; +{ + return fsserial_init (qconn, &smodemcmds, + qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice); +} + +/* Initialize a connection for use on a direct port. */ + +boolean +fsysdep_direct_init (qconn) + struct sconnection *qconn; +{ + return fsserial_init (qconn, &sdirectcmds, + qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice); +} + +/* Free up a serial port. */ + +static void +usserial_free (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + ubuffree (qsysdep->zdevice); + xfree ((pointer) qsysdep); + qconn->psysdep = NULL; +} + +/* This routine is used for both locking and unlocking. It is the + only routine which knows how to translate a device name into the + name of a lock file. If it can't figure out a name, it does + nothing and returns TRUE. */ + +static boolean +fsserial_lockfile (flok, qconn) + boolean flok; + const struct sconnection *qconn; +{ + struct ssysdep_conn *qsysdep; + const char *z; + char *zalc; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + if (qconn->qport == NULL) + z = NULL; + else + z = qconn->qport->uuconf_zlockname; + zalc = NULL; + if (z == NULL) + { +#if ! HAVE_SVR4_LOCKFILES + { + const char *zbase; + size_t clen; + + zbase = strrchr (qsysdep->zdevice, '/') + 1; + clen = strlen (zbase); + zalc = zbufalc (sizeof "LCK.." + clen); + memcpy (zalc, "LCK..", sizeof "LCK.." - 1); + memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1); +#if HAVE_SCO_LOCKFILES + { + char *zl; + + for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++) + if (isupper (*zl)) + *zl = tolower (*zl); + } +#endif + z = zalc; + } +#else /* ! HAVE_SVR4_LOCKFILES */ +#if HAVE_SVR4_LOCKFILES + { + struct stat s; + + if (stat (qsysdep->zdevice, &s) != 0) + { + ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice, + strerror (errno)); + return FALSE; + } + zalc = zbufalc (sizeof "LK.123.123.123"); + sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev), + major (s.st_rdev), minor (s.st_rdev)); + z = zalc; + } +#else /* ! HAVE_SVR4_LOCKFILES */ + z = strrchr (qsysdep->zdevice, '/') + 1; +#endif /* ! HAVE_SVR4_LOCKFILES */ +#endif /* ! HAVE_SVR4_LOCKFILES */ + } + + if (flok) + fret = fsdo_lock (z, FALSE, (boolean *) NULL); + else + fret = fsdo_unlock (z, FALSE); + +#if HAVE_COHERENT_LOCKFILES + if (fret) + { + if (flok) + { + if (lockttyexist (z)) + { + ulog (LOG_NORMAL, "%s: port already locked"); + fret = FALSE; + } + else + fret = fscoherent_disable_tty (z, &qsysdep->zenable); + } + else + { + fret = TRUE; + if (qsysdep->zenable != NULL) + { + const char *azargs[3]; + int aidescs[3]; + pid_t ipid; + + azargs[0] = "/etc/enable"; + azargs[1] = qsysdep->zenable; + azargs[2] = NULL; + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, + (const char *) NULL, TRUE, TRUE, + (const char *) NULL, (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s", + qsysdep->zenable, strerror (errno)); + fret = FALSE; + } + else + { + if (ixswait ((unsigned long) ipid, (const char *) NULL) + == 0) + fret = TRUE; + else + fret = FALSE; + } + ubuffree (qsysdep->zenable); + qsysdep->zenable = NULL; + } + } + } +#endif /* HAVE_COHERENT_LOCKFILES */ + + ubuffree (zalc); + return fret; +} + +/* If we can mark a modem line in use, then when we lock a port we + must open it and mark it in use. We can't wait until the actual + open because we can't fail out if it is locked then. */ + +static boolean +fsserial_lock (qconn, fin) + struct sconnection *qconn; + boolean fin; +{ + if (! fsserial_lockfile (TRUE, qconn)) + return FALSE; + +#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL + /* Open the line and try to mark it in use. */ + { + struct ssysdep_conn *qsysdep; + int iflag; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + if (fin) + iflag = 0; + else + iflag = iSunblock; + + qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag); + if (qsysdep->o < 0) + { +#if O_NONBLOCK != 0 + if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL) + { + iSunblock = O_NONBLOCK; + qsysdep->o = open (qsysdep->zdevice, + O_RDWR | O_NONBLOCK); + } +#endif + if (qsysdep->o < 0) + { + if (errno != EBUSY) + ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice, + strerror (errno)); + (void) fsserial_lockfile (FALSE, qconn); + return FALSE; + } + } + +#if HAVE_TIOCSINUSE + /* If we can't mark it in use, return FALSE to indicate that the + lock failed. */ + if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0) + { + if (errno != EALREADY) + ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno)); +#ifdef TIOCNOTTY + (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); +#endif + (void) close (qsysdep->o); + qsysdep->o = -1; + (void) fsserial_lockfile (FALSE, qconn); + return FALSE; + } +#endif + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); +#ifdef TIOCNOTTY + (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); +#endif + (void) close (qsysdep->o); + qsysdep->o = -1; + (void) fsserial_lockfile (FALSE, qconn); + return FALSE; + } + +#ifdef TIOCSCTTY + /* On BSD 4.4, make it our controlling terminal. */ + (void) ioctl (qsysdep->o, TIOCSCTTY, 0); +#endif + } +#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */ + + return TRUE; +} + +/* Unlock a modem or direct port. */ + +static boolean +fsserial_unlock (qconn) + struct sconnection *qconn; +{ + boolean fret; + struct ssysdep_conn *qsysdep; + + fret = TRUE; + + /* The file may have been opened by fsserial_lock, so close it here + if necessary. */ + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + if (qsysdep->o >= 0) + { +#ifdef TIOCNOTTY + (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); +#endif + if (close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + qsysdep->o = -1; + } + + if (! fsserial_lockfile (FALSE, qconn)) + fret = FALSE; + + return fret; +} + +/* Open a serial line. This sets the terminal settings. We begin in + seven bit mode and let the protocol change if necessary. */ + +#if HAVE_POSIX_TERMIOS +typedef speed_t baud_code; +#else +typedef int baud_code; +#endif + +static struct sbaud_table +{ + baud_code icode; + long ibaud; +} asSbaud_table[] = +{ + { B50, 50 }, + { B75, 75 }, + { B110, 110 }, + { B134, 134 }, + { B150, 150 }, + { B200, 200 }, + { B300, 300 }, + { B600, 600 }, + { B1200, 1200 }, + { B1800, 1800 }, + { B2400, 2400 }, + { B4800, 4800 }, + { B9600, 9600 }, +#ifdef B19200 + { B19200, 19200 }, +#else /* ! defined (B19200) */ +#ifdef EXTA + { EXTA, 19200 }, +#endif /* EXTA */ +#endif /* ! defined (B19200) */ +#ifdef B38400 + { B38400, 38400 }, +#else /* ! defined (B38400) */ +#ifdef EXTB + { EXTB, 38400 }, +#endif /* EXTB */ +#endif /* ! defined (B38400) */ +#ifdef B57600 + { B57600, 57600 }, +#endif +#ifdef B76800 + { B76800, 76800 }, +#endif +#ifdef B115200 + { B115200, 115200 }, +#endif + { B0, 0 } +}; + +#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0]) + +#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS +/* Hold the MIN value for the terminal to avoid setting it + unnecessarily. */ +static int cSmin; +#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ + +static boolean +fsserial_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *q; + baud_code ib; + + q = (struct ssysdep_conn *) qconn->psysdep; + + if (q->zdevice != NULL) + ulog_device (strrchr (q->zdevice, '/') + 1); + else + { + const char *zport; + boolean fdummy; + +#if DEBUG > 0 + if (qconn->qport != NULL && + qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) + ulog (LOG_FATAL, "fsserial_open: Can't happen"); +#endif + zport = zsysdep_port_name (&fdummy); + if (zport != NULL) + ulog_device (zport); + } + + ib = B0; + if (ibaud != 0) + { + int i; + + for (i = 0; i < CBAUD_TABLE; i++) + if (asSbaud_table[i].ibaud == ibaud) + break; + if (i >= CBAUD_TABLE) + { + ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud); + return FALSE; + } + ib = asSbaud_table[i].icode; + } + + /* The port may have already been opened by the locking routine. */ + if (q->o < 0) + { + int iflag; + + if (fwait) + iflag = 0; + else + iflag = iSunblock; + + q->o = open (q->zdevice, O_RDWR | iflag); + if (q->o < 0) + { +#if O_NONBLOCK != 0 + if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL) + { + iSunblock = O_NONBLOCK; + q->o = open (q->zdevice, O_RDWR | O_NONBLOCK); + } +#endif + if (q->o < 0) + { + ulog (LOG_ERROR, "open (%s): %s", q->zdevice, + strerror (errno)); + return FALSE; + } + } + + if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + return FALSE; + } + +#ifdef TIOCSCTTY + /* On BSD 4.4, make it our controlling terminal. */ + (void) ioctl (q->o, TIOCSCTTY, 0); +#endif + } + + /* Get the port flags, and make sure the ports are blocking. */ + + q->iflags = fcntl (q->o, F_GETFL, 0); + if (q->iflags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + return FALSE; + } + q->istdout_flags = -1; + + if (! fgetterminfo (q->o, &q->sorig)) + { + q->fterminal = FALSE; + return TRUE; + } + + q->fterminal = TRUE; + + q->snew = q->sorig; + +#if HAVE_BSD_TTY + + q->snew.stty.sg_flags = RAW | ANYP; + if (ibaud == 0) + ib = q->snew.stty.sg_ospeed; + else + { + q->snew.stty.sg_ispeed = ib; + q->snew.stty.sg_ospeed = ib; + } + + /* We don't want to receive any interrupt characters. */ + q->snew.stchars.t_intrc = -1; + q->snew.stchars.t_quitc = -1; + q->snew.stchars.t_eofc = -1; + q->snew.stchars.t_brkc = -1; + q->snew.sltchars.t_suspc = -1; + q->snew.sltchars.t_rprntc = -1; + q->snew.sltchars.t_dsuspc = -1; + q->snew.sltchars.t_flushc = -1; + q->snew.sltchars.t_werasc = -1; + q->snew.sltchars.t_lnextc = -1; + +#ifdef NTTYDISC + /* We want to use the ``new'' terminal driver so that we can use the + local mode bits to control XON/XOFF. */ + { + int iparam; + + if (ioctl (q->o, TIOCGETD, &iparam) >= 0 + && iparam != NTTYDISC) + { + iparam = NTTYDISC; + (void) ioctl (q->o, TIOCSETD, &iparam); + } + } +#endif + +#ifdef TIOCHPCL + /* When the file is closed, hang up the line. This is a safety + measure in case the program crashes. */ + (void) ioctl (q->o, TIOCHPCL, 0); +#endif + +#ifdef TIOCFLUSH + { + int iparam; + + /* Flush pending input. */ +#ifdef FREAD + iparam = FREAD; +#else + iparam = 0; +#endif + (void) ioctl (q->o, TIOCFLUSH, &iparam); + } +#endif /* TIOCFLUSH */ + +#endif /* HAVE_BSD_TTY */ + +#if HAVE_SYSV_TERMIO + + if (ibaud == 0) + ib = q->snew.c_cflag & CBAUD; + + q->snew.c_iflag &=~ ICLEAR_IFLAG; + q->snew.c_oflag &=~ ICLEAR_OFLAG; + q->snew.c_cflag &=~ ICLEAR_CFLAG; + q->snew.c_cflag |= (ib | ISET_CFLAG); + q->snew.c_lflag &=~ ICLEAR_LFLAG; + cSmin = 1; + q->snew.c_cc[VMIN] = cSmin; + q->snew.c_cc[VTIME] = 0; + +#ifdef TCFLSH + /* Flush pending input. */ + (void) ioctl (q->o, TCFLSH, 0); +#endif + +#endif /* HAVE_SYSV_TERMIO */ + +#if HAVE_POSIX_TERMIOS + + if (ibaud == 0) + ib = cfgetospeed (&q->snew); + + q->snew.c_iflag &=~ ICLEAR_IFLAG; + q->snew.c_oflag &=~ ICLEAR_OFLAG; + q->snew.c_cflag &=~ ICLEAR_CFLAG; + q->snew.c_cflag |= ISET_CFLAG; + q->snew.c_lflag &=~ ICLEAR_LFLAG; + cSmin = 1; + q->snew.c_cc[VMIN] = cSmin; + q->snew.c_cc[VTIME] = 0; + + (void) cfsetospeed (&q->snew, ib); + (void) cfsetispeed (&q->snew, ib); + + /* Flush pending input. */ + (void) tcflush (q->o, TCIFLUSH); + +#endif /* HAVE_POSIX_TERMIOS */ + + if (! fsetterminfo (q->o, &q->snew)) + { + ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno)); + return FALSE; + } + + if (ibaud != 0) + q->ibaud = ibaud; + else + { + int i; + + q->ibaud = (long) 1200; + for (i = 0; i < CBAUD_TABLE; i++) + { + if (asSbaud_table[i].icode == ib) + { + q->ibaud = asSbaud_table[i].ibaud; + break; + } + } + + DEBUG_MESSAGE1 (DEBUG_PORT, + "fsserial_open: Baud rate is %ld", q->ibaud); + } + + return TRUE; +} + +/* Open a standard input port. The code alternates q->o between 0 and + 1 as appropriate. It is always 0 before any call to fsblock. */ + +static boolean +fsstdin_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) qconn->psysdep; + q->o = 0; + if (! fsserial_open (qconn, ibaud, fwait)) + return FALSE; + q->istdout_flags = fcntl (1, F_GETFL, 0); + if (q->istdout_flags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + return FALSE; + } + return TRUE; +} + +/* Open a modem port. */ + +static boolean +fsmodem_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + if (ibaud == (long) 0) + ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud; + return fsserial_open (qconn, ibaud, fwait); +} + +/* Open a direct port. */ + +static boolean +fsdirect_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + if (ibaud == (long) 0) + ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; + return fsserial_open (qconn, ibaud, fwait); +} + +/* Change the blocking status of the port. We keep track of the + current blocking status to avoid calling fcntl unnecessarily; fcntl + turns out to be surprisingly expensive, at least on Ultrix. */ + +static boolean +fsblock (qs, fblock) + struct ssysdep_conn *qs; + boolean fblock; +{ + int iwant; + int isys; + + if (fblock) + iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK); + else + iwant = qs->iflags | iSunblock; + + if (iwant == qs->iflags) + return TRUE; + + isys = fcntl (qs->o, F_SETFL, iwant); + if (isys < 0) + { +#if O_NONBLOCK != 0 + if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL) + { + iSunblock = O_NONBLOCK; + iwant = qs->iflags | O_NONBLOCK; + isys = fcntl (qs->o, F_SETFL, iwant); + } +#endif + if (isys < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + return FALSE; + } + } + + qs->iflags = iwant; + + if (qs->istdout_flags >= 0) + { + if (fblock) + iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK); + else + iwant = qs->istdout_flags | iSunblock; + + if (fcntl (1, F_SETFL, iwant) < 0) + { + /* We don't bother to fix up iSunblock here, since we + succeeded above. */ + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + return FALSE; + } + + qs->istdout_flags = iwant; + } + + return TRUE; +} + +/* Close a serial port. */ + +static boolean +fsserial_close (q) + struct ssysdep_conn *q; +{ + if (q->o >= 0) + { + /* Use a 30 second timeout to avoid hanging while draining + output. */ + if (q->fterminal) + { + fSalarm = FALSE; + + if (fsysdep_catch ()) + { + usysdep_start_catch (); + usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); + (void) alarm (30); + + (void) fsetterminfodrain (q->o, &q->sorig); + } + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + (void) alarm (0); + usysdep_end_catch (); + + /* If we timed out, use the non draining call. Hopefully + this can't hang. */ + if (fSalarm) + (void) fsetterminfo (q->o, &q->sorig); + } + +#ifdef TIOCNOTTY + /* We don't want this as our controlling terminal any more, so + get rid of it. This is necessary because we don't want to + open /dev/tty, since that can confuse the serial port locking + on some computers. */ + (void) ioctl (q->o, TIOCNOTTY, (char *) NULL); +#endif + + (void) close (q->o); + q->o = -1; + + /* Sleep to give the terminal a chance to settle, in case we are + about to call out again. */ + sleep (2); + } + + return TRUE; +} + +/* Close a stdin port. */ + +/*ARGSUSED*/ +static boolean +fsstdin_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + (void) close (1); + (void) close (2); + qsysdep->o = 0; + return fsserial_close (qsysdep); +} + +/* Close a modem port. */ + +static boolean +fsmodem_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + struct uuconf_dialer sdialer; + const struct uuconf_chat *qchat; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + fret = TRUE; + + /* Figure out the dialer so that we can run the complete or abort + chat scripts. */ + if (qdialer == NULL) + { + if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) + { + const char *zdialer; + int iuuconf; + + zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]; + iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer); + if (iuuconf == UUCONF_SUCCESS) + qdialer = &sdialer; + else + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + } + } + else + qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer; + } + + /* Get the complete or abort chat script to use. */ + qchat = NULL; + if (qdialer != NULL) + { + if (fsuccess) + qchat = &qdialer->uuconf_scomplete; + else + qchat = &qdialer->uuconf_sabort; + } + + if (qchat != NULL + && (qchat->uuconf_pzprogram != NULL + || qchat->uuconf_pzchat != NULL)) + { + boolean fsighup_ignored; + HELD_SIG_MASK smask; + int i; + sig_atomic_t afhold[INDEXSIG_COUNT]; + + /* We're no longer interested in carrier. */ + (void) fsmodem_carrier (qconn, FALSE); + + /* The port I/O routines check whether any signal has been + received, and abort if one has. While we are closing down + the modem, we don't care if we received a signal in the past, + but we do care if we receive a new signal (otherwise it would + be difficult to kill a uucico which was closing down a + modem). We never care if we get SIGHUP at this point. So we + turn off SIGHUP, remember what signals we've already seen, + and clear our notion of what signals we've seen. We have to + block the signals while we remember and clear the array, + since we might otherwise miss a signal which occurred between + the copy and the clear (old systems can't block signals; they + will just have to suffer the race). */ + usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored); + smask = isblocksigs (); + for (i = 0; i < INDEXSIG_COUNT; i++) + { + afhold[i] = afSignal[i]; + afSignal[i] = FALSE; + } + usunblocksigs (smask); + + if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL, + (const struct uuconf_dialer *) NULL, (const char *) NULL, + FALSE, qconn->qport->uuconf_zname, + qsysdep->ibaud)) + fret = FALSE; + + /* Restore the old signal array and the SIGHUP handler. It is + not necessary to block signals here, since all we are doing + is exactly what the signal handler itself would do if the + signal occurred. */ + for (i = 0; i < INDEXSIG_COUNT; i++) + if (afhold[i]) + afSignal[i] = TRUE; + if (! fsighup_ignored) + usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL); + } + + if (qdialer != NULL + && qdialer == &sdialer) + (void) uuconf_dialer_free (puuconf, &sdialer); + +#if ! HAVE_RESET_BUG + /* Reset the terminal to make sure we drop DTR. It should be + dropped when we close the descriptor, but that doesn't seem to + happen on some systems. Use a 30 second timeout to avoid hanging + while draining output. */ + if (qsysdep->fterminal) + { +#if HAVE_BSD_TTY + qsysdep->snew.stty.sg_ispeed = B0; + qsysdep->snew.stty.sg_ospeed = B0; +#endif +#if HAVE_SYSV_TERMIO + qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0; +#endif +#if HAVE_POSIX_TERMIOS + (void) cfsetospeed (&qsysdep->snew, B0); +#endif + + fSalarm = FALSE; + + if (fsysdep_catch ()) + { + usysdep_start_catch (); + usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); + (void) alarm (30); + + (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew); + } + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + (void) alarm (0); + usysdep_end_catch (); + + /* Let the port settle. */ + sleep (2); + } +#endif /* ! HAVE_RESET_BUG */ + + if (! fsserial_close (qsysdep)) + fret = FALSE; + + return fret; +} + +/* Close a direct port. */ + +/*ARGSUSED*/ +static boolean +fsdirect_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + return fsserial_close ((struct ssysdep_conn *) qconn->psysdep); +} + +/* Reset a serial port by hanging up. */ + +static boolean +fsserial_reset (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + sterminal sbaud; + + q = (struct ssysdep_conn *) qconn->psysdep; + + if (! q->fterminal) + return TRUE; + + sbaud = q->snew; + +#if HAVE_BSD_TTY + sbaud.stty.sg_ispeed = B0; + sbaud.stty.sg_ospeed = B0; +#endif +#if HAVE_SYSV_TERMIO + sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0; +#endif +#if HAVE_POSIX_TERMIOS + if (cfsetospeed (&sbaud, B0) < 0) + { + ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno)); + return FALSE; + } +#endif + + if (! fsetterminfodrain (q->o, &sbaud)) + { + ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno)); + return FALSE; + } + + /* Give the terminal a chance to settle. */ + sleep (2); + + if (! fsetterminfo (q->o, &q->snew)) + { + ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Reset a standard input port. */ + +static boolean +fsstdin_reset (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + qsysdep->o = 0; + return fsserial_reset (qconn); +} + +/* Begin dialing out on a modem port. This opens the dialer device if + there is one. */ + +boolean +fsysdep_modem_begin_dial (qconn, qdial) + struct sconnection *qconn; + struct uuconf_dialer *qdial; +{ + struct ssysdep_conn *qsysdep; + const char *z; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + +#ifdef TIOCMODEM + /* If we can tell the modem to obey modem control, do so. */ + { + int iperm; + + iperm = 0; + (void) ioctl (qsysdep->o, TIOCMODEM, &iperm); + } +#endif /* TIOCMODEM */ + + /* If we supposed to toggle DTR, do so. */ + + if (qdial->uuconf_fdtr_toggle) + { +#ifdef TIOCCDTR + (void) ioctl (qsysdep->o, TIOCCDTR, 0); + sleep (2); + (void) ioctl (qsysdep->o, TIOCSDTR, 0); +#else /* ! defined (TIOCCDTR) */ + (void) fconn_reset (qconn); +#endif /* ! defined (TIOCCDTR) */ + + if (qdial->uuconf_fdtr_toggle_wait) + sleep (2); + } + + if (! fsmodem_carrier (qconn, FALSE)) + return FALSE; + + /* Open the dial device if there is one. */ + z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device; + if (z != NULL) + { + char *zfree; + int o; + + qsysdep->ohold = qsysdep->o; + + zfree = NULL; + if (*z != '/') + { + zfree = zbufalc (sizeof "/dev/" + strlen (z)); + sprintf (zfree, "/dev/%s", z); + z = zfree; + } + + o = open ((char *) z, O_RDWR | O_NOCTTY); + if (o < 0) + { + ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno)); + ubuffree (zfree); + return FALSE; + } + ubuffree (zfree); + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (o); + return FALSE; + } + + qsysdep->o = o; + } + + return TRUE; +} + +/* Tell the port to require or not require carrier. On BSD this uses + TIOCCAR and TIOCNCAR, which I assume are generally supported (it + can also use the LNOMDM bit supported by IS68K Unix). On System V + it resets or sets CLOCAL. We only require carrier if the port + supports it. This will only be called with fcarrier TRUE if the + dialer supports carrier. */ + +static boolean +fsmodem_carrier (qconn, fcarrier) + struct sconnection *qconn; + boolean fcarrier; +{ + register struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) qconn->psysdep; + + if (! q->fterminal) + return TRUE; + + if (fcarrier) + { + if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier) + { +#ifdef TIOCCAR + /* Tell the modem to pay attention to carrier. */ + if (ioctl (q->o, TIOCCAR, 0) < 0) + { + ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno)); + return FALSE; + } +#endif /* TIOCCAR */ + +#if HAVE_BSD_TTY +#ifdef LNOMDM + /* IS68K Unix uses a local LNOMDM bit. */ + { + int iparam; + + iparam = LNOMDM; + if (ioctl (q->o, TIOCLBIC, &iparam) < 0) + { + ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s", + strerror (errno)); + return FALSE; + } + } +#endif /* LNOMDM */ +#endif /* HAVE_BSD_TTY */ + +#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS + /* Put the modem into nonlocal mode. */ + q->snew.c_cflag &=~ CLOCAL; + if (! fsetterminfo (q->o, &q->snew)) + { + ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno)); + return FALSE; + } +#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ + } + } + else + { +#ifdef TIOCNCAR + /* Tell the modem to ignore carrier. */ + if (ioctl (q->o, TIOCNCAR, 0) < 0) + { + ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno)); + return FALSE; + } +#endif /* TIOCNCAR */ + +#if HAVE_BSD_TTY +#ifdef LNOMDM + /* IS68K Unix uses a local LNOMDM bit. */ + { + int iparam; + + iparam = LNOMDM; + if (ioctl (q->o, TIOCLBIS, &iparam) < 0) + { + ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s", + strerror (errno)); + return FALSE; + } + } +#endif /* LNOMDM */ +#endif /* HAVE_BSD_TTY */ + +#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS + /* Put the modem into local mode (ignore carrier) to start the chat + script. */ + q->snew.c_cflag |= CLOCAL; + if (! fsetterminfo (q->o, &q->snew)) + { + ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno)); + return FALSE; + } + +#if HAVE_CLOCAL_BUG + /* On SCO and AT&T UNIX PC you have to reopen the port. */ + { + int onew; + + onew = open (q->zdevice, O_RDWR); + if (onew < 0) + { + ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno)); + return FALSE; + } + + if (fcntl (onew, F_SETFD, + fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (onew); + return FALSE; + } + + (void) close (q->o); + q->o = onew; + } +#endif /* HAVE_CLOCAL_BUG */ + +#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ + } + + return TRUE; +} + +/* Finish dialing out on a modem by closing any dialer device and waiting + for carrier. */ + +boolean +fsysdep_modem_end_dial (qconn, qdial) + struct sconnection *qconn; + struct uuconf_dialer *qdial; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) qconn->psysdep; + + if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL) + { + (void) close (q->o); + q->o = q->ohold; + } + + if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier + && qdial->uuconf_fcarrier) + { + /* Tell the port that we need carrier. */ + if (! fsmodem_carrier (qconn, TRUE)) + return FALSE; + +#ifdef TIOCWONLINE + + /* We know how to wait for carrier, so do so. */ + + /* If we already got a signal, just quit now. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + + /* This bit of code handles signals just like fsysdep_conn_read + does. See that function for a longer explanation. */ + + /* Use fsysdep_catch to handle a longjmp from the signal + handler. */ + + fSalarm = FALSE; + + if (fsysdep_catch ()) + { + /* Start catching SIGALRM; normally we ignore it. */ + usysdep_start_catch (); + usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); + (void) alarm (qdial->uuconf_ccarrier_wait); + + /* We really don't care if we get an error, since that will + probably just mean that TIOCWONLINE isn't supported in + which case there's nothing we can do anyhow. If we get + SIGINT we want to keep waiting for carrier, because + SIGINT just means don't start any new sessions. We don't + handle SIGINT correctly if we do a longjmp in the signal + handler; too bad. */ + while (ioctl (q->o, TIOCWONLINE, 0) < 0 + && errno == EINTR) + { + /* Log the signal. */ + ulog (LOG_ERROR, (const char *) NULL); + if (FGOT_QUIT_SIGNAL () || fSalarm) + break; + } + } + + /* Turn off the pending SIGALRM and ignore SIGALARM again. */ + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + (void) alarm (0); + usysdep_end_catch (); + + /* If we got a random signal, just return FALSE. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + + /* If we timed out, give an error. */ + if (fSalarm) + { + ulog (LOG_ERROR, "Timed out waiting for carrier"); + return FALSE; + } + +#endif /* TIOCWONLINE */ + } + + return TRUE; +} + +/* Read data from a connection, with a timeout. This routine handles + all types of connections, including TLI. + + This function should return when we have read cmin characters or + the timeout has occurred. We have to work a bit to get Unix to do + this efficiently on a terminal. The simple implementation + schedules a SIGALRM signal and then calls read; if there is a + single character available, the call to read will return + immediately, so there must be a loop which terminates when the + SIGALRM is delivered or the correct number of characters has been + read. This can be very inefficient with a fast CPU or a low baud + rate (or both!), since each call to read may return only one or two + characters. + + Under POSIX or System V, we can specify a minimum number of + characters to read, so there is no serious trouble. + + Under BSD, we figure out how many characters we have left to read, + how long it will take for them to arrive at the current baud rate, + and sleep that long. + + Doing this with a timeout and avoiding all possible race conditions + get very hairy, though. Basically, we're going to schedule a + SIGALRM for when the timeout expires. I don't really want to do a + longjmp in the SIGALRM handler, though, because that may lose data. + Therefore, I have the signal handler set a variable. However, this + means that there will be a span of time between the time the code + checks the variable and the time it calls the read system call; if + the SIGALRM occurs during that time, the read might hang forever. + To avoid this, the SIGALRM handler not only sets a global variable, + it also schedules another SIGALRM for one second in the future + (POSIX specifies that a signal handler is permitted to safely call + alarm). To avoid getting a continual sequence of SIGALRM + interrupts, we change the signal handler to ignore SIGALRM when + we're about to exit the function. This means that every time we + execute fsysdep_conn_read we make at least five system calls. It's + the best I've been able to come up with, though. + + When fsysdep_conn_read finishes, there will be no SIGALRM scheduled + and SIGALRM will be ignored. */ + +boolean +fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport) + struct sconnection *qconn; + char *zbuf; + size_t *pclen; + size_t cmin; + int ctimeout; + boolean freport; +{ + CATCH_PROTECT size_t cwant; + boolean fret; + register struct ssysdep_conn * const q + = (struct ssysdep_conn *) qconn->psysdep; + + cwant = *pclen; + *pclen = 0; + + /* Guard against a bad timeout. We return TRUE when a timeout + expires. It is possible to get a negative timeout here because + the calling code does not check user supplied timeouts for + plausibility. */ + if (ctimeout <= 0) + return TRUE; + + /* We want to do a blocking read. */ + if (! fsblock (q, TRUE)) + return FALSE; + + fSalarm = FALSE; + + /* We're going to set up an alarm signal to last for the entire + read. If the read system call cannot be interrupted, the signal + handler will do a longjmp causing fsysdep_catch (a macro) to + return FALSE. We handle that here. If read can be interrupted, + fsysdep_catch will be defined to TRUE. */ + if (fsysdep_catch ()) + { + /* Prepare to catch SIGALRM and schedule the signal. */ + usysdep_start_catch (); + usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); + alarm (ctimeout); + } + else + { + /* We caught a signal. We don't actually have to do anything, + as all the appropriate checks are made at the start of the + following loop. */ + } + + fret = FALSE; + + while (TRUE) + { + int cgot; + +#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS + /* If we can tell the terminal not to return until we have a + certain number of characters, do so. */ + if (q->fterminal) + { + int csetmin; + + /* I'm not that confident about setting MIN to values larger + than 127, although up to 255 would probably work. */ + if (cmin < 127) + csetmin = cmin; + else + csetmin = 127; + + if (csetmin != cSmin) + { + q->snew.c_cc[VMIN] = csetmin; + while (! fsetterminfo (q->o, &q->snew)) + { + if (errno != EINTR + || FGOT_QUIT_SIGNAL ()) + { + int ierr; + + /* We turn off the signal before reporting the + error to minimize any problems with + interrupted system calls. */ + ierr = errno; + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + usysdep_end_catch (); + ulog (LOG_ERROR, "Can't set MIN for terminal: %s", + strerror (ierr)); + return FALSE; + } + + if (fSalarm) + { + ulog (LOG_ERROR, + "Timed out when setting MIN to %d; retrying", + csetmin); + fSalarm = FALSE; + alarm (ctimeout); + } + } + cSmin = csetmin; + } + } +#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ + + /* If we've received a signal, get out now. */ + if (FGOT_QUIT_SIGNAL ()) + break; + + /* If we've already gotten a SIGALRM, get out with whatever + we've accumulated. */ + if (fSalarm) + { + fret = TRUE; + break; + } + + /* Right here is the race condition which we avoid by having the + SIGALRM handler schedule another SIGALRM. */ +#if HAVE_TLI + if (q->ftli) + { + int iflags; + + cgot = t_rcv (q->o, zbuf, cwant, &iflags); + if (cgot < 0 && t_errno != TSYSERR) + { + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + usysdep_end_catch (); + + if (freport) + ulog (LOG_ERROR, "t_rcv: %s", + (t_errno >= 0 && t_errno < t_nerr + ? t_errlist[t_errno] + : "unknown TLI error")); + + return FALSE; + } + } + else +#endif + cgot = read (q->o, zbuf, cwant); + + /* If the read returned an error, check for signals. */ + if (cgot < 0) + { + if (errno == EINTR) + { + /* Log the signal. */ + ulog (LOG_ERROR, (const char *) NULL); + } + if (fSalarm) + { + fret = TRUE; + break; + } + if (FGOT_QUIT_SIGNAL ()) + break; + } + + /* If read returned an error, get out. We just ignore EINTR + here, since it must be from some signal we don't care about. + If the read returned 0 then the line must have been hung up + (normally we would have received SIGHUP, but we can't count + on that). We turn off the signals before calling ulog to + reduce problems with interrupted system calls. */ + if (cgot <= 0) + { + if (cgot < 0 && errno == EINTR) + cgot = 0; + else + { + int ierr; + + ierr = errno; + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + usysdep_end_catch (); + + if (freport) + { + if (cgot == 0) + ulog (LOG_ERROR, "Line disconnected"); + else + ulog (LOG_ERROR, "read: %s", strerror (ierr)); + } + + return FALSE; + } + } + + cwant -= cgot; + if (cgot >= cmin) + cmin = 0; + else + cmin -= cgot; + zbuf += cgot; + *pclen += cgot; + + /* If we have enough data, get out now. */ + if (cmin == 0) + { + fret = TRUE; + break; + } + +#if HAVE_BSD_TTY + /* We still want more data, so sleep long enough for the rest of + it to arrive. We don't this for System V or POSIX because + setting MIN is good enough (we can't sleep longer than it + takes to get MAX_INPUT characters anyhow). + + The baud rate is approximately 10 times the number of + characters which will arrive in one second, so the number of + milliseconds to sleep == + characters * (milliseconds / character) == + characters * (1000 * (seconds / character)) == + characters * (1000 * (1 / (baud / 10))) == + characters * (10000 / baud) + + We arbitrarily reduce the sleep amount by 10 milliseconds to + attempt to account for the amount of time it takes to set up + the sleep. This is how long it takes to get half a character + at 19200 baud. We then don't bother to sleep for less than + 10 milliseconds. We don't sleep if the read was interrupted. + + We use select to sleep. It would be easy to use poll as + well, but it's unlikely that any system with BSD ttys would + have poll but not select. Using select avoids hassles with + the pending SIGALRM; if it hits the select will be + interrupted, and otherwise the select will not affect it. */ + +#if ! HAVE_SELECT + #error This code requires select; feel free to extend it +#endif + + if (q->fterminal && cmin > 1 && cgot > 0) + { + int csleepchars; + int isleep; + + /* We don't try to read all the way up to MAX_INPUT, + since that might drop a character. */ + if (cmin <= MAX_INPUT - 10) + csleepchars = cmin; + else + csleepchars = MAX_INPUT - 10; + + isleep = (int) (((long) csleepchars * 10000L) / q->ibaud); + isleep -= 10; + + if (isleep > 10) + { + struct timeval s; + + s.tv_sec = isleep / 1000; + s.tv_usec = (isleep % 1000) * 1000; + + /* Some versions of select take a pointer to an int, + while some take a pointer to an fd_set. I just cast + the arguments to a generic pointer, and assume that + any machine which distinguishes int * from fd_set * + (I would be amazed if there are any such machines) + have an appropriate prototype somewhere or other. */ + (void) select (0, (pointer) NULL, (pointer) NULL, + (pointer) NULL, &s); + + /* Here either the select finished sleeping or we got a + SIGALRM. If the latter occurred, fSalarm was set to + TRUE; it will be checked at the top of the loop. */ + } + } +#endif /* HAVE_BSD_TTY */ + } + + /* Turn off the pending SIGALRM and return. */ + + usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); + alarm (0); + usysdep_end_catch (); + + return fret; +} + +/* Read from a stdin port. */ + +static boolean +fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport) + struct sconnection *qconn; + char *zbuf; + size_t *pclen; + size_t cmin; + int ctimeout; + boolean freport; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + qsysdep->o = 0; + return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport); +} + +/* Write data to a connection. This routine handles all types of + connections, including TLI. */ + +boolean +fsysdep_conn_write (qconn, zwrite, cwrite) + struct sconnection *qconn; + const char *zwrite; + size_t cwrite; +{ + struct ssysdep_conn *q; + int czero; + + q = (struct ssysdep_conn *) qconn->psysdep; + + /* We want blocking writes here. */ + if (! fsblock (q, TRUE)) + return FALSE; + + czero = 0; + + while (cwrite > 0) + { + int cdid; + + /* Loop until we don't get an interrupt. */ + while (TRUE) + { + /* If we've received a signal, don't continue. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + +#if HAVE_TLI + if (q->ftli) + { + cdid = t_snd (q->o, zwrite, cwrite, 0); + if (cdid < 0 && t_errno != TSYSERR) + { + ulog (LOG_ERROR, "t_snd: %s", + (t_errno >= 0 && t_errno < t_nerr + ? t_errlist[t_errno] + : "unknown TLI error")); + return FALSE; + } + } + else +#endif + cdid = write (q->o, zwrite, cwrite); + + if (cdid >= 0) + break; + if (errno != EINTR) + break; + + /* We were interrupted by a signal. Log it. */ + ulog (LOG_ERROR, (const char *) NULL); + } + + if (cdid < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) + { + ulog (LOG_ERROR, "write: %s", strerror (errno)); + return FALSE; + } + cdid = 0; + } + + if (cdid == 0) + { + /* On some systems write will return 0 if carrier is lost. + If we fail to write anything ten times in a row, we + assume that this has happened. This is hacked in like + this because there seems to be no reliable way to tell + exactly why the write returned 0. */ + ++czero; + if (czero >= 10) + { + ulog (LOG_ERROR, "Line disconnected"); + return FALSE; + } + } + else + { + czero = 0; + + cwrite -= cdid; + zwrite += cdid; + } + } + + return TRUE; +} + +/* Write to a stdin port. */ + +static boolean +fsstdin_write (qconn, zwrite, cwrite) + struct sconnection *qconn; + const char *zwrite; + size_t cwrite; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + qsysdep->o = 0; + if (! fsblock (qsysdep, TRUE)) + return FALSE; + qsysdep->o = 1; + return fsysdep_conn_write (qconn, zwrite, cwrite); +} + +/* The fsysdep_conn_io routine is supposed to both read and write data + until it has either filled its read buffer or written out all the + data it was given. This lets us write out large packets without + losing incoming data. It handles all types of connections, + including TLI. */ + +boolean +fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread) + struct sconnection *qconn; + const char *zwrite; + size_t *pcwrite; + char *zread; + size_t *pcread; +{ + struct ssysdep_conn *q; + size_t cwrite, cread; + int czero; + + q = (struct ssysdep_conn *) qconn->psysdep; + + cwrite = *pcwrite; + *pcwrite = 0; + cread = *pcread; + *pcread = 0; + + czero = 0; + + while (TRUE) + { + int cgot, cdid; + size_t cdo; + + /* This used to always use nonblocking writes, but it turns out + that some systems don't support them on terminals. + + The current algorithm is: + loop: + unblocked read + if read buffer full, return + if nothing to write, return + if HAVE_UNBLOCKED_WRITES + write all data + else + write up to SINGLE_WRITE bytes + if all data written, return + if no data written + blocked write of up to SINGLE_WRITE bytes + + This algorithm should work whether the system supports + unblocked writes on terminals or not. If the system supports + unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will + call write more often than it needs to. If the system does + not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1, + then the write may hang so long that incoming data is lost. + This is actually possible at high baud rates on any system + when a blocking write is done; there is no solution, except + hardware handshaking. */ + + /* If we are running on standard input, we switch the file + descriptors by hand. */ + if (q->istdout_flags >= 0) + q->o = 0; + + /* Do an unblocked read. */ + if (! fsblock (q, FALSE)) + return FALSE; + + /* Loop until we get something (error or data) other than an + acceptable EINTR. */ + while (TRUE) + { + /* If we've received a signal, don't continue. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + +#if HAVE_TLI + if (q->ftli) + { + int iflags; + + cgot = t_rcv (q->o, zread, cread, &iflags); + if (cgot < 0) + { + if (t_errno == TNODATA) + errno = EAGAIN; + else if (t_errno != TSYSERR) + { + ulog (LOG_ERROR, "t_rcv: %s", + (t_errno >= 0 && t_errno < t_nerr + ? t_errlist[t_errno] + : "unknown TLI error")); + return FALSE; + } + } + } + else +#endif + cgot = read (q->o, zread, cread); + + if (cgot >= 0) + break; + if (errno != EINTR) + break; + + /* We got interrupted by a signal. Log it. */ + ulog (LOG_ERROR, (const char *) NULL); + } + + if (cgot < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) + { + ulog (LOG_ERROR, "read: %s", strerror (errno)); + return FALSE; + } + cgot = 0; + } + + cread -= cgot; + zread += cgot; + *pcread += cgot; + + /* If we've filled the read buffer, or we have nothing left to + write, return out. */ + if (cread == 0 || cwrite == 0) + return TRUE; + + /* The port is currently unblocked. Do a write. */ + cdo = cwrite; + +#if ! HAVE_UNBLOCKED_WRITES + if (q->fterminal && cdo > SINGLE_WRITE) + cdo = SINGLE_WRITE; +#endif + + if (q->istdout_flags >= 0) + q->o = 1; + + /* Loop until we get something besides EINTR. */ + while (TRUE) + { + /* If we've received a signal, don't continue. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + +#if HAVE_TLI + if (q->ftli) + { + cdid = t_snd (q->o, zwrite, cdo, 0); + if (cdid < 0) + { + if (t_errno == TFLOW) + errno = EAGAIN; + else if (t_errno != TSYSERR) + { + ulog (LOG_ERROR, "t_snd: %s", + (t_errno >= 0 && t_errno < t_nerr + ? t_errlist[t_errno] + : "unknown TLI error")); + return FALSE; + } + } + } + else +#endif + cdid = write (q->o, zwrite, cdo); + + if (cdid >= 0) + break; + if (errno != EINTR) + break; + + /* We got interrupted by a signal. Log it. */ + ulog (LOG_ERROR, (const char *) NULL); + } + + if (cdid < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) + { + ulog (LOG_ERROR, "write: %s", strerror (errno)); + return FALSE; + } + cdid = 0; + } + + if (cdid > 0) + { + /* We wrote some data. If we wrote everything, return out. + Otherwise loop around and do another read. */ + cwrite -= cdid; + zwrite += cdid; + *pcwrite += cdid; + + if (cwrite == 0) + return TRUE; + + czero = 0; + } + else + { + /* We didn't write any data. Do a blocking write. */ + + if (q->istdout_flags >= 0) + q->o = 0; + + if (! fsblock (q, TRUE)) + return FALSE; + + cdo = cwrite; + if (cdo > SINGLE_WRITE) + cdo = SINGLE_WRITE; + + DEBUG_MESSAGE1 (DEBUG_PORT, + "fsysdep_conn_io: Blocking write of %lud", + (unsigned long) cdo); + + if (q->istdout_flags >= 0) + q->o = 1; + + /* Loop until we get something besides EINTR. */ + while (TRUE) + { + /* If we've received a signal, don't continue. */ + if (FGOT_QUIT_SIGNAL ()) + return FALSE; + +#if HAVE_TLI + if (q->ftli) + { + cdid = t_snd (q->o, zwrite, cdo, 0); + if (cdid < 0 && t_errno != TSYSERR) + { + ulog (LOG_ERROR, "t_snd: %s", + (t_errno >= 0 && t_errno < t_nerr + ? t_errlist[t_errno] + : "unknown TLI error")); + return FALSE; + } + } + else +#endif + cdid = write (q->o, zwrite, cdo); + + if (cdid >= 0) + break; + if (errno != EINTR) + break; + + /* We got interrupted by a signal. Log it. */ + ulog (LOG_ERROR, (const char *) NULL); + } + + if (cdid < 0) + { + ulog (LOG_ERROR, "write: %s", strerror (errno)); + return FALSE; + } + + if (cdid == 0) + { + /* On some systems write will return 0 if carrier is + lost. If we fail to write anything ten times in a + row, we assume that this has happened. This is + hacked in like this because there seems to be no + reliable way to tell exactly why the write returned + 0. */ + ++czero; + if (czero >= 10) + { + ulog (LOG_ERROR, "Line disconnected"); + return FALSE; + } + } + else + { + cwrite -= cdid; + zwrite += cdid; + *pcwrite += cdid; + czero = 0; + } + } + } +} + +/* Send a break character to a serial port. */ + +static boolean +fsserial_break (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) qconn->psysdep; + +#if HAVE_BSD_TTY + (void) ioctl (q->o, TIOCSBRK, 0); + sleep (2); + (void) ioctl (q->o, TIOCCBRK, 0); + return TRUE; +#endif /* HAVE_BSD_TTY */ +#if HAVE_SYSV_TERMIO + (void) ioctl (q->o, TCSBRK, 0); + return TRUE; +#endif /* HAVE_SYSV_TERMIO */ +#if HAVE_POSIX_TERMIOS + return tcsendbreak (q->o, 0) == 0; +#endif /* HAVE_POSIX_TERMIOS */ +} + +/* Send a break character to a stdin port. */ + +static boolean +fsstdin_break (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + qsysdep->o = 1; + return fsserial_break (qconn); +} + +/* Change the setting of a serial port. */ + +/*ARGSUSED*/ +static boolean +fsserial_set (qconn, tparity, tstrip, txonxoff) + struct sconnection *qconn; + enum tparitysetting tparity; + enum tstripsetting tstrip; + enum txonxoffsetting txonxoff; +{ + register struct ssysdep_conn *q; + boolean fchanged, fdo; + int iset = 0; + int iclear = 0; + + q = (struct ssysdep_conn *) qconn->psysdep; + + if (! q->fterminal) + return TRUE; + + fchanged = FALSE; + + /* Set the parity for output characters. */ + +#if HAVE_BSD_TTY + + /* This will also cause parity detection on input characters. */ + + fdo = FALSE; + switch (tparity) + { + case PARITYSETTING_DEFAULT: + break; + case PARITYSETTING_NONE: +#if HAVE_PARITY_BUG + /* The Sony NEWS mishandles this for some reason. */ + iset = 0; + iclear = ANYP; +#else + iset = ANYP; + iclear = 0; +#endif + fdo = TRUE; + break; + case PARITYSETTING_EVEN: + iset = EVENP; + iclear = ODDP; + fdo = TRUE; + break; + case PARITYSETTING_ODD: + iset = ODDP; + iclear = EVENP; + fdo = TRUE; + break; + case PARITYSETTING_MARK: + case PARITYSETTING_SPACE: + /* Not supported. */ + break; + } + + if (fdo) + { + if ((q->snew.stty.sg_flags & iset) != iset + || (q->snew.stty.sg_flags & iclear) != 0) + { + q->snew.stty.sg_flags |= iset; + q->snew.stty.sg_flags &=~ iclear; + fchanged = TRUE; + } + } + +#else /* ! HAVE_BSD_TTY */ + + fdo = FALSE; + switch (tparity) + { + case PARITYSETTING_DEFAULT: + break; + case PARITYSETTING_NONE: + iset = CS8; + iclear = PARENB | PARODD | (CSIZE &~ CS8); + fdo = TRUE; + break; + case PARITYSETTING_EVEN: + iset = PARENB | CS7; + iclear = PARODD | (CSIZE &~ CS7); + fdo = TRUE; + break; + case PARITYSETTING_ODD: + iset = PARENB | PARODD | CS7; + iclear = CSIZE &~ CS7; + fdo = TRUE; + break; + case PARITYSETTING_MARK: + case PARITYSETTING_SPACE: + /* Not supported. */ + break; + } + + if (fdo) + { + if ((q->snew.c_cflag & iset) != iset + || (q->snew.c_cflag & iclear) != 0) + { + q->snew.c_cflag |= iset; + q->snew.c_cflag &=~ iclear; + fchanged = TRUE; + } + } + +#endif /* ! HAVE_BSD_TTY */ + + /* Set whether input characters are stripped to seven bits. */ + +#if HAVE_BSD_TTY + +#ifdef LPASS8 + { + int i; + + i = LPASS8; + if (tstrip == STRIPSETTING_EIGHTBITS) + { + i = LPASS8; + (void) ioctl (q->o, TIOCLBIS, &i); + } + else if (tstrip == STRIPSETTING_SEVENBITS) + { + i = LPASS8; + (void) ioctl (q->o, TIOCLBIC, &i); + } + } +#endif + +#else /* ! HAVE_BSD_TTY */ + + fdo = FALSE; + switch (tstrip) + { + case STRIPSETTING_DEFAULT: + break; + case STRIPSETTING_EIGHTBITS: + iset = 0; + iclear = ISTRIP; + fdo = TRUE; + break; + case STRIPSETTING_SEVENBITS: + iset = ISTRIP; + iclear = 0; + fdo = TRUE; + break; + } + + if (fdo) + { + if ((q->snew.c_iflag & iset) != iset + || (q->snew.c_iflag & iclear) != 0) + { + q->snew.c_iflag |= iset; + q->snew.c_iflag &=~ iclear; + fchanged = TRUE; + } + } + +#endif /* ! HAVE_BSD_TTY */ + + /* Set XON/XOFF handshaking. */ + +#if HAVE_BSD_TTY + + fdo = FALSE; + switch (txonxoff) + { + case XONXOFF_DEFAULT: + break; + case XONXOFF_OFF: + iset = RAW; + iclear = TANDEM | CBREAK; + fdo = TRUE; + break; + case XONXOFF_ON: + iset = CBREAK | TANDEM; + iclear = RAW; + fdo = TRUE; + break; + } + + if (fdo) + { + if ((q->snew.stty.sg_flags & iset) != iset + || (q->snew.stty.sg_flags & iclear) != 0) + { + q->snew.stty.sg_flags |= iset; + q->snew.stty.sg_flags &=~ iclear; + fchanged = TRUE; + } + } + +#else /* ! HAVE_BSD_TTY */ + + fdo = FALSE; + switch (txonxoff) + { + case XONXOFF_DEFAULT: + break; + case XONXOFF_OFF: + iset = 0; + iclear = IXON | IXOFF; + fdo = TRUE; + break; + case XONXOFF_ON: +#ifdef CRTSCTS +#if HAVE_POSIX_TERMIOS + /* This is system dependent, but I haven't figured out a good + way around it yet. If we are doing hardware flow control, we + don't send XON/XOFF characters but we do recognize them. */ + if ((q->snew.c_cflag & CRTSCTS) != 0) + { + iset = IXON; + iclear = IXOFF; + fdo = TRUE; + break; + } +#endif /* HAVE_POSIX_TERMIOS */ +#endif /* defined (CRTSCTS) */ + iset = IXON | IXOFF; + iclear = 0; + fdo = TRUE; + break; + } + + if (fdo) + { + if ((q->snew.c_iflag & iset) != iset + || (q->snew.c_iflag & iclear) != 0) + { + q->snew.c_iflag |= iset; + q->snew.c_iflag &=~ iclear; + fchanged = TRUE; + } + } + +#endif /* ! HAVE_BSD_TTY */ + + if (fchanged) + { + if (! fsetterminfodrain (q->o, &q->snew)) + { + ulog (LOG_ERROR, "Can't change terminal settings: %s", + strerror (errno)); + return FALSE; + } + } + +#if HAVE_BSD_TTY + if (txonxoff == XONXOFF_ON + && (q->snew.stty.sg_flags & ANYP) == ANYP) + { + int i; + + /* At least on Ultrix, we seem to have to set LLITOUT and + LPASS8. This shouldn't foul things up anywhere else. As far + as I can tell, this has to be done after setting the terminal + into cbreak mode, not before. */ +#ifndef LLITOUT +#define LLITOUT 0 +#endif +#ifndef LPASS8 +#define LPASS8 0 +#endif +#ifndef LAUTOFLOW +#define LAUTOFLOW 0 +#endif + i = LLITOUT | LPASS8 | LAUTOFLOW; + (void) ioctl (q->o, TIOCLBIS, &i); + +#if HAVE_STRIP_BUG + /* Ultrix 4.0 has a peculiar problem: setting CBREAK always + causes input characters to be stripped. I hope this does not + apply to other BSD systems. It is possible to work around + this by using the termio call. I wish this sort of stuff was + not necessary!!! */ + { + struct termio s; + + if (ioctl (q->o, TCGETA, &s) >= 0) + { + s.c_iflag &=~ ISTRIP; + (void) ioctl (q->o, TCSETA, &s); + } + } +#endif /* HAVE_STRIP_BUG */ + } +#endif /* HAVE_BSD_TTY */ + + return TRUE; +} + +/* Change settings of a stdin port. */ + +static boolean +fsstdin_set (qconn, tparity, tstrip, txonxoff) + struct sconnection *qconn; + enum tparitysetting tparity; + enum tstripsetting tstrip; + enum txonxoffsetting txonxoff; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + qsysdep->o = 0; + return fsserial_set (qconn, tparity, tstrip, txonxoff); +} + +/* Run a chat program. */ + +static boolean +fsrun_chat (oread, owrite, pzprog) + int oread; + int owrite; + char **pzprog; +{ + int aidescs[3]; + FILE *e; + pid_t ipid; + char *z; + size_t c; + + aidescs[0] = oread; + aidescs[1] = owrite; + aidescs[2] = SPAWN_READ_PIPE; + + /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the + responsibility of maintaing security on the chat program. */ + ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE, + (const char *) NULL, FALSE, TRUE, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno)); + return FALSE; + } + + e = fdopen (aidescs[2], (char *) "r"); + if (e == NULL) + { + ulog (LOG_ERROR, "fdopen: %s", strerror (errno)); + (void) close (aidescs[2]); + (void) kill (ipid, SIGKILL); + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + return FALSE; + } + + /* The FILE e now is attached to stderr of the program. Forward + every line the program outputs to the log file. */ + z = NULL; + c = 0; + while (getline (&z, &c, e) > 0) + { + size_t clen; + + clen = strlen (z); + if (z[clen - 1] == '\n') + z[clen - 1] = '\0'; + if (*z != '\0') + ulog (LOG_NORMAL, "chat: %s", z); + } + + xfree ((pointer) z); + (void) fclose (e); + + return ixswait ((unsigned long) ipid, "Chat program") == 0; +} + +/* Run a chat program on a stdin port. */ + +/*ARGSUSED*/ +static boolean +fsstdin_chat (qconn, pzprog) + struct sconnection *qconn; + char **pzprog; +{ + return fsrun_chat (0, 1, pzprog); +} + +/* Run a chat program on any general type of connection. */ + +boolean +fsysdep_conn_chat (qconn, pzprog) + struct sconnection *qconn; + char **pzprog; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + return fsrun_chat (qsysdep->o, qsysdep->o, pzprog); +} + +/* Return baud rate of a serial port. */ + +static long +isserial_baud (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + return qsysdep->ibaud; +} diff --git a/gnu/libexec/uucp/libunix/signal.c b/gnu/libexec/uucp/libunix/signal.c new file mode 100644 index 00000000000..33e24a72457 --- /dev/null +++ b/gnu/libexec/uucp/libunix/signal.c @@ -0,0 +1,208 @@ +/* signal.c + Signal handling routines. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* Signal handling routines. When we catch a signal, we want to set + the appropriate elements of afSignal and afLog_signal to TRUE. If + we are on a system which restarts system calls, we may also want to + longjmp out. On a system which does not restart system calls, + these signal handling routines are well-defined by ANSI C. */ + +#if HAVE_RESTARTABLE_SYSCALLS +volatile sig_atomic_t fSjmp; +volatile jmp_buf sSjmp_buf; +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + +/* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be + set in the sigaction structure to force system calls to be + interrupted. */ +#ifndef SA_INTERRUPT +#define SA_INTERRUPT 0 +#endif + +/* The SVR3 sigset function can be called just like signal, unless + system calls are restarted which is extremely unlikely; we prevent + this case in sysh.unx. */ +#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC +#define signal sigset +#endif + +/* The sigvec structure changed from 4.2BSD to 4.3BSD. These macros + make the 4.3 code backward compatible. */ +#ifndef SV_INTERRUPT +#define SV_INTERRUPT 0 +#endif +#if ! HAVE_SIGVEC_SV_FLAGS +#define sv_flags sv_onstack +#endif + +/* Catch a signal. Reinstall the signal handler if necessary, set the + appropriate variables, and do a longjmp if necessary. */ + +RETSIGTYPE +ussignal (isig) + int isig; +{ + int iindex; + +#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET + (void) signal (isig, ussignal); +#endif + + switch (isig) + { + default: iindex = INDEXSIG_SIGHUP; break; +#ifdef SIGINT + case SIGINT: iindex = INDEXSIG_SIGINT; break; +#endif +#ifdef SIGQUIT + case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break; +#endif +#ifdef SIGTERM + case SIGTERM: iindex = INDEXSIG_SIGTERM; break; +#endif +#ifdef SIGPIPE + case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break; +#endif + } + + afSignal[iindex] = TRUE; + afLog_signal[iindex] = TRUE; + +#if HAVE_RESTARTABLE_SYSCALLS + if (fSjmp) + longjmp (sSjmp_buf, 1); +#endif /* HAVE_RESTARTABLE_SYSCALLS */ +} + +/* Prepare to catch a signal. This is basically the ANSI C routine + signal, but it uses sigaction or sigvec instead if they are + available. If fforce is FALSE, we do not set the signal if it is + currently being ignored. If pfignored is not NULL and fforce is + FALSE, then *pfignored will be set to TRUE if the signal was + previously being ignored (if fforce is TRUE the value returned in + *pfignored is meaningless). If we can't change the signal handler + we give a fatal error. */ + +void +usset_signal (isig, pfn, fforce, pfignored) + int isig; + RETSIGTYPE (*pfn) P((int)); + boolean fforce; + boolean *pfignored; +{ +#if HAVE_SIGACTION + + struct sigaction s; + + if (! fforce) + { + (void) (sigemptyset (&s.sa_mask)); + if (sigaction (isig, (struct sigaction *) NULL, &s) != 0) + ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno)); + + if (s.sa_handler == SIG_IGN) + { + if (pfignored != NULL) + *pfignored = TRUE; + return; + } + + if (pfignored != NULL) + *pfignored = FALSE; + } + + s.sa_handler = pfn; + (void) (sigemptyset (&s.sa_mask)); + s.sa_flags = SA_INTERRUPT; + + if (sigaction (isig, &s, (struct sigaction *) NULL) != 0) + ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno)); + +#else /* ! HAVE_SIGACTION */ +#if HAVE_SIGVEC + + struct sigvec s; + + if (! fforce) + { + if (sigvec (isig, (struct sigvec *) NULL, &s) != 0) + ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno)); + + if (s.sv_handler == SIG_IGN) + { + if (pfignored != NULL) + *pfignored = TRUE; + return; + } + + if (pfignored != NULL) + *pfignored = FALSE; + } + + s.sv_handler = pfn; + s.sv_mask = 0; + s.sv_flags = SV_INTERRUPT; + + if (sigvec (isig, &s, (struct sigvec *) NULL) != 0) + ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno)); + +#else /* ! HAVE_SIGVEC */ + + if (! fforce) + { + if (signal (isig, SIG_IGN) == SIG_IGN) + { + if (pfignored != NULL) + *pfignored = TRUE; + return; + } + + if (pfignored != NULL) + *pfignored = FALSE; + } + + (void) signal (isig, pfn); + +#endif /* ! HAVE_SIGVEC */ +#endif /* ! HAVE_SIGACTION */ +} + +/* The routine called by the system independent code, which always + uses the same signal handler. */ + +void +usysdep_signal (isig) + int isig; +{ + usset_signal (isig, ussignal, FALSE, (boolean *) NULL); +} diff --git a/gnu/libexec/uucp/libunix/sindir.c b/gnu/libexec/uucp/libunix/sindir.c new file mode 100644 index 00000000000..d9875081891 --- /dev/null +++ b/gnu/libexec/uucp/libunix/sindir.c @@ -0,0 +1,26 @@ +/* sindir.c + Stick a directory and file name together. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +char * +zsysdep_in_dir (zdir, zfile) + const char *zdir; + const char *zfile; +{ + size_t cdir, cfile; + char *zret; + + cdir = strlen (zdir); + cfile = strlen (zfile); + zret = zbufalc (cdir + cfile + 2); + memcpy (zret, zdir, cdir); + memcpy (zret + cdir + 1, zfile, cfile); + zret[cdir] = '/'; + zret[cdir + cfile + 1] = '\0'; + return zret; +} diff --git a/gnu/libexec/uucp/libunix/size.c b/gnu/libexec/uucp/libunix/size.c new file mode 100644 index 00000000000..8d021db3cd5 --- /dev/null +++ b/gnu/libexec/uucp/libunix/size.c @@ -0,0 +1,27 @@ +/* size.c + Get the size in bytes of a file. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +long +csysdep_size (zfile) + const char *zfile; +{ + struct stat s; + + if (stat ((char *) zfile, &s) < 0) + { + if (errno == ENOENT) + return -1; + ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); + return -2; + } + + return s.st_size; +} diff --git a/gnu/libexec/uucp/libunix/sleep.c b/gnu/libexec/uucp/libunix/sleep.c new file mode 100644 index 00000000000..b232f9674ff --- /dev/null +++ b/gnu/libexec/uucp/libunix/sleep.c @@ -0,0 +1,14 @@ +/* sleep.c + Sleep for a number of seconds. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "system.h" + +void +usysdep_sleep (c) + int c; +{ + (void) sleep (c); +} diff --git a/gnu/libexec/uucp/libunix/spawn.c b/gnu/libexec/uucp/libunix/spawn.c new file mode 100644 index 00000000000..7ab080d1a9c --- /dev/null +++ b/gnu/libexec/uucp/libunix/spawn.c @@ -0,0 +1,398 @@ +/* spawn.c + Spawn a program securely. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#ifndef environ +extern char **environ; +#endif + +/* Spawn a child in a fairly secure fashion. This returns the process + ID of the child or -1 on error. It takes far too many arguments: + + pazargs -- arguments (element 0 is command) + aidescs -- file descriptors for stdin, stdout and stderr + fkeepuid -- TRUE if euid should be left unchanged + fkeepenv -- TRUE if environment should be left unmodified + zchdir -- directory to chdir to + fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT + fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC + zpath -- value for environment variable PATH + zuu_machine -- value for environment variable UU_MACHINE + zuu_user -- value for environment variable UU_USER + + The aidescs array is three elements long. 0 is stdin, 1 is stdout + and 2 is stderr. The array may contain either file descriptor + numbers to dup appropriately, or one of the following: + + SPAWN_NULL -- set descriptor to /dev/null + SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read + SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write + + If fkeepenv is FALSE, a standard environment is created. The + environment arguments (zpath, zuu_machine and zuu_user) are only + used if fkeepenv is FALSE; any of them may be NULL. + + This routine expects that all file descriptors have been set to + close-on-exec, so it doesn't have to worry about closing them + explicitly. It sets the close-on-exec flag for the new pipe + descriptors it returns. */ + +pid_t +ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell, + zpath, zuu_machine, zuu_user) + const char **pazargs; + int aidescs[3]; + boolean fkeepuid; + boolean fkeepenv; + const char *zchdir; + boolean fnosigs; + boolean fshell; + const char *zpath; + const char *zuu_machine; + const char *zuu_user; +{ + char *zshcmd; + int i; + char *azenv[9]; + char **pazenv; + boolean ferr; + int ierr = 0; + int onull; + int aichild_descs[3]; + int cpar_close; + int aipar_close[4]; + int cchild_close; + int aichild_close[3]; + pid_t iret = 0; + const char *zcmd; + + /* If we might have to use the shell, allocate enough space for the + quoted command before forking. Otherwise the allocation would + modify the data segment and we could not safely use vfork. */ + zshcmd = NULL; + if (fshell) + { + size_t clen; + + clen = 0; + for (i = 0; pazargs[i] != NULL; i++) + clen += strlen (pazargs[i]); + zshcmd = zbufalc (2 * clen + i); + } + + /* Set up a standard environment. This is again done before forking + because it will modify the data segment. */ + if (fkeepenv) + pazenv = environ; + else + { + const char *zterm, *ztz; + char *zspace; + int ienv; + + if (zpath == NULL) + zpath = CMDPATH; + + azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath)); + sprintf (azenv[0], "PATH=%s", zpath); + zspace = azenv[0] + sizeof "PATH=" - 1; + while ((zspace = strchr (zspace, ' ')) != NULL) + *zspace = ':'; + + azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir)); + sprintf (azenv[1], "HOME=%s", zSspooldir); + + zterm = getenv ("TERM"); + if (zterm == NULL) + zterm = "unknown"; + azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm)); + sprintf (azenv[2], "TERM=%s", zterm); + + azenv[3] = zbufcpy ("SHELL=/bin/sh"); + + azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER)); + sprintf (azenv[4], "USER=%s", OWNER); + + ienv = 5; + + ztz = getenv ("TZ"); + if (ztz != NULL) + { + azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz)); + sprintf (azenv[ienv], "TZ=%s", ztz); + ++ienv; + } + + if (zuu_machine != NULL) + { + azenv[ienv] = zbufalc (sizeof "UU_MACHINE=" + + strlen (zuu_machine)); + sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine); + ++ienv; + } + + if (zuu_user != NULL) + { + azenv[ienv] = zbufalc (sizeof "UU_USER=" + + strlen (zuu_user)); + sprintf (azenv[ienv], "UU_USER=%s", zuu_user); + ++ienv; + } + + azenv[ienv] = NULL; + pazenv = azenv; + } + + /* Set up any needed pipes. */ + + ferr = FALSE; + onull = -1; + cpar_close = 0; + cchild_close = 0; + + for (i = 0; i < 3; i++) + { + if (aidescs[i] == SPAWN_NULL) + { + if (onull < 0) + { + onull = open ((char *) "/dev/null", O_RDWR); + if (onull < 0 + || fcntl (onull, F_SETFD, + fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ierr = errno; + (void) close (onull); + ferr = TRUE; + break; + } + aipar_close[cpar_close] = onull; + ++cpar_close; + } + aichild_descs[i] = onull; + } + else if (aidescs[i] != SPAWN_READ_PIPE + && aidescs[i] != SPAWN_WRITE_PIPE) + aichild_descs[i] = aidescs[i]; + else + { + int aipipe[2]; + + if (pipe (aipipe) < 0) + { + ierr = errno; + ferr = TRUE; + break; + } + + if (aidescs[i] == SPAWN_READ_PIPE) + { + aidescs[i] = aipipe[0]; + aichild_close[cchild_close] = aipipe[0]; + aichild_descs[i] = aipipe[1]; + aipar_close[cpar_close] = aipipe[1]; + } + else + { + aidescs[i] = aipipe[1]; + aichild_close[cchild_close] = aipipe[1]; + aichild_descs[i] = aipipe[0]; + aipar_close[cpar_close] = aipipe[0]; + } + + ++cpar_close; + ++cchild_close; + + if (fcntl (aidescs[i], F_SETFD, + fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ierr = errno; + ferr = TRUE; + break; + } + } + } + +#if DEBUG > 1 + if (! ferr && FDEBUGGING (DEBUG_EXECUTE)) + { + ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]); + for (i = 1; pazargs[i] != NULL; i++) + ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]); + ulog (LOG_DEBUG_END, "%s", ""); + } +#endif + + if (! ferr) + { + /* This should really be vfork if available. */ + iret = ixsfork (); + if (iret < 0) + { + ferr = TRUE; + ierr = errno; + } + } + + if (ferr) + { + for (i = 0; i < cchild_close; i++) + (void) close (aichild_close[i]); + iret = -1; + } + + if (iret != 0) + { + /* The parent. Close the child's ends of the pipes and return + the process ID, or an error. */ + for (i = 0; i < cpar_close; i++) + (void) close (aipar_close[i]); + ubuffree (zshcmd); + if (! fkeepenv) + { + char **pz; + + for (pz = azenv; *pz != NULL; pz++) + ubuffree (*pz); + } + errno = ierr; + return iret; + } + + /* The child. */ + +#ifdef STDIN_FILENO +#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2 + #error The following code makes invalid assumptions +#endif +#endif + + for (i = 0; i < 3; i++) + { + if (aichild_descs[i] != i) + (void) dup2 (aichild_descs[i], i); + /* This should only be necessary if aichild_descs[i] == i, but + some systems copy the close-on-exec flag for a dupped + descriptor, which is wrong according to POSIX. */ + (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC); + } + + zcmd = pazargs[0]; + pazargs[0] = strrchr (zcmd, '/'); + if (pazargs[0] == NULL) + pazargs[0] = zcmd; + else + ++pazargs[0]; + + if (! fkeepuid) + { + (void) setuid (getuid ()); + (void) setgid (getgid ()); + } + + if (zchdir != NULL) + (void) chdir (zchdir); + + if (fnosigs) + { +#ifdef SIGHUP + (void) signal (SIGHUP, SIG_IGN); +#endif +#ifdef SIGINT + (void) signal (SIGINT, SIG_IGN); +#endif +#ifdef SIGQUIT + (void) signal (SIGQUIT, SIG_IGN); +#endif + } + + (void) execve ((char *) zcmd, (char **) pazargs, pazenv); + + /* The exec failed. If permitted, try using /bin/sh to execute a + shell script. */ + + if (errno == ENOEXEC && fshell) + { + char *zto; + const char *azshargs[4]; + + pazargs[0] = zcmd; + zto = zshcmd; + for (i = 0; pazargs[i] != NULL; i++) + { + const char *zfrom; + + for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++) + { + /* Some versions of /bin/sh appear to have a bug such + that quoting a '/' sometimes causes an error. I + don't know exactly when this happens (I can recreate + it on Ultrix 4.0), but in any case it is harmless to + not quote a '/'. */ + if (*zfrom != '/') + *zto++ = '\\'; + *zto++ = *zfrom; + } + *zto++ = ' '; + } + *(zto - 1) = '\0'; + + azshargs[0] = "sh"; + azshargs[1] = "-c"; + azshargs[2] = zshcmd; + azshargs[3] = NULL; + + (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv); + } + + _exit (EXIT_FAILURE); + + /* Avoid compiler warning. */ + return -1; +} diff --git a/gnu/libexec/uucp/libunix/splcmd.c b/gnu/libexec/uucp/libunix/splcmd.c new file mode 100644 index 00000000000..9f6616a36dd --- /dev/null +++ b/gnu/libexec/uucp/libunix/splcmd.c @@ -0,0 +1,115 @@ +/* splcmd.c + Spool a command. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> +#include <ctype.h> + +/* Given a set of commands to execute for a remote system, create a + command file holding them. This creates a single command file + holding all the commands passed in. It returns a jobid. */ + +char * +zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds) + const struct uuconf_system *qsys; + int bgrade; + int ccmds; + const struct scmd *pascmds; +{ + char *z; + FILE *e; + int i; + const struct scmd *q; + char *zjobid; + +#if DEBUG > 0 + if (! UUCONF_GRADE_LEGAL (bgrade)) + ulog (LOG_FATAL, "Bad grade %d", bgrade); +#endif + + z = zscmd_file (qsys, bgrade); + if (z == NULL) + return NULL; + + e = esysdep_fopen (z, FALSE, FALSE, TRUE); + if (e == NULL) + { + ubuffree (z); + return NULL; + } + + for (i = 0, q = pascmds; i < ccmds; i++, q++) + { + switch (q->bcmd) + { + case 'S': + fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto, + q->zuser, q->zoptions, q->ztemp, q->imode, + q->znotify == NULL ? (const char *) "" : q->znotify); + break; + case 'R': + fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, + q->zoptions); + break; + case 'X': + fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, + q->zoptions); + break; + case 'E': + fprintf (e, "E %s %s %s -%s %s 0%o %s 0 %s\n", q->zfrom, q->zto, + q->zuser, q->zoptions, q->ztemp, q->imode, + q->znotify, q->zcmd); + break; + default: + ulog (LOG_ERROR, + "zsysdep_spool_commands: Unrecognized type %d", + q->bcmd); + (void) fclose (e); + (void) remove (z); + ubuffree (z); + return NULL; + } + } + + if (fclose (e) != 0) + { + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + (void) remove (z); + ubuffree (z); + return NULL; + } + + zjobid = zsfile_to_jobid (qsys, z, bgrade); + if (zjobid == NULL) + (void) remove (z); + ubuffree (z); + return zjobid; +} diff --git a/gnu/libexec/uucp/libunix/splnam.c b/gnu/libexec/uucp/libunix/splnam.c new file mode 100644 index 00000000000..06ce3605ce5 --- /dev/null +++ b/gnu/libexec/uucp/libunix/splnam.c @@ -0,0 +1,19 @@ +/* splnam.c + Get the full name of a file in the spool directory. */ + +#include "uucp.h" + +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +/* Get the real name of a spool file. */ + +char * +zsysdep_spool_file_name (qsys, zfile, pseq) + const struct uuconf_system *qsys; + const char *zfile; + pointer pseq; +{ + return zsfind_file (zfile, qsys->uuconf_zname, bsgrade (pseq)); +} diff --git a/gnu/libexec/uucp/libunix/spool.c b/gnu/libexec/uucp/libunix/spool.c new file mode 100644 index 00000000000..f28229fe4e1 --- /dev/null +++ b/gnu/libexec/uucp/libunix/spool.c @@ -0,0 +1,420 @@ +/* spool.c + Find a file in the spool directory. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/04 19:33:02 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* There are several types of files that go in the spool directory, + and they go into various different subdirectories. Whenever the + system name LOCAL appears below, it means whatever the local system + name is. + + Command files + These contain instructions for uucico indicating what files to transfer + to and from what systems. Each line of a work file is a command + beginning with S, R or X. + #if ! SPOOLDIR_TAYLOR + They are named C.ssssssgqqqq, where ssssss is the system name to + transfer to or from, g is the grade and qqqq is the sequence number. + #if SPOOLDIR_V2 + They are put in the spool directory. + #elif SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + They are put in the directory "C.". + #elif SPOOLDIR_HDB + They are put in a directory named for the system for which they were + created. + #elif SPOOLDIR_ULTRIX + If the directory sys/ssssss exists, they are put in the directory + sys/ssssss/C; otherwise, they are put in the directory sys/DEFAULT/C. + #endif + #elif SPOOLDIR_SVR4 + They are put in the directory sys/g, where sys is the system name + and g is the grade. + #endif + #else SPOOLDIR_TAYLOR + They are named C.gqqqq, where g is the grade and qqqq is the sequence + number, and are placed in the directory ssssss/C. where ssssss is + the system name to transfer to or from. + #endif + + Data files + There are files to be transferred to other systems. Some files to + be transferred may not be in the spool directory, depending on how + uucp was invoked. Data files are named in work files, so it is + never necessary to look at them directly (except to remove old ones); + it is only necessary to create them. These means that the many + variations in naming are inconsequential. + #if ! SPOOLDIR_TAYLOR + They are named D.ssssssgqqqq where ssssss is a system name (which + may be LOCAL for locally initiated transfers or a remote system for + remotely initiated transfers, except that HDB appears to use the + system the file is being transferred to), g is the grade and qqqq + is the sequence number. Some systems use a trailing subjob ID + number, but we currently do not. The grade is not important, and + some systems do not use it. If the data file is to become an + execution file on another system the grade (if present) will be + 'X'. Otherwise Ultrix appears to use 'b'; the uux included with + gnuucp 1.0 appears to use 'S'; SCO does not appear to use a grade, + although it does use a subjob ID number. + #if SPOOLDIR_V2 + They are put in the spool directory. + #elif SPOOLDIR_BSD42 + If the name begins with D.LOCAL, the file is put in the directory + D.LOCAL. Otherwise the file is put in the directory D.. + #elif SPOOLDIR_BSD43 + If the name begins with D.LOCALX, the file is put in the directory + D.LOCALX. Otherwise if the name begins with D.LOCAL, the file is + put in the directory D.LOCAL Otherwise the file is put in the + directory "D.". + #elif SPOOLDIR_HDB + They are put in a directory named for the system for which they + were created. + #elif SPOOLDIR_ULTRIX + Say the file is being transferred to system REMOTE. If the + directory sys/REMOTE exists, then if the file begins with D.LOCALX + it is put in sys/REMOTE/D.LOCALX, if the file begins with D.LOCAL + it is put in sys/REMOTE/D.LOCAL, and otherwise it is put in + "sys/REMOTE/D.". If the directory sys/REMOTE does not exist, the + same applies except that DEFAULT is used instead of REMOTE. + #elif SPOOLDIR_SVR4 + They are put in the directory sys/g, where sys is the system name + and g is the grade. + #endif + #else SPOOLDIR_TAYLOR + If the file is to become an executable file on another system it is + named D.Xqqqq, otherwise it is named D.qqqq where in both cases + qqqq is a sequence number. If the corresponding C. file is in + directory ssssss/C., a D.X file is placed in ssssss/D.X and a D. + file is placed in "ssssss/D.". + #endif + + Execute files + These are files that specify programs to be executed. They are + created by uux, perhaps as run on another system. These names are + important, because a file transfer done to an execute file name + causes an execution to occur. The name is X.ssssssgqqqq, where + ssssss is the requesting system, g is the grade, and qqqq is a + sequence number. + #if SPOOLDIR_V2 || SPOOLDIR_BSD42 + These files are placed in the spool directory. + #elif SPOOLDIR_BSD43 + These files are placed in the directory X.. + #elif SPOOLDIR_HDB || SPOOLDIR_SVR4 + These files are put in a directory named for the system for which + the files were created. + #elif SPOOLDIR_ULTRIX + If there is a spool directory (sys/ssssss) for the requesting + system, the files are placed in sys/ssssss/X.; otherwise, the files + are placed in "sys/DEFAULT/X.". + #elif SPOOLDIR_TAYLOR + The system name is automatically truncated to seven characters when + a file is created. The files are placed in the subdirectory X. of + a directory named for the system for which the files were created. + #endif + + Temporary receive files + These are used when receiving files from another system. They are + later renamed to the final name. The actual name is unimportant, + although it generally begins with TM.. + #if SPOOLDIR_V2 || SPOOLDIR_BSD42 + These files are placed in the spool directory. + #elif SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR + These files are placed in the directory .Temp. + #elif SPOOLDIR_HDB || SPOOLDIR_SVR4 + These files are placed in a directory named for the system for + which they were created. + #endif + + System status files + These are used to record when the last call was made to the system + and what the status is. They are used to prevent frequent recalls + to a system which is not responding. I will not attempt to + recreate the format of these exactly, since they are not all that + important. They will be put in the directory .Status, as in HDB, + and they use the system name as the name of the file. + + Sequence file + This is used to generate a unique sequence number. It contains an + ASCII number. + #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + The file is named SEQF and is kept in the spool directory. + #elif SPOOLDIR_HDB || SPOOLDIR_SVR4 + A separate sequence file is kept for each system in the directory + .Sequence with the name of the system. + #elif SPOOLDIR_ULTRIX + Each system with a file sys/ssssss has a sequence file in + sys/ssssss/.SEQF. Other systems use sys/DEFAULT/.SEQF. + #else SPOOLDIR_TAYLOR + A sequence file named SEQF is kept in the directory ssssss for each + system. + #endif + */ + +/* Given the name of a file as specified in a UUCP command, and the + system for which this file has been created, return where to find + it in the spool directory. The file will begin with C. (a command + file), D. (a data file) or X. (an execution file). Under + SPOOLDIR_SVR4 we need to know the grade of the file created by the + local system; this is the bgrade argument, which is -1 for a file + from a remote system. */ + +/*ARGSUSED*/ +char * +zsfind_file (zsimple, zsystem, bgrade) + const char *zsimple; + const char *zsystem; + int bgrade; +{ + if (! fspool_file (zsimple)) + { + ulog (LOG_ERROR, "Unrecognized file name %s", zsimple); + return NULL; + } + +#if ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR + if (*zsimple == 'X') + { + size_t clen; + + /* Files beginning with X. are execute files. It is important + for security reasons that we know the system which created + the X. file. This is easy under SPOOLDIR_HDB or + SPOOLDIR_SVR4 SPOOLDIR_TAYLOR, because the file will be in a + directory named for the system. Under other schemes, we must + get the system name from the X. file name. To prevent + security violations, we set the system name directly here; + this will cause problems if the maximum file name length is + too short, but hopefully no problem will occur since any + System V systems will be using HDB or SVR4 or TAYLOR. */ + clen = strlen (zsimple); + if (clen <= 7 || strncmp (zsimple + 2, zsystem, clen - 7) != 0) + { + static char *zbuf; + static size_t cbuf; + size_t cwant; + + cwant = strlen (zsystem) + 8; + if (cwant > cbuf) + { + zbuf = (char *) xrealloc ((pointer) zbuf, cwant); + cbuf = cwant; + } + sprintf (zbuf, "X.%s%s", zsystem, + clen < 5 ? zsimple : zsimple + clen - 5); + zsimple = zbuf; + } + } +#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR */ + +#if SPOOLDIR_V2 + /* V2 never uses subdirectories. */ + return zbufcpy (zsimple); +#endif /* SPOOLDIR_V2 */ + +#if SPOOLDIR_HDB + /* HDB always uses the system name as a directory. */ + return zsysdep_in_dir (zsystem, zsimple); +#endif /* SPOOLDIR_HDB */ + +#if SPOOLDIR_SVR4 + /* SVR4 uses grade directories within the system directory for local + command and data files. */ + if (bgrade < 0 || *zsimple == 'X') + return zsysdep_in_dir (zsystem, zsimple); + else + { + char abgrade[2]; + + abgrade[0] = bgrade; + abgrade[1] = '\0'; + return zsappend3 (zsystem, abgrade, zsimple); + } +#endif /* SPOOLDIR_SVR4 */ + +#if ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 + switch (*zsimple) + { + case 'C': +#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + return zsysdep_in_dir ("C.", zsimple); +#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */ +#if SPOOLDIR_ULTRIX + if (fsultrix_has_spool (zsystem)) + return zsappend4 ("sys", zsystem, "C.", zsimple); + else + return zsappend4 ("sys", "DEFAULT", "C.", zsimple); +#endif /* SPOOLDIR_ULTRIX */ +#if SPOOLDIR_TAYLOR + return zsappend3 (zsystem, "C.", zsimple); +#endif /* SPOOLDIR_TAYLOR */ + + case 'D': +#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + { + size_t c; + boolean ftruncated; + + /* D.LOCAL in D.LOCAL/, others in D./. If BSD43, D.LOCALX in + D.LOCALX/. */ + ftruncated = TRUE; + if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0) + { + c = strlen (zSlocalname); + ftruncated = FALSE; + } + else if (strncmp (zsimple + 2, zSlocalname, 7) == 0) + c = 7; + else if (strncmp (zsimple + 2, zSlocalname, 6) == 0) + c = 6; + else + c = 0; +#if SPOOLDIR_BSD43 + if (c > 0 && zsimple[c + 2] == 'X') + c++; +#endif /* SPOOLDIR_BSD43 */ + if (c > 0) + { + char *zalloc; + + zalloc = zbufalc (c + 3); + memcpy (zalloc, zsimple, c + 2); + zalloc[c + 2] = '\0'; + + /* If we truncated the system name, and there is no existing + directory with the truncated name, then just use D.. */ + if (! ftruncated || fsysdep_directory (zalloc)) + { + char *zret; + + zret = zsysdep_in_dir (zalloc, zsimple); + ubuffree (zalloc); + return zret; + } + ubuffree (zalloc); + } + return zsysdep_in_dir ("D.", zsimple); + } +#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */ +#if SPOOLDIR_ULTRIX + { + size_t c; + boolean ftruncated; + char *zfree; + const char *zdir; + char *zret; + + /* D.LOCALX in D.LOCALX/, D.LOCAL in D.LOCAL/, others in D./. */ + ftruncated = TRUE; + if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0) + { + c = strlen (zSlocalname); + ftruncated = FALSE; + } + else if (strncmp (zsimple + 2, zSlocalname, 7) == 0) + c = 7; + else if (strncmp (zsimple + 2, zSlocalname, 6) == 0) + c = 6; + else + c = 0; + if (c > 0 && zsimple[c + 2] == 'X') + ++c; + if (c > 0) + { + zfree = zbufalc (c + 3); + memcpy (zfree, zsimple, c + 2); + zfree[c + 2] = '\0'; + zdir = zfree; + + /* If we truncated the name, and there is no directory for + the truncated name, then don't use it. */ + if (ftruncated) + { + char *zlook; + + zlook = zsappend3 ("sys", + (fsultrix_has_spool (zsystem) + ? zsystem + : "DEFAULT"), + zdir); + if (! fsysdep_directory (zlook)) + zdir = "D."; + ubuffree (zlook); + } + } + else + { + zfree = NULL; + zdir = "D."; + } + + zret = zsappend4 ("sys", + (fsultrix_has_spool (zsystem) + ? zsystem + : "DEFAULT"), + zdir, + zsimple); + ubuffree (zfree); + return zret; + } +#endif /* SPOOLDIR_ULTRIX */ +#if SPOOLDIR_TAYLOR + if (zsimple[2] == 'X') + return zsappend3 (zsystem, "D.X", zsimple); + else + return zsappend3 (zsystem, "D.", zsimple); +#endif /* SPOOLDIR_TAYLOR */ + + + case 'X': +#if SPOOLDIR_BSD42 + return zbufcpy (zsimple); +#endif +#if SPOOLDIR_BSD43 + return zsysdep_in_dir ("X.", zsimple); +#endif +#if SPOOLDIR_ULTRIX + return zsappend4 ("sys", + (fsultrix_has_spool (zsystem) + ? zsystem + : "DEFAULT"), + "X.", + zsimple); +#endif +#if SPOOLDIR_TAYLOR + return zsappend3 (zsystem, "X.", zsimple); +#endif + } + + /* This is just to avoid warnings; it will never be executed. */ + return NULL; +#endif /* ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ +} diff --git a/gnu/libexec/uucp/libunix/srmdir.c b/gnu/libexec/uucp/libunix/srmdir.c new file mode 100644 index 00000000000..28487ef3097 --- /dev/null +++ b/gnu/libexec/uucp/libunix/srmdir.c @@ -0,0 +1,112 @@ +/* srmdir.c + Remove a directory and all its contents. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FTW_H +#include <ftw.h> +#endif + +static int isremove_dir P((const char *, const struct stat *, int)); + +/* Keep a list of directories to be removed. */ + +struct sdirlist +{ + struct sdirlist *qnext; + char *zdir; +}; + +static struct sdirlist *qSdirlist; + +/* Remove a directory and all files in it. */ + +boolean +fsysdep_rmdir (zdir) + const char *zdir; +{ + boolean fret; + struct sdirlist *q; + + qSdirlist = NULL; + + fret = TRUE; + if (ftw ((char *) zdir, isremove_dir, 5) != 0) + { + ulog (LOG_ERROR, "ftw: %s", strerror (errno)); + fret = FALSE; + } + + q = qSdirlist; + while (q != NULL) + { + struct sdirlist *qnext; + + if (rmdir (q->zdir) != 0) + { + ulog (LOG_ERROR, "rmdir (%s): %s", q->zdir, strerror (errno)); + fret = FALSE; + } + ubuffree (q->zdir); + qnext = q->qnext; + xfree ((pointer) q); + q = qnext; + } + + return fret; +} + +/* Remove a file in a directory. */ + +/*ARGSUSED*/ +static int +isremove_dir (zfile, qstat, iflag) + const char *zfile; + const struct stat *qstat; + int iflag; +{ + if (iflag == FTW_D || iflag == FTW_DNR) + { + struct sdirlist *q; + + q = (struct sdirlist *) xmalloc (sizeof (struct sdirlist)); + q->qnext = qSdirlist; + q->zdir = zbufcpy (zfile); + qSdirlist = q; + } + else + { + if (remove (zfile) != 0) + ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); + } + + return 0; +} diff --git a/gnu/libexec/uucp/libunix/statsb.c b/gnu/libexec/uucp/libunix/statsb.c new file mode 100644 index 00000000000..79a14c0e64c --- /dev/null +++ b/gnu/libexec/uucp/libunix/statsb.c @@ -0,0 +1,572 @@ +/* statsb.c + System dependent routines for uustat. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/04 19:33:06 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +#if HAVE_TIME_H +#include <time.h> +#endif + +#if HAVE_UTIME_H +#include <utime.h> +#endif + +/* Local functions. */ + +static int ussettime P((const char *z, time_t inow)); +static boolean fskill_or_rejuv P((pointer puuconf, const char *zid, + boolean fkill)); + +/* See whether the user is permitted to kill arbitrary jobs. This is + true only for root and uucp. We check for uucp by seeing if the + real user ID and the effective user ID are the same; this works + because we should be suid to uucp, so our effective user ID will + always be uucp while our real user ID will be whoever ran the + program. */ + +boolean +fsysdep_privileged () +{ + uid_t iuid; + + iuid = getuid (); + return iuid == 0 || iuid == geteuid (); +} + +/* Set file access time to the present. On many systems this could be + done by passing NULL to utime, but on some that doesn't work. This + routine is not time critical, so we never rely on NULL. */ + +static int +ussettime(z, inow) + const char *z; + time_t inow; +{ +#if HAVE_UTIME_H + struct utimbuf s; + + s.actime = inow; + s.modtime = inow; + return utime ((char *) z, &s); +#else + time_t ai[2]; + + ai[0] = inow; + ai[1] = inow; + return utime ((char *) z, ai); +#endif +} + +/* Kill a job, given the jobid. */ + +boolean +fsysdep_kill_job (puuconf, zid) + pointer puuconf; + const char *zid; +{ + return fskill_or_rejuv (puuconf, zid, TRUE); +} + +/* Rejuvenate a job, given the jobid. */ + +boolean +fsysdep_rejuvenate_job (puuconf, zid) + pointer puuconf; + const char *zid; +{ + return fskill_or_rejuv (puuconf, zid, FALSE); +} + +/* Kill or rejuvenate a job, given the jobid. */ + +static boolean +fskill_or_rejuv (puuconf, zid, fkill) + pointer puuconf; + const char *zid; + boolean fkill; +{ + char *zfile; + char *zsys; + char bgrade; + time_t inow = 0; + int iuuconf; + struct uuconf_system ssys; + FILE *e; + boolean fret; + char *zline; + size_t cline; + int isys; + + zfile = zsjobid_to_file (zid, &zsys, &bgrade); + if (zfile == NULL) + return FALSE; + + if (! fkill) + inow = time ((time_t *) NULL); + + iuuconf = uuconf_system_info (puuconf, zsys, &ssys); + if (iuuconf == UUCONF_NOT_FOUND) + { + if (! funknown_system (puuconf, zsys, &ssys)) + { + ulog (LOG_ERROR, "%s: Bad job id", zid); + ubuffree (zfile); + ubuffree (zsys); + return FALSE; + } + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (zfile); + ubuffree (zsys); + return FALSE; + } + + e = fopen (zfile, "r"); + if (e == NULL) + { + if (errno == ENOENT) + ulog (LOG_ERROR, "%s: Job not found", zid); + else + ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); + (void) uuconf_system_free (puuconf, &ssys); + ubuffree (zfile); + ubuffree (zsys); + return FALSE; + } + + /* Now we have to read through the file to identify any temporary + files. */ + fret = TRUE; + zline = NULL; + cline = 0; + while (getline (&zline, &cline, e) > 0) + { + struct scmd s; + + if (! fparse_cmd (zline, &s)) + { + ulog (LOG_ERROR, "Bad line in command file %s", zfile); + fret = FALSE; + continue; + } + + /* You are only permitted to delete a job if you submitted it or + if you are root or uucp. */ + if (strcmp (s.zuser, zsysdep_login_name ()) != 0 + && ! fsysdep_privileged ()) + { + ulog (LOG_ERROR, "%s: Not submitted by you", zid); + xfree ((pointer) zline); + (void) fclose (e); + (void) uuconf_system_free (puuconf, &ssys); + ubuffree (zfile); + ubuffree (zsys); + return FALSE; + } + + if (s.bcmd == 'S' || s.bcmd == 'E') + { + char *ztemp; + + ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade); + if (ztemp == NULL) + fret = FALSE; + else + { + if (fkill) + isys = remove (ztemp); + else + isys = ussettime (ztemp, inow); + + if (isys != 0 && errno != ENOENT) + { + ulog (LOG_ERROR, "%s (%s): %s", + fkill ? "remove" : "utime", ztemp, + strerror (errno)); + fret = FALSE; + } + + ubuffree (ztemp); + } + } + } + + xfree ((pointer) zline); + (void) fclose (e); + (void) uuconf_system_free (puuconf, &ssys); + ubuffree (zsys); + + if (fkill) + isys = remove (zfile); + else + isys = ussettime (zfile, inow); + + if (isys != 0 && errno != ENOENT) + { + ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime", + zfile, strerror (errno)); + fret = FALSE; + } + + ubuffree (zfile); + + return fret; +} + +/* Get the time a work job was queued. */ + +long +ixsysdep_work_time (qsys, pseq) + const struct uuconf_system *qsys; + pointer pseq; +{ + char *zjobid, *zfile; + long iret; + + zjobid = zsysdep_jobid (qsys, pseq); + zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL); + if (zfile == NULL) + return 0; + ubuffree (zjobid); + iret = ixsysdep_file_time (zfile); + ubuffree (zfile); + return iret; +} + +/* Get the time a file was created (actually, the time it was last + modified). */ + +long +ixsysdep_file_time (zfile) + const char *zfile; +{ + struct stat s; + + if (stat ((char *) zfile, &s) < 0) + { + if (errno != ENOENT) + ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); + return ixsysdep_time ((long *) NULL); + } + + return (long) s.st_mtime; +} + +/* Start getting the status files. */ + +boolean +fsysdep_all_status_init (phold) + pointer *phold; +{ + DIR *qdir; + + qdir = opendir ((char *) ".Status"); + if (qdir == NULL) + { + ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno)); + return FALSE; + } + + *phold = (pointer) qdir; + return TRUE; +} + +/* Get the next status file. */ + +char * +zsysdep_all_status (phold, pferr, qstat) + pointer phold; + boolean *pferr; + struct sstatus *qstat; +{ + DIR *qdir = (DIR *) phold; + struct dirent *qentry; + + while (TRUE) + { + errno = 0; + qentry = readdir (qdir); + if (qentry == NULL) + { + if (errno == 0) + *pferr = FALSE; + else + { + ulog (LOG_ERROR, "readdir: %s", strerror (errno)); + *pferr = TRUE; + } + return NULL; + } + + if (qentry->d_name[0] != '.') + { + struct uuconf_system ssys; + + /* Hack seriously; fsysdep_get_status only looks at the + zname element of the qsys argument, so if we fake that we + can read the status file. This should really be done + differently. */ + ssys.uuconf_zname = qentry->d_name; + if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL)) + return zbufcpy (qentry->d_name); + + /* If fsysdep_get_status fails, it will output an error + message. We just continue with the next entry, so that + most of the status files will be displayed. */ + } + } +} + +/* Finish getting the status file. */ + +void +usysdep_all_status_free (phold) + pointer phold; +{ + DIR *qdir = (DIR *) phold; + + (void) closedir (qdir); +} + +/* Get the status of all processes holding lock files. We do this by + invoking ps after we've figured out the process entries to use. */ + +boolean +fsysdep_lock_status () +{ + DIR *qdir; + struct dirent *qentry; + int calc; + int *pai; + int cgot; + int aidescs[3]; + char *zcopy, *ztok; + int cargs, iarg; + char **pazargs; + + qdir = opendir ((char *) zSlockdir); + if (qdir == NULL) + { + ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno)); + return FALSE; + } + + /* We look for entries that start with "LCK.." and ignore everything + else. This won't find all possible lock files, but it should + find all the locks on terminals and systems. */ + + calc = 0; + pai = NULL; + cgot = 0; + while ((qentry = readdir (qdir)) != NULL) + { + char *zname; + int o; +#if HAVE_V2_LOCKFILES + int i; +#else + char ab[12]; +#endif + int cread; + int ierr; + int ipid; + + if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0) + continue; + + zname = zsysdep_in_dir (zSlockdir, qentry->d_name); + o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0); + if (o < 0) + { + if (errno != ENOENT) + ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno)); + ubuffree (zname); + continue; + } + +#if HAVE_V2_LOCKFILES + cread = read (o, &i, sizeof i); +#else + cread = read (o, ab, sizeof ab - 1); +#endif + + ierr = errno; + (void) close (o); + + if (cread < 0) + { + ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr)); + ubuffree (zname); + continue; + } + + ubuffree (zname); + +#if HAVE_V2_LOCKFILES + ipid = i; +#else + ab[cread] = '\0'; + ipid = strtol (ab, (char **) NULL, 10); +#endif + + printf ("%s: %d\n", qentry->d_name, ipid); + + if (cgot >= calc) + { + calc += 10; + pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int)); + } + + pai[cgot] = ipid; + ++cgot; + } + + if (cgot == 0) + return TRUE; + + aidescs[0] = SPAWN_NULL; + aidescs[1] = 1; + aidescs[2] = 2; + + /* Parse PS_PROGRAM into an array of arguments. */ + zcopy = zbufcpy (PS_PROGRAM); + + cargs = 0; + for (ztok = strtok (zcopy, " \t"); + ztok != NULL; + ztok = strtok ((char *) NULL, " \t")) + ++cargs; + + pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *)); + + memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM); + for (ztok = strtok (zcopy, " \t"), iarg = 0; + ztok != NULL; + ztok = strtok ((char *) NULL, " \t"), ++iarg) + pazargs[iarg] = ztok; + pazargs[iarg] = NULL; + +#if ! HAVE_PS_MULTIPLE + /* We have to invoke ps multiple times. */ + { + int i; + char *zlast, *zset; + + zlast = pazargs[cargs - 1]; + zset = zbufalc (strlen (zlast) + 20); + for (i = 0; i < cgot; i++) + { + pid_t ipid; + + sprintf (zset, "%s%d", zlast, pai[i]); + pazargs[cargs - 1] = zset; + + ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE, + (const char *) NULL, FALSE, TRUE, + (const char *) NULL, (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); + else + (void) ixswait ((unsigned long) ipid, PS_PROGRAM); + } + ubuffree (zset); + } +#else + { + char *zlast; + int i; + pid_t ipid; + + zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1); + strcpy (zlast, pazargs[cargs - 1]); + for (i = 0; i < cgot; i++) + { + char ab[20]; + + sprintf (ab, "%d", pai[i]); + strcat (zlast, ab); + if (i + 1 < cgot) + strcat (zlast, ","); + } + pazargs[cargs - 1] = zlast; + + ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE, + (const char *) NULL, FALSE, TRUE, + (const char *) NULL, (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); + else + (void) ixswait ((unsigned long) ipid, PS_PROGRAM); + ubuffree (zlast); + } +#endif + + ubuffree (zcopy); + xfree ((pointer) pazargs); + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/status.c b/gnu/libexec/uucp/libunix/status.c new file mode 100644 index 00000000000..f403068a709 --- /dev/null +++ b/gnu/libexec/uucp/libunix/status.c @@ -0,0 +1,212 @@ +/* status.c + Routines to get and set the status for a system. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + +/* If we are using HDB spool layout, store status using HDB status + values. SVR4 is a variant of HDB. */ + +#define MAP_STATUS 1 + +static const int aiMapstatus[] = +{ + 0, 13, 7, 6, 4, 20, 3, 2 +}; +#define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0])) + +#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ + +#define MAP_STATUS 0 + +#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ + +/* Get the status of a system. This assumes that we are in the spool + directory. */ + +boolean +fsysdep_get_status (qsys, qret, pfnone) + const struct uuconf_system *qsys; + struct sstatus *qret; + boolean *pfnone; +{ + char *zname; + FILE *e; + char *zline; + char *zend, *znext; + boolean fbad; + int istat; + + if (pfnone != NULL) + *pfnone = FALSE; + + zname = zsysdep_in_dir (".Status", qsys->uuconf_zname); + e = fopen (zname, "r"); + if (e == NULL) + { + if (errno != ENOENT) + { + ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); + ubuffree (zname); + return FALSE; + } + zline = NULL; + } + else + { + size_t cline; + + zline = NULL; + cline = 0; + if (getline (&zline, &cline, e) <= 0) + { + xfree ((pointer) zline); + zline = NULL; + } + (void) fclose (e); + } + + if (zline == NULL) + { + /* There is either no status file for this system, or it's been + truncated, so fake a good status. */ + qret->ttype = STATUS_COMPLETE; + qret->cretries = 0; + qret->ilast = 0; + qret->cwait = 0; + if (pfnone != NULL) + *pfnone = TRUE; + ubuffree (zname); + return TRUE; + } + + /* It turns out that scanf is not used much in this program, so for + the benefit of small computers we avoid linking it in. This is + basically + + sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries, + &qret->ilast, &qret->cwait); + + except that it's done with strtol. */ + + fbad = FALSE; + istat = (int) strtol (zline, &zend, 10); + if (zend == zline) + fbad = TRUE; + +#if MAP_STATUS + /* On some systems it may be appropriate to map system dependent status + values on to our status values. */ + { + int i; + + for (i = 0; i < CMAPENTRIES; ++i) + { + if (aiMapstatus[i] == istat) + { + istat = i; + break; + } + } + } +#endif /* MAP_STATUS */ + + if (istat < 0 || istat >= (int) STATUS_VALUES) + istat = (int) STATUS_COMPLETE; + qret->ttype = (enum tstatus_type) istat; + znext = zend; + qret->cretries = (int) strtol (znext, &zend, 10); + if (zend == znext) + fbad = TRUE; + znext = zend; + qret->ilast = strtol (znext, &zend, 10); + if (zend == znext) + fbad = TRUE; + znext = zend; + qret->cwait = (int) strtol (znext, &zend, 10); + if (zend == znext) + fbad = TRUE; + + xfree ((pointer) zline); + + if (fbad) + { + ulog (LOG_ERROR, "%s: Bad status file format", zname); + ubuffree (zname); + return FALSE; + } + + ubuffree (zname); + + return TRUE; +} + +/* Set the status of a remote system. This assumes the system is + locked when this is called, and that the program is in the spool + directory. */ + +boolean +fsysdep_set_status (qsys, qset) + const struct uuconf_system *qsys; + const struct sstatus *qset; +{ + char *zname; + FILE *e; + int istat; + + zname = zsysdep_in_dir (".Status", qsys->uuconf_zname); + + e = esysdep_fopen (zname, TRUE, FALSE, TRUE); + ubuffree (zname); + if (e == NULL) + return FALSE; + istat = (int) qset->ttype; + +#if MAP_STATUS + /* On some systems it may be appropriate to map istat onto a system + dependent number. */ + if (istat >= 0 && istat < CMAPENTRIES) + istat = aiMapstatus[istat]; +#endif /* MAP_STATUS */ + + fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries, + qset->ilast, qset->cwait, azStatus[(int) qset->ttype], + qsys->uuconf_zname); + if (fclose (e) != 0) + { + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + return FALSE; + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/strerr.c b/gnu/libexec/uucp/libunix/strerr.c new file mode 100644 index 00000000000..d2a6c2128d0 --- /dev/null +++ b/gnu/libexec/uucp/libunix/strerr.c @@ -0,0 +1,22 @@ +/* strerr.c + Return a string for a Unix errno value. */ + +#include "uucp.h" + +#include <errno.h> + +#ifndef sys_nerr +extern int sys_nerr; +#endif +#ifndef sys_errlist +extern char *sys_errlist[]; +#endif + +char * +strerror (ierr) + int ierr; +{ + if (ierr >= 0 && ierr < sys_nerr) + return sys_errlist[ierr]; + return (char *) "unknown error"; +} diff --git a/gnu/libexec/uucp/libunix/time.c b/gnu/libexec/uucp/libunix/time.c new file mode 100644 index 00000000000..d0462433a7d --- /dev/null +++ b/gnu/libexec/uucp/libunix/time.c @@ -0,0 +1,32 @@ +/* time.c + Get the current time. */ + +#include "uucp.h" + +#if HAVE_TIME_H +#include <time.h> +#endif + +#include "system.h" + +#ifndef time +extern time_t time (); +#endif + +/* Get the time in seconds since the epoch, with optional + microseconds. We use ixsysdep_process_time to get the microseconds + if it will work (it won't if it uses times, since that returns a + time based only on the process). */ + +long +ixsysdep_time (pimicros) + long *pimicros; +{ +#if HAVE_GETTIMEOFDAY || HAVE_FTIME + return ixsysdep_process_time (pimicros); +#else + if (pimicros != NULL) + *pimicros = 0; + return (long) time ((time_t *) NULL); +#endif +} diff --git a/gnu/libexec/uucp/libunix/tmpfil.c b/gnu/libexec/uucp/libunix/tmpfil.c new file mode 100644 index 00000000000..2dac0024388 --- /dev/null +++ b/gnu/libexec/uucp/libunix/tmpfil.c @@ -0,0 +1,83 @@ +/* tmpfil.c + Get a temporary file name. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" + +#define ZDIGS \ + "0123456789abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-" +#define CDIGS (sizeof ZDIGS - 1) + +/*ARGSUSED*/ +char * +zstemp_file (qsys) + const struct uuconf_system *qsys; +{ + static int icount; + const char *const zdigs = ZDIGS; + char ab[14]; + pid_t ime; + int iset; + + ab[0] = 'T'; + ab[1] = 'M'; + ab[2] = '.'; + + ime = getpid (); + iset = 3; + while (ime > 0 && iset < 10) + { + ab[iset] = zdigs[ime % CDIGS]; + ime /= CDIGS; + ++iset; + } + + ab[iset] = '.'; + ++iset; + + ab[iset] = zdigs[icount / CDIGS]; + ++iset; + ab[iset] = zdigs[icount % CDIGS]; + ++iset; + + ab[iset] = '\0'; + + ++icount; + if (icount >= CDIGS * CDIGS) + icount = 0; + +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 + return zbufcpy (ab); +#endif +#if SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR + return zsysdep_in_dir (".Temp", ab); +#endif +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + return zsysdep_in_dir (qsys->uuconf_zname, ab); +#endif +} diff --git a/gnu/libexec/uucp/libunix/trunc.c b/gnu/libexec/uucp/libunix/trunc.c new file mode 100644 index 00000000000..c93e82e3940 --- /dev/null +++ b/gnu/libexec/uucp/libunix/trunc.c @@ -0,0 +1,157 @@ +/* trunc.c + Truncate a file to zero length. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +/* External functions. */ +#ifndef lseek +extern off_t lseek (); +#endif + +/* Truncate a file to zero length. If this fails, it closes and + removes the file. We support a number of different means of + truncation, which is probably a waste of time since this function + is currently only called when the 'f' protocol resends a file. */ + +#if HAVE_FTRUNCATE +#undef HAVE_LTRUNC +#define HAVE_LTRUNC 0 +#endif + +#if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC +#ifdef F_CHSIZE +#define HAVE_F_CHSIZE 1 +#else /* ! defined (F_CHSIZE) */ +#ifdef F_FREESP +#define HAVE_F_FREESP 1 +#endif /* defined (F_FREESP) */ +#endif /* ! defined (F_CHSIZE) */ +#endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */ + +openfile_t +esysdep_truncate (e, zname) + openfile_t e; + const char *zname; +{ + int o; + +#if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP + int itrunc; + + if (! ffilerewind (e)) + { + ulog (LOG_ERROR, "rewind: %s", strerror (errno)); + (void) ffileclose (e); + (void) remove (zname); + return EFILECLOSED; + } + +#if USE_STDIO + o = fileno (e); +#else + o = e; +#endif + +#if HAVE_FTRUNCATE + itrunc = ftruncate (o, 0); +#endif +#if HAVE_LTRUNC + itrunc = ltrunc (o, (long) 0, SEEK_SET); +#endif +#if HAVE_F_CHSIZE + itrunc = fcntl (o, F_CHSIZE, (off_t) 0); +#endif +#if HAVE_F_FREESP + /* This selection is based on an implementation of ftruncate by + kucharsk@Solbourne.com (William Kucharski). */ + { + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = 0; + fl.l_type = F_WRLCK; + + itrunc = fcntl (o, F_FREESP, &fl); + } +#endif + + if (itrunc != 0) + { +#if HAVE_FTRUNCATE + ulog (LOG_ERROR, "ftruncate: %s", strerror (errno)); +#endif +#ifdef HAVE_LTRUNC + ulog (LOG_ERROR, "ltrunc: %s", strerror (errno)); +#endif +#ifdef HAVE_F_CHSIZE + ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno)); +#endif +#ifdef HAVE_F_FREESP + ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno)); +#endif + + (void) ffileclose (e); + (void) remove (zname); + return EFILECLOSED; + } + + return e; +#else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */ + (void) ffileclose (e); + (void) remove (zname); + + o = creat ((char *) zname, IPRIVATE_FILE_MODE); + + if (o == -1) + { + ulog (LOG_ERROR, "creat (%s): %s", zname, strerror (errno)); + return EFILECLOSED; + } + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (o); + return EFILECLOSED; + } + +#if USE_STDIO + e = fdopen (o, (char *) BINWRITE); + + if (e == NULL) + { + ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno)); + (void) close (o); + (void) remove (zname); + return NULL; + } +#else /* ! USE_STDIO */ + e = o; +#endif /* ! USE_STDIO */ + + return e; +#endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */ +} diff --git a/gnu/libexec/uucp/libunix/uacces.c b/gnu/libexec/uucp/libunix/uacces.c new file mode 100644 index 00000000000..c92c78eae35 --- /dev/null +++ b/gnu/libexec/uucp/libunix/uacces.c @@ -0,0 +1,205 @@ +/* uacces.c + Check access to a file by user name. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +#include <pwd.h> +#include <errno.h> + +#if HAVE_GETGRENT +#include <grp.h> +#if GETGRENT_DECLARATION_OK +#ifndef getgrent +extern struct group *getgrent (); +#endif +#endif +#endif /* HAVE_GETGRENT */ + +#if GETPWNAM_DECLARATION_OK +#ifndef getpwnam +extern struct passwd *getpwnam (); +#endif +#endif + +/* Do access(2) on a stat structure, except that the user name is + provided. If the user name in zuser is NULL, require the file to + be accessible to the world. Return TRUE if access is permitted, + FALSE otherwise. This does not log an error message. */ + +boolean +fsuser_access (q, imode, zuser) + const struct stat *q; + int imode; + const char *zuser; +{ + static char *zuser_hold; + static uid_t iuid_hold; + static gid_t igid_hold; + static int cgroups_hold; + static gid_t *paigroups_hold; + int ir, iw, ix, iand; + + if (imode == F_OK) + return TRUE; + + if (zuser != NULL) + { + /* We keep static variables around for the last user we did, to + avoid looking up a user multiple times. */ + if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0) + { + struct passwd *qpwd; + + if (zuser_hold != NULL) + { + ubuffree (zuser_hold); + zuser_hold = NULL; + cgroups_hold = 0; + xfree ((pointer) paigroups_hold); + paigroups_hold = NULL; + } + + qpwd = getpwnam ((char *) zuser); + if (qpwd == NULL) + { + /* Check this as a remote request. */ + zuser = NULL; + } + else + { +#if HAVE_GETGRENT + struct group *qg; +#endif + + zuser_hold = zbufcpy (zuser); + + iuid_hold = qpwd->pw_uid; + igid_hold = qpwd->pw_gid; + +#if HAVE_GETGRENT + /* Get the list of groups for this user. This is + definitely more appropriate for BSD than for System + V. It may just be a waste of time, and perhaps it + should be configurable. */ + setgrent (); + while ((qg = getgrent ()) != NULL) + { + const char **pz; + + if (qg->gr_gid == igid_hold) + continue; + for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++) + { + if ((*pz)[0] == *zuser + && strcmp (*pz, zuser) == 0) + { + paigroups_hold = ((gid_t *) + (xrealloc + ((pointer) paigroups_hold, + ((cgroups_hold + 1) + * sizeof (gid_t))))); + paigroups_hold[cgroups_hold] = qg->gr_gid; + ++cgroups_hold; + break; + } + } + } + endgrent (); +#endif + } + } + } + + + /* Now do the actual access check. */ + + if (zuser != NULL) + { + /* The superuser can do anything. */ + if (iuid_hold == 0) + return TRUE; + + /* If this is the uid we're running under, there's no point to + checking access further, because when we actually try the + operation the system will do the checking for us. */ + if (iuid_hold == geteuid ()) + return TRUE; + } + + ir = S_IROTH; + iw = S_IWOTH; + ix = S_IXOTH; + + if (zuser != NULL) + { + if (iuid_hold == q->st_uid) + { + ir = S_IRUSR; + iw = S_IWUSR; + ix = S_IXUSR; + } + else + { + boolean fgroup; + + fgroup = FALSE; + if (igid_hold == q->st_gid) + fgroup = TRUE; + else + { + int i; + + for (i = 0; i < cgroups_hold; i++) + { + if (paigroups_hold[i] == q->st_gid) + { + fgroup = TRUE; + break; + } + } + } + + if (fgroup) + { + ir = S_IRGRP; + iw = S_IWGRP; + ix = S_IXGRP; + } + } + } + + iand = 0; + if ((imode & R_OK) != 0) + iand |= ir; + if ((imode & W_OK) != 0) + iand |= iw; + if ((imode & X_OK) != 0) + iand |= ix; + + return (q->st_mode & iand) == iand; +} diff --git a/gnu/libexec/uucp/libunix/ufopen.c b/gnu/libexec/uucp/libunix/ufopen.c new file mode 100644 index 00000000000..5a7b6f22b0d --- /dev/null +++ b/gnu/libexec/uucp/libunix/ufopen.c @@ -0,0 +1,218 @@ +/* ufopen.c + Open a file with the permissions of the invoking user. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* Local functions. */ + +static boolean fsuser_perms P((uid_t *pieuid)); +static boolean fsuucp_perms P((long ieuid)); + +/* Switch to permissions of the invoking user. */ + +static boolean +fsuser_perms (pieuid) + uid_t *pieuid; +{ + uid_t ieuid, iuid; + + ieuid = geteuid (); + iuid = getuid (); + if (pieuid != NULL) + *pieuid = ieuid; + +#if HAVE_SETREUID + /* Swap the effective user id and the real user id. We can then + swap them back again when we want to return to the uucp user's + permissions. */ + if (setreuid (ieuid, iuid) < 0) + { + ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", + (long) ieuid, (long) iuid, strerror (errno)); + return FALSE; + } +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set the effective user id to the real user id. Since the + effective user id is saved (it's the saved setuid) we will able + to set back to it later. If the real user id is root we will not + be able to switch back and forth, so don't even try. */ + if (iuid != 0) + { + if (setuid (iuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno)); + return FALSE; + } + } +#else /* ! HAVE_SAVED_SETUID */ + /* There's no way to switch between real permissions and effective + permissions. Just try to open the file with the uucp + permissions. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} + +/* Restore the uucp permissions. */ + +/*ARGSUSED*/ +static boolean +fsuucp_perms (ieuid) + long ieuid; +{ +#if HAVE_SETREUID + /* Swap effective and real user id's back to what they were. */ + if (! fsuser_perms ((uid_t *) NULL)) + return FALSE; +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set ourselves back to our original effective user id. */ + if (setuid ((uid_t) ieuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno)); + /* Is this error message helpful or confusing? */ + if (errno == EPERM) + ulog (LOG_ERROR, + "Probably HAVE_SAVED_SETUID in policy.h should be set to 0"); + return FALSE; + } +#else /* ! HAVE_SAVED_SETUID */ + /* We didn't switch, no need to switch back. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} + +/* Open a file with the permissions of the invoking user. Ignore the + fbinary argument since Unix has no distinction between text and + binary files. */ + +/*ARGSUSED*/ +openfile_t +esysdep_user_fopen (zfile, frd, fbinary) + const char *zfile; + boolean frd; + boolean fbinary; +{ + uid_t ieuid; + openfile_t e; + const char *zerr; + int o = 0; + + if (! fsuser_perms (&ieuid)) + return EFILECLOSED; + + zerr = NULL; + +#if USE_STDIO + e = fopen (zfile, frd ? "r" : "w"); + if (e == NULL) + zerr = "fopen"; + else + o = fileno (e); +#else + if (frd) + { + e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0); + zerr = "open"; + } + else + { + e = creat ((char *) zfile, IPUBLIC_FILE_MODE); + zerr = "creat"; + } + if (e >= 0) + { + o = e; + zerr = NULL; + } +#endif + + if (! fsuucp_perms ((long) ieuid)) + { + if (ffileisopen (e)) + (void) ffileclose (e); + return EFILECLOSED; + } + + if (zerr != NULL) + { + ulog (LOG_ERROR, "%s (%s): %s", zerr, zfile, strerror (errno)); +#if ! HAVE_SETREUID + /* Are these error messages helpful or confusing? */ +#if HAVE_SAVED_SETUID + if (errno == EACCES && getuid () == 0) + ulog (LOG_ERROR, + "The superuser may only transfer files that are readable by %s", + OWNER); +#else + if (errno == EACCES) + ulog (LOG_ERROR, + "You may only transfer files that are readable by %s", OWNER); +#endif +#endif /* ! HAVE_SETREUID */ + return EFILECLOSED; + } + + if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) ffileclose (e); + return EFILECLOSED; + } + + return e; +} diff --git a/gnu/libexec/uucp/libunix/ultspl.c b/gnu/libexec/uucp/libunix/ultspl.c new file mode 100644 index 00000000000..34921d22804 --- /dev/null +++ b/gnu/libexec/uucp/libunix/ultspl.c @@ -0,0 +1,21 @@ +/* ultspl.c + See whether there is an Ultrix spool directory for a system. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +boolean +fsultrix_has_spool (zsystem) + const char *zsystem; +{ + char *z; + boolean fret; + + z = zsysdep_in_dir ("sys", zsystem); + fret = fsysdep_directory (z); + ubuffree (z); + return fret; +} diff --git a/gnu/libexec/uucp/libunix/unknwn.c b/gnu/libexec/uucp/libunix/unknwn.c new file mode 100644 index 00000000000..76f53459475 --- /dev/null +++ b/gnu/libexec/uucp/libunix/unknwn.c @@ -0,0 +1,43 @@ +/* unknwn.c + Check remote.unknown shell script. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +/* Run the remote.unknown shell script. If it succeeds, we return + FALSE because that means that the system is not permitted to log + in. If the execution fails, we return TRUE. */ + +boolean +fsysdep_unknown_caller (zscript, zsystem) + const char *zscript; + const char *zsystem; +{ + const char *azargs[3]; + int aidescs[3]; + pid_t ipid; + + azargs[0] = zscript; + azargs[1] = zsystem; + azargs[2] = NULL; + + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + ipid = ixsspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL, FALSE, + TRUE, (const char *) NULL, (const char *) NULL, + (const char *) NULL); + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); + return FALSE; + } + + return ixswait ((unsigned long) ipid, (const char *) NULL) != 0; +} diff --git a/gnu/libexec/uucp/libunix/uuto.c b/gnu/libexec/uucp/libunix/uuto.c new file mode 100644 index 00000000000..debba9d6fd0 --- /dev/null +++ b/gnu/libexec/uucp/libunix/uuto.c @@ -0,0 +1,31 @@ +/* uuto.c + Translate a destination for uuto. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +/* Translate a uuto destination for Unix. */ + +char * +zsysdep_uuto (zdest, zlocalname) + const char *zdest; + const char *zlocalname; +{ + const char *zexclam; + char *zto; + + zexclam = strrchr (zdest, '!'); + if (zexclam == NULL) + return NULL; + zto = (char *) zbufalc (zexclam - zdest + + sizeof "!~/receive///" + + strlen (zexclam) + + strlen (zlocalname)); + memcpy (zto, zdest, (size_t) (zexclam - zdest)); + sprintf (zto + (zexclam - zdest), "!~/receive/%s/%s/", + zexclam + 1, zlocalname); + return zto; +} diff --git a/gnu/libexec/uucp/libunix/walk.c b/gnu/libexec/uucp/libunix/walk.c new file mode 100644 index 00000000000..ab96123127d --- /dev/null +++ b/gnu/libexec/uucp/libunix/walk.c @@ -0,0 +1,59 @@ +/* walk.c + Walk a directory tree. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#if HAVE_FTW_H +#include <ftw.h> +#endif + +static int iswalk_dir P((const char *zname, const struct stat *qstat, + int iflag)); + +/* Walk a directory tree. */ + +static size_t cSlen; +static void (*puSfn) P((const char *zfull, const char *zrelative, + pointer pinfo)); +static pointer pSinfo; + +boolean +usysdep_walk_tree (zdir, pufn, pinfo) + const char *zdir; + void (*pufn) P((const char *zfull, const char *zrelative, + pointer pinfo)); + pointer pinfo; +{ + cSlen = strlen (zdir) + 1; + puSfn = pufn; + pSinfo = pinfo; + return ftw ((char *) zdir, iswalk_dir, 5) == 0; +} + +/* Pass a file found in the directory tree to the system independent + function. */ + +/*ARGSUSED*/ +static int +iswalk_dir (zname, qstat, iflag) + const char *zname; + const struct stat *qstat; + int iflag; +{ + char *zcopy; + + if (iflag != FTW_F) + return 0; + + zcopy = zbufcpy (zname + cSlen); + + (*puSfn) (zname, zcopy, pSinfo); + + ubuffree (zcopy); + + return 0; +} diff --git a/gnu/libexec/uucp/libunix/wldcrd.c b/gnu/libexec/uucp/libunix/wldcrd.c new file mode 100644 index 00000000000..cfbd15eb848 --- /dev/null +++ b/gnu/libexec/uucp/libunix/wldcrd.c @@ -0,0 +1,212 @@ +/* wldcrd.c + Expand wildcards. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <ctype.h> +#include <errno.h> + +#if HAVE_GLOB && ! HAVE_GLOB_H +#undef HAVE_GLOB +#define HAVE_GLOB 0 +#endif + +#if HAVE_GLOB +#include <glob.h> +#endif + +/* Local variables to hold the wildcard in progress. */ + +#if HAVE_GLOB +static glob_t sSglob; +static int iSglob; +#else +static char *zSwildcard_alloc; +static char *zSwildcard; +#endif + +/* Start getting a wildcarded file spec. Use the glob function if it + is available, and otherwise use the shell. */ + +boolean +fsysdep_wildcard_start (zfile) + const char *zfile; +{ +#if HAVE_GLOB + +#if DEBUG > 0 + if (*zfile != '/') + ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile); +#endif + + if (glob (zfile, 0, (int (*) ()) NULL, &sSglob) != 0) + sSglob.gl_pathc = 0; + iSglob = 0; + return TRUE; + +#else /* ! HAVE_GLOB */ + + char *zcmd, *zto; + const char *zfrom; + size_t c; + const char *azargs[4]; + FILE *e; + pid_t ipid; + +#if DEBUG > 0 + if (*zfile != '/') + ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile); +#endif + + zSwildcard_alloc = NULL; + zSwildcard = NULL; + + zcmd = zbufalc (sizeof ECHO_PROGRAM + sizeof " " + 2 * strlen (zfile)); + memcpy (zcmd, ECHO_PROGRAM, sizeof ECHO_PROGRAM - 1); + zto = zcmd + sizeof ECHO_PROGRAM - 1; + *zto++ = ' '; + zfrom = zfile; + while (*zfrom != '\0') + { + /* To avoid shell trickery, we quote all characters except + letters, digits, and wildcard specifiers. We don't quote '/' + to avoid an Ultrix sh bug. */ + if (! isalnum (*zfrom) + && *zfrom != '*' + && *zfrom != '?' + && *zfrom != '[' + && *zfrom != ']' + && *zfrom != '/') + *zto++ = '\\'; + *zto++ = *zfrom++; + } + *zto = '\0'; + + azargs[0] = "/bin/sh"; + azargs[1] = "-c"; + azargs[2] = zcmd; + azargs[3] = NULL; + + ubuffree (zcmd); + + e = espopen (azargs, TRUE, &ipid); + if (e == NULL) + { + ulog (LOG_ERROR, "espopen: %s", strerror (errno)); + return FALSE; + } + + zSwildcard_alloc = NULL; + c = 0; + if (getline (&zSwildcard_alloc, &c, e) <= 0) + { + xfree ((pointer) zSwildcard_alloc); + zSwildcard_alloc = NULL; + } + + if (ixswait ((unsigned long) ipid, ECHO_PROGRAM) != 0) + { + xfree ((pointer) zSwildcard_alloc); + return FALSE; + } + + if (zSwildcard_alloc == NULL) + return FALSE; + + DEBUG_MESSAGE1 (DEBUG_EXECUTE, + "fsysdep_wildcard_start: got \"%s\"", + zSwildcard_alloc); + + zSwildcard = zSwildcard_alloc; + + return TRUE; + +#endif /* ! HAVE_GLOB */ +} + +/* Get the next wildcard spec. */ + +/*ARGSUSED*/ +char * +zsysdep_wildcard (zfile) + const char *zfile; +{ +#if HAVE_GLOB + + char *zret; + + if (iSglob >= sSglob.gl_pathc) + return NULL; + zret = zbufcpy (sSglob.gl_pathv[iSglob]); + ++iSglob; + return zret; + +#else /* ! HAVE_GLOB */ + + char *zret; + + if (zSwildcard_alloc == NULL || zSwildcard == NULL) + return NULL; + + zret = zSwildcard; + + while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard))) + ++zSwildcard; + + if (*zSwildcard != '\0') + { + *zSwildcard = '\0'; + ++zSwildcard; + while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard))) + ++zSwildcard; + } + + if (*zSwildcard == '\0') + zSwildcard = NULL; + + return zbufcpy (zret); + +#endif /* ! HAVE_GLOB */ +} + +/* Finish up getting wildcard specs. */ + +boolean +fsysdep_wildcard_end () +{ +#if HAVE_GLOB + globfree (&sSglob); + return TRUE; +#else /* ! HAVE_GLOB */ + xfree ((pointer) zSwildcard_alloc); + zSwildcard_alloc = NULL; + zSwildcard = NULL; + return TRUE; +#endif /* ! HAVE_GLOB */ +} diff --git a/gnu/libexec/uucp/libunix/work.c b/gnu/libexec/uucp/libunix/work.c new file mode 100644 index 00000000000..3d055c282ed --- /dev/null +++ b/gnu/libexec/uucp/libunix/work.c @@ -0,0 +1,765 @@ +/* work.c + Routines to read command files. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char work_rcsid[] = "$Id: work.c,v 1.1 1993/08/04 19:33:20 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" + +#include <ctype.h> +#include <errno.h> + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +/* Local functions. */ + +static char *zswork_directory P((const char *zsystem)); +static boolean fswork_file P((const char *zsystem, const char *zfile, + char *pbgrade)); +static int iswork_cmp P((constpointer pkey, constpointer pdatum)); + +/* These functions can support multiple actions going on at once. + This allows the UUCP package to send and receive multiple files at + the same time. This is a very flexible feature, but I'm not sure + it will actually be used all that much. + + The ssfile structure holds a command file name and all the lines + read in from that command file. The union within the ssline + structure initially holds a line from the file and then holds a + pointer back to the ssfile structure; a pointer to this union is + used as a sequence pointer. The ztemp entry of the ssline + structure holds the name of a temporary file to delete, if any. */ + +#define CFILELINES (10) + +struct ssline +{ + char *zline; + struct ssfile *qfile; + char *ztemp; +}; + +struct ssfile +{ + char *zfile; + int clines; + int cdid; + struct ssline aslines[CFILELINES]; +}; + +/* Static variables for the work scan. */ + +static char **azSwork_files; +static size_t cSwork_files; +static size_t iSwork_file; +static struct ssfile *qSwork_file; + +/* Given a system name, return a directory to search for work. */ + +static char * +zswork_directory (zsystem) + const char *zsystem; +{ +#if SPOOLDIR_V2 + return zbufcpy ("."); +#endif /* SPOOLDIR_V2 */ +#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43 + return zbufcpy ("C."); +#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */ +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + return zbufcpy (zsystem); +#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */ +#if SPOOLDIR_ULTRIX + return zsappend3 ("sys", + (fsultrix_has_spool (zsystem) + ? zsystem + : "DEFAULT"), + "C."); +#endif /* SPOOLDIR_ULTRIX */ +#if SPOOLDIR_TAYLOR + return zsysdep_in_dir (zsystem, "C."); +#endif /* SPOOLDIR_TAYLOR */ +} + +/* See whether a file name from the directory returned by + zswork_directory is really a command for a particular system. + Return the command grade. */ + +/*ARGSUSED*/ +static boolean +fswork_file (zsystem, zfile, pbgrade) + const char *zsystem; + const char *zfile; + char *pbgrade; +{ +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX + int cfilesys, csys; + + /* The file name should be C.ssssssgqqqq, where g is exactly one + letter and qqqq is exactly four numbers. The system name may be + truncated to six or seven characters. The system name of the + file must match the system name we're looking for, since there + could be work files for several systems in one directory. */ + if (zfile[0] != 'C' || zfile[1] != '.') + return FALSE; + csys = strlen (zsystem); + cfilesys = strlen (zfile) - 7; + if (csys != cfilesys + && (csys < 6 || (cfilesys != 6 && cfilesys != 7))) + return FALSE; + *pbgrade = zfile[cfilesys + 2]; + return strncmp (zfile + 2, zsystem, cfilesys) == 0; +#endif /* V2 || BSD42 || BSD43 || ULTRIX */ +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + int clen; + + /* The HDB file name should be C.ssssssgqqqq where g is exactly one + letter and qqqq is exactly four numbers or letters. We don't + check the system name, because it is guaranteed by the directory + we are looking in and some versions of uucp set it to the local + system rather than the remote one. I'm not sure of the exact + format of the SVR4 file name, but it does not include the grade + at all. */ + if (zfile[0] != 'C' || zfile[1] != '.') + return FALSE; + clen = strlen (zfile); + if (clen < 7) + return FALSE; +#if ! SPOOLDIR_SVR4 + *pbgrade = zfile[clen - 5]; +#endif + return TRUE; +#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */ +#if SPOOLDIR_TAYLOR + /* We don't keep the system name in the file name, since that + forces truncation. Our file names are always C.gqqqq. */ + *pbgrade = zfile[2]; + return (zfile[0] == 'C' + && zfile[1] == '.' + && strlen (zfile) == 7); +#endif /* SPOOLDIR_TAYLOR */ +} + +/* A comparison function to look through the list of file names. */ + +static int +iswork_cmp (pkey, pdatum) + constpointer pkey; + constpointer pdatum; +{ + const char * const *pzkey = (const char * const *) pkey; + const char * const *pzdatum = (const char * const *) pdatum; + + return strcmp (*pzkey, *pzdatum); +} + +/* See whether there is any work to do for a particular system. */ + +boolean +fsysdep_has_work (qsys) + const struct uuconf_system *qsys; +{ + char *zdir; + DIR *qdir; + struct dirent *qentry; +#if SPOOLDIR_SVR4 + DIR *qgdir; + struct dirent *qgentry; +#endif + + zdir = zswork_directory (qsys->uuconf_zname); + if (zdir == NULL) + return FALSE; + qdir = opendir ((char *) zdir); + if (qdir == NULL) + { + ubuffree (zdir); + return FALSE; + } + +#if SPOOLDIR_SVR4 + qgdir = qdir; + while ((qgentry = readdir (qgdir)) != NULL) + { + char *zsub; + + if (qgentry->d_name[0] == '.' + || qgentry->d_name[1] != '\0') + continue; + zsub = zsysdep_in_dir (zdir, qgentry->d_name); + qdir = opendir (zsub); + ubuffree (zsub); + if (qdir == NULL) + continue; +#endif + + while ((qentry = readdir (qdir)) != NULL) + { + char bgrade; + + if (fswork_file (qsys->uuconf_zname, qentry->d_name, &bgrade)) + { + closedir (qdir); +#if SPOOLDIR_SVR4 + closedir (qgdir); +#endif + ubuffree (zdir); + return TRUE; + } + } + +#if SPOOLDIR_SVR4 + closedir (qdir); + } + qdir = qgdir; +#endif + + closedir (qdir); + ubuffree (zdir); + return FALSE; +} + +/* Initialize the work scan. We have to read all the files in the + work directory, so that we can sort them by work grade. The bgrade + argument is the minimum grade to consider. We don't want to return + files that we have already considered; usysdep_get_work_free will + clear the data out when we are done with the system. This returns + FALSE on error. */ + +#define CWORKFILES (10) + +boolean +fsysdep_get_work_init (qsys, bgrade) + const struct uuconf_system *qsys; + int bgrade; +{ + char *zdir; + DIR *qdir; + struct dirent *qentry; + size_t chad; + size_t callocated; +#if SPOOLDIR_SVR4 + DIR *qgdir; + struct dirent *qgentry; +#endif + + zdir = zswork_directory (qsys->uuconf_zname); + if (zdir == NULL) + return FALSE; + + qdir = opendir (zdir); + if (qdir == NULL) + { + boolean fret; + + if (errno == ENOENT) + fret = TRUE; + else + { + ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno)); + fret = FALSE; + } + ubuffree (zdir); + return fret; + } + + chad = cSwork_files; + callocated = cSwork_files; + + /* Sort the files we already know about so that we can check the new + ones with bsearch. It would be faster to use a hash table, and + the code should be probably be changed. The sort done at the end + of this function does not suffice because it only includes the + files added last time, and does not sort the entire array. Some + (bad) qsort implementations are very slow when given a sorted + array, which causes particularly bad effects here. */ + if (chad > 0) + qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp); + +#if SPOOLDIR_SVR4 + qgdir = qdir; + while ((qgentry = readdir (qgdir)) != NULL) + { + char *zsub; + + if (qgentry->d_name[0] == '.' + || qgentry->d_name[1] != '\0' + || UUCONF_GRADE_CMP (bgrade, qgentry->d_name[0]) < 0) + continue; + zsub = zsysdep_in_dir (zdir, qgentry->d_name); + qdir = opendir (zsub); + if (qdir == NULL) + { + if (errno != ENOTDIR && errno != ENOENT) + { + ulog (LOG_ERROR, "opendir (%s): %s", zsub, + strerror (errno)); + ubuffree (zsub); + return FALSE; + } + ubuffree (zsub); + continue; + } + ubuffree (zsub); +#endif + + while ((qentry = readdir (qdir)) != NULL) + { + char bfilegrade; + char *zname; + +#if ! SPOOLDIR_SVR4 + zname = zbufcpy (qentry->d_name); +#else + zname = zsysdep_in_dir (qgentry->d_name, qentry->d_name); + bfilegrade = qgentry->d_name[0]; +#endif + + if (! fswork_file (qsys->uuconf_zname, qentry->d_name, + &bfilegrade) + || UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0 + || (azSwork_files != NULL + && bsearch ((pointer) &zname, + (pointer) azSwork_files, + chad, sizeof (char *), + iswork_cmp) != NULL)) + ubuffree (zname); + else + { + DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, + "fsysdep_get_work_init: Found %s", + zname); + + if (cSwork_files >= callocated) + { + callocated += CWORKFILES; + azSwork_files = + (char **) xrealloc ((pointer) azSwork_files, + callocated * sizeof (char *)); + } + + azSwork_files[cSwork_files] = zname; + ++cSwork_files; + } + } + +#if SPOOLDIR_SVR4 + closedir (qdir); + } + qdir = qgdir; +#endif + + closedir (qdir); + ubuffree (zdir); + + /* Sorting the files alphabetically will get the grades in the + right order, since all the file prefixes are the same. */ + + if (cSwork_files > chad) + qsort ((pointer) (azSwork_files + chad), cSwork_files - chad, + sizeof (char *), iswork_cmp); + + return TRUE; +} + +/* Get the next work entry for a system. This must parse the next + line in the next work file. The type of command is set into + qcmd->bcmd; if there are no more commands we call + fsysdep_get_work_init to rescan, in case any came in since the last + call. If there are still no commands, qcmd->bcmd is set to 'H'. + Each field in the structure is set to point to a spot in an + malloced string. The only time we use the grade here is when + calling fsysdep_get_work_init to rescan. */ + +boolean +fsysdep_get_work (qsys, bgrade, qcmd) + const struct uuconf_system *qsys; + int bgrade; + struct scmd *qcmd; +{ + char *zdir; + + if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines) + qSwork_file = NULL; + + if (azSwork_files == NULL) + { + qcmd->bcmd = 'H'; + return TRUE; + } + + zdir = NULL; + + /* This loop continues until a line is returned. */ + while (TRUE) + { + /* This loop continues until a file is opened and read in. */ + while (qSwork_file == NULL) + { + FILE *e; + struct ssfile *qfile; + int iline, callocated; + char *zline; + size_t cline; + char *zname; + + /* Read all the lines of a command file into memory. */ + do + { + if (iSwork_file >= cSwork_files) + { + /* Rescan the work directory. */ + if (! fsysdep_get_work_init (qsys, bgrade)) + { + ubuffree (zdir); + return FALSE; + } + if (iSwork_file >= cSwork_files) + { + qcmd->bcmd = 'H'; + ubuffree (zdir); + return TRUE; + } + } + + if (zdir == NULL) + { + zdir = zswork_directory (qsys->uuconf_zname); + if (zdir == NULL) + return FALSE; + } + + zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]); + + ++iSwork_file; + + e = fopen (zname, "r"); + if (e == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zname, + strerror (errno)); + ubuffree (zname); + } + } + while (e == NULL); + + qfile = (struct ssfile *) xmalloc (sizeof (struct ssfile)); + callocated = CFILELINES; + iline = 0; + + zline = NULL; + cline = 0; + while (getline (&zline, &cline, e) > 0) + { + if (iline >= callocated) + { + /* The sizeof (struct ssfile) includes CFILELINES + entries already, so using callocated * sizeof + (struct ssline) will give us callocated * + CFILELINES entries. */ + qfile = + ((struct ssfile *) + xrealloc ((pointer) qfile, + (sizeof (struct ssfile) + + (callocated * sizeof (struct ssline))))); + callocated += CFILELINES; + } + qfile->aslines[iline].zline = zbufcpy (zline); + qfile->aslines[iline].qfile = NULL; + qfile->aslines[iline].ztemp = NULL; + iline++; + } + + xfree ((pointer) zline); + + if (fclose (e) != 0) + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + + if (iline == 0) + { + /* There were no lines in the file; this is a poll file, + for which we return a 'P' command. */ + qfile->aslines[0].zline = zbufcpy ("P"); + qfile->aslines[0].qfile = NULL; + qfile->aslines[0].ztemp = NULL; + iline = 1; + } + + qfile->zfile = zname; + qfile->clines = iline; + qfile->cdid = 0; + qSwork_file = qfile; + } + + /* This loop continues until all the lines from the current file + are used up, or a line is returned. */ + while (TRUE) + { + int iline; + + if (qSwork_file->cdid >= qSwork_file->clines) + { + /* We don't want to free qSwork_file here, since it must + remain until all the lines have been completed. It + is freed in fsysdep_did_work. */ + qSwork_file = NULL; + /* Go back to the main loop which finds another file. */ + break; + } + + iline = qSwork_file->cdid; + ++qSwork_file->cdid; + + /* Now parse the line into a command. */ + if (! fparse_cmd (qSwork_file->aslines[iline].zline, qcmd)) + { + ulog (LOG_ERROR, "Bad line in command file %s", + qSwork_file->zfile); + ubuffree (qSwork_file->aslines[iline].zline); + qSwork_file->aslines[iline].zline = NULL; + continue; + } + + qSwork_file->aslines[iline].qfile = qSwork_file; + qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]); + + if (qcmd->bcmd == 'S' || qcmd->bcmd == 'E') + { + char *zreal; + + zreal = zsysdep_spool_file_name (qsys, qcmd->ztemp, + qcmd->pseq); + if (zreal == NULL) + { + ubuffree (qSwork_file->aslines[iline].zline); + qSwork_file->aslines[iline].zline = NULL; + ubuffree (zdir); + return FALSE; + } + qSwork_file->aslines[iline].ztemp = zreal; + } + + ubuffree (zdir); + return TRUE; + } + } +} + +/* When a command has been complete, fsysdep_did_work is called. The + sequence entry was set above to be the address of an aslines + structure whose pfile entry points to the ssfile corresponding to + this file. We can then check whether all the lines have been + completed (they will have been if the pfile entry is NULL) and + remove the file if they have been. This means that we only remove + a command file if we manage to complete every transfer it specifies + in a single UUCP session. I don't know if this is how regular UUCP + works. */ + +boolean +fsysdep_did_work (pseq) + pointer pseq; +{ + struct ssfile *qfile; + struct ssline *qline; + int i; + + qline = (struct ssline *) pseq; + + ubuffree (qline->zline); + qline->zline = NULL; + + qfile = qline->qfile; + qline->qfile = NULL; + + /* Remove the temporary file, if there is one. It really doesn't + matter if this fails, and not checking the return value lets us + attempt to remove D.0 or whatever an unused temporary file is + called without complaining. */ + if (qline->ztemp != NULL) + { + (void) remove (qline->ztemp); + ubuffree (qline->ztemp); + qline->ztemp = NULL; + } + + /* If not all the lines have been returned from fsysdep_get_work, + we can't remove the file yet. */ + if (qfile->cdid < qfile->clines) + return TRUE; + + /* See whether all the commands have been completed. */ + for (i = 0; i < qfile->clines; i++) + if (qfile->aslines[i].qfile != NULL) + return TRUE; + + /* All commands have finished. */ + if (remove (qfile->zfile) != 0) + { + ulog (LOG_ERROR, "remove (%s): %s", qfile->zfile, + strerror (errno)); + return FALSE; + } + + ubuffree (qfile->zfile); + xfree ((pointer) qfile); + + if (qfile == qSwork_file) + qSwork_file = NULL; + + return TRUE; +} + +/* Free up the results of a work scan, when we're done with this + system. */ + +/*ARGSUSED*/ +void +usysdep_get_work_free (qsys) + const struct uuconf_system *qsys; +{ + if (azSwork_files != NULL) + { + size_t i; + + for (i = 0; i < cSwork_files; i++) + ubuffree ((pointer) azSwork_files[i]); + xfree ((pointer) azSwork_files); + azSwork_files = NULL; + cSwork_files = 0; + iSwork_file = 0; + } + if (qSwork_file != NULL) + { + int i; + + ubuffree (qSwork_file->zfile); + for (i = 0; i < qSwork_file->cdid; i++) + { + ubuffree (qSwork_file->aslines[i].zline); + ubuffree (qSwork_file->aslines[i].ztemp); + } + for (i = qSwork_file->cdid; i < qSwork_file->clines; i++) + ubuffree (qSwork_file->aslines[i].zline); + xfree ((pointer) qSwork_file); + qSwork_file = NULL; + } +} + +/* Save the temporary file used by a send command, and return an + informative message to mail to the requestor. This is called when + a file transfer failed, to make sure that the potentially valuable + file is not completely lost. */ + +const char * +zsysdep_save_temp_file (pseq) + pointer pseq; +{ + struct ssline *qline = (struct ssline *) pseq; + char *zto, *zslash; + size_t cwant; + static char *zbuf; + static int cbuf; + + if (! fsysdep_file_exists (qline->ztemp)) + return NULL; + + zslash = strrchr (qline->ztemp, '/'); + if (zslash == NULL) + zslash = qline->ztemp; + else + ++zslash; + + zto = zbufalc (sizeof PRESERVEDIR + sizeof "/" + strlen (zslash)); + sprintf (zto, "%s/%s", PRESERVEDIR, zslash); + + if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE, + (const char *) NULL)) + { + ubuffree (zto); + return "Could not move file to preservation directory"; + } + + cwant = sizeof "File saved as\n\t/" + strlen (zSspooldir) + strlen (zto); + if (cwant > cbuf) + { + ubuffree (zbuf); + zbuf = zbufalc (cwant); + cbuf = cwant; + } + + sprintf (zbuf, "File saved as\n\t%s/%s", zSspooldir, zto); + ubuffree (zto); + return zbuf; +} + +/* Get the jobid of a work file. This is needed by uustat. */ + +char * +zsysdep_jobid (qsys, pseq) + const struct uuconf_system *qsys; + pointer pseq; +{ + return zsfile_to_jobid (qsys, ((struct ssline *) pseq)->qfile->zfile, + bsgrade (pseq)); +} + +/* Get the grade of a work file. The pseq argument can be NULL when + this is called from zsysdep_spool_file_name, and simply means that + this is a remote file; returning -1 will cause zsfind_file to do + the right thing. */ + +char +bsgrade (pseq) + pointer pseq; +{ + const char *zfile; + char bgrade; + + if (pseq == NULL) + return -1; + + zfile = ((struct ssline *) pseq)->qfile->zfile; + +#if ! SPOOLDIR_SVR4 + bgrade = zfile[strlen (zfile) - CSEQLEN - 1]; +#else + bgrade = *(strchr (zfile, '/') + 1); +#endif + + return bgrade; +} diff --git a/gnu/libexec/uucp/libunix/xqtfil.c b/gnu/libexec/uucp/libunix/xqtfil.c new file mode 100644 index 00000000000..2cdcc185a00 --- /dev/null +++ b/gnu/libexec/uucp/libunix/xqtfil.c @@ -0,0 +1,265 @@ +/* xqtfil.c + Routines to read execute files. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.1 1993/08/04 19:33:21 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +/* Under the V2 or BSD42 spool directory scheme, all execute files are + in the main spool directory. Under the BSD43 scheme, they are all + in the directory X.. Under the HDB or SVR4 scheme, they are in + directories named after systems. Under the ULTRIX scheme, they are + in X. subdirectories of subdirectories of sys. Under the TAYLOR + scheme, they are all in the subdirectory X. of a directory named + after the system. + + This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search + directories of directories. */ + +#if SPOOLDIR_V2 || SPOOLDIR_BSD42 +#define ZDIR "." +#define SUBDIRS 0 +#endif +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR +#define ZDIR "." +#define SUBDIRS 1 +#endif +#if SPOOLDIR_ULTRIX +#define ZDIR "sys" +#define SUBDIRS 1 +#endif +#if SPOOLDIR_BSD43 +#define ZDIR "X." +#define SUBDIRS 0 +#endif + +/* Static variables for the execute file scan. */ + +static DIR *qSxqt_topdir; +#if ! SUBDIRS +static const char *zSdir; +#else /* SUBDIRS */ +static char *zSdir; +static DIR *qSxqt_dir; +static char *zSsystem; +#endif /* SUBDIRS */ + +/* Initialize the scan for execute files. The function + usysdep_get_xqt_free will clear the data out when we are done with + the system. This returns FALSE on error. */ + +/*ARGSUSED*/ +boolean +fsysdep_get_xqt_init () +{ + usysdep_get_xqt_free (); + + qSxqt_topdir = opendir ((char *) ZDIR); + if (qSxqt_topdir == NULL) + { + if (errno == ENOENT) + return TRUE; + ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Return the name of the next execute file to read and process. If + this returns NULL, *pferr must be checked. If will be TRUE on + error, FALSE if there are no more files. On a successful return + *pzsystem will be set to the system for which the execute file was + created. */ + +char * +zsysdep_get_xqt (pzsystem, pferr) + char **pzsystem; + boolean *pferr; +{ + *pferr = FALSE; + + if (qSxqt_topdir == NULL) + return NULL; + + /* This loop continues until we find a file. */ + while (TRUE) + { + DIR *qdir; + struct dirent *q; + +#if ! SUBDIRS + zSdir = ZDIR; + qdir = qSxqt_topdir; +#else /* SUBDIRS */ + /* This loop continues until we find a subdirectory to read. */ + while (qSxqt_dir == NULL) + { + struct dirent *qtop; + + qtop = readdir (qSxqt_topdir); + if (qtop == NULL) + { + (void) closedir (qSxqt_topdir); + qSxqt_topdir = NULL; + return NULL; + } + + /* No system name may start with a dot (this is enforced by + tisystem in sysinf.c). This allows us to quickly skip + impossible directories. */ + if (qtop->d_name[0] == '.') + continue; + + DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, + "zsysdep_get_xqt: Found %s in top directory", + qtop->d_name); + + ubuffree (zSdir); + +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 + zSdir = zbufcpy (qtop->d_name); +#endif +#if SPOOLDIR_ULTRIX + zSdir = zsappend3 ("sys", qtop->d_name, "X."); +#endif +#if SPOOLDIR_TAYLOR + zSdir = zsysdep_in_dir (qtop->d_name, "X."); +#endif + + ubuffree (zSsystem); + zSsystem = zbufcpy (qtop->d_name); + + qSxqt_dir = opendir (zSdir); + + if (qSxqt_dir == NULL + && errno != ENOTDIR + && errno != ENOENT) + ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno)); + } + + qdir = qSxqt_dir; +#endif /* SUBDIRS */ + + q = readdir (qdir); + +#if DEBUG > 1 + if (q != NULL) + DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, + "zsysdep_get_xqt: Found %s in subdirectory %s", + q->d_name, zSdir); +#endif + + /* If we've found an execute file, return it. We have to get + the system name, which is easy for HDB or TAYLOR. For other + spool directory schemes, we have to pull it out of the X. + file name; this would be insecure, except that zsfind_file + clobbers the file name to include the real system name. */ + if (q != NULL + && q->d_name[0] == 'X' + && q->d_name[1] == '.') + { + char *zret; + +#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR + *pzsystem = zbufcpy (zSsystem); +#else + { + size_t clen; + + clen = strlen (q->d_name) - 7; + *pzsystem = zbufalc (clen + 1); + memcpy (*pzsystem, q->d_name + 2, clen); + (*pzsystem)[clen] = '\0'; + } +#endif + + zret = zsysdep_in_dir (zSdir, q->d_name); +#if DEBUG > 1 + DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, + "zsysdep_get_xqt: Returning %s (system %s)", + zret, *pzsystem); +#endif + return zret; + } + + /* If we've reached the end of the directory, then if we are + using subdirectories loop around to read the next one, + otherwise we are finished. */ + if (q == NULL) + { + (void) closedir (qdir); +#if SUBDIRS + qSxqt_dir = NULL; + continue; +#else + qSxqt_topdir = NULL; + return NULL; +#endif + } + } +} + +/* Free up the results of an execute file scan, when we're done with + this system. */ + +/*ARGSUSED*/ +void +usysdep_get_xqt_free () +{ + if (qSxqt_topdir != NULL) + { + (void) closedir (qSxqt_topdir); + qSxqt_topdir = NULL; + } +#if SUBDIRS + if (qSxqt_dir != NULL) + { + (void) closedir (qSxqt_dir); + qSxqt_dir = NULL; + } + ubuffree (zSdir); + zSdir = NULL; + ubuffree (zSsystem); + zSsystem = NULL; +#endif +} diff --git a/gnu/libexec/uucp/libunix/xqtsub.c b/gnu/libexec/uucp/libunix/xqtsub.c new file mode 100644 index 00000000000..53e290a0d14 --- /dev/null +++ b/gnu/libexec/uucp/libunix/xqtsub.c @@ -0,0 +1,698 @@ +/* xqtsub.c + System dependent functions used only by uuxqt. + + Copyright (C) 1991, 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + 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 of the + License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 1993/08/04 19:33:22 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" + +#include <ctype.h> +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include <dirent.h> +#else /* ! HAVE_DIRENT_H */ +#include <sys/dir.h> +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +/* Get a value for EX_TEMPFAIL. */ + +#if HAVE_SYSEXITS_H +#include <sysexits.h> +#endif + +#ifndef EX_TEMPFAIL +#define EX_TEMPFAIL 75 +#endif + +/* Get the full pathname of the command to execute, given the list of + permitted commands and the allowed path. */ + +char * +zsysdep_find_command (zcmd, pzcmds, pzpath, pferr) + const char *zcmd; + char **pzcmds; + char **pzpath; + boolean *pferr; +{ + char **pz; + + *pferr = FALSE; + + for (pz = pzcmds; *pz != NULL; pz++) + { + char *zslash; + + if (strcmp (*pz, "ALL") == 0) + break; + + zslash = strrchr (*pz, '/'); + if (zslash != NULL) + ++zslash; + else + zslash = *pz; + if (strcmp (zslash, zcmd) == 0 + || strcmp (*pz, zcmd) == 0) + { + /* If we already have an absolute path, we can get out + immediately. */ + if (**pz == '/') + return zbufcpy (*pz); + break; + } + } + + /* If we didn't find this command, get out. */ + if (*pz == NULL) + return NULL; + + /* We didn't find an absolute pathname, so we must look through + the path. */ + for (pz = pzpath; *pz != NULL; pz++) + { + char *zname; + struct stat s; + + zname = zsysdep_in_dir (*pz, zcmd); + if (stat (zname, &s) == 0) + return zname; + } + + *pferr = FALSE; + return NULL; +} + +/* Expand a local filename for uuxqt. This is special because uuxqt + only wants to expand filenames that start with ~ (it does not want + to prepend the current directory to other names) and if the ~ is + double, it is turned into a single ~. This returns NULL to + indicate that no change was required; it has no way to return + error. */ + +char * +zsysdep_xqt_local_file (qsys, zfile) + const struct uuconf_system *qsys; + const char *zfile; +{ + if (*zfile != '~') + return NULL; + if (zfile[1] == '~') + { + size_t clen; + char *zret; + + clen = strlen (zfile); + zret = zbufalc (clen); + memcpy (zret, zfile + 1, clen); + return zret; + } + return zsysdep_local_file (zfile, qsys->uuconf_zpubdir); +} + +#if ! ALLOW_FILENAME_ARGUMENTS + +/* Check to see whether an argument specifies a file name; if it does, + make sure that the file may legally be sent and/or received. For + Unix, we do not permit any occurrence of "/../" in the name, nor + may it start with "../". Otherwise, if it starts with "/" we check + against the list of permitted files. */ + +boolean +fsysdep_xqt_check_file (qsys, zfile) + const struct uuconf_system *qsys; + const char *zfile; +{ + size_t clen; + + clen = strlen (zfile); + if ((clen == sizeof "../" - 1 + && strcmp (zfile, "../") == 0) + || (clen >= sizeof "/.." - 1 + && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0) + || strstr (zfile, "/../") != NULL + || (*zfile == '/' + && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, + qsys->uuconf_zpubdir, TRUE, FALSE, + (const char *) NULL) + || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive, + qsys->uuconf_zpubdir, TRUE, FALSE, + (const char *) NULL)))) + { + ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile); + return FALSE; + } + + return TRUE; +} + +#endif /* ! ALLOW_FILENAME_ARGUMENTS */ + +/* Invoke the command specified by an execute file. */ + +/*ARGSUSED*/ +boolean +fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput, + fshell, iseq, pzerror, pftemp) + const struct uuconf_system *qsys; + const char *zuser; + const char **pazargs; + const char *zfullcmd; + const char *zinput; + const char *zoutput; + boolean fshell; + int iseq; + char **pzerror; + boolean *pftemp; +{ + int aidescs[3]; + boolean ferr; + pid_t ipid; + int ierr; + char abxqtdir[sizeof XQTDIR + 4]; + const char *zxqtdir; + int istat; + char *zpath; +#if ALLOW_SH_EXECUTION + const char *azshargs[4]; +#endif + + *pzerror = NULL; + *pftemp = FALSE; + + aidescs[0] = SPAWN_NULL; + aidescs[1] = SPAWN_NULL; + aidescs[2] = SPAWN_NULL; + + ferr = FALSE; + + if (zinput != NULL) + { + aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0); + if (aidescs[0] < 0) + { + ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno)); + ferr = TRUE; + } + else if (fcntl (aidescs[0], F_SETFD, + fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ferr = TRUE; + } + } + + if (! ferr && zoutput != NULL) + { + aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE); + if (aidescs[1] < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno)); + *pftemp = TRUE; + ferr = TRUE; + } + else if (fcntl (aidescs[1], F_SETFD, + fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ferr = TRUE; + } + } + + if (! ferr) + { + *pzerror = zstemp_file (qsys); + aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE); + if (aidescs[2] < 0) + { + if (errno == ENOENT) + { + if (! fsysdep_make_dirs (*pzerror, FALSE)) + { + *pftemp = TRUE; + ferr = TRUE; + } + else + aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE); + } + if (! ferr && aidescs[2] < 0) + { + ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno)); + *pftemp = TRUE; + ferr = TRUE; + } + } + if (! ferr + && fcntl (aidescs[2], F_SETFD, + fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ferr = TRUE; + } + } + + if (iseq == 0) + zxqtdir = XQTDIR; + else + { + sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); + zxqtdir = abxqtdir; + } + + if (ferr) + { + if (aidescs[0] != SPAWN_NULL) + (void) close (aidescs[0]); + if (aidescs[1] != SPAWN_NULL) + (void) close (aidescs[1]); + if (aidescs[2] != SPAWN_NULL) + (void) close (aidescs[2]); + ubuffree (*pzerror); + return FALSE; + } + +#if ALLOW_SH_EXECUTION + if (fshell) + { + azshargs[0] = "/bin/sh"; + azshargs[1] = "-c"; + azshargs[2] = zfullcmd; + azshargs[3] = NULL; + pazargs = azshargs; + } +#else + fshell = FALSE; +#endif + + if (qsys->uuconf_pzpath == NULL) + zpath = NULL; + else + { + size_t c; + char **pz; + + c = 0; + for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++) + c += strlen (*pz) + 1; + zpath = zbufalc (c); + *zpath = '\0'; + for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++) + { + strcat (zpath, *pz); + if (pz[1] != NULL) + strcat (zpath, ":"); + } + } + + /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we + aren't already using the shell. */ + ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE, + ! fshell, zpath, qsys->uuconf_zname, zuser); + + ierr = errno; + + ubuffree (zpath); + + if (aidescs[0] != SPAWN_NULL) + (void) close (aidescs[0]); + if (aidescs[1] != SPAWN_NULL) + (void) close (aidescs[1]); + if (aidescs[2] != SPAWN_NULL) + (void) close (aidescs[2]); + + if (ipid < 0) + { + ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr)); + *pftemp = TRUE; + return FALSE; + } + + istat = ixswait ((unsigned long) ipid, "Execution"); + + if (istat == EX_TEMPFAIL) + *pftemp = TRUE; + + return istat == 0; +} + +/* Lock a uuxqt process. */ + +int +ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts) + const char *zcmd; + int cmaxuuxqts; +{ + char ab[sizeof "LCK.XQT.9999"]; + int i; + + if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000) + cmaxuuxqts = 9999; + for (i = 0; i < cmaxuuxqts; i++) + { + sprintf (ab, "LCK.XQT.%d", i); + if (fsdo_lock (ab, TRUE, (boolean *) NULL)) + break; + } + if (i >= cmaxuuxqts) + return -1; + + if (zcmd != NULL) + { + char abcmd[sizeof "LXQ.123456789"]; + + sprintf (abcmd, "LXQ.%.9s", zcmd); + abcmd[strcspn (abcmd, " \t/")] = '\0'; + if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL)) + { + (void) fsdo_unlock (ab, TRUE); + return -1; + } + } + + return i; +} + +/* Unlock a uuxqt process. */ + +boolean +fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts) + int iseq; + const char *zcmd; + int cmaxuuxqts; +{ + char ab[sizeof "LCK.XQT.9999"]; + boolean fret; + + fret = TRUE; + + sprintf (ab, "LCK.XQT.%d", iseq); + if (! fsdo_unlock (ab, TRUE)) + fret = FALSE; + + if (zcmd != NULL) + { + char abcmd[sizeof "LXQ.123456789"]; + + sprintf (abcmd, "LXQ.%.9s", zcmd); + abcmd[strcspn (abcmd, " \t/")] = '\0'; + if (! fsdo_unlock (abcmd, TRUE)) + fret = FALSE; + } + + return fret; +} + +/* See whether a particular uuxqt command is locked (this depends on + the implementation of fsdo_lock). */ + +boolean +fsysdep_uuxqt_locked (zcmd) + const char *zcmd; +{ + char ab[sizeof "LXQ.123456789"]; + struct stat s; + + sprintf (ab, "LXQ.%.9s", zcmd); + return stat (ab, &s) == 0; +} + +/* Lock a particular execute file. */ + +boolean +fsysdep_lock_uuxqt_file (zfile) + const char *zfile; +{ + char *zcopy, *z; + boolean fret; + + zcopy = zbufcpy (zfile); + + z = strrchr (zcopy, '/'); + if (z == NULL) + *zcopy = 'L'; + else + *(z + 1) = 'L'; + + fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL); + ubuffree (zcopy); + return fret; +} + +/* Unlock a particular execute file. */ + +boolean +fsysdep_unlock_uuxqt_file (zfile) + const char *zfile; +{ + char *zcopy, *z; + boolean fret; + + zcopy = zbufcpy (zfile); + + z = strrchr (zcopy, '/'); + if (z == NULL) + *zcopy = 'L'; + else + *(z + 1) = 'L'; + + fret = fsdo_unlock (zcopy, TRUE); + ubuffree (zcopy); + return fret; +} + +/* Lock the execute directory. Since we use a different directory + depending on which LCK.XQT.dddd file we got, there is actually no + need to create a lock file. We do make sure that the directory + exists, though. */ + +boolean +fsysdep_lock_uuxqt_dir (iseq) + int iseq; +{ + const char *zxqtdir; + char abxqtdir[sizeof XQTDIR + 4]; + + if (iseq == 0) + zxqtdir = XQTDIR; + else + { + sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); + zxqtdir = abxqtdir; + } + + if (mkdir (zxqtdir, S_IRWXU) < 0 + && errno != EEXIST) + { + ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* Unlock the execute directory and clear it out. The lock is + actually the LCK.XQT.dddd file, so we don't unlock it, but we do + remove all the files. */ + +boolean +fsysdep_unlock_uuxqt_dir (iseq) + int iseq; +{ + const char *zxqtdir; + char abxqtdir[sizeof XQTDIR + 4]; + DIR *qdir; + + if (iseq == 0) + zxqtdir = XQTDIR; + else + { + sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); + zxqtdir = abxqtdir; + } + + qdir = opendir ((char *) zxqtdir); + if (qdir != NULL) + { + struct dirent *qentry; + + while ((qentry = readdir (qdir)) != NULL) + { + char *z; + + if (strcmp (qentry->d_name, ".") == 0 + || strcmp (qentry->d_name, "..") == 0) + continue; + z = zsysdep_in_dir (zxqtdir, qentry->d_name); + if (remove (z) < 0) + { + int ierr; + + ierr = errno; + if (! fsysdep_directory (z)) + ulog (LOG_ERROR, "remove (%s): %s", z, + strerror (ierr)); + else + (void) fsysdep_rmdir (z); + } + ubuffree (z); + } + + closedir (qdir); + } + + return TRUE; +} + +/* Move files into the execution directory. */ + +boolean +fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput) + int cfiles; + const char *const *pzfrom; + const char *const *pzto; + boolean fto; + int iseq; + char **pzinput; +{ + char *zinput; + const char *zxqtdir; + char abxqtdir[sizeof XQTDIR + 4]; + int i; + + if (pzinput == NULL) + zinput = NULL; + else + zinput = *pzinput; + + if (iseq == 0) + zxqtdir = XQTDIR; + else + { + sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); + zxqtdir = abxqtdir; + } + + for (i = 0; i < cfiles; i++) + { + const char *zfrom, *zto; + char *zfree; + + if (pzto[i] == NULL) + continue; + + zfree = zsysdep_in_dir (zxqtdir, pzto[i]); + + zfrom = pzfrom[i]; + zto = zfree; + + if (zinput != NULL && strcmp (zinput, zfrom) == 0) + { + *pzinput = zbufcpy (zto); + zinput = NULL; + } + + if (! fto) + { + const char *ztemp; + + ztemp = zfrom; + zfrom = zto; + zto = ztemp; + (void) chmod (zfrom, IPRIVATE_FILE_MODE); + } + + if (rename (zfrom, zto) < 0) + { +#if HAVE_RENAME + /* On some systems the system call rename seems to fail for + arbitrary reasons. To get around this, we always try to + copy the file by hand if the rename failed. */ + errno = EXDEV; +#endif + + if (errno != EXDEV) + { + ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto, + strerror (errno)); + ubuffree (zfree); + break; + } + + if (! fcopy_file (zfrom, zto, FALSE, FALSE)) + { + ubuffree (zfree); + break; + } + if (remove (zfrom) < 0) + ulog (LOG_ERROR, "remove (%s): %s", zfrom, + strerror (errno)); + } + + if (fto) + (void) chmod (zto, IPUBLIC_FILE_MODE); + + ubuffree (zfree); + } + + if (i < cfiles) + { + if (fto) + (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq, + (char **) NULL); + return FALSE; + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/libuuconf/COPYING.LIB b/gnu/libexec/uucp/libuuconf/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/libexec/uucp/libuuconf/MANIFEST b/gnu/libexec/uucp/libuuconf/MANIFEST new file mode 100644 index 00000000000..8d1eb364663 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/MANIFEST @@ -0,0 +1,92 @@ +README +COPYING.LIB +MANIFEST +Makefile.in +alloc.h +syshdr.unx +uucnfi.h +addblk.c +addstr.c +allblk.c +alloc.c +base.c +bool.c +callin.c +calout.c +chatc.c +cmdarg.c +cmdfil.c +cmdlin.c +debfil.c +deblev.c +diacod.c +dial.c +diasub.c +dnams.c +errno.c +errstr.c +filnam.c +freblk.c +fredia.c +free.c +freprt.c +fresys.c +grdcmp.c +hdial.c +hdnams.c +hinit.c +hlocnm.c +hport.c +hrmunk.c +hsinfo.c +hsnams.c +hsys.c +hunk.c +iniglb.c +init.c +int.c +lckdir.c +lineno.c +llocnm.c +local.c +locnm.c +logfil.c +maxuxq.c +mrgblk.c +paramc.c +port.c +pubdir.c +prtsub.c +rdlocs.c +rdperm.c +reliab.c +remunk.c +sinfo.c +snams.c +split.c +spool.c +stafil.c +syssub.c +tcalou.c +tdial.c +tdialc.c +tdnams.c +tgcmp.c +thread.c +time.c +tinit.c +tlocnm.c +tport.c +tportc.c +tsinfo.c +tsnams.c +tsys.c +tval.c +ugtlin.c +unk.c +val.c +vinit.c +vport.c +vsinfo.c +vsnams.c +vsys.c diff --git a/gnu/libexec/uucp/libuuconf/Makefile b/gnu/libexec/uucp/libuuconf/Makefile new file mode 100644 index 00000000000..098382d1f6a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/Makefile @@ -0,0 +1,25 @@ +# This is the Makefile for the Taylor UUCP uuconf library + +LIB= uuconf +SRCS= addblk.c addstr.c allblk.c alloc.c base.c bool.c callin.c \ + calout.c chatc.c cmdarg.c cmdfil.c cmdlin.c debfil.c deblev.c \ + diacod.c dial.c diasub.c dnams.c errno.c errstr.c filnam.c \ + freblk.c fredia.c free.c freprt.c fresys.c grdcmp.c hdial.c \ + hdnams.c hinit.c hlocnm.c hport.c hrmunk.c hsinfo.c hsnams.c \ + hsys.c hunk.c iniglb.c init.c int.c lckdir.c lineno.c llocnm.c \ + local.c locnm.c logfil.c maxuxq.c mrgblk.c paramc.c port.c \ + prtsub.c pubdir.c rdlocs.c rdperm.c reliab.c remunk.c sinfo.c \ + snams.c split.c spool.c stafil.c syssub.c tcalou.c tdial.c \ + tdialc.c tdnams.c tgcmp.c thread.c time.c tinit.c tlocnm.c \ + tport.c tportc.c tsinfo.c tsnams.c tsys.c tval.c ugtlin.c \ + unk.c val.c vinit.c vport.c vsinfo.c vsnams.c vsys.c +CFLAGS+= -I$(.CURDIR)/../common_sources \ + -DNEWCONFIGLIB=\"$(newconfigdir)\"\ + -DOLDCONFIGLIB=\"$(oldconfigdir)\" + +NOMAN= noman +NOPROFILE= noprofile + +install: + +.include <bsd.lib.mk> diff --git a/gnu/libexec/uucp/libuuconf/README b/gnu/libexec/uucp/libuuconf/README new file mode 100644 index 00000000000..64a5eecf03a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/README @@ -0,0 +1,113 @@ +This is the README file for the beta release of the uuconf library. + +It was written by Ian Lance Taylor. I can be reached at ian@airs.com, +or, equivalently, uunet!airs!ian, or c/o Infinity Development Systems, +P.O. Box 520, Waltham MA, 02254. + +This package is covered by the Gnu Library General Public License. +See the file COPYING.LIB for details. If you would like to do +something with this package that you feel is reasonable but you feel +is prohibited by the license, contact me to see if we can work it out. + +WHAT IT IS + +This is a beta release of the uuconf library. The uuconf library +provides a set of functions which can be used to read UUCP +configuration files. V2, HDB, and Taylor UUCP configuration files are +supported. + +Also included are two programs, uuchk and uuconv. uuchk will read +configuration files and display the information it finds in a verbose +format. This can be helpful to ensure that your configuration files +are set up as you expect. uuconv can be used to convert configuration +files from one type to another. This is particularly helpful for +people installing Taylor UUCP on a existing system who want to take +advantage of the additional functionality provided by the Taylor UUCP +configuration files. + +This is strictly a beta release. The library provides all the +information needed for uuchk and uuconv, but does not yet provide +everything needed for uucp or cu. I am releasing it now to get +feedback and to provide the uuconv program to people using Taylor +UUCP. + +This may well be the only time this library is release independently. +This library will be provided with Taylor UUCP, and future releases of +the library will probably only occur as part of the complete Taylor +UUCP package. + +HOW TO USE IT + +Configure and optionally install the package as described in INSTALL. + +The functions provided by the library are described in uuconf.h. At +the moment there is no additional documentation. + +Programs which use the library should include uuconf.h, and should not +include any of the other header files. The functions listed in +uuconf.h all begin with the string "uuconf_". The internal library +functions all begin with the string "_uuconf_". The internal library +functions should not be called by a program which uses the library, as +they may change in future releases. The uuchk program is an example +of program which uses the library; uuconv is not, as it relies upon +internal data structures. + +The uuchk program takes a single optional option, -I, which may be +used to specify an alternate Taylor UUCP main configuration file. The +default configuration file is $(newconfigdir)/config ($(newconfigdir) +is defined in Makefile). For example: + uuchk + uuchk -I /usr/tmp/tstuu/Config1 + +The uuconv program requires two options: -i to specify the input type +and -o to specify the output type. Both options take a string +argument, which must be one of "v2", "hdb", or "taylor". uuconv also +takes an optional -I option, which is the same as the -I option to +uuchk. The conversion is not intended to be perfect, and the results +should be manually inspected. In particular, the dialcode file is not +converted (as the format is the same for all three configuration file +types, it may simply be copied to the appropriate new name). uuconv +will create new files in the current working directory. For example: + uuconv -i hdb -o taylor + uuconv -i taylor -I /usr/tmp/tstuu/Config1 -o v2 + +NOTES + +The initial underscore on the internal library functions is required +by the GNU standards. As ANSI C reserves external identifiers with an +initial underscore for the implementation, it is possible, though +unlikely, that this will cause problems on other implementations; no +workaround is currently provided for such problems. + +The library functions rely upon the following functions: + + fclose fopen free fseek + ftell getc isalpha isdigit + islower isspace isupper malloc + realloc rewind strchr strcmp + strcspn strlen strncmp strspn + tolower toupper + +and the following header files: + + ctype.h errno.h stdio.h + +If the following functions cannot be found by the configure script, +replacements will be used (the replacement for strerror is Unix +dependent): + + getline memcpy strcasecmp strdup + strerror strncasecmp strtol + +If the following header files are found, they will be included: + + libc.h limits.h memory.h stddef.h + stdlib.h string.h strings.h sys/types.h + +The following functions are required on Unix only: + + fcntl fileno + +The following headers are used, if found, on Unix only: + + fcntl.h sys/file.h diff --git a/gnu/libexec/uucp/libuuconf/addblk.c b/gnu/libexec/uucp/libuuconf/addblk.c new file mode 100644 index 00000000000..6244dad875e --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/addblk.c @@ -0,0 +1,56 @@ +/* addblk.c + Add an malloc block to a memory block. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_addblk_rcsid[] = "$Id: addblk.c,v 1.1 1993/08/04 19:33:31 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Add a memory buffer allocated by malloc to a memory block. This is + used by the uuconf_cmd functions so that they don't have to + constantly copy data into memory. Returns 0 on success, non 0 on + failure. */ + +int +uuconf_add_block (pblock, padd) + pointer pblock; + pointer padd; +{ + struct sblock *q = (struct sblock *) pblock; + struct sadded *qnew; + + qnew = (struct sadded *) uuconf_malloc (pblock, sizeof (struct sadded)); + if (qnew == NULL) + return 1; + + qnew->qnext = q->qadded; + qnew->padded = padd; + q->qadded = qnew; + + return 0; +} diff --git a/gnu/libexec/uucp/libuuconf/addstr.c b/gnu/libexec/uucp/libuuconf/addstr.c new file mode 100644 index 00000000000..8498d502c9c --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/addstr.c @@ -0,0 +1,139 @@ +/* addstr.c + Add a string to a list of strings. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_addstr_rcsid[] = "$Id: addstr.c,v 1.1 1993/08/04 19:33:32 jtc Exp $"; +#endif + +#include <errno.h> + +/* When setting system information, we need to be able to distinguish + between a value that is not set and a value that has been set to + NULL. We do this by initializing the value to point to the + variable _uuconf_unset, and then correcting it in the function + _uuconf_isystem_basic_default. This variable is declared in this + file because some linkers will apparently not pull in an object + file which merely declarates a variable. This functions happens to + be pulled in by almost everything. */ + +char *_uuconf_unset; + +/* Add a string to a list of strings. The list is maintained as an + array of elements ending in NULL. The total number of available + slots is always a multiple of CSLOTS, so by counting the current + number of elements we can tell whether a new slot is needed. If + the fcopy argument is TRUE, the new string is duplicated into + memory. If the fcheck argument is TRUE, this does not add a string + that is already in the list. The pblock argument may be used to do + the allocations within a memory block. This returns a standard + uuconf error code. */ + +#define CSLOTS (8) + +int +_uuconf_iadd_string (qglobal, zadd, fcopy, fcheck, ppzstrings, pblock) + struct sglobal *qglobal; + char *zadd; + boolean fcopy; + boolean fcheck; + char ***ppzstrings; + pointer pblock; +{ + char **pz; + size_t c; + + if (fcheck && *ppzstrings != NULL) + { + for (pz = *ppzstrings; *pz != NULL; pz++) + if (strcmp (zadd, *pz) == 0) + return UUCONF_SUCCESS; + } + + if (fcopy) + { + size_t clen; + char *znew; + + clen = strlen (zadd) + 1; + znew = (char *) uuconf_malloc (pblock, clen); + if (znew == NULL) + { + if (qglobal != NULL) + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) znew, (pointer) zadd, clen); + zadd = znew; + } + + pz = *ppzstrings; + if (pz == NULL || pz == (char **) &_uuconf_unset) + { + pz = (char **) uuconf_malloc (pblock, CSLOTS * sizeof (char *)); + if (pz == NULL) + { + if (qglobal != NULL) + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + *ppzstrings = pz; + } + else + { + c = 0; + while (*pz != NULL) + { + ++pz; + ++c; + } + + if ((c + 1) % CSLOTS == 0) + { + char **pznew; + + pznew = (char **) uuconf_malloc (pblock, + ((c + 1 + CSLOTS) + * sizeof (char *))); + if (pznew == NULL) + { + if (qglobal != NULL) + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) pznew, (pointer) *ppzstrings, + c * sizeof (char *)); + uuconf_free (pblock, *ppzstrings); + *ppzstrings = pznew; + pz = pznew + c; + } + } + + pz[0] = zadd; + pz[1] = NULL; + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/allblk.c b/gnu/libexec/uucp/libuuconf/allblk.c new file mode 100644 index 00000000000..b3dd7e0a762 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/allblk.c @@ -0,0 +1,51 @@ +/* allblk.c + Allocate a memory block. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_allblk_rcsid[] = "$Id: allblk.c,v 1.1 1993/08/04 19:33:33 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Allocate a new memory block. If this fails, uuconf_errno will be + set, and the calling routine may return UUCONF_MALLOC_FAILED | + UUCONF_ERROR_ERRNO. */ + +pointer +uuconf_malloc_block () +{ + struct sblock *qret; + + qret = (struct sblock *) malloc (sizeof (struct sblock)); + if (qret == NULL) + return NULL; + qret->qnext = NULL; + qret->ifree = 0; + qret->plast = NULL; + qret->qadded = NULL; + return (pointer) qret; +} diff --git a/gnu/libexec/uucp/libuuconf/alloc.c b/gnu/libexec/uucp/libuuconf/alloc.c new file mode 100644 index 00000000000..2808c62088f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/alloc.c @@ -0,0 +1,82 @@ +/* alloc.c + Allocate within a memory block. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_alloc_rcsid[] = "$Id: alloc.c,v 1.1 1993/08/04 19:33:34 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Allocate some memory out of a memory block. If the memory block is + NULL, this just calls malloc; this is convenient for a number of + routines. If this fails, uuconf_errno will be set, and the calling + routine may return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO. */ + +pointer +uuconf_malloc (pblock, c) + pointer pblock; + size_t c; +{ + struct sblock *q = (struct sblock *) pblock; + pointer pret; + + if (c == 0) + return NULL; + + if (q == NULL) + return malloc (c); + + /* Make sure that c is aligned to a double boundary. */ + c = ((c + sizeof (double) - 1) / sizeof (double)) * sizeof (double); + + while (q->ifree + c > CALLOC_SIZE) + { + if (q->qnext != NULL) + q = q->qnext; + else + { + if (c > CALLOC_SIZE) + q->qnext = (struct sblock *) malloc (sizeof (struct sblock) + + c - CALLOC_SIZE); + else + q->qnext = (struct sblock *) malloc (sizeof (struct sblock)); + if (q->qnext == NULL) + return NULL; + q = q->qnext; + q->qnext = NULL; + q->ifree = 0; + q->qadded = NULL; + break; + } + } + + pret = q->u.ab + q->ifree; + q->ifree += c; + q->plast = pret; + + return pret; +} diff --git a/gnu/libexec/uucp/libuuconf/alloc.h b/gnu/libexec/uucp/libuuconf/alloc.h new file mode 100644 index 00000000000..c5c9cad8e32 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/alloc.h @@ -0,0 +1,71 @@ +/* alloc.h + Header file for uuconf memory allocation routines. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +/* This header file is private to the uuconf memory allocation + routines, and should not be included by any other files. */ + +/* We want to be able to keep track of allocated memory blocks, so + that we can free them up later. This will let us free up all the + memory allocated to hold information for a system, for example. We + do this by allocating large chunks and doling them out. Calling + uuconf_malloc_block will return a pointer to a magic cookie which + can then be passed to uuconf_malloc and uuconf_free. Passing the + pointer to uuconf_free_block will free all memory allocated for + that block. */ + +/* We allocate this much space in each block. On most systems, this + will make the actual structure 1024 bytes, which may be convenient + for some types of memory allocators. */ +#define CALLOC_SIZE (1008) + +/* This is the actual structure of a block. */ +struct sblock +{ + /* Next block in linked list. */ + struct sblock *qnext; + /* Index of next free spot. */ + size_t ifree; + /* Last value returned by uuconf_malloc for this block. */ + pointer plast; + /* List of additional memory blocks. */ + struct sadded *qadded; + /* Buffer of data. We put it in a union with a double to make sure + it is adequately aligned. */ + union + { + char ab[CALLOC_SIZE]; + double l; + } u; +}; + +/* There is a linked list of additional memory blocks inserted by + uuconf_add_block. */ +struct sadded +{ + /* The next in the list. */ + struct sadded *qnext; + /* The added block. */ + pointer padded; +}; diff --git a/gnu/libexec/uucp/libuuconf/base.c b/gnu/libexec/uucp/libuuconf/base.c new file mode 100644 index 00000000000..c40f660523a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/base.c @@ -0,0 +1,54 @@ +/* base.c + Subroutine to turn a cmdtab_offset table into a uuconf_cmdtab table. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_base_rcsid[] = "$Id: base.c,v 1.1 1993/08/04 19:33:38 jtc Exp $"; +#endif + +/* This turns a cmdtab_offset table into a uuconf_cmdtab table. Each + offset is adjusted by a base value. */ + +void +_uuconf_ucmdtab_base (qoff, celes, pbase, qset) + register const struct cmdtab_offset *qoff; + size_t celes; + char *pbase; + register struct uuconf_cmdtab *qset; +{ + register size_t i; + + for (i = 0; i < celes; i++, qoff++, qset++) + { + qset->uuconf_zcmd = qoff->zcmd; + qset->uuconf_itype = qoff->itype; + if (qoff->ioff == (size_t) -1) + qset->uuconf_pvar = NULL; + else + qset->uuconf_pvar = pbase + qoff->ioff; + qset->uuconf_pifn = qoff->pifn; + } +} |
