home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / screen3 / part05 / fileio.c
Encoding:
C/C++ Source or Header  |  1991-12-18  |  48.2 KB  |  2,351 lines

  1. /* Copyright (c) 1991
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Noteworthy contributors to screen's design and implementation:
  21.  *    Wayne Davison (davison@borland.com)
  22.  *    Patrick Wolfe (pat@kai.com, kailand!pat)
  23.  *    Bart Schaefer (schaefer@cse.ogi.edu)
  24.  *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  25.  *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  26.  *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  27.  *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  28.  *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  29.  *    Marc Boucher (marc@CAM.ORG)
  30.  *
  31.  ****************************************************************
  32.  */
  33.  
  34. #ifndef lint
  35.   static char rcs_id[] = "$Id: fileio.c,v 1.80 91/10/11 11:27:48 jnweiger Exp $ FAU";
  36. #endif
  37.  
  38. #if defined(pyr) || defined(MIPS) || defined(GOULD_NP1) || defined(B43)
  39. extern int errno;
  40. #endif
  41. #include <sys/types.h>
  42. #include <sys/file.h>
  43. #include <sys/stat.h>
  44. #if defined(BSD) || defined(sequent) || defined(pyr)
  45. # include <strings.h>
  46. #else
  47. # include <string.h>
  48. #endif
  49. #include <fcntl.h>
  50.  
  51. #include "config.h"
  52. #include "screen.h"
  53. #include "extern.h"
  54.  
  55. #ifdef _SEQUENT_
  56. # define UTHOST        /* _SEQUENT_ has got ut_find_host() */
  57. #endif
  58.  
  59. #ifdef UTMPOK
  60. # include <utmp.h>
  61. #endif
  62.  
  63. #ifndef GETUTENT
  64. # ifdef GETTTYENT
  65. #  include <ttyent.h>
  66. # else
  67. struct ttyent
  68. {
  69.   char *ty_name;
  70. };
  71. static char *tt, *ttnext;
  72. static char ttys[] = "/etc/ttys";
  73. # endif
  74. #endif
  75.  
  76. #ifdef LOADAV
  77.  
  78. #include <nlist.h>
  79.  
  80. static char KmemName[] = "/dev/kmem";
  81. # if defined(_SEQUENT_) || defined(MIPS) || defined(SVR4)
  82. static char UnixName[] = "/unix";
  83. # else
  84. #  ifdef sequent
  85. static char UnixName[] = "/dynix";
  86. #  else
  87. #   ifdef hpux
  88. static char UnixName[] = "/hp-ux";
  89. #   else
  90. #    ifdef xelos
  91. static char UnixName[] = "/xelos";
  92. #    else
  93. static char UnixName[] = "/vmunix";
  94. #    endif
  95. #   endif
  96. #  endif
  97. # endif
  98.  
  99. # ifdef alliant
  100. static char AvenrunSym[] = "_Loadavg";
  101. # else
  102. #  if defined(hpux) || defined(_SEQUENT_) || defined(SVR4)
  103. static char AvenrunSym[] = "avenrun";
  104. #  else
  105. static char AvenrunSym[] = "_avenrun";
  106. #  endif
  107. # endif
  108. static struct nlist nl[2];
  109. int avenrun;
  110. static kmemf;
  111. # ifdef LOADAV_3LONGS
  112. long loadav[3];
  113. # else
  114. #  ifdef LOADAV_4LONGS
  115. long loadav[4];
  116. #  else
  117. double loadav[3];
  118. #  endif
  119. # endif
  120.  
  121. #endif /* LOADAV */
  122.  
  123. #define BUFFERFILE "screen-exchange"
  124.  
  125.  
  126. #if defined(UTMPOK) && defined(GETUTENT)
  127. extern struct utmp *getutline(), *pututline();
  128. # if defined(_SEQUENT_)
  129. extern struct utmp *ut_add_user(), *ut_delete_user();
  130. extern char *ut_find_host();
  131. # endif
  132. #endif
  133. #ifdef NETHACK
  134. extern nethackflag;
  135. #endif
  136.  
  137. extern char *RcFileName, *home, *extra_incap, *extra_outcap;
  138. extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
  139. extern char *PowDetachString, *VisualBellString;
  140. extern int VBellWait, MsgWait, MsgMinWait;
  141. extern struct key ktab[];
  142. extern char Esc, MetaEsc;
  143. extern char *shellaka, SockPath[], *SockNamePtr, *LoginName;
  144. extern loginflag, TtyMode, auto_detach;
  145. extern iflag, mflag, rflag, dflag;
  146. extern flowctl, wrap;
  147. extern HS, termcapHS, use_hardstatus, visual_bell, default_monitor;
  148. extern default_histheight;
  149. extern default_startup;
  150. extern slowpaste;
  151. extern DeadlyMsg, HasWindow;
  152. extern ForeNum, screenwidth, screenheight;
  153. extern struct win *fore;
  154. extern char screenterm[];
  155. extern int join_with_cr;
  156. extern struct mode OldMode, NewMode;
  157. extern int HasWindow;
  158. extern char mark_key_tab[];
  159. extern int real_uid, eff_uid;
  160. extern int real_gid, eff_gid;
  161.  
  162. #ifdef PASSWORD
  163. int CheckPassword;
  164. char Password[20];
  165. #endif
  166.  
  167. #ifdef COPY_PASTE
  168. extern char *copybuffer;
  169. extern copylen;
  170. #endif
  171.  
  172. static char *CatExtra __P((char *, char *));
  173. static char **SaveArgs __P((int, char **));
  174. static int Parse __P((char *, char **));
  175. static int IsNum __P((char *, int));
  176. static int IsNumColon __P((char *, int, char *));
  177. static char *stripdev __P((char *));
  178. static slot_t TtyNameSlot __P((char *));
  179.  
  180. #if !defined(GETTTYENT) && !defined(GETUTENT)
  181. static void setttyent __P((void));
  182. static struct ttyent *getttyent __P((void));
  183. #endif
  184.  
  185. /*
  186.  * XXX: system
  187.  */
  188. extern time_t time __P((time_t *));
  189. #ifndef SVR4
  190. extern char *getpass __P((char *));
  191. # ifdef LOADAV
  192. extern int nlist __P((char *, struct nlist *));
  193. # endif
  194. #endif
  195.  
  196. char *KeyNames[] = 
  197. {
  198.   "screen",
  199.   "select0", "select1", "select2", "select3", "select4",
  200.   "select5", "select6", "select7", "select8", "select9",
  201.   "aka", "autoflow", "clear", "colon", "copy", "detach", "flow",
  202.   "hardcopy", "help", "history", "info", "kill", "lastmsg", "license",
  203.   "lockscreen", "log", "login", "monitor", "next", "other", "paste",
  204.   "pow_detach", "prev", "quit", "readbuf", "redisplay", "removebuf",
  205.   "reset", "set", "shell", "suspend", "termcap", "time", "vbell",
  206.   "version", "width", "windows", "wrap", "writebuf", "xoff", "xon",
  207.   0,
  208. };
  209.  
  210.  
  211. /* Must be in alpha order !!! */
  212.  
  213. char *RCNames[] =
  214. {
  215.   "activity", "all", "autodetach", "bell", "bind", "chdir", "crlf",
  216.   "echo", "escape", "flow", "hardstatus", "login", "markkeys", "mode",
  217.   "monitor", "msgminwait", "msgwait", "nethack", "password",
  218.   "pow_detach_msg", "screen", "scrollback", "shell", "shellaka",
  219.   "sleep", "slowpaste", "startup_message", "term", "termcap",
  220.   "terminfo", "vbell", "vbell_msg", "vbellwait", "visualbell",
  221.   "visualbell_msg", "wrap",
  222. };
  223.  
  224. enum RCcases
  225. {
  226.   RC_ACTIVITY,
  227.   RC_ALL,
  228.   RC_AUTODETACH,
  229.   RC_BELL,
  230.   RC_BIND,
  231.   RC_CHDIR,
  232.   RC_CRLF,
  233.   RC_ECHO,
  234.   RC_ESCAPE,
  235.   RC_FLOW,
  236.   RC_HARDSTATUS,
  237.   RC_LOGIN,
  238.   RC_MARKKEYS,
  239.   RC_MODE,
  240.   RC_MONITOR,
  241.   RC_MSGMINWAIT,
  242.   RC_MSGWAIT,
  243.   RC_NETHACK,
  244.   RC_PASSWORD,
  245.   RC_POW_DETACH_MSG,
  246.   RC_SCREEN,
  247.   RC_SCROLLBACK,
  248.   RC_SHELL,
  249.   RC_SHELLAKA,
  250.   RC_SLEEP,
  251.   RC_SLOWPASTE,
  252.   RC_STARTUP_MESSAGE,
  253.   RC_TERM,
  254.   RC_TERMCAP,
  255.   RC_TERMINFO,
  256.   RC_VBELL,
  257.   RC_VBELL_MSG,
  258.   RC_VBELLWAIT,
  259.   RC_VISUALBELL,
  260.   RC_VISUALBELL_MSG,
  261.   RC_WRAP,
  262.   RC_RCEND,
  263. };
  264.  
  265.  
  266. #ifdef UTMPOK
  267. static utmp, utmpf;
  268. static char UtmpName[] = "/etc/utmp";
  269. # ifdef MIPS
  270.   static utmpfappend;
  271. # endif
  272. #endif
  273.  
  274. static FILE *fp = NULL;
  275. static char *rc_name;
  276.  
  277. char *SaveStr(str)
  278. register char *str;
  279. {
  280.   register char *cp;
  281.  
  282.   if ((cp = malloc((unsigned) strlen(str) + 1)) == NULL)
  283.     Msg_nomem;
  284.   else
  285.     strcpy(cp, str);
  286.   return cp;
  287. }
  288.  
  289. static char *CatExtra(str1, str2)
  290. register char *str1, *str2;
  291. {
  292.   register char *cp;
  293.   register int len1, len2, add_colon;
  294.  
  295.   len1 = strlen(str1);
  296.   if (len1 == 0)
  297.     return(str2);
  298.   add_colon = (str1[len1 - 1] != ':');
  299.   if (str2)
  300.     {
  301.       len2 = strlen(str2);
  302.       if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
  303.     Msg_nomem;
  304.       bcopy(cp, cp + len1 + add_colon, len2 + 1);
  305.     }
  306.   else
  307.     {
  308.       if (len1 == 0)
  309.     return 0;
  310.       if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
  311.     Msg_nomem;
  312.     }
  313.   bcopy(str1, cp, len1);
  314.   if (add_colon)
  315.     cp[len1] = ':';
  316.  
  317.   return cp;
  318. }
  319.  
  320. static char *findrcfile(rcfile)
  321. char *rcfile;
  322. {
  323.   static char buf[256];
  324.   char *rc, *p;
  325.  
  326.   if (rcfile)
  327.     {
  328.       rc = SaveStr(rcfile);
  329.       debug1("findrcfile: you specified '%s'\n", rcfile);
  330.     }
  331.   else
  332.     {
  333.       debug("findrcfile: you specified nothing...\n");
  334.       if ((p = getenv("ISCREENRC")) != NULL && *p != '\0')
  335.     {
  336.       debug1("  ... but $ISCREENRC has: '%s'\n", p);
  337.       rc = SaveStr(p);
  338.     }
  339.       else if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
  340.     {
  341.       debug1("  ... but $SCREENRC has: '%s'\n", p);
  342.       rc = SaveStr(p);
  343.     }
  344.       else
  345.     {
  346.       debug("  ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
  347.       if ((unsigned)strlen(home) > 244)
  348.         Msg(0, "Rc: home too large");
  349.       sprintf(buf, "%s/.iscreenrc", home);
  350.           if (access(buf, R_OK))
  351.         sprintf(buf, "%s/.screenrc", home);
  352.       rc = SaveStr(buf);
  353.     }
  354.     }
  355.   return rc;
  356. }
  357.  
  358. /*
  359.  * this will be called twice:
  360.  * 1) rcfilename = "/etc/screenrc"
  361.  * 2) rcfilename = RcFileName
  362.  */
  363. void
  364. StartRc(rcfilename)
  365. char *rcfilename;
  366. {
  367.   register int argc, len;
  368.   register char *p, *cp;
  369.   char buf[256];
  370.   char *args[MAXARGS], *t;
  371.  
  372.   rc_name = findrcfile(rcfilename);
  373.  
  374.   if ((fp = secfopen(rc_name, "r")) == NULL)
  375.     {
  376.       if (RcFileName && strcmp(RcFileName, rc_name) == 0)
  377.     {
  378.           /*
  379.            * User explicitly gave us that name,
  380.            * this is the only case, where we get angry, if we can't read
  381.            * the file.
  382.            */
  383.       debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
  384.           Msg(0, "Unable to open \"%s\".", rc_name);
  385.       /* NOTREACHED */
  386.     }
  387.       debug1("StartRc: '%s' no good. ignored\n", rc_name);
  388.       Free(rc_name);
  389.       rc_name = "";
  390.       return;
  391.     }
  392.   if ((t = getenv("TERM")) == NULL)
  393.     Msg(0, "No TERM in environment.");
  394.   debug1("startrc got termcp:%s\n", t);
  395.   while (fgets(buf, sizeof buf, fp) != NULL)
  396.     {
  397.       if ((p = rindex(buf, '\n')) != NULL)
  398.     *p = '\0';
  399.       if ((argc = Parse(buf, args)) == 0)
  400.     continue;
  401.       if (strcmp(args[0], "echo") == 0)
  402.     {
  403.       if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
  404.         {
  405.           DeadlyMsg = 0;
  406.           Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
  407.         }
  408.       else
  409.         {
  410.           printf((argc == 3) ? "%s" : "%s\r\n", args[argc - 1]);
  411.         }
  412.     }
  413.       else if (strcmp(args[0], "sleep") == 0)
  414.     {
  415.       if (argc != 2)
  416.         {
  417.           DeadlyMsg = 0;
  418.           Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
  419.         }
  420.       else
  421.         sleep(atoi(args[1]));
  422.     }
  423. #ifdef TERMINFO
  424.       else if (strcmp(args[0], "terminfo") == 0)
  425. #else
  426.       else if (strcmp(args[0], "termcap") == 0)
  427. #endif
  428.     {
  429.       if (argc < 3 || argc > 4)
  430.         Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
  431.       for (p = args[1]; p && *p; p = cp)
  432.         {
  433.           if ((cp = index(p, '|')) != 0)
  434.         *cp++ = '\0';
  435.           len = strlen(p);
  436.           if (p[len - 1] == '*')
  437.         {
  438.           if (!(len - 1) || !strncmp(p, t, len - 1))
  439.             break;
  440.         }
  441.           else if (!strcmp(p, t))
  442.         break;
  443.         }
  444.       if (!(p && *p))
  445.         continue;
  446.       extra_incap = CatExtra(args[2], extra_incap);
  447.       if (argc == 4)
  448.         extra_outcap = CatExtra(args[3], extra_outcap);
  449.     }
  450.     }
  451.   fclose(fp);
  452.   Free(rc_name);
  453.   rc_name = "";
  454. }
  455.  
  456. char *ParseChar(p, cp)
  457. char *p, *cp;
  458. {
  459.   if (*p == '^')
  460.     {
  461.       if (*++p == '?')
  462.         *cp = '\177';
  463.       else if (*p >= '@')
  464.         *cp = Ctrl(*p);
  465.       else
  466.         return 0;
  467.       ++p;
  468.     }
  469.   else if (*p == '\\' && *++p <= '7' && *p >= '0')
  470.     {
  471.       *cp = 0;
  472.       do
  473.         *cp = *cp * 8 + *p - '0';
  474.       while (*++p <= '7' && *p >= '0');
  475.     }
  476.   else
  477.     *cp = *p++;
  478.   return p;
  479. }
  480.  
  481. /*
  482.  * CompileKeys must be called before Markroutine is first used.
  483.  * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
  484.  *
  485.  * s is an ascii string in a termcap-like syntax. It looks like
  486.  *   "j=u:k=d:l=r:h=l: =.:" and so on...
  487.  * this example rebinds the cursormovement to the keys u (up), d (down),
  488.  * l (left), r (right). placing a mark will now be done with ".".
  489.  */
  490. int CompileKeys(s, array)
  491. char *s, *array;
  492. {
  493.   int i;
  494.   unsigned char key, value;
  495.  
  496.   if (!s || !*s)
  497.     {
  498.       for (i = 0; i < 256; i++)
  499.         array[i] = i;
  500.       return 0;
  501.     }
  502.   while (*s)
  503.     {
  504.       s = ParseChar(s, (char *) &key);
  505.       if (*s != '=')
  506.     return -1;
  507.       do 
  508.     {
  509.           s = ParseChar(++s, (char *) &value);
  510.       array[value] = key;
  511.     }
  512.       while (*s == '=');
  513.       if (!*s) 
  514.     break;
  515.       if (*s++ != ':')
  516.     return -1;
  517.     }
  518.   return 0;
  519. }
  520.  
  521. static char **SaveArgs(argc, argv)
  522. register int argc;
  523. register char **argv;
  524. {
  525.   register char **ap, **pp;
  526.  
  527.   if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0)
  528.     Msg_nomem;
  529. #ifdef notdef
  530.   debug("saveargs:\n"); 
  531. #endif
  532.   while (argc--)
  533.     {
  534.       debug1(" '%s'", *argv);
  535.       *pp++ = SaveStr(*argv++);
  536.     }
  537.   debug("\n");
  538.   *pp = 0;
  539.   return ap;
  540. }
  541.  
  542. void
  543. AbortRc()
  544. {
  545.   debug("AbortRc();\n");
  546.   if (fp == NULL)
  547.     debug(" fp not open\n")
  548.   else
  549.     (void) fclose(fp);
  550. }
  551.  
  552. void
  553. FinishRc(rcfilename)
  554. char *rcfilename;
  555. {
  556.   /* in FinishRc screen is not yet open, thus Msg() is deadly here.
  557.    */
  558.   char buf[256];
  559.  
  560.   rc_name = findrcfile(rcfilename);
  561.  
  562.   if ((fp = secfopen(rc_name, "r")) == NULL)
  563.     {
  564.       if (RcFileName && strcmp(RcFileName, rc_name) == 0)
  565.     {
  566.           /*
  567.         * User explicitly gave us that name, 
  568.        * this is the only case, where we get angry, if we can't read
  569.        * the file.
  570.        */
  571.         debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
  572.           Msg(0, "Unable to open \"%s\".", rc_name);
  573.       /* NOTREACHED */
  574.     }
  575.       debug1("FinishRc: '%s' no good. ignored\n", rc_name);
  576.       Free(rc_name);
  577.       rc_name = "";
  578.       return;
  579.     }
  580.  
  581.   debug("finishrc is going...\n");
  582.   while (fgets(buf, sizeof buf, fp) != NULL)
  583.     {
  584.       RcLine(buf);
  585.     }
  586.   (void) fclose(fp);
  587.   Free(rc_name);
  588.   rc_name = "";
  589. }
  590.  
  591. /*
  592.  * this is a KEY_SET pressed
  593.  */
  594. void
  595. DoSet(argv)
  596. char **argv;
  597. {
  598.   char *p;
  599.   static char buf[256];
  600.  
  601.   p = buf;
  602.   debug("DoSet\n");
  603.   if (!argv || !*argv || !**argv)
  604.     {
  605.       debug("empty DoSet\n");
  606.       sprintf(buf, "set ");
  607.       RcLine(buf);
  608.       return;
  609.     }
  610.   sprintf(p, "set"); p+=3;
  611.   while(*argv && ((unsigned)strlen(buf) + (unsigned)strlen(*argv) < 255))
  612.     {
  613.       sprintf(p, " %s", *argv++);
  614.       p += strlen(p);
  615.     }
  616.   RcLine(buf);
  617. }
  618.  
  619. /*
  620.  *    "$HOST blafoo"       -> "localhost blafoo"
  621.  *    "${HOST}blafoo"          -> "localhostblafoo"
  622.  *    "\$HOST blafoo"     -> "$HOST blafoo"
  623.  *    "\\$HOST blafoo"    -> "\localhost blafoo"
  624.  *    "'$HOST ${HOST}'"    -> "'$HOST ${HOST}'" 
  625.  *    "'\$HOST'"           -> "'\$HOST'"
  626.  *    "\'$HOST' $HOST"       -> "'localhost' $HOST"
  627.  */
  628. static char *expand_env_vars(ss)
  629. char *ss;
  630. {
  631.   static char ebuf[2048];
  632.   register int esize = 2047, quofl = 0;
  633.   register char *e = ebuf;
  634.   register char *s = ss;
  635.   register char *v;
  636.  
  637.   while (*s && *s != '\n' && esize > 0)
  638.     {
  639.       if (*s == '\'')
  640.     quofl ^= 1;
  641.       if (*s == '$' && !quofl)
  642.     {
  643.       char *p, c;
  644.  
  645.       p = ++s;
  646.       if (*s == '{')
  647.         {
  648.           p = ++s;
  649.           while (*p != '}')
  650.             if (*p++ == '\0')
  651.               return ss;
  652.         }
  653.       else
  654.         {
  655.           while (*p != ' ' && *p != '\0' && *p != '\n')
  656.         p++;
  657.         }
  658.       c = *p;
  659.       debug1("exp: c='%c'\n", c);
  660.       *p = '\0';
  661.       if (v = getenv(s)) 
  662.         {
  663.           debug2("exp: $'%s'='%s'\n", s, v);
  664.           while (*v && esize-- > 0)
  665.             *e++ = *v++;
  666.         }
  667.       else 
  668.         debug1("exp: '%s' not env\n", s);
  669.       if ((*p = c) == '}')
  670.         p++;
  671.       s = p;
  672.     }
  673.       else
  674.     {
  675.       if (s[0] == '\\' && !quofl)
  676.         if (s[1] == '$' || (s[1] == '\\' && s[2] == '$') ||
  677.             s[1] == '\'' || (s[1] == '\\' && s[2] == '\''))
  678.           s++;
  679.       *e++ = *s++;
  680.       esize--;
  681.     }
  682.     }
  683.   if (esize <= 0)
  684.     Msg(0, "expand_env_vars: buffer overflow\n");
  685.   *e = '\0';
  686.   return ebuf;
  687. }
  688.  
  689. void
  690. RcLine(ubuf)
  691. char *ubuf;
  692. {
  693.   char *args[MAXARGS];
  694.   register char *buf, *p, **pp, **ap;
  695.   register int argc, setflag;
  696.   int q, qq;
  697.   char key;
  698.   int low, high, mid, x;
  699.  
  700.   buf = expand_env_vars(ubuf); 
  701.  
  702.   ap = args;
  703.  
  704.   if ((p = rindex(buf, '\n')) != NULL)
  705.     *p = '\0';
  706.   if (strncmp("set ", buf, 4) == 0)
  707.     {
  708.       buf += 4;
  709.       setflag = 1;
  710.       debug1("RcLine: '%s' is a set command\n", buf);
  711.     }
  712.   else if (strncmp("se ", buf, 3) == 0)
  713.     {
  714.       buf += 3;
  715.       setflag = 1;
  716.       debug1("RcLine: '%s' is a se command\n", buf);
  717.     }
  718.   else
  719.     {
  720.       setflag = 0;
  721.       debug1("RcLine: '%s'\n", buf);
  722.     }
  723.   if ((argc = Parse(buf, ap)) == 0)
  724.     {
  725.       if (setflag)
  726.     {
  727.       DeadlyMsg = 0;
  728.       Msg(0, "%s: set what?\n", rc_name);
  729.     }
  730.       return;
  731.     }
  732.  
  733.   low = 0;
  734.   high = (int)RC_RCEND - 1;
  735.   while (low <= high)
  736.     {
  737.       mid = (low + high) / 2;
  738.       x = strcmp(ap[0], RCNames[mid]);
  739.       if (x < 0)
  740.         high = mid - 1;
  741.       else if (x > 0)
  742.         low = mid + 1;
  743.       else
  744.         break;
  745.     }
  746.   if (low > high)
  747.     mid = (int)RC_RCEND;
  748.   switch ((enum RCcases) mid)
  749.     {
  750.     case RC_ESCAPE:
  751.       if (argc != 2 || !ParseEscape(ap[1]))
  752.     {
  753.       DeadlyMsg = 0; 
  754.       Msg(0, "%s: two characters required after escape.", rc_name);
  755.       return;
  756.     }
  757.       if (Esc != MetaEsc)
  758.     ktab[Esc].type = KEY_OTHER;
  759.       else
  760.     ktab[Esc].type = KEY_IGNORE;
  761.       return;
  762.     case RC_CHDIR:
  763.       if (setflag)
  764.     break;
  765.       p = argc < 2 ? home : ap[1];
  766.       if (chdir(p) == -1)
  767.     {
  768.       DeadlyMsg = 0; 
  769.       Msg(errno, "%s", p);
  770.     }
  771.       return;
  772.     case RC_SHELL:
  773.       if (argc != 2)
  774.     {
  775.       DeadlyMsg = 0; 
  776.       Msg(0, "%s: shell: one argument required.", rc_name);
  777.       return;
  778.     }
  779.       ShellProg = ShellArgs[0] = SaveStr(ap[1]);
  780.       return;
  781.     case RC_SHELLAKA:
  782.       if (argc != 2)
  783.     {
  784.       DeadlyMsg = 0; 
  785.       Msg(0, "%s: shellaka: one argument required.", rc_name);
  786.       return;
  787.     }
  788.       shellaka = SaveStr(ap[1]);
  789.       return;
  790.     case RC_SCREEN:
  791.       if (setflag)
  792.     break;
  793.       DoScreen(rc_name, ap + 1);
  794.       return;
  795.     case RC_SLEEP:
  796.     case RC_TERMCAP:
  797.     case RC_TERMINFO:
  798.       return;            /* Already handled */
  799.     case RC_TERM:
  800.       if ((argc != 2) || ((unsigned)strlen(args[1]) >= 20))
  801.     {
  802.       DeadlyMsg = 0;
  803.       Msg(0,"%s: term: one argument required.", rc_name);
  804.       return;
  805.     }
  806.       strcpy(screenterm, args[1]);
  807.       debug1("screenterm set to %s\n", screenterm);
  808.       MakeTermcap(0);
  809.       return;    
  810.     case RC_ECHO:
  811.       if (HasWindow && *rc_name == '\0')
  812.     {
  813.       /*
  814.        * user typed ^A:echo... well, echo isn't FinishRc's job,
  815.        * but as he wanted to test us, we show good will
  816.        */
  817.       DeadlyMsg = 0;
  818.       if (argc == 2 || (argc == 3 && !strcmp(ap[1], "-n")))
  819.         Msg(0, "%s", ap[argc - 1]);
  820.       else
  821.          Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
  822.     }
  823.       return;
  824.     case RC_BELL:
  825.       if (argc != 2)
  826.     {
  827.       DeadlyMsg = 0; 
  828.       Msg(0, "%s: bell: one argument required.", rc_name);
  829.       return;
  830.     }
  831.       if (BellString)
  832.     Free(BellString);
  833.       BellString = SaveStr(ap[1]);
  834.       return;
  835.     case RC_ACTIVITY:
  836.       if (argc != 2)
  837.     {
  838.       DeadlyMsg = 0; 
  839.       Msg(0, "%s: activity: one argument required.", rc_name);
  840.       return;
  841.     }
  842.       if (ActivityString)
  843.     Free(ActivityString);
  844.       ActivityString = SaveStr(ap[1]);
  845.       return;
  846.     case RC_POW_DETACH_MSG:
  847.       if (argc != 2)
  848.     {
  849.       DeadlyMsg = 0;
  850.       Msg(0, "%s: pow_detach: one argument required.", rc_name);
  851.       return;
  852.     }
  853.       if (PowDetachString)
  854.         Free(PowDetachString);
  855.       PowDetachString = SaveStr(ap[1]);
  856.       return;
  857.     case RC_LOGIN:
  858. #ifdef UTMPOK
  859.       q = loginflag;
  860.       ParseOnOff(argc, ap, &loginflag);
  861.       if (fore && setflag)
  862.     {
  863.       SlotToggle(loginflag?(1):(-1));
  864.       loginflag = q;
  865.     }
  866. #endif
  867.       return;
  868.     case RC_FLOW:
  869.       if (argc == 3 && ap[2][0] == 'i')
  870.     {
  871.       iflag = 1;
  872.       argc--;
  873.     }
  874.       if (argc == 2 && ap[1][0] == 'a')
  875.     flowctl = 3;
  876.       else
  877.     {
  878.       ParseOnOff(argc, ap, &flowctl);
  879.       flowctl++;
  880.     }
  881.       return;
  882.     case RC_WRAP:
  883.       ParseOnOff(argc, ap, &wrap);
  884.       return;
  885.     case RC_HARDSTATUS:
  886.       ParseOnOff(argc, ap, &use_hardstatus);
  887.       if (use_hardstatus)
  888.     HS = termcapHS;
  889.       else
  890.     HS = 0;
  891.       return;
  892.     case RC_MONITOR:
  893.     {
  894.       int f; 
  895.  
  896.       ParseOnOff(argc, ap, &f);
  897.       if (fore && setflag)
  898.         fore->monitor = (f == 0) ? MON_OFF : MON_ON;
  899.       else
  900.         default_monitor = (f == 0) ? MON_OFF : MON_ON;
  901.     }
  902.       return;
  903.     case RC_VBELL:
  904.     case RC_VISUALBELL:
  905.       ParseOnOff(argc, ap, &visual_bell);
  906.       return;
  907.     case RC_VBELLWAIT:
  908.       ParseNum(argc, ap, &VBellWait);
  909.       if (fore && rc_name[0] == '\0')
  910.         Msg(0, "vbellwait set to %d seconds", VBellWait);
  911.       return;
  912.     case RC_MSGWAIT:
  913.       ParseNum(argc, ap, &MsgWait);
  914.       if (fore && rc_name[0] == '\0')
  915.         Msg(0, "msgwait set to %d seconds", MsgWait);
  916.       return;
  917.     case RC_MSGMINWAIT:
  918.       ParseNum(argc, ap, &MsgMinWait);
  919.       if (fore && rc_name[0] == '\0')
  920.         Msg(0, "msgminwait set to %d seconds", MsgMinWait);
  921.       return;
  922.     case RC_SCROLLBACK:
  923.       if (fore && setflag)
  924.     {
  925.       int i;
  926.  
  927.       ParseNum(argc, ap, &i);
  928.       ChangeScrollback(fore, i, fore->width);
  929.       if (fore && rc_name[0] == '\0')
  930.         Msg(0, "scrollback set to %d", fore->histheight);
  931.     }
  932.       else
  933.     ParseNum(argc, ap, &default_histheight);
  934.       return;
  935.     case RC_SLOWPASTE:
  936.       ParseNum(argc, ap, &slowpaste);
  937.       if (fore && rc_name[0] == '\0')
  938.     Msg(0, "slowpaste set to %d milliseconds", slowpaste);
  939.       return;
  940.     case RC_MARKKEYS:
  941.       if (argc != 2)
  942.     {
  943.       DeadlyMsg = 0;
  944.       Msg(0, "%s: markkeys: one argument required.", rc_name);
  945.       return;
  946.     }
  947.       if (CompileKeys(ap[1], mark_key_tab))
  948.     {
  949.       DeadlyMsg = 0;
  950.       Msg(0, "%s: markkeys: syntax error.", rc_name);
  951.       return;
  952.     }
  953.       debug1("markkeys %s\n", ap[1]);
  954.       return;
  955. #ifdef NETHACK
  956.     case RC_NETHACK:
  957.       ParseOnOff(argc, ap, &nethackflag);
  958.       return;
  959. #endif
  960.     case RC_VBELL_MSG:
  961.     case RC_VISUALBELL_MSG:
  962.       if (argc != 2)
  963.     {
  964.       DeadlyMsg = 0;
  965.       Msg(0, "%s: vbell_msg: one argument required.", rc_name);
  966.       return;
  967.     }
  968.       if (VisualBellString)
  969.     Free(VisualBellString);
  970.       VisualBellString = SaveStr(ap[1]);
  971.       debug1(" new vbellstr '%s'\n", VisualBellString);
  972.       return;
  973.     case RC_MODE:
  974.       if (argc != 2)
  975.     {
  976.       DeadlyMsg = 0; 
  977.       Msg(0, "%s: mode: one argument required.", rc_name);
  978.       return;
  979.     }
  980.       if (!IsNum(ap[1], 7))
  981.     {
  982.       DeadlyMsg = 0; 
  983.       Msg(0, "%s: mode: octal number expected.", rc_name);
  984.       return;
  985.     }
  986.       (void) sscanf(ap[1], "%o", &TtyMode);
  987.       return;
  988.     case RC_CRLF:
  989.       ParseOnOff(argc, ap, &join_with_cr);
  990.       return;
  991.     case RC_AUTODETACH:
  992.       ParseOnOff(argc, ap, &auto_detach);
  993.       return;
  994.     case RC_STARTUP_MESSAGE:
  995.       ParseOnOff(argc, ap, &default_startup);
  996.       return;
  997. #ifdef PASSWORD
  998.     case RC_PASSWORD:
  999.       CheckPassword = 1;
  1000.       if (argc >= 2)
  1001.     {
  1002.       strncpy(Password, ap[1], sizeof Password);
  1003.       if (!strcmp(Password, "none"))
  1004.         CheckPassword = 0;
  1005.     }
  1006.       else
  1007.     {
  1008.       char *mstr = 0;
  1009.       int msleep = 0, st;
  1010.           char salt[2];
  1011.  
  1012.       /* there is a clear screen sequence in the buffer. */
  1013.       fflush(stdout);
  1014.       if (HasWindow)
  1015.         {
  1016.               ClearDisplay();
  1017.           SetTTY(0, &OldMode);
  1018.         }
  1019.       strncpy(Password, getpass("New screen password:"),
  1020.           sizeof(Password));
  1021.       if (strcmp(Password, getpass("Retype new password:")))
  1022.         {
  1023. #ifdef NETHACK
  1024.               if (nethackflag)
  1025.             mstr = "[ Passwords don't match - your armor crumbles away ]";
  1026.           else
  1027. #endif
  1028.           mstr = "[ Passwords don't match - checking turned off ]";
  1029.           msleep = 1;
  1030.           CheckPassword = 0;
  1031.         }
  1032.       if (Password[0] == '\0')
  1033.         {
  1034.           CheckPassword = 0;
  1035.           mstr = "[ No password - no secure ]";
  1036.           msleep = 1;
  1037.         }
  1038.       for (st=0; st<2; st++)
  1039.             salt[st] = 'A' + (int)((time(0) >> 6*st) % 26);
  1040.       strncpy(Password, crypt(Password, salt), sizeof(Password));
  1041.       if (CheckPassword)
  1042.         {
  1043. #ifdef COPY_PASTE
  1044.           if (copybuffer)
  1045.  
  1046.         Free(copybuffer);
  1047.           copylen = strlen(Password);
  1048.           if ((copybuffer = (char *) malloc(copylen+1)) == NULL)
  1049.         {
  1050.           Msg_nomem;
  1051.           return;
  1052.         }
  1053.           strcpy(copybuffer, Password);
  1054.           mstr = "[ Password moved into copybuffer ]";
  1055.           msleep = 1;
  1056. #else                /* COPY_PASTE */
  1057.           mstr = "[ Crypted password is \"%s\" ]";
  1058.           msleep = 4;
  1059. #endif                /* COPY_PASTE */
  1060.         }
  1061.           if (HasWindow)
  1062.         {
  1063.           SetTTY(0, &NewMode);
  1064.           Activate(); /* Redraw */
  1065.           if (mstr)
  1066.             {
  1067.               Msg(0, mstr, Password);
  1068.             }
  1069.         }
  1070.           else
  1071.         {
  1072.           if (mstr)
  1073.             {
  1074.               printf(mstr, Password);
  1075.               putchar('\n');
  1076.               sleep(msleep);
  1077.             }
  1078.               ClearDisplay();
  1079.         }
  1080.     }
  1081.       debug1("finishrc: our password is: --%s%-- \n", Password);
  1082.       return;
  1083. #endif                /* PASSWORD */
  1084.     case RC_ALL:
  1085.       if (!setflag || !HasWindow || *rc_name)
  1086.         break;
  1087.       display_help();
  1088.       return;
  1089.     case RC_BIND:
  1090.       if (setflag)
  1091.     break;
  1092.       p = ap[1];
  1093.       if (argc < 2 || *p == '\0')
  1094.     {
  1095.       DeadlyMsg = 0; 
  1096.       Msg(0, "%s: key expected after bind.", rc_name);
  1097.       return;
  1098.     }
  1099.       if ((p = ParseChar(p, &key)) == NULL || *p)
  1100.     {
  1101.       DeadlyMsg = 0; 
  1102.       Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
  1103.           rc_name);
  1104.       return;
  1105.     }
  1106.       if (ktab[key].type != KEY_IGNORE)
  1107.     {
  1108.       ktab[key].type = KEY_IGNORE;
  1109.       if ((pp = ktab[key].args) != NULL)
  1110.         {
  1111.           for (; *pp; pp++)
  1112.         Free(*pp);
  1113.           Free(ktab[key].args);
  1114.         }
  1115.     }
  1116.       if (argc > 2)
  1117.     {
  1118.       for (pp = KeyNames; *pp; ++pp)
  1119.         if (strcmp(ap[2], *pp) == 0)
  1120.           break;
  1121.       if (*pp)
  1122.         {
  1123.           ktab[key].type = (enum keytype) (pp - KeyNames + 1);
  1124.           if (argc > 3)
  1125.         {
  1126.           ktab[key].args = SaveArgs(argc - 3, ap + 3);
  1127.         }
  1128.           else
  1129.         ktab[key].args = NULL;
  1130.         }
  1131.       else
  1132.         {
  1133.           ktab[key].type = KEY_CREATE;
  1134.           ktab[key].args = SaveArgs(argc - 2, ap + 2);
  1135.         }
  1136.     }
  1137.       return;
  1138.     case RC_RCEND:
  1139.     default:
  1140.     {
  1141.       char ibuf[3];
  1142.       /*
  1143.        * now we are user-friendly: 
  1144.        * if anyone typed a key name like "help" or "next" ...
  1145.        * we did not match anything above. so look in the KeyNames table.
  1146.        */
  1147.       debug1("--ap[0] %s\n", ap[0]);
  1148.       for (pp = KeyNames; *pp; ++pp)
  1149.         if (strcmp(ap[0], *pp) == 0)
  1150.         break;
  1151.       if (*pp == 0)
  1152.         break;
  1153.  
  1154.       ibuf[0] = Esc;
  1155.       ibuf[1] = pp - KeyNames +1;
  1156.       debug1("RcLine: it was a keyname: '%s'\n", *pp);
  1157.       q = 2; qq = 0;
  1158.       if (HasWindow)
  1159.         ProcessInput(ibuf, &q, (char *)0, &qq, 0);
  1160.       else
  1161.         {
  1162.           DeadlyMsg = 0; 
  1163.           Msg(0, "%s: Key '%s' has no effect while no window open...\n",
  1164.               rc_name, ap[0]);
  1165.         }
  1166.     }
  1167.       return;
  1168.     }
  1169.   DeadlyMsg = 0; 
  1170.   Msg(0, "%s: unknown %skeyword \"%s\"", rc_name, 
  1171.       setflag?"'set' ":"", ap[0]);
  1172. }
  1173.  
  1174. static int Parse(buf, args)
  1175. char *buf, **args;
  1176. {
  1177.   register char *p = buf, **ap = args;
  1178.   register int delim, argc;
  1179.  
  1180.   argc = 0;
  1181.   for (;;)
  1182.     {
  1183.       while (*p && (*p == ' ' || *p == '\t'))
  1184.     ++p;
  1185.       if (*p == '\0' || *p == '#')
  1186.     {
  1187.       *p = '\0';
  1188.       return argc;
  1189.     }
  1190.       if (argc > MAXARGS - 1)
  1191.     Msg(0, "%s: too many tokens.", rc_name);
  1192.       delim = 0;
  1193.       if (*p == '"' || *p == '\'')
  1194.     delim = *p++;
  1195.       argc++;
  1196.       *ap = p;
  1197.       *++ap = 0;
  1198.       while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  1199.     ++p;
  1200.       if (*p == '\0')
  1201.     {
  1202.       if (delim)
  1203.         {
  1204.           DeadlyMsg = 0;
  1205.           Msg(0, "%s: Missing quote.", rc_name);
  1206.           return 0;
  1207.     }
  1208.       return argc;
  1209.     }
  1210.       *p++ = '\0';
  1211.     }
  1212. }
  1213.  
  1214. int ParseEscape(p)
  1215. char *p;
  1216. {
  1217.   if ((p = ParseChar(p, &Esc)) == NULL ||
  1218.       (p = ParseChar(p, &MetaEsc)) == NULL || *p)
  1219.     return 0;
  1220.   return 1;
  1221. }
  1222.  
  1223. void
  1224. ParseNum(argc, ap, var)
  1225. int argc;
  1226. char *ap[];
  1227. int *var;
  1228. {
  1229.   int i;
  1230.   char *p;
  1231.  
  1232.   if (argc == 2 && ap[1][0] != '\0')
  1233.     {
  1234.       i = 0; 
  1235.       p = ap[1];
  1236.       while (*p)
  1237.     {
  1238.       if (*p >= '0' && *p <= '9')
  1239.         i = 10 * i + (*p - '0');
  1240.       else
  1241.         {
  1242.           DeadlyMsg = 0;
  1243.           Msg(0, "%s: %s: invalid argument. Give numeric argument",
  1244.           rc_name, ap[0]);
  1245.           return;
  1246.         }    
  1247.       p++;
  1248.     }
  1249.     }
  1250.   else
  1251.     {
  1252.       DeadlyMsg = 0;
  1253.       Msg(0, "%s: %s: invalid argument. Give one argument",
  1254.           rc_name, ap[0]);
  1255.       return;
  1256.     }
  1257.   debug1("ParseNum got %d\n", i);
  1258.   *var = i;
  1259. }
  1260.  
  1261. void
  1262. ParseOnOff(argc, ap, var)
  1263. int argc;
  1264. char *ap[];
  1265. int *var;
  1266. {
  1267.   register int num = -1;
  1268.  
  1269.   if (argc == 2 && ap[1][0] == 'o')
  1270.     {
  1271.       if (ap[1][1] == 'f')
  1272.     num = 0;
  1273.       else if (ap[1][1] == 'n')
  1274.     num = 1;
  1275.     }
  1276.   if (num < 0)
  1277.     {
  1278.       DeadlyMsg = 0;
  1279.       Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, ap[0]);
  1280.       return;
  1281.     }
  1282.   *var = num;
  1283. }
  1284.  
  1285.  
  1286. static int IsNum(s, base)
  1287. register char *s;
  1288. register int base;
  1289. {
  1290.   for (base += '0'; *s; ++s)
  1291.     if (*s < '0' || *s > base)
  1292.       return 0;
  1293.   return 1;
  1294. }
  1295.  
  1296. static int IsNumColon(s, base, p)
  1297. int base;
  1298. char *s, *p;
  1299. {
  1300.   char *q;
  1301.   if ((q = rindex(s, ':')) != NULL)
  1302.     {
  1303.       strncpy(p, q + 1, 19);
  1304.       *q = '\0';
  1305.     }
  1306.   else
  1307.     *p = '\0';
  1308.   return IsNum(s, base);
  1309. }
  1310.  
  1311. void
  1312. SlotToggle(how)
  1313. int how;
  1314. /*
  1315.  * how = 0    real toggle mode
  1316.  * how > 0    do try to set a utmp slot.
  1317.  * how < 0    try to withdraw a utmp slot
  1318.  *
  1319.  * slot = -1    window not logged in.
  1320.  * slot = 0     window not logged in, but should be logged in. 
  1321.  *              (unable to write utmp, or detached).
  1322.  */
  1323. {
  1324.   debug1("SlotToggle %d\n", how);
  1325.   if (how == 0)
  1326.     how = (fore->slot == (slot_t) -1)?(1):(-1);
  1327.     /* 
  1328.      * slot 0 or active -> we try to log out.
  1329.      * slot -1          -> we try to log in.
  1330.      */
  1331. #ifdef UTMPOK
  1332.   if (how > 0)
  1333.     {
  1334.       debug(" try to log in\n");
  1335.       if ((fore->slot == (slot_t) -1) || (fore->slot == (slot_t) 0))
  1336.     {
  1337. #ifdef USRLIMIT
  1338.           if (CountUsers() >= USRLIMIT)
  1339.             Msg(0, "User limit reached.");
  1340.           else
  1341. #endif
  1342.             {
  1343.               if (SetUtmp(fore, ForeNum) == 0)
  1344.                 Msg(0, "This window is now logged in.");
  1345.               else
  1346.                 Msg(0, "This window should now be logged in.");
  1347.             }
  1348.     }
  1349.       else
  1350.     Msg(0, "This window is already logged in.");
  1351.     }
  1352.   else if (how < 0)
  1353.     {
  1354.       debug(" try to log out\n");
  1355.       if (fore->slot == (slot_t) -1)
  1356.     Msg(0, "This window is already logged out\n");
  1357.       else if (fore->slot == (slot_t) 0)
  1358.     {
  1359.       debug("What a relief! In fact, it was not logged in\n");
  1360.       Msg(0, "This window is not logged in.");
  1361.       fore->slot = (slot_t) -1;
  1362.     }
  1363.       else
  1364.     {
  1365.       RemoveUtmp(fore);
  1366.       if (fore->slot != (slot_t) -1)
  1367.         Msg(0, "What? Cannot remove Utmp slot?");
  1368.       else
  1369.         Msg(0, "This window is no longer logged in.");
  1370.     }
  1371.     }
  1372. #else    /* !UTMPOK */
  1373.   Msg(0, "Unable to modify /etc/utmp.\n");
  1374. #endif
  1375. }
  1376.  
  1377. void
  1378. DoScreen(fn, av)
  1379. char *fn, **av;
  1380. {
  1381.   register int flowflag, num, lflag = loginflag;
  1382.   register char *aka = NULL;
  1383.   register int histheight = default_histheight;
  1384.   char buf[20];
  1385.   char termbuf[25];
  1386.   char *termp;
  1387.   char *args[2];
  1388.  
  1389.   flowflag = flowctl;
  1390.   termbuf[0] = '\0';
  1391.   termp = NULL;
  1392.   while (av && *av && av[0][0] == '-')
  1393.     {
  1394.       switch (av[0][1])
  1395.     {
  1396.     case 'f':
  1397.       switch (av[0][2])
  1398.         {
  1399.         case 'n':
  1400.         case '0':
  1401.           flowflag = 1;
  1402.           break;
  1403.         case 'y':
  1404.         case '1':
  1405.         case '\0':
  1406.           flowflag = 2;
  1407.           break;
  1408.         case 'a':
  1409.           flowflag = 3;
  1410.           break;
  1411.         default:
  1412.           break;
  1413.         }
  1414.       break;
  1415.     case 'k':
  1416.     case 't':
  1417.       if (av[0][2])
  1418.         aka = &av[0][2];
  1419.       else if (*++av)
  1420.         aka = *av;
  1421.       else
  1422.         --av;
  1423.       break;
  1424.     case 'T':
  1425.       if (av[0][2])
  1426.         termp = &av[0][2];
  1427.       else if (*++av)
  1428.         termp = *av;
  1429.       else
  1430.         --av;
  1431.       break;
  1432.     case 'h':
  1433.       if (av[0][2])
  1434.         histheight = atoi(av[0] + 2);
  1435.       else if (*++av)
  1436.         histheight = atoi(*av);
  1437.       else 
  1438.         --av;
  1439.       break;
  1440.     case 'l':
  1441.       switch (av[0][2])
  1442.         {
  1443.         case 'n':
  1444.         case '0':
  1445.           lflag = 0;
  1446.           break;
  1447.         case 'y':
  1448.         case '1':
  1449.         case '\0':
  1450.           lflag = 1;
  1451.           break;
  1452.         default:
  1453.           break;
  1454.         }
  1455.       break;
  1456.     default:
  1457.       Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
  1458.       break;
  1459.     }
  1460.       ++av;
  1461.     }
  1462.   num = 0;
  1463.   if (av && *av && IsNumColon(*av, 10, buf))
  1464.     {
  1465.       if (*buf != '\0')
  1466.     aka = buf;
  1467.       num = atoi(*av);
  1468.       if (num < 0 || num > MAXWIN - 1)
  1469.     Msg(0, "%s: illegal screen number %d.", fn, num);
  1470.       ++av;
  1471.     }
  1472.   if (!av || !*av)
  1473.     {
  1474.       av = args;
  1475.       av[0] = ShellProg;
  1476.       av[1] = NULL;
  1477.       if (!aka)
  1478.     aka = shellaka;
  1479.     }
  1480.   MakeWindow(aka, av, 0, flowflag, num, (char *) 0, lflag, histheight, termp);
  1481. }
  1482.  
  1483. void
  1484. WriteFile(dump)
  1485. int dump;
  1486. {
  1487.   /* dump==0:    create .termcap,
  1488.    * dump==1:    hardcopy,
  1489.    * #ifdef COPY_PASTE
  1490.    * dump==2:    BUFFERFILE
  1491.    * #endif COPY_PASTE 
  1492.    */
  1493.   register int i, j, k;
  1494.   register char *p;
  1495.   register FILE *f;
  1496.   char fn[1024];
  1497.  
  1498.   switch (dump)
  1499.     {
  1500.     case DUMP_TERMCAP:
  1501.       i = SockNamePtr - SockPath;
  1502.       strncpy(fn, SockPath, i);
  1503.       strcpy(fn + i, ".termcap");
  1504.       break;
  1505.     case DUMP_HARDCOPY:
  1506.       sprintf(fn, "hardcopy.%d", ForeNum);
  1507.       break;
  1508.     case DUMP_EXCHANGE:
  1509.       sprintf(fn, "/tmp/%s", BUFFERFILE);
  1510.       umask(0);
  1511.       break;
  1512.     }
  1513.  
  1514.   debug2("WriteFile(%d) %s\n", dump, fn);
  1515.   if (UserContext() > 0)
  1516.     {
  1517.       debug("Writefile: usercontext\n");
  1518.       if ((f = fopen(fn, "w")) == NULL)
  1519.     {
  1520.       debug1("WriteFile: fopen(%s) failed\n", fn);
  1521.       UserReturn(0);
  1522.     }
  1523.       else
  1524.     {
  1525.       switch (dump)
  1526.         {
  1527.         case DUMP_HARDCOPY:
  1528.           for (i = 0; i < screenheight; ++i)
  1529.         {
  1530.           p = fore->image[i];
  1531.           for (k = screenwidth - 1; k >= 0 && p[k] == ' '; --k)
  1532.             ;
  1533.           for (j = 0; j <= k; ++j)
  1534.             putc(p[j], f);
  1535.           putc('\n', f);
  1536.         }
  1537.           break;
  1538.         case DUMP_TERMCAP:
  1539.           if ((p = index(MakeTermcap(fore->aflag), '=')) != NULL)
  1540.         {
  1541.           fputs(++p, f);
  1542.           putc('\n', f);
  1543.         }
  1544.           break;
  1545. #ifdef COPY_PASTE
  1546.         case DUMP_EXCHANGE:
  1547.           p = copybuffer;
  1548.           for (i = 0; i < copylen; i++)
  1549.         putc(*p++, f);
  1550.           break;
  1551. #endif
  1552.         }
  1553.       (void) fclose(f);
  1554.       UserReturn(1);
  1555.     }
  1556.     }
  1557.   if (UserStatus() <= 0)
  1558.     Msg(0, "Cannot open \"%s\"", fn);
  1559.   else
  1560.     {
  1561.       switch (dump)
  1562.     {
  1563.     case DUMP_TERMCAP:
  1564.       Msg(0, "Termcap entry written to \"%s\".", fn);
  1565.       break;
  1566.     case DUMP_HARDCOPY:
  1567.       Msg(0, "Screen image written to \"%s\".", fn);
  1568.       break;
  1569. #ifdef COPY_PASTE
  1570.     case DUMP_EXCHANGE:
  1571.       Msg(0, "Copybuffer written to \"%s\".", fn);
  1572. #endif
  1573.     }
  1574.     }
  1575. }
  1576.  
  1577. #ifdef COPY_PASTE
  1578.  
  1579. void
  1580. ReadFile()
  1581. {
  1582.   int i, l, size;
  1583.   char fn[1024], c;
  1584.   struct stat stb;
  1585.  
  1586.   sprintf(fn, "/tmp/%s", BUFFERFILE);
  1587.   debug1("ReadFile(%s)\n", fn);
  1588.   if ((i = secopen(fn, O_RDONLY, 0)) < 0)
  1589.     {
  1590.       Msg(errno, "no %s -- no slurp", fn);
  1591.       return;
  1592.     }
  1593.   if (fstat(i, &stb))
  1594.     {
  1595.       Msg(errno, "no good %s -- no slurp", fn);
  1596.       close(i);
  1597.       return;
  1598.     }
  1599.   size = stb.st_size;
  1600.   if (copybuffer)
  1601.     Free(copybuffer);
  1602.   copylen = 0;
  1603.   if ((copybuffer = malloc(size)) == NULL)
  1604.     {
  1605.       close(i);
  1606.       Msg_nomem;
  1607.       return;
  1608.     }
  1609.   errno = 0;
  1610.   if ((l = read(i, copybuffer, size)) != size)
  1611.     {
  1612.       copylen = (l > 0) ? l : 0;
  1613. #ifdef NETHACK
  1614.       if (nethackflag)
  1615.         Msg(errno, "You choke on your food: %d bytes", copylen);
  1616.       else
  1617. #endif
  1618.       Msg(errno, "Got only %d bytes from %s", copylen, fn);
  1619.       close(i);
  1620.       return;
  1621.     }
  1622.   copylen = l;
  1623.   if (read(i, &c, 1) > 0)
  1624.     Msg(0, "Slurped only %d characters into buffer - try again", copylen);
  1625.   else
  1626.     Msg(0, "Slurped %d characters into buffer", copylen);
  1627.   close(i);
  1628.   return;
  1629. }
  1630.  
  1631. void
  1632. KillBuffers()
  1633. {
  1634.   char fn[1024];
  1635.   sprintf(fn, "/tmp/%s", BUFFERFILE);
  1636.   errno = 0;
  1637.   if (access(fn, W_OK) == -1)
  1638.     {
  1639.       Msg(errno, "%s not removed", fn);
  1640.       return;
  1641.     }
  1642.   else
  1643.     {
  1644.       unlink(fn);
  1645.       Msg(errno, "%s removed", fn);
  1646.     }
  1647. }
  1648. #endif    /* COPY_PASTE */
  1649.  
  1650. #ifdef USRLIMIT
  1651. CountUsers()
  1652. {
  1653. #ifdef GETUTENT
  1654.   struct utmp *ut, *getutent();
  1655. #else
  1656.   struct utmp utmpbuf;
  1657. #endif
  1658.   int UserCount;
  1659.  
  1660.   debug1("CountUsers() - utmp=%d\n",utmp);
  1661.   if (!utmp)
  1662.     return(0);
  1663.   UserCount = 0;
  1664. #ifdef GETUTENT
  1665.   setutent();
  1666.   while (ut = getutent())
  1667.     if (ut->ut_type == USER_PROCESS)
  1668.       UserCount++;
  1669. #else
  1670.   (void) lseek(utmpf, (off_t) 0, 0);
  1671.   while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
  1672.     {
  1673.       if (utmpbuf.ut_name[0] != '\0')
  1674.        UserCount++;
  1675.     }
  1676. #endif
  1677.   return(UserCount);
  1678. }
  1679. #endif
  1680.  
  1681. #ifdef UTMPOK
  1682.  
  1683. static slot_t loginslot;
  1684. static struct utmp utmp_logintty;
  1685. #ifdef _SEQUENT_
  1686. static char loginhost[100+1];
  1687. #endif
  1688.  
  1689. void
  1690. InitUtmp()
  1691. {
  1692.   debug("InitUtmp testing...\n");
  1693.   if ((utmpf = open(UtmpName, O_RDWR)) == -1)
  1694.     {
  1695.       if (errno != EACCES)
  1696.     Msg(errno, UtmpName);
  1697.       debug("InitUtmp failed.\n");
  1698.       utmp = 0;
  1699.       return;
  1700.     }
  1701. #ifdef GETUTENT
  1702.   close(utmpf);
  1703.   utmpf= -1;
  1704. #endif
  1705. #ifdef MIPS
  1706.   if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
  1707.     {
  1708.       if (errno != EACCES)
  1709.     Msg(errno, UtmpName);
  1710.       return;
  1711.     }
  1712. #endif
  1713.   utmp = 1;
  1714.   ReInitUtmp();
  1715. }
  1716.  
  1717. void
  1718. ReInitUtmp()
  1719. {
  1720.   if (!utmp)
  1721.     {
  1722.       debug("Reinitutmp: utmp == 0\n");
  1723.       return;
  1724.     }
  1725.   debug("(Re)InitUtmp: removing your logintty\n");
  1726.   loginslot = TtyNameSlot(ttyname(0));
  1727.   if (loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
  1728.     {
  1729. #ifdef _SEQUENT_
  1730.       if (p=ut_find_host(loginslot))
  1731.         strncpy(loginhost, p, 100);
  1732. #endif
  1733.       RemoveLoginSlot(loginslot, &utmp_logintty);
  1734.     }
  1735.   debug1(" slot %d zapped\n", loginslot);
  1736. }
  1737.  
  1738. void
  1739. RestoreLoginSlot()
  1740. {
  1741.   debug("RestoreLoginSlot()\n");
  1742.   if (utmp && loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
  1743.     {
  1744. #ifdef GETUTENT
  1745. # ifdef _SEQUENT_
  1746.       int fail;
  1747.       debug1(" logging you in again (slot %s)\n", loginslot);
  1748. /*
  1749.  * We have problems if we add the console and use ut_add_user()
  1750.  * because the id will be 'scon' instead of 'co'. So we
  1751.  * restore it with pututline(). The reason why we don't use
  1752.  * pututline all the time is that we want to set the host field.
  1753.  * Unfortunatelly this can only be done with ut_add_user().
  1754.  */
  1755.       if (*loginhost)
  1756.         {
  1757.           fail = (ut_add_user(LoginName, loginslot, utmp_logintty.ut_pid,
  1758.                               *loginhost?loginhost:(char *)0) == 0);
  1759.         }
  1760.       else
  1761.         {
  1762.           setutent();
  1763.           fail = (pututline(&utmp_logintty) == 0);
  1764.         }
  1765.       if (fail)
  1766. # else    /* _SEQUENT_ */
  1767.       debug1(" logging you in again (slot %s)\n", loginslot);
  1768.       setutent();
  1769.       if (pututline(&utmp_logintty)==0)
  1770. # endif    /* _SEQUENT */
  1771. #else    /* GETUTENT */
  1772.       debug1(" logging you in again (slot %d)\n", loginslot);
  1773. # ifdef sequent
  1774.       /* call sequent undocumented routine to count logins and add utmp entry if possible */
  1775.       if (add_utmp(loginslot, &utmp_logintty) == -1)
  1776. # else
  1777.       (void) lseek(utmpf, (off_t) (loginslot * sizeof(struct utmp)), 0);
  1778.       if (write(utmpf, (char *) &utmp_logintty, sizeof(struct utmp))
  1779.       != sizeof(struct utmp))
  1780. # endif /* sequent */
  1781. #endif    /* GETUTENT */
  1782.         {
  1783. #ifdef NETHACK
  1784.           if (nethackflag)
  1785.             Msg(errno, "/etc/utmp is to hard to dig");
  1786.       else
  1787. #endif
  1788.           Msg(errno,"Could not write /etc/utmp");
  1789.         }
  1790.     }
  1791.   loginslot = (slot_t) 0;
  1792. }
  1793.  
  1794. void
  1795. RemoveLoginSlot(slot, up)
  1796. slot_t slot;
  1797. struct utmp *up;
  1798. {
  1799. #ifdef GETUTENT
  1800.   struct utmp *uu;
  1801. #endif
  1802.   struct utmp u;
  1803.  
  1804. #ifdef GETUTENT
  1805.   debug2("RemoveLoginSlot(%s, %08x)\n", (slot == (slot_t) 0 ||
  1806.          slot == (slot_t) -1 ) ? "no slot" : slot, up);
  1807. #else
  1808.   debug2("RemoveLoginSlot(%d, %08x)\n", slot, up);
  1809. #endif
  1810.   if (!utmp)
  1811.     return;
  1812.   if (slot != (slot_t) 0 && slot != (slot_t) -1)
  1813.     {
  1814.       bzero((char *) &u, sizeof u);
  1815. #ifdef GETUTENT
  1816.       setutent();
  1817.       strncpy(u.ut_line, slot, sizeof(u.ut_line));
  1818.       if ((uu = getutline(&u)) == 0)
  1819.         {
  1820.       DeadlyMsg = 0;
  1821.           Msg(0, "Utmp slot not found -> not removed");
  1822.           return;
  1823.         }
  1824.       *up= *uu;
  1825. # ifdef _SEQUENT_
  1826.       if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
  1827. # else
  1828.       uu->ut_type = DEAD_PROCESS;
  1829.       uu->ut_exit.e_termination = 0;
  1830.       uu->ut_exit.e_exit= 0;
  1831.       if (pututline(uu) == 0)
  1832. # endif
  1833. #else
  1834.       (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  1835.       if (read(utmpf, (char *) up, sizeof u) != sizeof u)
  1836.     {
  1837.       DeadlyMsg = 0;
  1838.       Msg(errno, "cannot read /etc/utmp ???");
  1839.       sleep(1);
  1840.     }
  1841.       (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  1842.       if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  1843. #endif
  1844.         {
  1845. #ifdef NETHACK
  1846.           if (nethackflag)
  1847.         {
  1848.           DeadlyMsg = 0;
  1849.               Msg(errno, "/etc/utmp is to hard to dig");
  1850.         }
  1851.           else
  1852. #endif
  1853.         {
  1854.           DeadlyMsg = 0;
  1855.               Msg(errno,"Could not write /etc/utmp");
  1856.         }
  1857.         }
  1858.     }
  1859.   else 
  1860.     {
  1861.       debug1("There is no utmp-slot to be removed(%d)\n", slot);
  1862.     }
  1863. }
  1864.  
  1865. static char *stripdev(nam)
  1866. char *nam;
  1867. {
  1868.   if (nam == 0)
  1869.     return(0);
  1870.   if (strncmp(nam, "/dev/", 5) == 0)
  1871.     return(nam + 5);
  1872.   return(nam);
  1873. }
  1874.  
  1875. static slot_t TtyNameSlot(nam)
  1876. char *nam;
  1877. {
  1878.   char *name;
  1879.   register slot_t slot;
  1880. #ifndef GETUTENT
  1881.   register struct ttyent *tp;
  1882. #endif
  1883.  
  1884.   debug1("TtyNameSlot(%s)\n", nam);
  1885.   if (!utmp || nam == NULL)
  1886.     return (slot_t)0;
  1887.   name = stripdev(nam);
  1888. #ifdef GETUTENT
  1889.   slot = name;
  1890. #else
  1891.   slot = 1;
  1892.   setttyent();
  1893.   while ((tp = getttyent()) != NULL && strcmp(name, tp->ty_name) != 0)
  1894.     {
  1895.       debug2("'%s' %d, ", tp->ty_name, slot);
  1896.       ++slot;
  1897.     }
  1898.   debug("\n");
  1899. # ifdef MIPS
  1900.   if (tp == NULL)
  1901.     {
  1902.       slot = CreateUtmp(name);
  1903.     }
  1904. # endif /* MIPS */
  1905. #endif
  1906.   return slot;
  1907. }
  1908.  
  1909. int
  1910. SetUtmp(wi, displaynumber)
  1911. struct win *wi;
  1912. int displaynumber;
  1913. {
  1914.   register char *p;
  1915.   register slot_t slot;
  1916.   char *line;
  1917.   struct utmp u;
  1918. #ifdef UTHOST
  1919. # ifdef _SEQUENT_
  1920.   char host[100+5];
  1921. # else
  1922.   char host[sizeof(utmp_logintty.ut_host)+5];
  1923. # endif
  1924. #endif
  1925.  
  1926.   wi->slot = (slot_t) 0;
  1927.   if (!utmp)
  1928.     return -1;
  1929.   if ((slot = TtyNameSlot(wi->tty)) == (slot_t) NULL)
  1930.     {
  1931.       debug1("SetUtmp failed (tty %s).\n",wi->tty);
  1932.       return -1;
  1933.     }
  1934.   debug2("SetUtmp %d will get slot %d...\n", displaynumber, (int)slot);
  1935.  
  1936. #ifdef UTHOST
  1937.   host[sizeof(host)-5] = '\0';
  1938. # ifdef _SEQUENT_
  1939.   strncpy(host, loginhost, sizeof(host) - 5);
  1940. # else
  1941.   strncpy(host, utmp_logintty.ut_host, sizeof(host) - 5);
  1942. # endif
  1943.   if (loginslot != (slot_t)0 && loginslot != (slot_t)-1 && host[0] != '\0')
  1944.     {
  1945.       /*
  1946.        * we want to set our ut_host field to something like
  1947.        * ":ttyhf:s.0" or
  1948.        * "faui45:s.0" or
  1949.        * "132.199.81.4:s.0" but not
  1950.        * "faui45.informati"......:s.0
  1951.        */
  1952.       for (p = host; *p; p++)
  1953.     {
  1954.       if ((*p < '0' || *p > '9') && (*p != '.'))
  1955.         break;
  1956.     }
  1957.       if (*p)
  1958.     {
  1959.       for (p = host; *p; p++)
  1960.         {
  1961.           if (*p == '.')
  1962.         {
  1963.           *p = '\0';
  1964.           break;
  1965.         }
  1966.         }
  1967.     }
  1968.     }
  1969.   else
  1970.     {
  1971.       strncpy(host + 1, stripdev(ttyname(0)), sizeof(host) - 6);
  1972.       host[0] = ':';
  1973.     }
  1974.   debug1("rlogin hostname: '%s'\n", host);
  1975.   sprintf(host + strlen(host), ":S.%c", '0' + displaynumber);
  1976.   debug1("rlogin hostname: '%s'\n", host);
  1977. #endif /* UTHOST */
  1978.  
  1979.   line = stripdev(wi->tty);
  1980.   bzero((char *) &u, sizeof u);
  1981. #ifdef GETUTENT
  1982. # ifdef _SEQUENT_
  1983.   if (ut_add_user(LoginName, slot, wi->wpid, host)==0)
  1984. # else
  1985.   strncpy(u.ut_user, LoginName, sizeof(u.ut_user));
  1986.   strncpy(u.ut_id, line + strlen(line) - 2, sizeof(u.ut_id));
  1987.   strncpy(u.ut_line, line, sizeof(u.ut_line));
  1988.   u.ut_pid = wi->wpid;
  1989.   u.ut_type = USER_PROCESS;
  1990.   (void) time(&u.ut_time);
  1991. #  ifdef UTHOST
  1992.   strncpy(u.ut_host, host, sizeof(u.ut_host));
  1993. #  endif /* UTHOST */
  1994.   if (pututline(&u) == 0)
  1995. # endif /* _SEQUENT_ */
  1996. #else    /* GETUTENT */
  1997.   strncpy(u.ut_line, line, sizeof(u.ut_line));
  1998.   strncpy(u.ut_name, LoginName, sizeof(u.ut_name));
  1999. # ifdef UTHOST
  2000.   strncpy(u.ut_host, host, sizeof(u.ut_host));
  2001. # endif    /* UTHOST */
  2002. # ifdef MIPS
  2003.   u.ut_type = 7; /* USER_PROCESS */
  2004.   strncpy(u.ut_id, line + 3, 4);
  2005. # endif /* MIPS */
  2006.   (void) time(&u.ut_time);
  2007. # ifdef sequent
  2008. /* call sequent undocumented routine to count logins and add utmp entry if possible */
  2009.   if (add_utmp(slot, &u) == -1)
  2010. # else
  2011.   (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  2012.   if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  2013. # endif /* sequent */
  2014. #endif    /* GETUTENT */
  2015.     {
  2016. #ifdef NETHACK
  2017.       if (nethackflag)
  2018.         Msg(errno, "/etc/utmp is to hard to dig");
  2019.       else
  2020. #endif
  2021.       Msg(errno,"Could not write /etc/utmp");
  2022.       return -1;
  2023.     }
  2024.   debug("SetUtmp successful\n");
  2025.   wi->slot = slot;
  2026.   return 0;
  2027. }
  2028.  
  2029. #ifdef MIPS
  2030.  
  2031. #define GETTTYENT
  2032. static int ttyfd = 0;
  2033.  
  2034. static void setttyent()
  2035. {
  2036.   if (ttyfd)
  2037.     close(ttyfd);
  2038.   ttyfd = open(UtmpName, O_RDONLY);
  2039. }
  2040.  
  2041. static struct ttyent *getttyent()
  2042. {
  2043.   static struct utmp u;
  2044.   static struct ttyent t;
  2045.  
  2046.   if (!ttyfd)
  2047.     return NULL;
  2048.   
  2049.   if (read(ttyfd, &u, sizeof u)) 
  2050.     {
  2051.       t.ty_name = u.ut_line;
  2052.       return &t;
  2053.     }
  2054.   return NULL;
  2055. }
  2056.  
  2057. CreateUtmp(name)
  2058. char *name;
  2059. {
  2060.   int slot;
  2061.   struct utmp u;
  2062.  
  2063.   strncpy(u.ut_line, name, 8);
  2064.   strncpy(u.ut_name, LoginName, 8);
  2065.   u.ut_type = 7; /* USER_PROCESS */
  2066.   strncpy(u.ut_id, name+3, 4);
  2067.   (void) time(&u.ut_time);
  2068.   slot = (lseek(utmpfappend, 0, 2) + 1) / sizeof u;
  2069.   (void) write(utmpfappend, (char *)&u, sizeof u);
  2070.   close(utmpfappend);
  2071.   if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
  2072.     {
  2073.       if (errno != EACCES)
  2074.         Msg(errno, UtmpName);
  2075.       return;
  2076.     }
  2077.   return slot;
  2078. }
  2079. #endif /* MIPS */
  2080.  
  2081. /*
  2082.  * if slot could be removed or was 0,  wi->slot = -1;
  2083.  * else not changed.
  2084.  */
  2085. int
  2086. RemoveUtmp(wi)
  2087. struct win *wi;
  2088. {
  2089. #ifdef GETUTENT
  2090.   struct utmp *uu;
  2091. #endif
  2092.   struct utmp u;
  2093.   slot_t slot;
  2094.  
  2095.   slot=wi->slot;
  2096. #ifdef GETUTENT
  2097.   debug1("RemoveUtmp(%s)\n", (slot == (slot_t) 0) ?
  2098.          "no slot (0)":((slot == (slot_t) -1) ? "no slot (-1)" : slot));
  2099. #else
  2100.   debug1("RemoveUtmp(wi.slot: %d)\n", slot);
  2101. #endif
  2102.   if (!utmp)
  2103.     return -1;
  2104.   if (slot == (slot_t) 0 || slot == (slot_t) -1)
  2105.     {
  2106.       debug1("There is no utmp-slot to be removed(%d)\n", slot);
  2107.       wi->slot = (slot_t) -1;
  2108.       return 0;
  2109.     }
  2110.   bzero((char *) &u, sizeof u);
  2111. #ifdef GETUTENT
  2112.   setutent();
  2113.   strncpy(u.ut_line, slot, sizeof(u.ut_line));
  2114.   if ((uu = getutline(&u)) == 0)
  2115.     {
  2116.       Msg(0, "Utmp slot not found -> not removed");
  2117.       return -1;
  2118.     }
  2119. # ifdef _SEQUENT_
  2120.   if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
  2121. # else
  2122.   uu->ut_type = DEAD_PROCESS;
  2123.   uu->ut_exit.e_termination = 0;
  2124.   uu->ut_exit.e_exit= 0;
  2125.   if (pututline(uu) == 0)
  2126. # endif
  2127. #else    /* GETUTENT */
  2128.   (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  2129.   if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  2130. #endif
  2131.     {
  2132. #ifdef NETHACK
  2133.       if (nethackflag)
  2134.         Msg(errno, "/etc/utmp is to hard to dig");
  2135.       else
  2136. #endif
  2137.       Msg(errno,"Could not write /etc/utmp");
  2138.       return -1;
  2139.     }
  2140.   debug("RemoveUtmp successful\n");
  2141.   wi->slot = (slot_t) -1;
  2142.   return 0;
  2143. }
  2144.  
  2145. #endif    /* UTMPOK */
  2146.  
  2147. #if !defined(GETTTYENT) && !defined(GETUTENT)
  2148.  
  2149. static void setttyent()
  2150. {
  2151.   struct stat s;
  2152.   register int f;
  2153.   register char *p, *ep;
  2154.  
  2155.   if (ttnext)
  2156.     {
  2157.       ttnext = tt;
  2158.       return;
  2159.     }
  2160.   if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
  2161.     Msg(errno, ttys);
  2162.   if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
  2163.     Msg_nomem;
  2164.   if (read(f, tt, s.st_size) != s.st_size)
  2165.     Msg(errno, ttys);
  2166.   close(f);
  2167.   for (p = tt, ep = p + s.st_size; p < ep; ++p)
  2168.     if (*p == '\n')
  2169.       *p = '\0';
  2170.   *p = '\0';
  2171.   ttnext = tt;
  2172. }
  2173.  
  2174. static struct ttyent *getttyent()
  2175. {
  2176.   static struct ttyent t;
  2177.  
  2178.   if (*ttnext == '\0')
  2179.     return NULL;
  2180.   t.ty_name = ttnext + 2;
  2181.   ttnext += strlen(ttnext) + 1;
  2182.   return &t;
  2183. }
  2184.  
  2185. #endif    /* GETTTYENT */
  2186.  
  2187. #ifdef LOADAV
  2188.  
  2189. void
  2190. InitKmem()
  2191. {
  2192.   debug("Init Kmem...\n");
  2193.   if ((kmemf = open(KmemName, O_RDONLY)) == -1)
  2194.     return;
  2195.   debug("Kmem opened\n");
  2196.   nl[0].n_name = AvenrunSym;
  2197.   debug2("Searching in %s for %s\n", UnixName, nl[0].n_name);
  2198.   nlist(UnixName, nl);
  2199.   if (/* nl[0].n_type == 0 || */ nl[0].n_value == 0)
  2200.     {
  2201.       close(kmemf);
  2202.       return;
  2203.     }
  2204.   debug("AvenrunSym found!!\n");
  2205.   avenrun = 1;
  2206. }
  2207.  
  2208. int
  2209. GetAvenrun()
  2210. {
  2211.   if (lseek(kmemf, (off_t) nl[0].n_value, 0) == (off_t) - 1)
  2212.     return 0;
  2213.   if (read(kmemf, (char *) loadav, sizeof loadav) != sizeof loadav)
  2214.     return 0;
  2215.  
  2216.   return 1;
  2217. }
  2218.  
  2219. #endif    /* LOADAV */
  2220.  
  2221.  
  2222. /*
  2223.  * (Almost) secure open and fopen... mlschroe.
  2224.  */
  2225.  
  2226. FILE *
  2227. secfopen(name, mode)
  2228. char *name;
  2229. char *mode;
  2230. {
  2231.   FILE *fi;
  2232. #ifdef NOREUID
  2233.   int flags, fd;
  2234. #endif
  2235.  
  2236.   debug2("secfopen(%s, %s)\n", name, mode);
  2237.   if (eff_uid == real_uid)
  2238.     return(fopen(name, mode));
  2239. #ifndef NOREUID
  2240.   setreuid(eff_uid, real_uid);
  2241.   setregid(eff_gid, real_gid);
  2242.   fi = fopen(name, mode);
  2243.   setreuid(real_uid, eff_uid);
  2244.   setregid(real_gid, eff_gid);
  2245. #else
  2246.   if (mode[0] && mode[1] == '+')
  2247.     flags = O_RDWR;
  2248.   else
  2249.     flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
  2250.   if (mode[0] == 'w')
  2251.     flags |= O_CREAT | O_TRUNC;
  2252.   else if (mode[0] == 'a')
  2253.     flags |= O_CREAT | O_APPEND;
  2254.   else if (mode[0] != 'r')
  2255.     {
  2256.       errno = EINVAL;
  2257.       return(0);
  2258.     }
  2259.   if ((fd = secopen(name, flags, 0666)) < 0)
  2260.     return(0);
  2261.   if ((fi = fdopen(fd, mode)) == 0)
  2262.     {
  2263.       close(fd);
  2264.       return(0);
  2265.     }
  2266. #endif
  2267.   return(fi);
  2268. }
  2269.  
  2270.  
  2271. int
  2272. secopen(name, flags, mode)
  2273. char *name;
  2274. int flags;
  2275. int mode;
  2276. {
  2277.   int fd;
  2278. #ifdef NOREUID
  2279.   int q;
  2280.   struct stat stb;
  2281. #endif
  2282.  
  2283.   debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
  2284.   if (eff_uid == real_uid)
  2285.     return(open(name, flags, mode));
  2286. #ifndef NOREUID
  2287.   setreuid(eff_uid, real_uid);
  2288.   setregid(eff_gid, real_gid);
  2289.   fd = open(name, flags, mode);
  2290.   setreuid(real_uid, eff_uid);
  2291.   setregid(real_gid, eff_gid);
  2292. #else
  2293.   /* Truncation/creation is done in UserContext */
  2294.   if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
  2295.     {
  2296.       if (UserContext() > 0)
  2297.     {
  2298.           if ((fd = open(name, flags, mode)) >= 0)
  2299.         {
  2300.           close(fd);
  2301.           UserReturn(0);
  2302.             }
  2303.       if (errno == 0)
  2304.         errno = EACCES;
  2305.       UserReturn(errno);
  2306.     }
  2307.       if (q = UserStatus())
  2308.     {
  2309.       if (q > 0)
  2310.         errno = q;
  2311.           return(-1);
  2312.     }
  2313.     }
  2314.   if (access(name, F_OK))
  2315.     return(-1);
  2316.   if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
  2317.     return(-1);
  2318.   debug("open successful\n");
  2319.   if (fstat(fd, &stb))
  2320.     {
  2321.       close(fd);
  2322.       return(-1);
  2323.     }
  2324.   debug("fstat successful\n");
  2325.   if (stb.st_uid != real_uid)
  2326.     {
  2327.       switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
  2328.         {
  2329.     case O_RDONLY:
  2330.       q = 0004;
  2331.       break;
  2332.     case O_WRONLY:
  2333.       q = 0002;
  2334.       break;
  2335.     default:
  2336.       q = 0006;
  2337.       break;
  2338.         }
  2339.       if ((stb.st_mode & q) != q)
  2340.     {
  2341.           debug("secopen: permission denied\n");
  2342.       close(fd);
  2343.       errno = EACCES;
  2344.       return(-1);
  2345.     }
  2346.     }
  2347. #endif
  2348.   debug1("secopen ok - returning %d\n", fd);
  2349.   return(fd);
  2350. }
  2351.