diff options
author | jnweiger <jnweiger> | 2005-12-16 16:38:49 +0000 |
---|---|---|
committer | jnweiger <jnweiger> | 2005-12-16 16:38:49 +0000 |
commit | 8cb4b1196ba0c9011910807092f59cbf2ca77f24 (patch) | |
tree | db0c159183437e6a48d2d559a1d57e1d91107b45 /src/fileio.c | |
parent | 32462f2e30134ec5b785571151e848ab4c2824ee (diff) | |
download | screen-8cb4b1196ba0c9011910807092f59cbf2ca77f24.tar.gz |
historic version screen-3.2.0 Feb 10 1992
Diffstat (limited to 'src/fileio.c')
-rw-r--r-- | src/fileio.c | 2154 |
1 files changed, 1987 insertions, 167 deletions
diff --git a/src/fileio.c b/src/fileio.c index b54e335..1e76803 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -22,7 +22,7 @@ * Patrick Wolfe (pat@kai.com, kailand!pat) * Bart Schaefer (schaefer@cse.ogi.edu) * Nathan Glasser (nathan@brokaw.lcs.mit.edu) - * Larry W. Virden (lvirden@cas.org) + * Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu) * Howard Chu (hyc@hanauma.jpl.nasa.gov) * Tim MacKenzie (tym@dibbler.cs.monash.edu.au) * Markku Jarvinen (mta@{cc,cs,ee}.tut.fi) @@ -31,9 +31,13 @@ **************************************************************** */ -#include "rcs.h" -RCS_ID("$Id$ FAU") +#ifndef lint + static char rcs_id[] = "$Id$ FAU"; +#endif +#if defined(pyr) || defined(MIPS) || defined(GOULD_NP1) || defined(B43) +extern int errno; +#endif #include <sys/types.h> #ifndef sgi # include <sys/file.h> @@ -41,37 +45,264 @@ RCS_ID("$Id$ FAU") #include <sys/stat.h> #include <fcntl.h> -#include <signal.h> +#ifdef BSDI +# include <sys/signal.h> +#endif /* BSDI */ #include "config.h" #include "screen.h" #include "extern.h" +#ifdef _SEQUENT_ +# define UTHOST /* _SEQUENT_ has got ut_find_host() */ +#endif + +#ifndef GETUTENT +# ifdef GETTTYENT +# include <ttyent.h> +# else +struct ttyent +{ + char *ty_name; +}; +static char *tt, *ttnext; +static char ttys[] = "/etc/ttys"; +# endif +#endif + +#ifdef LOADAV +# ifndef NeXT +# include <nlist.h> + +static char KmemName[] = "/dev/kmem"; +# if defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) +static char UnixName[] = "/unix"; +# else +# ifdef sequent +static char UnixName[] = "/dynix"; +# else +# ifdef hpux +static char UnixName[] = "/hp-ux"; +# else +# ifdef xelos +static char UnixName[] = "/xelos"; +# else +static char UnixName[] = "/vmunix"; +# endif /* xelos */ +# endif /* hpux */ +# endif /* sequent */ +# endif /* _SEQUENT_ ... */ + +# ifdef alliant +static char AvenrunSym[] = "_Loadavg"; +# else +# if defined(hpux) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) +static char AvenrunSym[] = "avenrun"; +# else +static char AvenrunSym[] = "_avenrun"; +# endif +# endif /* alliant */ +static struct nlist nl[2]; +int avenrun; +static kmemf; +# ifdef LOADAV_3LONGS +long loadav[3]; +# else +# ifdef LOADAV_4LONGS +long loadav[4]; +# else +double loadav[3]; +# endif +# endif +# else /* NeXT */ +# include <mach.h> +kern_return_t error; +host_t host; +unsigned int info_count; +struct processor_set_basic_info info; +processor_set_t default_set; +float loadav; +int avenrun; +# endif /* NeXT */ +#endif /* LOADAV */ + +#if defined(UTMPOK) && defined(GETUTENT) && !defined(SVR4) +# if defined(hpux) /* cruel hpux release 8.0 */ +# define pututline _pututline +# endif /* hpux */ +extern struct utmp *getutline(), *pututline(); +# if defined(_SEQUENT_) +extern struct utmp *ut_add_user(), *ut_delete_user(); +extern char *ut_find_host(); +# endif +#endif #ifdef NETHACK extern nethackflag; #endif +int hardcopy_append = 0; +int all_norefresh = 0; -extern struct display *display; +extern char *RcFileName, *home, *extra_incap, *extra_outcap; +extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[]; +extern char *BufferFile, *PowDetachString, *VisualBellString; +extern int VBellWait, MsgWait, MsgMinWait; +extern struct key ktab[]; +extern char Esc, MetaEsc; +extern char *shellaka, SockPath[], *SockNamePtr, *LoginName; +extern int loginflag, allflag, TtyMode, auto_detach; +extern int iflag, rflag, dflag; +extern int default_flow, wrap; +extern HS, termcapHS, use_hardstatus, visual_bell, default_monitor; +extern int default_histheight; +extern int default_startup; +extern int slowpaste; +extern DeadlyMsg, HasWindow; +extern ForeNum, screenwidth, screenheight; +extern char display_tty[]; extern struct win *fore; +extern char screenterm[]; +extern int join_with_cr; +extern struct mode OldMode, NewMode; +extern int HasWindow; +extern char mark_key_tab[]; extern int real_uid, eff_uid; extern int real_gid, eff_gid; -extern char *extra_incap, *extra_outcap; -extern char *home, *RcFileName; -extern char SockPath[], *SockNamePtr; + +#ifdef PASSWORD +int CheckPassword; +char Password[20]; +#endif + #ifdef COPY_PASTE -extern char *BufferFile; +extern char *copybuffer; +extern copylen; #endif -extern int hardcopy_append; -extern char *hardcopydir; static char *CatExtra __P((char *, char *)); +static char **SaveArgs __P((int, char **)); +static int Parse __P((char *, char *[])); +static char *ParseChar __P((char *, char *)); +static void ParseNum __P((int, char *[], int*)); +static void ParseOnOff __P((int, char *[], int*)); +static void ParseSaveStr __P((int, char *[], char **, char *)); +static int IsNum __P((char *, int)); +static int IsNumColon __P((char *, int, char *, int)); +static slot_t TtyNameSlot __P((char *)); + +#if !defined(GETTTYENT) && !defined(GETUTENT) +static void setttyent __P((void)); +static struct ttyent *getttyent __P((void)); +#endif +/* + * XXX: system + */ +extern time_t time __P((time_t *)); +#if !defined(BSDI) && !defined(SVR4) +extern char *getpass __P((char *)); +#endif /* !BSDI && !SVR4 */ +#if defined(LOADAV) && !defined(NeXT) && !defined(NLIST_DECLARED) +extern int nlist __P((char *, struct nlist *)); +#endif + +char *KeyNames[] = +{ + "screen", + "select0", "select1", "select2", "select3", "select4", + "select5", "select6", "select7", "select8", "select9", + "aka", "clear", "colon", "copy", "detach", "flow", + "hardcopy", "help", "histnext", "history", "info", "kill", "lastmsg", + "license", + "lockscreen", "log", "login", "monitor", "next", "other", "paste", + "pow_detach", "prev", "quit", "readbuf", "redisplay", "removebuf", + "reset", "set", "shell", "suspend", "termcap", "time", "vbell", + "version", "width", "windows", "wrap", "writebuf", "xoff", "xon", + 0, +}; + + +/* Must be in alpha order !!! */ + +char *RCNames[] = +{ + "activity", "all", "autodetach", "bell", "bind", "bufferfile", "chdir", + "crlf", "echo", "escape", "flow", "hardcopy_append", "hardstatus", "login", + "markkeys", "mode", "monitor", "msgminwait", "msgwait", "nethack", "password", + "pow_detach_msg", "redraw", "refresh", "screen", "scrollback", "shell", + "shellaka", "sleep", "slowpaste", "startup_message", "term", "termcap", + "terminfo", "vbell", "vbell_msg", "vbellwait", "visualbell", + "visualbell_msg", "wrap", +}; + +enum RCcases +{ + RC_ACTIVITY, + RC_ALL, + RC_AUTODETACH, + RC_BELL, + RC_BIND, + RC_BUFFERFILE, + RC_CHDIR, + RC_CRLF, + RC_ECHO, + RC_ESCAPE, + RC_FLOW, + RC_HARDCOPY_APP, + RC_HARDSTATUS, + RC_LOGIN, + RC_MARKKEYS, + RC_MODE, + RC_MONITOR, + RC_MSGMINWAIT, + RC_MSGWAIT, + RC_NETHACK, + RC_PASSWORD, + RC_POW_DETACH_MSG, + RC_REDRAW, + RC_REFRESH, + RC_SCREEN, + RC_SCROLLBACK, + RC_SHELL, + RC_SHELLAKA, + RC_SLEEP, + RC_SLOWPASTE, + RC_STARTUP_MESSAGE, + RC_TERM, + RC_TERMCAP, + RC_TERMINFO, + RC_VBELL, + RC_VBELL_MSG, + RC_VBELLWAIT, + RC_VISUALBELL, + RC_VISUALBELL_MSG, + RC_WRAP, + RC_RCEND +}; + +#ifdef UTMPOK +static utmp, utmpf; +static char UtmpName[] = UTMPFILE; +# ifdef MIPS + static utmpfappend; +# endif +#endif static FILE *fp = NULL; -char *rc_name; +static char *rc_name; -static char * -CatExtra(str1, str2) +char *SaveStr(str) +register char *str; +{ + register char *cp; + + if ((cp = malloc(strlen(str) + 1)) == NULL) + Msg_nomem; + else + strcpy(cp, str); + return cp; +} + +static char *CatExtra(str1, str2) register char *str1, *str2; { register char *cp; @@ -85,7 +316,7 @@ register char *str1, *str2; { len2 = strlen(str2); if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL) - Panic(0, strnomem); + Msg_nomem; bcopy(cp, cp + len1 + add_colon, len2 + 1); } else @@ -93,7 +324,7 @@ register char *str1, *str2; if (len1 == 0) return 0; if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL) - Panic(0, strnomem); + Msg_nomem; cp[len1 + add_colon] = '\0'; } bcopy(str1, cp, len1); @@ -103,8 +334,7 @@ register char *str1, *str2; return cp; } -static char * -findrcfile(rcfile) +static char *findrcfile(rcfile) char *rcfile; { static char buf[256]; @@ -132,7 +362,7 @@ char *rcfile; { debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n"); if (strlen(home) > 244) - Panic(0, "Rc: home too large"); + Msg(0, "Rc: home too large"); sprintf(buf, "%s/.iscreenrc", home); if (access(buf, R_OK)) sprintf(buf, "%s/.screenrc", home); @@ -154,7 +384,7 @@ char *rcfilename; register int argc, len; register char *p, *cp; char buf[256]; - char *args[MAXARGS]; + char *args[MAXARGS], *t; rc_name = findrcfile(rcfilename); @@ -168,7 +398,7 @@ char *rcfilename; * the file. */ debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename); - Panic(0, "Unable to open \"%s\".", rc_name); + Msg(0, "Unable to open \"%s\".", rc_name); /* NOTREACHED */ } debug1("StartRc: '%s' no good. ignored\n", rc_name); @@ -176,6 +406,9 @@ char *rcfilename; rc_name = ""; return; } + if ((t = getenv("TERM")) == NULL) + Msg(0, "No TERM in environment."); + debug1("startrc got termcp:%s\n", t); while (fgets(buf, sizeof buf, fp) != NULL) { if ((p = rindex(buf, '\n')) != NULL) @@ -186,25 +419,23 @@ char *rcfilename; { if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3) { + DeadlyMsg = 0; Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name); - continue; } - AddStr(args[argc - 1]); - if (argc != 3) + else { - AddStr("\r\n"); - Flush(); + printf((argc == 3) ? "%s" : "%s\r\n", args[argc - 1]); } } else if (strcmp(args[0], "sleep") == 0) { - debug("sleeeeeeep\n"); if (argc != 2) { + DeadlyMsg = 0; Msg(0, "%s: sleep: one numeric argument expected.", rc_name); - continue; } - DisplaySleep(atoi(args[1])); + else + sleep(atoi(args[1])); } #ifdef TERMINFO else if (strcmp(args[0], "terminfo") == 0) @@ -212,13 +443,8 @@ char *rcfilename; else if (strcmp(args[0], "termcap") == 0) #endif { - if (!display) - continue; if (argc < 3 || argc > 4) - { - Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]); - continue; - } + Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]); for (p = args[1]; p && *p; p = cp) { if ((cp = index(p, '|')) != 0) @@ -226,10 +452,10 @@ char *rcfilename; len = strlen(p); if (p[len - 1] == '*') { - if (!(len - 1) || !strncmp(p, d_termname, len - 1)) + if (!(len - 1) || !strncmp(p, t, len - 1)) break; } - else if (!strcmp(p, d_termname)) + else if (!strcmp(p, t)) break; } if (!(p && *p)) @@ -244,10 +470,99 @@ char *rcfilename; rc_name = ""; } +static char * +ParseChar(p, cp) +char *p, *cp; +{ + if (*p == '^') + { + if (*++p == '?') + *cp = '\177'; + else if (*p >= '@') + *cp = Ctrl(*p); + else + return 0; + ++p; + } + else if (*p == '\\' && *++p <= '7' && *p >= '0') + { + *cp = 0; + do + *cp = *cp * 8 + *p - '0'; + while (*++p <= '7' && *p >= '0'); + } + else + *cp = *p++; + return p; +} + +/* + * CompileKeys must be called before Markroutine is first used. + * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab); + * + * s is an ascii string in a termcap-like syntax. It looks like + * "j=u:k=d:l=r:h=l: =.:" and so on... + * this example rebinds the cursormovement to the keys u (up), d (down), + * l (left), r (right). placing a mark will now be done with ".". + */ +int CompileKeys(s, array) +char *s, *array; +{ + int i; + unsigned char key, value; + + if (!s || !*s) + { + for (i = 0; i < 256; i++) + array[i] = i; + return 0; + } + while (*s) + { + s = ParseChar(s, (char *) &key); + if (*s != '=') + return -1; + do + { + s = ParseChar(++s, (char *) &value); + array[value] = key; + } + while (*s == '='); + if (!*s) + break; + if (*s++ != ':') + return -1; + } + return 0; +} + +static char **SaveArgs(argc, argv) +register int argc; +register char **argv; +{ + register char **ap, **pp; + + if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0) + Msg_nomem; +#ifdef notdef + debug("saveargs:\n"); +#endif + while (argc--) + { + debug1(" '%s'", *argv); + *pp++ = SaveStr(*argv++); + } + debug("\n"); + *pp = 0; + return ap; +} + void FinishRc(rcfilename) char *rcfilename; { + /* in FinishRc screen is not yet open, thus Msg() is deadly here. + */ char buf[256]; rc_name = findrcfile(rcfilename); @@ -262,7 +577,7 @@ char *rcfilename; * the file. */ debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename); - Panic(0, "Unable to open \"%s\".", rc_name); + Msg(0, "Unable to open \"%s\".", rc_name); /* NOTREACHED */ } debug1("FinishRc: '%s' no good. ignored\n", rc_name); @@ -274,7 +589,6 @@ char *rcfilename; debug("finishrc is going...\n"); while (fgets(buf, sizeof buf, fp) != NULL) { - debug1("RCFILE:%s", buf); RcLine(buf); } (void) fclose(fp); @@ -283,6 +597,34 @@ char *rcfilename; } /* + * this is a KEY_SET pressed + */ +void +DoSet(argv) +char **argv; +{ + char *p; + static char buf[256]; + + p = buf; + debug("DoSet\n"); + if (!argv || !*argv || !**argv) + { + debug("empty DoSet\n"); + sprintf(buf, "set "); + RcLine(buf); + return; + } + sprintf(p, "set"); p+=3; + while(*argv && (strlen(buf) + strlen(*argv) < 255)) + { + sprintf(p, " %s", *argv++); + p += strlen(p); + } + RcLine(buf); +} + +/* * "$HOST blafoo" -> "localhost blafoo" * "${HOST}blafoo" -> "localhostblafoo" * "\$HOST blafoo" -> "$HOST blafoo" @@ -290,24 +632,17 @@ char *rcfilename; * "'$HOST ${HOST}'" -> "'$HOST ${HOST}'" * "'\$HOST'" -> "'\$HOST'" * "\'$HOST' $HOST" -> "'localhost' $HOST" - * - * "$:termcapname:" -> "termcapvalue" - * "$:terminfoname:" -> "termcapvalue" - * - * "\101" -> "A" */ -char * -expand_vars(ss) +static char *expand_env_vars(ss) char *ss; { static char ebuf[2048]; - register int esize = 2047, vtype, quofl = 0; + register int esize = 2047, quofl = 0; register char *e = ebuf; register char *s = ss; register char *v; - char xbuf[11]; - while (*s && *s != '\0' && *s != '\n' && esize > 0) + while (*s && *s != '\n' && esize > 0) { if (*s == '\'') quofl ^= 1; @@ -316,99 +651,45 @@ char *ss; char *p, c; p = ++s; - switch (*s) + if (*s == '{') { - case '{': p = ++s; while (*p != '}') if (*p++ == '\0') return ss; - vtype = 0; /* env var */ - break; - case ':': - p = ++s; - while (*p != ':') - if (*p++ == '\0') - return ss; - vtype = 1; /* termcap string */ - break; - default: + } + else + { while (*p != ' ' && *p != '\0' && *p != '\n') p++; - vtype = 0; /* env var */ } c = *p; debug1("exp: c='%c'\n", c); *p = '\0'; - if (vtype == 0) - { - v = xbuf; - if (strcmp(s, "TERM") == 0) - v = display ? d_termname : "unknown"; - else if (strcmp(s, "COLUMNS") == 0) - sprintf(xbuf, "%d", display ? d_width : -1); - else if (strcmp(s, "LINES") == 0) - sprintf(xbuf, "%d", display ? d_height : -1); - else - v = getenv(s); - } - else - v = gettermcapstring(s); - if (v) + if (v = getenv(s)) { debug2("exp: $'%s'='%s'\n", s, v); while (*v && esize-- > 0) *e++ = *v++; } else - debug1("exp: '%s' not env\n", s); /* {-: */ - if ((*p = c) == '}' || c == ':') + debug1("exp: '%s' not env\n", s); + if ((*p = c) == '}') p++; s = p; } else { - /* - * \$, \\$, \\, \\\, \012 are reduced here, - * d_other sequences starting whith \ are passed through. - */ if (s[0] == '\\' && !quofl) - { - if (s[1] >= '0' && s[1] <= '7') - { - int i; - - s++; - i = *s - '0'; - s++; - if (*s >= '0' && *s <= '7') - { - i = i * 8 + *s - '0'; - s++; - if (*s >= '0' && *s <= '7') - { - i = i * 8 + *s - '0'; - s++; - } - } - debug2("expandvars: octal coded character %o (%d)\n", i, i); - *e++ = i; - } - else - { - if (s[1] == '$' || - (s[1] == '\\' && s[2] == '$') || - s[1] == '\'' || - (s[1] == '\\' && s[2] == '\'')) - s++; - } - } + if (s[1] == '$' || (s[1] == '\\' && s[2] == '$') || + s[1] == '\'' || (s[1] == '\\' && s[2] == '\'')) + s++; *e++ = *s++; esize--; } } if (esize <= 0) - Msg(0, "expand_vars: buffer overflow\n"); + Msg(0, "expand_env_vars: buffer overflow\n"); *e = '\0'; return ebuf; } @@ -417,21 +698,818 @@ void RcLine(ubuf) char *ubuf; { - char *args[MAXARGS], *buf; - struct action act; + char *args[MAXARGS]; + register char *buf, *p, **pp, **ap; + register int argc, setflag; + int q, qq; + char key; + int low, high, mid, x; - buf = expand_vars(ubuf); - if (Parse(buf, args) <= 0) - return; - if ((act.nr = FindCommnr(*args)) == RC_ILLEGAL) + buf = expand_env_vars(ubuf); + + ap = args; + + if ((p = rindex(buf, '\n')) != NULL) + *p = '\0'; + if (strncmp("set ", buf, 4) == 0) + { + buf += 4; + setflag = 1; + debug1("RcLine: '%s' is a set command\n", buf); + } + else if (strncmp("se ", buf, 3) == 0) { - Msg(0, "%s: unknown command '%s'", rc_name, *args); + buf += 3; + setflag = 1; + debug1("RcLine: '%s' is a se command\n", buf); + } + else + { + setflag = 0; + debug1("RcLine: '%s'\n", buf); + } + if ((argc = Parse(buf, ap)) == 0) + { + if (setflag) + { + DeadlyMsg = 0; + Msg(0, "%s: set what?\n", rc_name); + } return; } - act.args = args + 1; - DoAction(&act, -1); + + low = 0; + high = (int)RC_RCEND - 1; + while (low <= high) + { + mid = (low + high) / 2; + x = strcmp(ap[0], RCNames[mid]); + if (x < 0) + high = mid - 1; + else if (x > 0) + low = mid + 1; + else + break; + } + if (low > high) + mid = (int)RC_RCEND; + switch ((enum RCcases) mid) + { + case RC_ESCAPE: + if (argc != 2 || !ParseEscape(ap[1])) + { + DeadlyMsg = 0; + Msg(0, "%s: two characters required after escape.", rc_name); + return; + } + if (Esc != MetaEsc) + ktab[Esc].type = KEY_OTHER; + else + ktab[Esc].type = KEY_IGNORE; + return; + case RC_CHDIR: + if (setflag) + break; + p = argc < 2 ? home : ap[1]; + if (chdir(p) == -1) + { + DeadlyMsg = 0; + Msg(errno, "%s", p); + } + return; + case RC_SHELL: + ParseSaveStr(argc, ap, &ShellProg, "shell"); + ShellArgs[0] = ShellProg; + return; + case RC_SHELLAKA: + ParseSaveStr(argc, ap, &shellaka, "shellaka"); + return; + case RC_SCREEN: + if (setflag) + break; + DoScreen(rc_name, ap + 1); + return; + case RC_SLEEP: + case RC_TERMCAP: + case RC_TERMINFO: + return; /* Already handled */ + case RC_TERM: + { + char *tmp = NULL; + + ParseSaveStr(argc, ap, &tmp, "term"); + if (!tmp) + return; + if (strlen(tmp) >= 20) + { + DeadlyMsg = 0; + Msg(0,"%s: term: argument too long ( < 20)", rc_name); + Free(tmp); + return; + } + strcpy(screenterm, args[1]); + Free(tmp); + debug1("screenterm set to %s\n", screenterm); + MakeTermcap(0); + return; + } + case RC_ECHO: + if (HasWindow && *rc_name == '\0') + { + /* + * user typed ^A:echo... well, echo isn't FinishRc's job, + * but as he wanted to test us, we show good will + */ + DeadlyMsg = 0; + if (argc == 2 || (argc == 3 && !strcmp(ap[1], "-n"))) + Msg(0, "%s", ap[argc - 1]); + else + Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name); + } + return; + case RC_BELL: + ParseSaveStr(argc, ap, &BellString, "bell"); + return; + case RC_BUFFERFILE: + ParseSaveStr(argc, ap, &BufferFile, "bufferfile"); + return; + case RC_ACTIVITY: + ParseSaveStr(argc, ap, &ActivityString, "activity"); + return; + case RC_POW_DETACH_MSG: + ParseSaveStr(argc, ap, &PowDetachString, "pow_detach"); + return; + case RC_LOGIN: +#ifdef UTMPOK + q = loginflag; + ParseOnOff(argc, ap, &loginflag); + if (fore && setflag) + { + SlotToggle(loginflag?(1):(-1)); + loginflag = q; + } +#endif + return; + case RC_FLOW: + if (argc == 3 && ap[2][0] == 'i') + { + iflag = 1; + argc--; + } + if (argc == 2 && ap[1][0] == 'a') + default_flow = FLOW_AUTOFLAG; + else + ParseOnOff(argc, ap, &default_flow); + return; + case RC_WRAP: + ParseOnOff(argc, ap, &wrap); + return; + case RC_HARDSTATUS: + ParseOnOff(argc, ap, &use_hardstatus); + if (use_hardstatus) + HS = termcapHS; + else + HS = 0; + return; + case RC_MONITOR: + { + int f; + + ParseOnOff(argc, ap, &f); + if (fore && setflag) + fore->monitor = (f == 0) ? MON_OFF : MON_ON; + else + default_monitor = (f == 0) ? MON_OFF : MON_ON; + } + return; + case RC_REDRAW: + case RC_REFRESH: + { + int r; + + ParseOnOff(argc, ap, &r); + if (fore && setflag) + fore->norefresh = (r) ? 0 : 1; + else + { + all_norefresh = (r) ? 0 : 1; + if (all_norefresh) + Msg(0, "No refresh on window change!\n"); + else + Msg(0, "Window specific refresh\n"); + } + } + return; + case RC_VBELL: + case RC_VISUALBELL: + ParseOnOff(argc, ap, &visual_bell); + return; + case RC_VBELLWAIT: + ParseNum(argc, ap, &VBellWait); + if (fore && rc_name[0] == '\0') + Msg(0, "vbellwait set to %d seconds", VBellWait); + return; + case RC_MSGWAIT: + ParseNum(argc, ap, &MsgWait); + if (fore && rc_name[0] == '\0') + Msg(0, "msgwait set to %d seconds", MsgWait); + return; + case RC_MSGMINWAIT: + ParseNum(argc, ap, &MsgMinWait); + if (fore && rc_name[0] == '\0') + Msg(0, "msgminwait set to %d seconds", MsgMinWait); + return; + case RC_SCROLLBACK: + if (fore && setflag) + { + int i; + + ParseNum(argc, ap, &i); + ChangeScrollback(fore, i, fore->width); + if (fore && rc_name[0] == '\0') + Msg(0, "scrollback set to %d", fore->histheight); + } + else + ParseNum(argc, ap, &default_histheight); + return; + case RC_SLOWPASTE: + ParseNum(argc, ap, &slowpaste); + if (fore && rc_name[0] == '\0') + Msg(0, "slowpaste set to %d milliseconds", slowpaste); + return; + case RC_MARKKEYS: + { + char *tmp = NULL; + + ParseSaveStr(argc, ap, &tmp, "markkeys"); + if (CompileKeys(ap[1], mark_key_tab)) + { + DeadlyMsg = 0; + Msg(0, "%s: markkeys: syntax error.", rc_name); + Free(tmp); + return; + } + debug1("markkeys %s\n", ap[1]); + Free(tmp); + return; + } +#ifdef NETHACK + case RC_NETHACK: + ParseOnOff(argc, ap, &nethackflag); + return; +#endif + case RC_HARDCOPY_APP: + ParseOnOff(argc, ap, &hardcopy_append); + return; + case RC_VBELL_MSG: + case RC_VISUALBELL_MSG: + ParseSaveStr(argc, ap, &VisualBellString, "vbell_msg"); + debug1(" new vbellstr '%s'\n", VisualBellString); + return; + case RC_MODE: + if (argc != 2) + { + DeadlyMsg = 0; + Msg(0, "%s: mode: one argument required.", rc_name); + return; + } + if (!IsNum(ap[1], 7)) + { + DeadlyMsg = 0; + Msg(0, "%s: mode: octal number expected.", rc_name); + return; + } + (void) sscanf(ap[1], "%o", &TtyMode); + return; + case RC_CRLF: + ParseOnOff(argc, ap, &join_with_cr); + return; + case RC_AUTODETACH: + ParseOnOff(argc, ap, &auto_detach); + return; + case RC_STARTUP_MESSAGE: + ParseOnOff(argc, ap, &default_startup); + return; +#ifdef PASSWORD + case RC_PASSWORD: + CheckPassword = 1; + if (argc >= 2) + { + strncpy(Password, ap[1], sizeof Password); + if (!strcmp(Password, "none")) + CheckPassword = 0; + } + else + { + char *mstr = 0; + int msleep = 0, st; + char salt[2]; + +#ifdef POSIX + if (HasWindow) + { + Msg(0, "Cannot ask for password on POSIX systems"); + return; + } +#endif + /* there is a clear screen sequence in the buffer. */ + fflush(stdout); + if (HasWindow) + { + ClearDisplay(); + SetTTY(0, &OldMode); + } + strncpy(Password, getpass("New screen password:"), + sizeof(Password)); + if (strcmp(Password, getpass("Retype new password:"))) + { +#ifdef NETHACK + if (nethackflag) + mstr = "[ Passwords don't match - your armor crumbles away ]"; + else +#endif + mstr = "[ Passwords don't match - checking turned off ]"; + msleep = 1; + CheckPassword = 0; + } + if (Password[0] == '\0') + { + CheckPassword = 0; + mstr = "[ No password - no secure ]"; + msleep = 1; + } + for (st=0; st<2; st++) + salt[st] = 'A' + (int)((time(0) >> 6*st) % 26); + strncpy(Password, crypt(Password, salt), sizeof(Password)); + if (CheckPassword) + { +#ifdef COPY_PASTE + if (copybuffer) + + Free(copybuffer); + copylen = strlen(Password); + if ((copybuffer = (char *) malloc(copylen+1)) == NULL) + { + Msg_nomem; + return; + } + strcpy(copybuffer, Password); + mstr = "[ Password moved into copybuffer ]"; + msleep = 1; +#else /* COPY_PASTE */ + mstr = "[ Crypted password is \"%s\" ]"; + msleep = 5; +#endif /* COPY_PASTE */ + } + if (HasWindow) + { + SetTTY(0, &NewMode); + Activate(0); /* Redraw */ + if (mstr) + { + Msg(0, mstr, Password); + } + } + else + { + if (mstr) + { + printf(mstr, Password); + putchar('\n'); + sleep(msleep); + } + ClearDisplay(); + } + } + debug1("finishrc: our password is: --%s%-- \n", Password); + return; +#endif /* PASSWORD */ + case RC_ALL: + if (!setflag || !HasWindow || *rc_name) + break; + display_help(); + return; + case RC_BIND: + if (setflag) + break; + p = ap[1]; + if (argc < 2 || *p == '\0') + { + DeadlyMsg = 0; + Msg(0, "%s: key expected after bind.", rc_name); + return; + } + if ((p = ParseChar(p, &key)) == NULL || *p) + { + DeadlyMsg = 0; + Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.", + rc_name); + return; + } + if (ktab[key].type != KEY_IGNORE) + { + ktab[key].type = KEY_IGNORE; + if ((pp = ktab[key].args) != NULL) + { + for (; *pp; pp++) + Free(*pp); + Free(ktab[key].args); + } + } + if (argc > 2) + { + for (pp = KeyNames; *pp; ++pp) + if (strcmp(ap[2], *pp) == 0) + break; + if (*pp) + { + ktab[key].type = (enum keytype) (pp - KeyNames + 1); + if (argc > 3) + { + ktab[key].args = SaveArgs(argc - 3, ap + 3); + } + else + ktab[key].args = NULL; + } + else + { + ktab[key].type = KEY_CREATE; + ktab[key].args = SaveArgs(argc - 2, ap + 2); + } + } + return; + case RC_RCEND: + default: + { + char ibuf[3]; + /* + * now we are user-friendly: + * if anyone typed a key name like "help" or "next" ... + * we did not match anything above. so look in the KeyNames table. + */ + debug1("--ap[0] %s\n", ap[0]); + for (pp = KeyNames; *pp; ++pp) + if (strcmp(ap[0], *pp) == 0) + break; + if (*pp == 0) + break; + + ibuf[0] = Esc; + ibuf[1] = pp - KeyNames +1; + debug1("RcLine: it was a keyname: '%s'\n", *pp); + q = 2; qq = 0; + if (HasWindow) + ProcessInput(ibuf, &q, (char *)0, &qq, 0); + else + { + DeadlyMsg = 0; + Msg(0, "%s: Key '%s' has no effect while no window open...\n", + rc_name, ap[0]); + } + } + return; + } + DeadlyMsg = 0; + Msg(0, "%s: unknown %skeyword \"%s\"", rc_name, + setflag?"'set' ":"", ap[0]); +} + +static int +Parse(buf, args) +char *buf, **args; +{ + register char *p = buf, **ap = args; + register int delim, argc; + + argc = 0; + for (;;) + { + while (*p && (*p == ' ' || *p == '\t')) + ++p; + if (*p == '\0' || *p == '#') + { + *p = '\0'; + return argc; + } + if (argc > MAXARGS - 1) + Msg(0, "%s: too many tokens.", rc_name); + delim = 0; + if (*p == '"' || *p == '\'') + delim = *p++; + argc++; + *ap = p; + *++ap = 0; + while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t'))) + ++p; + if (*p == '\0') + { + if (delim) + { + DeadlyMsg = 0; + Msg(0, "%s: Missing quote.", rc_name); + return 0; + } + return argc; + } + *p++ = '\0'; + } +} + +int +ParseEscape(p) +char *p; +{ + if ((p = ParseChar(p, &Esc)) == NULL || + (p = ParseChar(p, &MetaEsc)) == NULL || *p) + return 0; + return 1; +} + +static void +ParseNum(argc, ap, var) +int argc; +char *ap[]; +int *var; +{ + int i; + char *p; + + if (argc == 2 && ap[1][0] != '\0') + { + i = 0; + p = ap[1]; + while (*p) + { + if (*p >= '0' && *p <= '9') + i = 10 * i + (*p - '0'); + else + { + DeadlyMsg = 0; + Msg(0, "%s: %s: invalid argument. Give numeric argument", + rc_name, ap[0]); + return; + } + p++; + } + } + else + { + DeadlyMsg = 0; + Msg(0, "%s: %s: invalid argument. Give one argument", + rc_name, ap[0]); + return; + } + debug1("ParseNum got %d\n", i); + *var = i; +} + +static void +ParseSaveStr(argc, ap, var, title) +int argc; +char *ap[]; +char **var; +char *title; +{ + if (argc != 2) + { + DeadlyMsg = 0; + Msg(0, "%s: %s: one argument required.", rc_name, title); + return; + } + if (*var) + Free(*var); + *var = SaveStr(ap[1]); + return; +} + +static void +ParseOnOff(argc, ap, var) +int argc; +char *ap[]; +int *var; +{ + register int num = -1; + + if (argc == 2 && ap[1][0] == 'o') + { + if (ap[1][1] == 'f') + num = 0; + else if (ap[1][1] == 'n') + num = 1; + } + if (num < 0) + { + DeadlyMsg = 0; + Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, ap[0]); + return; + } + *var = num; +} + + +static int IsNum(s, base) +register char *s; +register int base; +{ + for (base += '0'; *s; ++s) + if (*s < '0' || *s > base) + return 0; + return 1; } +static int IsNumColon(s, base, p, psize) +int base, psize; +char *s, *p; +{ + char *q; + if ((q = rindex(s, ':')) != NULL) + { + strncpy(p, q + 1, psize - 1); + p[psize - 1] = '\0'; + *q = '\0'; + } + else + *p = '\0'; + return IsNum(s, base); +} + +void +SlotToggle(how) +int how; +/* + * how = 0 real toggle mode + * how > 0 do try to set a utmp slot. + * how < 0 try to withdraw a utmp slot + * + * slot = -1 window not logged in. + * slot = 0 window not logged in, but should be logged in. + * (unable to write utmp, or detached). + */ +{ + debug1("SlotToggle %d\n", how); + if (how == 0) + how = (fore->slot == (slot_t) -1)?(1):(-1); + /* + * slot 0 or active -> we try to log out. + * slot -1 -> we try to log in. + */ +#ifdef UTMPOK + if (how > 0) + { + debug(" try to log in\n"); + if ((fore->slot == (slot_t) -1) || (fore->slot == (slot_t) 0)) + { +#ifdef USRLIMIT + if (CountUsers() >= USRLIMIT) + Msg(0, "User limit reached."); + else +#endif + { + if (SetUtmp(fore, ForeNum) == 0) + Msg(0, "This window is now logged in."); + else + Msg(0, "This window should now be logged in."); + } + } + else + Msg(0, "This window is already logged in."); + } + else if (how < 0) + { + debug(" try to log out\n"); + if (fore->slot == (slot_t) -1) + Msg(0, "This window is already logged out\n"); + else if (fore->slot == (slot_t) 0) + { + debug("What a relief! In fact, it was not logged in\n"); + Msg(0, "This window is not logged in."); + fore->slot = (slot_t) -1; + } + else + { + RemoveUtmp(fore); + if (fore->slot != (slot_t) -1) + Msg(0, "What? Cannot remove Utmp slot?"); + else + Msg(0, "This window is no longer logged in."); + } + } +#else /* !UTMPOK */ + Msg(0, "Unable to modify %s.\n", UTMPFILE); +#endif +} + +void +DoScreen(fn, av) +char *fn, **av; +{ + register int flowflag, num, lflag = loginflag, aflag = 0; + register char *aka = NULL; + register int histheight = default_histheight; + char buf[20]; + char termbuf[25]; + char *termp; + char *args[2]; + + flowflag = default_flow; + termbuf[0] = '\0'; + termp = NULL; + while (av && *av && av[0][0] == '-') + { + switch (av[0][1]) + { + case 'f': + switch (av[0][2]) + { + case 'n': + case '0': + flowflag = FLOW_NOW * 0; + break; + case 'y': + case '1': + case '\0': + flowflag = FLOW_NOW * 1; + break; + case 'a': + flowflag = FLOW_AUTOFLAG; + break; + default: + break; + } + break; + case 'k': + case 't': + if (av[0][2]) + aka = &av[0][2]; + else if (*++av) + aka = *av; + else + --av; + break; + case 'T': + if (av[0][2]) + termp = &av[0][2]; + else if (*++av) + termp = *av; + else + --av; + break; + case 'h': + if (av[0][2]) + histheight = atoi(av[0] + 2); + else if (*++av) + histheight = atoi(*av); + else + --av; + break; + case 'l': + switch (av[0][2]) + { + case 'n': + case '0': + lflag = 0; + break; + case 'y': + case '1': + case '\0': + lflag = 1; + break; + default: + break; + } + break; + case 'a': + aflag = 1; + break; + default: + Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]); + break; + } + ++av; + } + num = 0; + if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf))) + { + if (*buf != '\0') + aka = buf; + num = atoi(*av); + if (num < 0 || num > MAXWIN - 1) + { + Msg(0, "%s: illegal screen number %d.", fn, num); + num = 0; + } + ++av; + } + if (!av || !*av) + { + av = args; + av[0] = ShellProg; + av[1] = NULL; + if (!aka) + aka = shellaka; + } + MakeWindow(aka, av, aflag, flowflag, num, (char *) 0, lflag, histheight, termp); +} void WriteFile(dump) @@ -457,19 +1535,14 @@ int dump; strcpy(fn + i, ".termcap"); break; case DUMP_HARDCOPY: - if (hardcopydir) - sprintf(fn, "%s/hardcopy.%d", hardcopydir, fore->w_number); - else - sprintf(fn, "hardcopy.%d", fore->w_number); + sprintf(fn, "hardcopy.%d", ForeNum); if (hardcopy_append && !access(fn, W_OK)) mode = "a"; break; -#ifdef COPY_PASTE case DUMP_EXCHANGE: sprintf(fn, "%s", BufferFile); umask(0); break; -#endif } debug2("WriteFile(%d) %s\n", dump, fn); @@ -489,22 +1562,22 @@ int dump; if (*mode == 'a') { putc('>', f); - for (j = d_width - 2; j > 0; j--) + for (j = screenwidth - 2; j > 0; j--) putc('=', f); fputs("<\n", f); } - for (i = 0; i < d_height; i++) + for (i = 0; i < screenheight; ++i) { - p = fore->w_image[i]; - for (k = d_width - 1; k >= 0 && p[k] == ' '; k--) + p = fore->image[i]; + for (k = screenwidth - 1; k >= 0 && p[k] == ' '; --k) ; - for (j = 0; j <= k; j++) + for (j = 0; j <= k; ++j) putc(p[j], f); putc('\n', f); } break; case DUMP_TERMCAP: - if ((p = index(MakeTermcap(fore->w_aflag), '=')) != NULL) + if ((p = index(MakeTermcap(fore->aflag), '=')) != NULL) { fputs(++p, f); putc('\n', f); @@ -512,8 +1585,8 @@ int dump; break; #ifdef COPY_PASTE case DUMP_EXCHANGE: - p = d_copybuffer; - for (i = 0; i < d_copylen; i++) + p = copybuffer; + for (i = 0; i < copylen; i++) putc(*p++, f); break; #endif @@ -566,33 +1639,33 @@ ReadFile() return; } size = stb.st_size; - if (d_copybuffer) - free(d_copybuffer); - d_copylen = 0; - if ((d_copybuffer = malloc(size)) == NULL) + if (copybuffer) + Free(copybuffer); + copylen = 0; + if ((copybuffer = malloc(size)) == NULL) { close(i); - Msg(0, strnomem); + Msg_nomem; return; } errno = 0; - if ((l = read(i, d_copybuffer, size)) != size) + if ((l = read(i, copybuffer, size)) != size) { - d_copylen = (l > 0) ? l : 0; + copylen = (l > 0) ? l : 0; #ifdef NETHACK if (nethackflag) - Msg(errno, "You choke on your food: %d bytes", d_copylen); + Msg(errno, "You choke on your food: %d bytes", copylen); else #endif - Msg(errno, "Got only %d bytes from %s", d_copylen, fn); + Msg(errno, "Got only %d bytes from %s", copylen, fn); close(i); return; } - d_copylen = l; + copylen = l; if (read(i, &c, 1) > 0) - Msg(0, "Slurped only %d characters into buffer - try again", d_copylen); + Msg(0, "Slurped only %d characters into buffer - try again", copylen); else - Msg(0, "Slurped %d characters into buffer", d_copylen); + Msg(0, "Slurped %d characters into buffer", copylen); close(i); return; } @@ -603,28 +1676,743 @@ KillBuffers() char fn[1024]; sprintf(fn, "%s", BufferFile); errno = 0; -#ifndef NOREUID - setreuid(eff_uid, real_uid); - setregid(eff_gid, real_gid); -#else if (access(fn, W_OK) == -1) { Msg(errno, "%s not removed", fn); return; } + else + { + unlink(fn); + Msg(errno, "%s removed", fn); + } +} +#endif /* COPY_PASTE */ + +#ifdef USRLIMIT +CountUsers() +{ +#ifdef GETUTENT + struct utmp *ut, *getutent(); +#else + struct utmp utmpbuf; #endif - unlink(fn); - Msg(errno, "%s removed", fn); -#ifndef NOREUID - setreuid(real_uid, eff_uid); - setregid(real_gid, eff_gid); + int UserCount; + + debug1("CountUsers() - utmp=%d\n",utmp); + if (!utmp) + return(0); + UserCount = 0; +#ifdef GETUTENT + setutent(); + while (ut = getutent()) + if (ut->ut_type == USER_PROCESS) + UserCount++; +#else + (void) lseek(utmpf, (off_t) 0, 0); + while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0) + { + if (utmpbuf.ut_name[0] != '\0') + UserCount++; + } #endif + return(UserCount); +} +#endif + +#ifdef UTMPOK + +static slot_t loginslot; +static struct utmp utmp_logintty; +#ifdef _SEQUENT_ +static char loginhost[100+1]; +#endif + +void +InitUtmp() +{ + debug("InitUtmp testing...\n"); + if ((utmpf = open(UtmpName, O_RDWR)) == -1) + { + if (errno != EACCES) + Msg(errno, UtmpName); + debug("InitUtmp failed.\n"); + utmp = 0; + return; + } +#ifdef GETUTENT + close(utmpf); + utmpf= -1; +#endif +#ifdef MIPS + if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) + { + if (errno != EACCES) + Msg(errno, UtmpName); + return; + } +#endif + utmp = 1; +#ifndef apollo + ReInitUtmp(); +#endif +} + +void +ReInitUtmp() +{ +#ifndef apollo + if (!utmp) + { + debug("Reinitutmp: utmp == 0\n"); + return; + } +#endif + debug("(Re)InitUtmp: removing your logintty\n"); + loginslot = TtyNameSlot(display_tty); + if (loginslot!=(slot_t)0 && loginslot!=(slot_t)-1) + { +#ifdef _SEQUENT_ + if (p=ut_find_host(loginslot)) + strncpy(loginhost, p, 100); +#endif + RemoveLoginSlot(loginslot, &utmp_logintty); + } + debug1(" slot %d zapped\n", loginslot); +} + +void +RestoreLoginSlot() +{ + debug("RestoreLoginSlot()\n"); +#ifdef apollo + InitUtmp(); +#endif + if (utmp && loginslot!=(slot_t)0 && loginslot!=(slot_t)-1) + { +#ifdef GETUTENT +# ifdef _SEQUENT_ + int fail; + debug1(" logging you in again (slot %s)\n", loginslot); +/* + * We have problems if we add the console and use ut_add_user() + * because the id will be 'scon' instead of 'co'. So we + * restore it with pututline(). The reason why we don't use + * pututline all the time is that we want to set the host field. + * Unfortunatelly this can only be done with ut_add_user(). + */ + if (*loginhost) + { + fail = (ut_add_user(LoginName, loginslot, utmp_logintty.ut_pid, + *loginhost?loginhost:(char *)0) == 0); + } + else + { + setutent(); + fail = (pututline(&utmp_logintty) == 0); + } + if (fail) +# else /* _SEQUENT_ */ + debug1(" logging you in again (slot %s)\n", loginslot); + setutent(); + if (pututline(&utmp_logintty)==0) +# endif /* _SEQUENT */ +#else /* GETUTENT */ + debug1(" logging you in again (slot %d)\n", loginslot); +# ifdef sequent + /* call sequent undocumented routine to count logins and add utmp entry if possible */ + if (add_utmp(loginslot, &utmp_logintty) == -1) +# else + (void) lseek(utmpf, (off_t) (loginslot * sizeof(struct utmp)), 0); + if (write(utmpf, (char *) &utmp_logintty, sizeof(struct utmp)) + != sizeof(struct utmp)) +# endif /* sequent */ +#endif /* GETUTENT */ + { +#ifdef NETHACK + if (nethackflag) + Msg(errno, "%s is too hard to dig in.", UTMPFILE); + else +#endif + Msg(errno,"Could not write %s.", UTMPFILE); + } + } +#ifdef apollo + close(utmpf); +#endif + loginslot = (slot_t) 0; +} + +void +RemoveLoginSlot(slot, up) +slot_t slot; +struct utmp *up; +{ +#ifdef GETUTENT + struct utmp *uu; +#endif + struct utmp u; +#ifdef apollo + struct utmp *uq; +#endif + +#ifdef GETUTENT + debug2("RemoveLoginSlot(%s, %08x)\n", (slot == (slot_t) 0 || + slot == (slot_t) -1 ) ? "no slot" : slot, up); +#else + debug2("RemoveLoginSlot(%d, %08x)\n", slot, up); +#endif +#ifdef apollo + InitUtmp(); + bzero((char *)up, sizeof(struct utmp)); + uq = (struct utmp *)malloc(sizeof(struct utmp)); + bzero((char *)uq, sizeof(struct utmp)); +#endif /* apollo */ + if (!utmp) + return; + if (slot != (slot_t) 0 && slot != (slot_t) -1) + { + bzero((char *) &u, sizeof u); +#ifdef GETUTENT + setutent(); + strncpy(u.ut_line, slot, sizeof(u.ut_line)); + if ((uu = getutline(&u)) == 0) + { + DeadlyMsg = 0; + Msg(0, "Utmp slot not found -> not removed"); + return; + } + *up= *uu; +# ifdef _SEQUENT_ + if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0) +# else + uu->ut_type = DEAD_PROCESS; + uu->ut_exit.e_termination = 0; + uu->ut_exit.e_exit= 0; + if (pututline(uu) == 0) +# endif +#else + (void) lseek(utmpf, (off_t) (slot * sizeof u), 0); + if (read(utmpf, (char *) up, sizeof u) != sizeof u) + { + DeadlyMsg = 0; + Msg(errno, "cannot read %s ???", UTMPFILE); + sleep(1); + } + (void) lseek(utmpf, (off_t) (slot * sizeof u), 0); +# ifdef apollo + bcopy((char *)up, (char *)uq, sizeof(struct utmp)); + bzero(uq->ut_name, sizeof(uq->ut_name)); + bzero(uq->ut_host, sizeof(uq->ut_host)); + if (write(utmpf, (char *)uq, sizeof(struct utmp)) != sizeof(struct utmp)) +# else + if (write(utmpf, (char *) &u, sizeof u) != sizeof u) +# endif /* apollo */ +#endif + { +#ifdef NETHACK + if (nethackflag) + { + DeadlyMsg = 0; + Msg(errno, "%s is too hard to dig in.", UTMPFILE); + } + else +#endif + { + DeadlyMsg = 0; + Msg(errno, "Could not write %s.", UTMPFILE); + } + } + } + else + { + debug1("There is no utmp-slot to be removed(%d)\n", slot); + } +#ifdef apollo + close(utmpf); + free(uq); +#endif +} + +char * +stripdev(nam) +char *nam; +{ +#ifdef apollo + char *p; + + if (nam == NULL) + return NULL; + if (p = strstr(nam,"/dev/")) + return p + 5; +#else + if (nam == NULL) + return NULL; + if (strncmp(nam, "/dev/", 5) == 0) + return nam + 5; +#endif + return nam; } -#endif /* COPY_PASTE */ +static slot_t TtyNameSlot(nam) +char *nam; +{ + char *name; + register slot_t slot; +#ifndef GETUTENT + register struct ttyent *tp; +#endif +#ifdef apollo + struct utmp *up; +#endif + + debug1("TtyNameSlot(%s)\n", nam); +#ifdef apollo + InitUtmp(); +#endif + if (!utmp || nam == NULL) + return (slot_t)0; + name = stripdev(nam); +#ifdef GETUTENT + slot = name; +#else +# ifdef apollo + slot = 0; + up = (struct utmp *)malloc(sizeof(struct utmp)); + while (1) + { + if ((read(utmpf, (char *)up, sizeof(struct utmp)) == + sizeof(struct utmp)) && (strcmp(up->ut_line, name))) + slot++; + else + break; + } + close(utmpf); + free(up); +# else /* !apollo */ + slot = 1; + setttyent(); + while ((tp = getttyent()) != NULL && strcmp(name, tp->ty_name) != 0) + { + debug2("'%s' %d, ", tp->ty_name, slot); + ++slot; + } + debug("\n"); +# ifdef MIPS + if (tp == NULL) + { + slot = CreateUtmp(name); + } +# endif /* MIPS */ +# endif /* apollo */ +#endif /* GETUTENT */ + return slot; +} + +int +SetUtmp(wi, displaynumber) +struct win *wi; +int displaynumber; +{ + register char *p; + register slot_t slot; + char *line; + struct utmp u; +#ifdef UTHOST +# ifdef _SEQUENT_ + char host[100+5]; +# else + char host[sizeof(utmp_logintty.ut_host)+5]; +# endif +#endif + + wi->slot = (slot_t) 0; + if (!utmp) + return -1; + if ((slot = TtyNameSlot(wi->tty)) == (slot_t) NULL) + { + debug1("SetUtmp failed (tty %s).\n",wi->tty); + return -1; + } + debug2("SetUtmp %d will get slot %d...\n", displaynumber, (int)slot); +#ifdef apollo + InitUtmp(); +#endif + +#ifdef UTHOST + host[sizeof(host)-5] = '\0'; +# ifdef _SEQUENT_ + strncpy(host, loginhost, sizeof(host) - 5); +# else + strncpy(host, utmp_logintty.ut_host, sizeof(host) - 5); +# endif + if (loginslot != (slot_t)0 && loginslot != (slot_t)-1 && host[0] != '\0') + { + /* + * we want to set our ut_host field to something like + * ":ttyhf:s.0" or + * "faui45:s.0" or + * "132.199.81.4:s.0" (even this may hurt..), but not + * "faui45.informati"......:s.0 + */ + for (p = host; *p; p++) + { + if ((*p < '0' || *p > '9') && (*p != '.')) + break; + } + if (*p) + { + for (p = host; *p; p++) + { + if (*p == '.') + { + *p = '\0'; + break; + } + } + } + } + else + { + strncpy(host + 1, stripdev(display_tty), sizeof(host) - 6); + host[0] = ':'; + } + debug1("rlogin hostname: '%s'\n", host); + sprintf(host + strlen(host), ":S.%c", '0' + displaynumber); + debug1("rlogin hostname: '%s'\n", host); +#endif /* UTHOST */ + + line = stripdev(wi->tty); + bzero((char *) &u, sizeof u); + +#ifdef GETUTENT +# ifdef _SEQUENT_ + if (ut_add_user(LoginName, slot, wi->wpid, host)==0) +# else + strncpy(u.ut_user, LoginName, sizeof(u.ut_user)); + strncpy(u.ut_id, line + strlen(line) - 2, sizeof(u.ut_id)); + strncpy(u.ut_line, line, sizeof(u.ut_line)); + u.ut_pid = wi->wpid; + u.ut_type = USER_PROCESS; +# ifdef SVR4 + (void) time(&u.ut_tv.tv_sec); + u.ut_tv.tv_usec=0; +# else + (void) time(&u.ut_time); +# endif /* SVR4 */ +# ifdef UTHOST + strncpy(u.ut_host, host, sizeof(u.ut_host)); +# endif /* UTHOST */ + if (pututline(&u) == 0) +# endif /* _SEQUENT_ */ +#else /* GETUTENT */ + strncpy(u.ut_line, line, sizeof(u.ut_line)); + strncpy(u.ut_name, LoginName, sizeof(u.ut_name)); +# ifdef UTHOST + strncpy(u.ut_host, host, sizeof(u.ut_host)); +# endif /* UTHOST */ +# ifdef MIPS + u.ut_type = 7; /* USER_PROCESS */ + strncpy(u.ut_id, line + 3, 4); +# endif /* MIPS */ + (void) time(&u.ut_time); +# ifdef sequent +/* call sequent undocumented routine to count logins and add utmp entry if possible */ + if (add_utmp(slot, &u) == -1) +# else + (void) lseek(utmpf, (off_t) (slot * sizeof u), 0); + if (write(utmpf, (char *) &u, sizeof u) != sizeof u) +# endif /* sequent */ +#endif /* GETUTENT */ + + { +#ifdef NETHACK + if (nethackflag) + Msg(errno, "%s is too hard to dig in.", UTMPFILE); + else +#endif + Msg(errno,"Could not write %s.", UTMPFILE); +#ifdef apollo + close(utmpf); +#endif + return -1; + } + debug("SetUtmp successful\n"); + wi->slot = slot; +#ifdef apollo + close(utmpf); +#endif + return 0; +} + +#ifdef MIPS + +#define GETTTYENT +static int ttyfd = 0; + +static void setttyent() +{ + if (ttyfd) + close(ttyfd); + ttyfd = open(UtmpName, O_RDONLY); +} + +static struct ttyent *getttyent() +{ + static struct utmp u; + static struct ttyent t; + + if (!ttyfd) + return NULL; + + if (read(ttyfd, &u, sizeof u)) + { + t.ty_name = u.ut_line; + return &t; + } + return NULL; +} + +CreateUtmp(name) +char *name; +{ + int slot; + struct utmp u; + + strncpy(u.ut_line, name, 8); + strncpy(u.ut_name, LoginName, 8); + u.ut_type = 7; /* USER_PROCESS */ + strncpy(u.ut_id, name+3, 4); + (void) time(&u.ut_time); + slot = (lseek(utmpfappend, 0, 2) + 1) / sizeof u; + (void) write(utmpfappend, (char *)&u, sizeof u); + close(utmpfappend); + if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) + { + if (errno != EACCES) + Msg(errno, UtmpName); + return; + } + return slot; +} +#endif /* MIPS */ /* - * (Almost) secure open and fopen... + * if slot could be removed or was 0, wi->slot = -1; + * else not changed. + */ +int +RemoveUtmp(wi) +struct win *wi; +{ +#ifdef GETUTENT + struct utmp *uu; +#endif +#ifdef apollo + struct utmp *up; +#endif + struct utmp u; + slot_t slot; + + slot = wi->slot; +#ifdef GETUTENT + debug1("RemoveUtmp(%s)\n", (slot == (slot_t) 0) ? + "no slot (0)":((slot == (slot_t) -1) ? "no slot (-1)" : slot)); +#else + debug1("RemoveUtmp(wi.slot: %d)\n", slot); +#endif +#ifdef apollo + InitUtmp(); + up = (struct utmp *)malloc(sizeof(struct utmp)); + bzero((char *)up, sizeof(struct utmp)); +#endif /* apollo */ + if (!utmp) + return -1; + if (slot == (slot_t) 0 || slot == (slot_t) -1) + { + debug1("There is no utmp-slot to be removed(%d)\n", slot); + wi->slot = (slot_t) -1; + return 0; + } + bzero((char *) &u, sizeof u); +#ifdef GETUTENT + setutent(); + strncpy(u.ut_line, slot, sizeof(u.ut_line)); + if ((uu = getutline(&u)) == 0) + { + Msg(0, "Utmp slot not found -> not removed"); + return -1; + } +# ifdef _SEQUENT_ + if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0) +# else + uu->ut_type = DEAD_PROCESS; + uu->ut_exit.e_termination = 0; + uu->ut_exit.e_exit= 0; + if (pututline(uu) == 0) +# endif +#else /* GETUTENT */ + (void) lseek(utmpf, (off_t) (slot * sizeof u), 0); +# ifdef apollo + if (read(utmpf, (char *) up, sizeof u) != sizeof u) + { + DeadlyMsg = 0; + Msg(errno, "cannot read %s?", UTMPFILE); + sleep(1); + } + (void) lseek(utmpf, (off_t) (slot * sizeof u), 0); + bzero(up->ut_name, sizeof(u.ut_name)); + bzero(up->ut_host, sizeof(u.ut_host)); + if (write(utmpf, (char *)up, sizeof u) != sizeof u) +# else + if (write(utmpf, (char *) &u, sizeof u) != sizeof u) +# endif /* apollo */ +#endif + { +#ifdef NETHACK + if (nethackflag) + Msg(errno, "%s is too hard to dig in.", UTMPFILE); + else +#endif + Msg(errno,"Could not write %s.", UTMPFILE); +#ifdef apollo + close(utmpf); + free(up); +#endif + return -1; + } + debug("RemoveUtmp successfull\n"); + wi->slot = (slot_t) -1; +#ifdef apollo + close(utmpf); + free(up); +#endif + return 0; +} + +#endif /* UTMPOK */ + +#if !defined(GETTTYENT) && !defined(GETUTENT) + +static void setttyent() +{ + struct stat s; + register int f; + register char *p, *ep; + + if (ttnext) + { + ttnext = tt; + return; + } + if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1) + Msg(errno, ttys); + if ((tt = malloc((unsigned) s.st_size + 1)) == 0) + Msg_nomem; + if (read(f, tt, s.st_size) != s.st_size) + Msg(errno, ttys); + close(f); + for (p = tt, ep = p + s.st_size; p < ep; ++p) + if (*p == '\n') + *p = '\0'; + *p = '\0'; + ttnext = tt; +} + +static struct ttyent *getttyent() +{ + static struct ttyent t; + + if (*ttnext == '\0') + return NULL; + t.ty_name = ttnext + 2; + ttnext += strlen(ttnext) + 1; + return &t; +} + +#endif /* GETTTYENT */ + +#ifdef LOADAV +# ifdef LOADAV_NEXT +void +InitNeXTLoadAvg() +{ + error = processor_set_default(host_self(), &default_set); + if (error != KERN_SUCCESS) + mach_error("Error calling processor_set_default", error); + else + avenrun = 1; +} + +int +GetAvenrun() +{ + info_count = PROCESSOR_SET_BASIC_INFO_COUNT; + error = processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, + (processor_set_info_t)&info, &info_count); + if (error != KERN_SUCCESS) + { + mach_error("Error calling processor_set_info", error); + return 0; + } + else + { + loadav = (float)info.load_average / LOAD_SCALE; + return 1; + } +} + +# else /* need kmem for load avg */ + +void +InitKmem() +{ + debug("Init Kmem...\n"); +# ifndef apollo + if ((kmemf = open(KmemName, O_RDONLY)) == -1) + return; + debug("Kmem opened\n"); + nl[0].n_name = AvenrunSym; + debug2("Searching in %s for %s\n", UnixName, nl[0].n_name); + nlist(UnixName, nl); + if (/* nl[0].n_type == 0 || */ nl[0].n_value == 0) + { + close(kmemf); + return; + } +# ifdef sgi + nl[0].n_value &= ~(1 << 31); /* clear upper bit */ +# endif /* sgi */ + debug("AvenrunSym found!!\n"); +# endif /* apollo */ + avenrun = 1; +} + +int +GetAvenrun() +{ +# ifdef apollo + int load[3]; + register int i; + + proc1_$get_loadav(load); + for (i = 0; i < 3; i++) + loadav[i] = (double)load[i] / 65536.0; +# else + if (lseek(kmemf, (off_t) nl[0].n_value, 0) == (off_t) - 1) + return 0; + if (read(kmemf, (char *) loadav, sizeof loadav) != sizeof loadav) + return 0; +# endif /* apollo */ + + return 1; +} + +# endif /* !NeXT, need kmem for load avg */ +#endif /* LOADAV */ + +/* + * (Almost) secure open and fopen... mlschroe. */ FILE * @@ -638,16 +2426,15 @@ char *mode; #endif debug2("secfopen(%s, %s)\n", name, mode); + if (eff_uid == real_uid) + return(fopen(name, mode)); #ifndef NOREUID setreuid(eff_uid, real_uid); setregid(eff_gid, real_gid); fi = fopen(name, mode); setreuid(real_uid, eff_uid); setregid(real_gid, eff_gid); - return fi; #else - if (eff_uid == real_uid) - return(fopen(name, mode)); if (mode[0] && mode[1] == '+') flags = O_RDWR; else @@ -668,8 +2455,8 @@ char *mode; close(fd); return(0); } - return(fi); #endif + return(fi); } @@ -686,16 +2473,15 @@ int mode; #endif debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode); + if (eff_uid == real_uid) + return(open(name, flags, mode)); #ifndef NOREUID setreuid(eff_uid, real_uid); setregid(eff_gid, real_gid); fd = open(name, flags, mode); setreuid(real_uid, eff_uid); setregid(real_gid, eff_gid); - return fd; #else - if (eff_uid == real_uid) - return(open(name, flags, mode)); /* Truncation/creation is done in UserContext */ if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK))) { @@ -750,7 +2536,41 @@ int mode; return(-1); } } +#endif debug1("secopen ok - returning %d\n", fd); return(fd); +} + +#ifdef BUGGYGETLOGIN +char * +getlogin() +{ + char *tty; +#ifdef utmp +# undef utmp #endif + struct utmp u; + static char retbuf[sizeof(u.ut_user)+1]; + int fd; + + for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++) + ; + if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0)) + return NULL; + tty = stripdev(tty); + retbuf[0] = '\0'; + while (read(fd, &u, sizeof(struct utmp)) == sizeof(struct utmp)) + { + if (!strncmp(tty, u.ut_line, sizeof(u.ut_line))) + { + strncpy(retbuf, u.ut_user, sizeof(u.ut_user)); + retbuf[sizeof(u.ut_user)] = '\0'; + if (u.ut_type == USER_PROCESS) + break; + } + } + close(fd); + + return *retbuf ? retbuf : NULL; } +#endif |