* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Copyright (c) 1987 Oliver Laumann
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* Noteworthy contributors to screen's design and implementation:
* Wayne Davison (davison@borland.com)
* Patrick Wolfe (pat@kai.com, kailand!pat)
* Bart Schaefer (schaefer@cse.ogi.edu)
* Nathan Glasser (nathan@brokaw.lcs.mit.edu)
* Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
* Howard Chu (hyc@hanauma.jpl.nasa.gov)
* Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
* Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
* Marc Boucher (marc@CAM.ORG)
****************************************************************
static char rcs_id
[] = "$Id: fileio.c,v 1.2 92/02/03 02:27:42 jnweiger Exp $ FAU";
#if defined(pyr) || defined(MIPS) || defined(GOULD_NP1) || defined(B43)
# define UTHOST /* _SEQUENT_ has got ut_find_host() */
static char *tt
, *ttnext
;
static char ttys
[] = "/etc/ttys";
static char KmemName
[] = "/dev/kmem";
# if defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi)
static char UnixName
[] = "/unix";
static char UnixName
[] = "/dynix";
static char UnixName
[] = "/hp-ux";
static char UnixName
[] = "/xelos";
static char UnixName
[] = "/vmunix";
# endif /* _SEQUENT_ ... */
static char AvenrunSym
[] = "_Loadavg";
# if defined(hpux) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi)
static char AvenrunSym
[] = "avenrun";
static char AvenrunSym
[] = "_avenrun";
static struct nlist nl
[2];
struct processor_set_basic_info info
;
processor_set_t default_set
;
#if defined(UTMPOK) && defined(GETUTENT) && !defined(SVR4)
# if defined(hpux) /* cruel hpux release 8.0 */
# define pututline _pututline
extern struct utmp
*getutline(), *pututline();
extern struct utmp
*ut_add_user(), *ut_delete_user();
extern char *ut_find_host();
extern char *RcFileName
, *home
, *extra_incap
, *extra_outcap
;
extern char *BellString
, *ActivityString
, *ShellProg
, *ShellArgs
[];
extern char *BufferFile
, *PowDetachString
, *VisualBellString
;
extern int VBellWait
, MsgWait
, MsgMinWait
;
extern struct key ktab
[];
extern char Esc
, MetaEsc
;
extern char *shellaka
, SockPath
[], *SockNamePtr
, *LoginName
;
extern int loginflag
, allflag
, TtyMode
, auto_detach
;
extern int iflag
, rflag
, dflag
;
extern int default_flow
, wrap
;
extern HS
, termcapHS
, use_hardstatus
, visual_bell
, default_monitor
;
extern int default_histheight
;
extern int default_startup
;
extern DeadlyMsg
, HasWindow
;
extern ForeNum
, screenwidth
, screenheight
;
extern char display_tty
[];
extern char screenterm
[];
extern struct mode OldMode
, NewMode
;
extern char mark_key_tab
[];
extern int real_uid
, eff_uid
;
extern int real_gid
, eff_gid
;
static char *CatExtra
__P((char *, char *));
static char **SaveArgs
__P((int, char **));
static int Parse
__P((char *, char *[]));
static char *ParseChar
__P((char *, char *));
static void ParseNum
__P((int, char *[], int*));
static void ParseOnOff
__P((int, char *[], int*));
static void ParseSaveStr
__P((int, char *[], char **, char *));
static int IsNum
__P((char *, int));
static int IsNumColon
__P((char *, int, char *, int));
static slot_t TtyNameSlot
__P((char *));
#if !defined(GETTTYENT) && !defined(GETUTENT)
static void setttyent
__P((void));
static struct ttyent
*getttyent
__P((void));
extern time_t time
__P((time_t *));
#if !defined(BSDI) && !defined(SVR4)
extern char *getpass
__P((char *));
#endif /* !BSDI && !SVR4 */
#if defined(LOADAV) && !defined(NeXT) && !defined(NLIST_DECLARED)
extern int nlist
__P((char *, struct nlist
*));
"select0", "select1", "select2", "select3", "select4",
"select5", "select6", "select7", "select8", "select9",
"aka", "clear", "colon", "copy", "detach", "flow",
"hardcopy", "help", "histnext", "history", "info", "kill", "lastmsg",
"lockscreen", "log", "login", "monitor", "next", "other", "paste",
"pow_detach", "prev", "quit", "readbuf", "redisplay", "removebuf",
"reset", "set", "shell", "suspend", "termcap", "time", "vbell",
"version", "width", "windows", "wrap", "writebuf", "xoff", "xon",
/* Must be in alpha order !!! */
"activity", "all", "autodetach", "bell", "bind", "bufferfile", "chdir",
"crlf", "echo", "escape", "flow", "hardcopy_append", "hardstatus", "login",
"markkeys", "mode", "monitor", "msgminwait", "msgwait", "nethack", "password",
"pow_detach_msg", "redraw", "refresh", "screen", "scrollback", "shell",
"shellaka", "sleep", "slowpaste", "startup_message", "term", "termcap",
"terminfo", "vbell", "vbell_msg", "vbellwait", "visualbell",
"visualbell_msg", "wrap",
static char UtmpName
[] = UTMPFILE
;
if ((cp
= malloc(strlen(str
) + 1)) == NULL
)
static char *CatExtra(str1
, str2
)
register char *str1
, *str2
;
register int len1
, len2
, add_colon
;
add_colon
= (str1
[len1
- 1] != ':');
if ((cp
= realloc(str2
, (unsigned) len1
+ len2
+ add_colon
+ 1)) == NULL
)
bcopy(cp
, cp
+ len1
+ add_colon
, len2
+ 1);
if ((cp
= malloc((unsigned) len1
+ add_colon
+ 1)) == NULL
)
cp
[len1
+ add_colon
] = '\0';
static char *findrcfile(rcfile
)
debug1("findrcfile: you specified '%s'\n", rcfile
);
debug("findrcfile: you specified nothing...\n");
if ((p
= getenv("ISCREENRC")) != NULL
&& *p
!= '\0')
debug1(" ... but $ISCREENRC has: '%s'\n", p
);
else if ((p
= getenv("SCREENRC")) != NULL
&& *p
!= '\0')
debug1(" ... but $SCREENRC has: '%s'\n", p
);
debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
Msg(0, "Rc: home too large");
sprintf(buf
, "%s/.iscreenrc", home
);
sprintf(buf
, "%s/.screenrc", home
);
* this will be called twice:
* 1) rcfilename = "/etc/screenrc"
* 2) rcfilename = RcFileName
rc_name
= findrcfile(rcfilename
);
if ((fp
= secfopen(rc_name
, "r")) == NULL
)
if (RcFileName
&& strcmp(RcFileName
, rc_name
) == 0)
* User explicitly gave us that name,
* this is the only case, where we get angry, if we can't read
debug3("StartRc: '%s','%s', '%s'\n", RcFileName
, rc_name
, rcfilename
);
Msg(0, "Unable to open \"%s\".", rc_name
);
debug1("StartRc: '%s' no good. ignored\n", rc_name
);
if ((t
= getenv("TERM")) == NULL
)
Msg(0, "No TERM in environment.");
debug1("startrc got termcp:%s\n", t
);
while (fgets(buf
, sizeof buf
, fp
) != NULL
)
if ((p
= rindex(buf
, '\n')) != NULL
)
if ((argc
= Parse(buf
, args
)) == 0)
if (strcmp(args
[0], "echo") == 0)
if (argc
< 2 || (argc
== 3 && strcmp(args
[1], "-n")) || argc
> 3)
Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
printf((argc
== 3) ? "%s" : "%s\r\n", args
[argc
- 1]);
else if (strcmp(args
[0], "sleep") == 0)
Msg(0, "%s: sleep: one numeric argument expected.", rc_name
);
else if (strcmp(args
[0], "terminfo") == 0)
else if (strcmp(args
[0], "termcap") == 0)
if (argc
< 3 || argc
> 4)
Msg(0, "%s: %s: incorrect number of arguments.", rc_name
, args
[0]);
for (p
= args
[1]; p
&& *p
; p
= cp
)
if ((cp
= index(p
, '|')) != 0)
if (!(len
- 1) || !strncmp(p
, t
, len
- 1))
extra_incap
= CatExtra(args
[2], extra_incap
);
extra_outcap
= CatExtra(args
[3], extra_outcap
);
else if (*p
== '\\' && *++p
<= '7' && *p
>= '0')
*cp
= *cp
* 8 + *p
- '0';
while (*++p
<= '7' && *p
>= '0');
* CompileKeys must be called before Markroutine is first used.
* to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
* s is an ascii string in a termcap-like syntax. It looks like
* "j=u:k=d:l=r:h=l: =.:" and so on...
* this example rebinds the cursormovement to the keys u (up), d (down),
* l (left), r (right). placing a mark will now be done with ".".
int CompileKeys(s
, array
)
unsigned char key
, value
;
for (i
= 0; i
< 256; i
++)
s
= ParseChar(s
, (char *) &key
);
s
= ParseChar(++s
, (char *) &value
);
static char **SaveArgs(argc
, argv
)
register char **ap
, **pp
;
if ((pp
= ap
= (char **) malloc((unsigned) (argc
+ 1) * sizeof(char **))) == 0)
*pp
++ = SaveStr(*argv
++);
/* in FinishRc screen is not yet open, thus Msg() is deadly here.
rc_name
= findrcfile(rcfilename
);
if ((fp
= secfopen(rc_name
, "r")) == NULL
)
if (RcFileName
&& strcmp(RcFileName
, rc_name
) == 0)
* User explicitly gave us that name,
* this is the only case, where we get angry, if we can't read
debug3("FinishRc:'%s','%s','%s'\n", RcFileName
, rc_name
, rcfilename
);
Msg(0, "Unable to open \"%s\".", rc_name
);
debug1("FinishRc: '%s' no good. ignored\n", rc_name
);
debug("finishrc is going...\n");
while (fgets(buf
, sizeof buf
, fp
) != NULL
)
* this is a KEY_SET pressed
if (!argv
|| !*argv
|| !**argv
)
while(*argv
&& (strlen(buf
) + strlen(*argv
) < 255))
sprintf(p
, " %s", *argv
++);
* "$HOST blafoo" -> "localhost blafoo"
* "${HOST}blafoo" -> "localhostblafoo"
* "\$HOST blafoo" -> "$HOST blafoo"
* "\\$HOST blafoo" -> "\localhost blafoo"
* "'$HOST ${HOST}'" -> "'$HOST ${HOST}'"
* "'\$HOST'" -> "'\$HOST'"
* "\'$HOST' $HOST" -> "'localhost' $HOST"
static char *expand_env_vars(ss
)
register int esize
= 2047, quofl
= 0;
while (*s
&& *s
!= '\n' && esize
> 0)
while (*p
!= ' ' && *p
!= '\0' && *p
!= '\n')
debug1("exp: c='%c'\n", c
);
debug2("exp: $'%s'='%s'\n", s
, v
);
while (*v
&& esize
-- > 0)
debug1("exp: '%s' not env\n", s
);
if (s
[0] == '\\' && !quofl
)
if (s
[1] == '$' || (s
[1] == '\\' && s
[2] == '$') ||
s
[1] == '\'' || (s
[1] == '\\' && s
[2] == '\''))
Msg(0, "expand_env_vars: buffer overflow\n");
register char *buf
, *p
, **pp
, **ap
;
register int argc
, setflag
;
buf
= expand_env_vars(ubuf
);
if ((p
= rindex(buf
, '\n')) != NULL
)
if (strncmp("set ", buf
, 4) == 0)
debug1("RcLine: '%s' is a set command\n", buf
);
else if (strncmp("se ", buf
, 3) == 0)
debug1("RcLine: '%s' is a se command\n", buf
);
debug1("RcLine: '%s'\n", buf
);
if ((argc
= Parse(buf
, ap
)) == 0)
Msg(0, "%s: set what?\n", rc_name
);
high
= (int)RC_RCEND
- 1;
x
= strcmp(ap
[0], RCNames
[mid
]);
switch ((enum RCcases
) mid
)
if (argc
!= 2 || !ParseEscape(ap
[1]))
Msg(0, "%s: two characters required after escape.", rc_name
);
ktab
[Esc
].type
= KEY_OTHER
;
ktab
[Esc
].type
= KEY_IGNORE
;
p
= argc
< 2 ? home
: ap
[1];
ParseSaveStr(argc
, ap
, &ShellProg
, "shell");
ShellArgs
[0] = ShellProg
;
ParseSaveStr(argc
, ap
, &shellaka
, "shellaka");
DoScreen(rc_name
, ap
+ 1);
return; /* Already handled */
ParseSaveStr(argc
, ap
, &tmp
, "term");
Msg(0,"%s: term: argument too long ( < 20)", rc_name
);
strcpy(screenterm
, args
[1]);
debug1("screenterm set to %s\n", screenterm
);
if (HasWindow
&& *rc_name
== '\0')
* user typed ^A:echo... well, echo isn't FinishRc's job,
* but as he wanted to test us, we show good will
if (argc
== 2 || (argc
== 3 && !strcmp(ap
[1], "-n")))
Msg(0, "%s", ap
[argc
- 1]);
Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name
);
ParseSaveStr(argc
, ap
, &BellString
, "bell");
ParseSaveStr(argc
, ap
, &BufferFile
, "bufferfile");
ParseSaveStr(argc
, ap
, &ActivityString
, "activity");
ParseSaveStr(argc
, ap
, &PowDetachString
, "pow_detach");
ParseOnOff(argc
, ap
, &loginflag
);
SlotToggle(loginflag
?(1):(-1));
if (argc
== 3 && ap
[2][0] == 'i')
if (argc
== 2 && ap
[1][0] == 'a')
default_flow
= FLOW_AUTOFLAG
;
ParseOnOff(argc
, ap
, &default_flow
);
ParseOnOff(argc
, ap
, &wrap
);
ParseOnOff(argc
, ap
, &use_hardstatus
);
ParseOnOff(argc
, ap
, &f
);
fore
->monitor
= (f
== 0) ? MON_OFF
: MON_ON
;
default_monitor
= (f
== 0) ? MON_OFF
: MON_ON
;
ParseOnOff(argc
, ap
, &r
);
fore
->norefresh
= (r
) ? 0 : 1;
all_norefresh
= (r
) ? 0 : 1;
Msg(0, "No refresh on window change!\n");
Msg(0, "Window specific refresh\n");
ParseOnOff(argc
, ap
, &visual_bell
);
ParseNum(argc
, ap
, &VBellWait
);
if (fore
&& rc_name
[0] == '\0')
Msg(0, "vbellwait set to %d seconds", VBellWait
);
ParseNum(argc
, ap
, &MsgWait
);
if (fore
&& rc_name
[0] == '\0')
Msg(0, "msgwait set to %d seconds", MsgWait
);
ParseNum(argc
, ap
, &MsgMinWait
);
if (fore
&& rc_name
[0] == '\0')
Msg(0, "msgminwait set to %d seconds", MsgMinWait
);
ChangeScrollback(fore
, i
, fore
->width
);
if (fore
&& rc_name
[0] == '\0')
Msg(0, "scrollback set to %d", fore
->histheight
);
ParseNum(argc
, ap
, &default_histheight
);
ParseNum(argc
, ap
, &slowpaste
);
if (fore
&& rc_name
[0] == '\0')
Msg(0, "slowpaste set to %d milliseconds", slowpaste
);
ParseSaveStr(argc
, ap
, &tmp
, "markkeys");
if (CompileKeys(ap
[1], mark_key_tab
))
Msg(0, "%s: markkeys: syntax error.", rc_name
);
debug1("markkeys %s\n", ap
[1]);
ParseOnOff(argc
, ap
, &nethackflag
);
ParseOnOff(argc
, ap
, &hardcopy_append
);
ParseSaveStr(argc
, ap
, &VisualBellString
, "vbell_msg");
debug1(" new vbellstr '%s'\n", VisualBellString
);
Msg(0, "%s: mode: one argument required.", rc_name
);
Msg(0, "%s: mode: octal number expected.", rc_name
);
(void) sscanf(ap
[1], "%o", &TtyMode
);
ParseOnOff(argc
, ap
, &join_with_cr
);
ParseOnOff(argc
, ap
, &auto_detach
);
ParseOnOff(argc
, ap
, &default_startup
);
strncpy(Password
, ap
[1], sizeof Password
);
if (!strcmp(Password
, "none"))
Msg(0, "Cannot ask for password on POSIX systems");
/* there is a clear screen sequence in the buffer. */
strncpy(Password
, getpass("New screen password:"),
if (strcmp(Password
, getpass("Retype new password:")))
mstr
= "[ Passwords don't match - your armor crumbles away ]";
mstr
= "[ Passwords don't match - checking turned off ]";
mstr
= "[ No password - no secure ]";
salt
[st
] = 'A' + (int)((time(0) >> 6*st
) % 26);
strncpy(Password
, crypt(Password
, salt
), sizeof(Password
));
copylen
= strlen(Password
);
if ((copybuffer
= (char *) malloc(copylen
+1)) == NULL
)
strcpy(copybuffer
, Password
);
mstr
= "[ Password moved into copybuffer ]";
mstr
= "[ Crypted password is \"%s\" ]";
Activate(0); /* Redraw */
debug1("finishrc: our password is: --%s%-- \n", Password
);
if (!setflag
|| !HasWindow
|| *rc_name
)
if (argc
< 2 || *p
== '\0')
Msg(0, "%s: key expected after bind.", rc_name
);
if ((p
= ParseChar(p
, &key
)) == NULL
|| *p
)
Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
if (ktab
[key
].type
!= KEY_IGNORE
)
ktab
[key
].type
= KEY_IGNORE
;
if ((pp
= ktab
[key
].args
) != NULL
)
for (pp
= KeyNames
; *pp
; ++pp
)
if (strcmp(ap
[2], *pp
) == 0)
ktab
[key
].type
= (enum keytype
) (pp
- KeyNames
+ 1);
ktab
[key
].args
= SaveArgs(argc
- 3, ap
+ 3);
ktab
[key
].type
= KEY_CREATE
;
ktab
[key
].args
= SaveArgs(argc
- 2, ap
+ 2);
* now we are user-friendly:
* if anyone typed a key name like "help" or "next" ...
* we did not match anything above. so look in the KeyNames table.
debug1("--ap[0] %s\n", ap
[0]);
for (pp
= KeyNames
; *pp
; ++pp
)
if (strcmp(ap
[0], *pp
) == 0)
ibuf
[1] = pp
- KeyNames
+1;
debug1("RcLine: it was a keyname: '%s'\n", *pp
);
ProcessInput(ibuf
, &q
, (char *)0, &qq
, 0);
Msg(0, "%s: Key '%s' has no effect while no window open...\n",
Msg(0, "%s: unknown %skeyword \"%s\"", rc_name
,
setflag
?"'set' ":"", ap
[0]);
register char *p
= buf
, **ap
= args
;
register int delim
, argc
;
while (*p
&& (*p
== ' ' || *p
== '\t'))
if (*p
== '\0' || *p
== '#')
Msg(0, "%s: too many tokens.", rc_name
);
if (*p
== '"' || *p
== '\'')
while (*p
&& !(delim
? *p
== delim
: (*p
== ' ' || *p
== '\t')))
Msg(0, "%s: Missing quote.", rc_name
);
if ((p
= ParseChar(p
, &Esc
)) == NULL
||
(p
= ParseChar(p
, &MetaEsc
)) == NULL
|| *p
)
if (argc
== 2 && ap
[1][0] != '\0')
if (*p
>= '0' && *p
<= '9')
Msg(0, "%s: %s: invalid argument. Give numeric argument",
Msg(0, "%s: %s: invalid argument. Give one argument",
debug1("ParseNum got %d\n", i
);
ParseSaveStr(argc
, ap
, var
, title
)
Msg(0, "%s: %s: one argument required.", rc_name
, title
);
ParseOnOff(argc
, ap
, var
)
if (argc
== 2 && ap
[1][0] == 'o')
else if (ap
[1][1] == 'n')
Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name
, ap
[0]);
static int IsNum(s
, base
)
for (base
+= '0'; *s
; ++s
)
if (*s
< '0' || *s
> base
)
static int IsNumColon(s
, base
, p
, psize
)
if ((q
= rindex(s
, ':')) != NULL
)
strncpy(p
, q
+ 1, psize
- 1);
* how = 0 real toggle mode
* how > 0 do try to set a utmp slot.
* how < 0 try to withdraw a utmp slot
* slot = -1 window not logged in.
* slot = 0 window not logged in, but should be logged in.
* (unable to write utmp, or detached).
debug1("SlotToggle %d\n", how
);
how
= (fore
->slot
== (slot_t
) -1)?(1):(-1);
* slot 0 or active -> we try to log out.
* slot -1 -> we try to log in.
debug(" try to log in\n");
if ((fore
->slot
== (slot_t
) -1) || (fore
->slot
== (slot_t
) 0))
if (CountUsers() >= USRLIMIT
)
Msg(0, "User limit reached.");
if (SetUtmp(fore
, ForeNum
) == 0)
Msg(0, "This window is now logged in.");
Msg(0, "This window should now be logged in.");
Msg(0, "This window is already logged in.");
debug(" try to log out\n");
if (fore
->slot
== (slot_t
) -1)
Msg(0, "This window is already logged out\n");
else if (fore
->slot
== (slot_t
) 0)
debug("What a relief! In fact, it was not logged in\n");
Msg(0, "This window is not logged in.");
fore
->slot
= (slot_t
) -1;
if (fore
->slot
!= (slot_t
) -1)
Msg(0, "What? Cannot remove Utmp slot?");
Msg(0, "This window is no longer logged in.");
Msg(0, "Unable to modify %s.\n", UTMPFILE
);
register int flowflag
, num
, lflag
= loginflag
, aflag
= 0;
register char *aka
= NULL
;
register int histheight
= default_histheight
;
while (av
&& *av
&& av
[0][0] == '-')
flowflag
= FLOW_AUTOFLAG
;
histheight
= atoi(av
[0] + 2);
Msg(0, "%s: screen: invalid option -%c.", fn
, av
[0][1]);
if (av
&& *av
&& IsNumColon(*av
, 10, buf
, sizeof(buf
)))
if (num
< 0 || num
> MAXWIN
- 1)
Msg(0, "%s: illegal screen number %d.", fn
, num
);
MakeWindow(aka
, av
, aflag
, flowflag
, num
, (char *) 0, lflag
, histheight
, termp
);
/* dump==0: create .termcap,
i
= SockNamePtr
- SockPath
;
strncpy(fn
, SockPath
, i
);
strcpy(fn
+ i
, ".termcap");
sprintf(fn
, "hardcopy.%d", ForeNum
);
if (hardcopy_append
&& !access(fn
, W_OK
))
sprintf(fn
, "%s", BufferFile
);
debug2("WriteFile(%d) %s\n", dump
, fn
);
debug("Writefile: usercontext\n");
if ((f
= fopen(fn
, mode
)) == NULL
)
debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn
, mode
);
for (j
= screenwidth
- 2; j
> 0; j
--)
for (i
= 0; i
< screenheight
; ++i
)
for (k
= screenwidth
- 1; k
>= 0 && p
[k
] == ' '; --k
)
if ((p
= index(MakeTermcap(fore
->aflag
), '=')) != NULL
)
for (i
= 0; i
< copylen
; i
++)
Msg(0, "Cannot open \"%s\"", fn
);
Msg(0, "Termcap entry written to \"%s\".", fn
);
Msg(0, "Screen image %s to \"%s\".",
(*mode
== 'a') ? "appended" : "written", fn
);
Msg(0, "Copybuffer written to \"%s\".", fn
);
sprintf(fn
, "%s", BufferFile
);
debug1("ReadFile(%s)\n", fn
);
if ((i
= secopen(fn
, O_RDONLY
, 0)) < 0)
Msg(errno
, "no %s -- no slurp", fn
);
Msg(errno
, "no good %s -- no slurp", fn
);
if ((copybuffer
= malloc(size
)) == NULL
)
if ((l
= read(i
, copybuffer
, size
)) != size
)
copylen
= (l
> 0) ? l
: 0;
Msg(errno
, "You choke on your food: %d bytes", copylen
);
Msg(errno
, "Got only %d bytes from %s", copylen
, fn
);
Msg(0, "Slurped only %d characters into buffer - try again", copylen
);
Msg(0, "Slurped %d characters into buffer", copylen
);
sprintf(fn
, "%s", BufferFile
);
if (access(fn
, W_OK
) == -1)
Msg(errno
, "%s not removed", fn
);
Msg(errno
, "%s removed", fn
);
struct utmp
*ut
, *getutent();
debug1("CountUsers() - utmp=%d\n",utmp
);
if (ut
->ut_type
== USER_PROCESS
)
(void) lseek(utmpf
, (off_t
) 0, 0);
while (read(utmpf
, &utmpbuf
, sizeof(struct utmp
)) > 0)
if (utmpbuf
.ut_name
[0] != '\0')
static struct utmp utmp_logintty
;
static char loginhost
[100+1];
debug("InitUtmp testing...\n");
if ((utmpf
= open(UtmpName
, O_RDWR
)) == -1)
debug("InitUtmp failed.\n");
if ((utmpfappend
= open(UtmpName
, O_APPEND
)) == -1)
debug("Reinitutmp: utmp == 0\n");
debug("(Re)InitUtmp: removing your logintty\n");
loginslot
= TtyNameSlot(display_tty
);
if (loginslot
!=(slot_t
)0 && loginslot
!=(slot_t
)-1)
if (p
=ut_find_host(loginslot
))
strncpy(loginhost
, p
, 100);
RemoveLoginSlot(loginslot
, &utmp_logintty
);
debug1(" slot %d zapped\n", loginslot
);
debug("RestoreLoginSlot()\n");
if (utmp
&& loginslot
!=(slot_t
)0 && loginslot
!=(slot_t
)-1)
debug1(" logging you in again (slot %s)\n", loginslot
);
* We have problems if we add the console and use ut_add_user()
* because the id will be 'scon' instead of 'co'. So we
* restore it with pututline(). The reason why we don't use
* pututline all the time is that we want to set the host field.
* Unfortunatelly this can only be done with ut_add_user().
fail
= (ut_add_user(LoginName
, loginslot
, utmp_logintty
.ut_pid
,
*loginhost
?loginhost
:(char *)0) == 0);
fail
= (pututline(&utmp_logintty
) == 0);
debug1(" logging you in again (slot %s)\n", loginslot
);
if (pututline(&utmp_logintty
)==0)
debug1(" logging you in again (slot %d)\n", loginslot
);
/* call sequent undocumented routine to count logins and add utmp entry if possible */
if (add_utmp(loginslot
, &utmp_logintty
) == -1)
(void) lseek(utmpf
, (off_t
) (loginslot
* sizeof(struct utmp
)), 0);
if (write(utmpf
, (char *) &utmp_logintty
, sizeof(struct utmp
))
Msg(errno
, "%s is too hard to dig in.", UTMPFILE
);
Msg(errno
,"Could not write %s.", UTMPFILE
);
RemoveLoginSlot(slot
, up
)
debug2("RemoveLoginSlot(%s, %08x)\n", (slot
== (slot_t
) 0 ||
slot
== (slot_t
) -1 ) ? "no slot" : slot
, up
);
debug2("RemoveLoginSlot(%d, %08x)\n", slot
, up
);
bzero((char *)up
, sizeof(struct utmp
));
uq
= (struct utmp
*)malloc(sizeof(struct utmp
));
bzero((char *)uq
, sizeof(struct utmp
));
if (slot
!= (slot_t
) 0 && slot
!= (slot_t
) -1)
bzero((char *) &u
, sizeof u
);
strncpy(u
.ut_line
, slot
, sizeof(u
.ut_line
));
if ((uu
= getutline(&u
)) == 0)
Msg(0, "Utmp slot not found -> not removed");
if (ut_delete_user(slot
, uu
->ut_pid
, 0, 0) == 0)
uu
->ut_type
= DEAD_PROCESS
;
uu
->ut_exit
.e_termination
= 0;
(void) lseek(utmpf
, (off_t
) (slot
* sizeof u
), 0);
if (read(utmpf
, (char *) up
, sizeof u
) != sizeof u
)
Msg(errno
, "cannot read %s ???", UTMPFILE
);
(void) lseek(utmpf
, (off_t
) (slot
* sizeof u
), 0);
bcopy((char *)up
, (char *)uq
, sizeof(struct utmp
));
bzero(uq
->ut_name
, sizeof(uq
->ut_name
));
bzero(uq
->ut_host
, sizeof(uq
->ut_host
));
if (write(utmpf
, (char *)uq
, sizeof(struct utmp
)) != sizeof(struct utmp
))
if (write(utmpf
, (char *) &u
, sizeof u
) != sizeof u
)
Msg(errno
, "%s is too hard to dig in.", UTMPFILE
);
Msg(errno
, "Could not write %s.", UTMPFILE
);
debug1("There is no utmp-slot to be removed(%d)\n", slot
);
if (p
= strstr(nam
,"/dev/"))
if (strncmp(nam
, "/dev/", 5) == 0)
static slot_t
TtyNameSlot(nam
)
register struct ttyent
*tp
;
debug1("TtyNameSlot(%s)\n", nam
);
if (!utmp
|| nam
== NULL
)
up
= (struct utmp
*)malloc(sizeof(struct utmp
));
if ((read(utmpf
, (char *)up
, sizeof(struct utmp
)) ==
sizeof(struct utmp
)) && (strcmp(up
->ut_line
, name
)))
while ((tp
= getttyent()) != NULL
&& strcmp(name
, tp
->ty_name
) != 0)
debug2("'%s' %d, ", tp
->ty_name
, slot
);
SetUtmp(wi
, displaynumber
)
char host
[sizeof(utmp_logintty
.ut_host
)+5];
if ((slot
= TtyNameSlot(wi
->tty
)) == (slot_t
) NULL
)
debug1("SetUtmp failed (tty %s).\n",wi
->tty
);
debug2("SetUtmp %d will get slot %d...\n", displaynumber
, (int)slot
);
host
[sizeof(host
)-5] = '\0';
strncpy(host
, loginhost
, sizeof(host
) - 5);
strncpy(host
, utmp_logintty
.ut_host
, sizeof(host
) - 5);
if (loginslot
!= (slot_t
)0 && loginslot
!= (slot_t
)-1 && host
[0] != '\0')
* we want to set our ut_host field to something like
* "132.199.81.4:s.0" (even this may hurt..), but not
* "faui45.informati"......:s.0
if ((*p
< '0' || *p
> '9') && (*p
!= '.'))
strncpy(host
+ 1, stripdev(display_tty
), sizeof(host
) - 6);
debug1("rlogin hostname: '%s'\n", host
);
sprintf(host
+ strlen(host
), ":S.%c", '0' + displaynumber
);
debug1("rlogin hostname: '%s'\n", host
);
line
= stripdev(wi
->tty
);
bzero((char *) &u
, sizeof u
);
if (ut_add_user(LoginName
, slot
, wi
->wpid
, host
)==0)
strncpy(u
.ut_user
, LoginName
, sizeof(u
.ut_user
));
strncpy(u
.ut_id
, line
+ strlen(line
) - 2, sizeof(u
.ut_id
));
strncpy(u
.ut_line
, line
, sizeof(u
.ut_line
));
u
.ut_type
= USER_PROCESS
;
(void) time(&u
.ut_tv
.tv_sec
);
strncpy(u
.ut_host
, host
, sizeof(u
.ut_host
));
strncpy(u
.ut_line
, line
, sizeof(u
.ut_line
));
strncpy(u
.ut_name
, LoginName
, sizeof(u
.ut_name
));
strncpy(u
.ut_host
, host
, sizeof(u
.ut_host
));
u
.ut_type
= 7; /* USER_PROCESS */
strncpy(u
.ut_id
, line
+ 3, 4);
/* call sequent undocumented routine to count logins and add utmp entry if possible */
if (add_utmp(slot
, &u
) == -1)
(void) lseek(utmpf
, (off_t
) (slot
* sizeof u
), 0);
if (write(utmpf
, (char *) &u
, sizeof u
) != sizeof u
)
Msg(errno
, "%s is too hard to dig in.", UTMPFILE
);
Msg(errno
,"Could not write %s.", UTMPFILE
);
debug("SetUtmp successful\n");
ttyfd
= open(UtmpName
, O_RDONLY
);
static struct ttyent
*getttyent()
if (read(ttyfd
, &u
, sizeof u
))
strncpy(u
.ut_line
, name
, 8);
strncpy(u
.ut_name
, LoginName
, 8);
u
.ut_type
= 7; /* USER_PROCESS */
strncpy(u
.ut_id
, name
+3, 4);
slot
= (lseek(utmpfappend
, 0, 2) + 1) / sizeof u
;
(void) write(utmpfappend
, (char *)&u
, sizeof u
);
if ((utmpfappend
= open(UtmpName
, O_APPEND
)) == -1)
* if slot could be removed or was 0, wi->slot = -1;
debug1("RemoveUtmp(%s)\n", (slot
== (slot_t
) 0) ?
"no slot (0)":((slot
== (slot_t
) -1) ? "no slot (-1)" : slot
));
debug1("RemoveUtmp(wi.slot: %d)\n", slot
);
up
= (struct utmp
*)malloc(sizeof(struct utmp
));
bzero((char *)up
, sizeof(struct utmp
));
if (slot
== (slot_t
) 0 || slot
== (slot_t
) -1)
debug1("There is no utmp-slot to be removed(%d)\n", slot
);
bzero((char *) &u
, sizeof u
);
strncpy(u
.ut_line
, slot
, sizeof(u
.ut_line
));
if ((uu
= getutline(&u
)) == 0)
Msg(0, "Utmp slot not found -> not removed");
if (ut_delete_user(slot
, uu
->ut_pid
, 0, 0) == 0)
uu
->ut_type
= DEAD_PROCESS
;
uu
->ut_exit
.e_termination
= 0;
(void) lseek(utmpf
, (off_t
) (slot
* sizeof u
), 0);
if (read(utmpf
, (char *) up
, sizeof u
) != sizeof u
)
Msg(errno
, "cannot read %s?", UTMPFILE
);
(void) lseek(utmpf
, (off_t
) (slot
* sizeof u
), 0);
bzero(up
->ut_name
, sizeof(u
.ut_name
));
bzero(up
->ut_host
, sizeof(u
.ut_host
));
if (write(utmpf
, (char *)up
, sizeof u
) != sizeof u
)
if (write(utmpf
, (char *) &u
, sizeof u
) != sizeof u
)
Msg(errno
, "%s is too hard to dig in.", UTMPFILE
);
Msg(errno
,"Could not write %s.", UTMPFILE
);
debug("RemoveUtmp successfull\n");
#if !defined(GETTTYENT) && !defined(GETUTENT)
if ((f
= open(ttys
, O_RDONLY
)) == -1 || fstat(f
, &s
) == -1)
if ((tt
= malloc((unsigned) s
.st_size
+ 1)) == 0)
if (read(f
, tt
, s
.st_size
) != s
.st_size
)
for (p
= tt
, ep
= p
+ s
.st_size
; p
< ep
; ++p
)
static struct ttyent
*getttyent()
ttnext
+= strlen(ttnext
) + 1;
error
= processor_set_default(host_self(), &default_set
);
if (error
!= KERN_SUCCESS
)
mach_error("Error calling processor_set_default", error
);
info_count
= PROCESSOR_SET_BASIC_INFO_COUNT
;
error
= processor_set_info(default_set
, PROCESSOR_SET_BASIC_INFO
, &host
,
(processor_set_info_t
)&info
, &info_count
);
if (error
!= KERN_SUCCESS
)
mach_error("Error calling processor_set_info", error
);
loadav
= (float)info
.load_average
/ LOAD_SCALE
;
# else /* need kmem for load avg */
if ((kmemf
= open(KmemName
, O_RDONLY
)) == -1)
nl
[0].n_name
= AvenrunSym
;
debug2("Searching in %s for %s\n", UnixName
, nl
[0].n_name
);
if (/* nl[0].n_type == 0 || */ nl
[0].n_value
== 0)
nl
[0].n_value
&= ~(1 << 31); /* clear upper bit */
debug("AvenrunSym found!!\n");
loadav
[i
] = (double)load
[i
] / 65536.0;
if (lseek(kmemf
, (off_t
) nl
[0].n_value
, 0) == (off_t
) - 1)
if (read(kmemf
, (char *) loadav
, sizeof loadav
) != sizeof loadav
)
# endif /* !NeXT, need kmem for load avg */
* (Almost) secure open and fopen... mlschroe.
debug2("secfopen(%s, %s)\n", name
, mode
);
return(fopen(name
, mode
));
setreuid(eff_uid
, real_uid
);
setregid(eff_gid
, real_gid
);
setreuid(real_uid
, eff_uid
);
setregid(real_gid
, eff_gid
);
if (mode
[0] && mode
[1] == '+')
flags
= (mode
[0] == 'r') ? O_RDONLY
: O_WRONLY
;
flags
|= O_CREAT
| O_TRUNC
;
flags
|= O_CREAT
| O_APPEND
;
if ((fd
= secopen(name
, flags
, 0666)) < 0)
if ((fi
= fdopen(fd
, mode
)) == 0)
secopen(name
, flags
, mode
)
debug3("secopen(%s, 0x%x, 0%03o)\n", name
, flags
, mode
);
return(open(name
, flags
, mode
));
setreuid(eff_uid
, real_uid
);
setregid(eff_gid
, real_gid
);
fd
= open(name
, flags
, mode
);
setreuid(real_uid
, eff_uid
);
setregid(real_gid
, eff_gid
);
/* Truncation/creation is done in UserContext */
if ((flags
& O_TRUNC
) || ((flags
& O_CREAT
) && access(name
, F_OK
)))
if ((fd
= open(name
, flags
, mode
)) >= 0)
if ((fd
= open(name
, flags
& ~(O_TRUNC
| O_CREAT
), 0)) < 0)
debug("open successful\n");
debug("fstat successful\n");
if (stb
.st_uid
!= real_uid
)
switch (flags
& (O_RDONLY
| O_WRONLY
| O_RDWR
))
if ((stb
.st_mode
& q
) != q
)
debug("secopen: permission denied\n");
debug1("secopen ok - returning %d\n", fd
);
static char retbuf
[sizeof(u
.ut_user
)+1];
for (fd
= 0; fd
<= 2 && (tty
= ttyname(fd
)) == NULL
; fd
++)
if ((tty
== NULL
) || ((fd
= open(UTMP_FILE
, O_RDONLY
)) < 0))
while (read(fd
, &u
, sizeof(struct utmp
)) == sizeof(struct utmp
))
if (!strncmp(tty
, u
.ut_line
, sizeof(u
.ut_line
)))
strncpy(retbuf
, u
.ut_user
, sizeof(u
.ut_user
));
retbuf
[sizeof(u
.ut_user
)] = '\0';
if (u
.ut_type
== USER_PROCESS
)
return *retbuf
? retbuf
: NULL
;