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