home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
screen-3.5
/
part03
/
fileio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-25
|
16KB
|
750 lines
/* Copyright (c) 1993
* 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 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
****************************************************************
*/
#include "rcs.h"
RCS_ID("$Id: fileio.c,v 1.2 1993/06/23 17:46:30 jnweiger Exp $ FAU")
#include <sys/types.h>
#ifndef sgi
# include <sys/file.h>
#endif /* sgi */
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "config.h"
#include "screen.h"
#include "extern.h"
#ifdef NETHACK
extern nethackflag;
#endif
extern struct display *display;
extern struct win *fore;
extern int real_uid, eff_uid;
extern int real_gid, eff_gid;
extern char *extra_incap, *extra_outcap;
extern char *home, *RcFileName;
extern char SockPath[], *SockNamePtr;
#ifdef COPY_PASTE
extern char *BufferFile;
#endif
extern int hardcopy_append;
extern char *hardcopydir;
static char *CatExtra __P((char *, char *));
static FILE *fp = NULL;
char *rc_name;
static char *
CatExtra(str1, str2)
register char *str1, *str2;
{
register char *cp;
register int len1, len2, add_colon;
len1 = strlen(str1);
if (len1 == 0)
return(str2);
add_colon = (str1[len1 - 1] != ':');
if (str2)
{
len2 = strlen(str2);
if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
Panic(0, strnomem);
bcopy(cp, cp + len1 + add_colon, len2 + 1);
}
else
{
if (len1 == 0)
return 0;
if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
Panic(0, strnomem);
cp[len1 + add_colon] = '\0';
}
bcopy(str1, cp, len1);
if (add_colon)
cp[len1] = ':';
return cp;
}
static char *
findrcfile(rcfile)
char *rcfile;
{
static char buf[256];
char *rc, *p;
if (rcfile)
{
rc = SaveStr(rcfile);
debug1("findrcfile: you specified '%s'\n", rcfile);
}
else
{
debug("findrcfile: you specified nothing...\n");
if ((p = getenv("ISCREENRC")) != NULL && *p != '\0')
{
debug1(" ... but $ISCREENRC has: '%s'\n", p);
rc = SaveStr(p);
}
else if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
{
debug1(" ... but $SCREENRC has: '%s'\n", p);
rc = SaveStr(p);
}
else
{
debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
if (strlen(home) > 244)
Panic(0, "Rc: home too large");
sprintf(buf, "%s/.iscreenrc", home);
if (access(buf, R_OK))
sprintf(buf, "%s/.screenrc", home);
rc = SaveStr(buf);
}
}
return rc;
}
/*
* this will be called twice:
* 1) rcfilename = "/etc/screenrc"
* 2) rcfilename = RcFileName
*/
void
StartRc(rcfilename)
char *rcfilename;
{
register int argc, len;
register char *p, *cp;
char buf[256];
char *args[MAXARGS];
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
* the file.
*/
debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
Panic(0, "Unable to open \"%s\".", rc_name);
/* NOTREACHED */
}
debug1("StartRc: '%s' no good. ignored\n", rc_name);
Free(rc_name);
rc_name = "";
return;
}
while (fgets(buf, sizeof buf, fp) != NULL)
{
if ((p = rindex(buf, '\n')) != NULL)
*p = '\0';
if ((argc = Parse(buf, args)) == 0)
continue;
if (strcmp(args[0], "echo") == 0)
{
if (!display)
continue;
if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
{
Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
continue;
}
AddStr(args[argc - 1]);
if (argc != 3)
{
AddStr("\r\n");
Flush();
}
}
else if (strcmp(args[0], "sleep") == 0)
{
if (!display)
continue;
debug("sleeeeeeep\n");
if (argc != 2)
{
Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
continue;
}
DisplaySleep(atoi(args[1]));
}
#ifdef TERMINFO
else if (strcmp(args[0], "terminfo") == 0)
#else
else if (strcmp(args[0], "termcap") == 0)
#endif
{
if (!display)
continue;
if (argc < 3 || argc > 4)
{
Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
continue;
}
for (p = args[1]; p && *p; p = cp)
{
if ((cp = index(p, '|')) != 0)
*cp++ = '\0';
len = strlen(p);
if (p[len - 1] == '*')
{
if (!(len - 1) || !strncmp(p, d_termname, len - 1))
break;
}
else if (!strcmp(p, d_termname))
break;
}
if (!(p && *p))
continue;
extra_incap = CatExtra(args[2], extra_incap);
if (argc == 4)
extra_outcap = CatExtra(args[3], extra_outcap);
}
}
fclose(fp);
Free(rc_name);
rc_name = "";
}
void
FinishRc(rcfilename)
char *rcfilename;
{
char buf[256];
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
* the file.
*/
debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
Panic(0, "Unable to open \"%s\".", rc_name);
/* NOTREACHED */
}
debug1("FinishRc: '%s' no good. ignored\n", rc_name);
Free(rc_name);
rc_name = "";
return;
}
debug("finishrc is going...\n");
while (fgets(buf, sizeof buf, fp) != NULL)
{
RcLine(buf);
}
(void) fclose(fp);
Free(rc_name);
rc_name = "";
}
/*
* "$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"
*
* "$:termcapname:" -> "termcapvalue"
* "$:terminfoname:" -> "termcapvalue"
*
* "\101" -> "A"
*/
char *
expand_vars(ss)
char *ss;
{
static char ebuf[2048];
register int esize = 2047, vtype, quofl = 0;
register char *e = ebuf;
register char *s = ss;
register char *v;
char xbuf[11];
while (*s && *s != '\0' && *s != '\n' && esize > 0)
{
if (*s == '\'')
quofl ^= 1;
if (*s == '$' && !quofl)
{
char *p, c;
p = ++s;
switch (*s)
{
case '{':
p = ++s;
while (*p != '}')
if (*p++ == '\0')
return ss;
vtype = 0; /* env var */
break;
case ':':
p = ++s;
while (*p != ':')
if (*p++ == '\0')
return ss;
vtype = 1; /* termcap string */
break;
default:
while (*p != ' ' && *p != '\0' && *p != '\n')
p++;
vtype = 0; /* env var */
}
c = *p;
debug1("exp: c='%c'\n", c);
*p = '\0';
if (vtype == 0)
{
v = xbuf;
if (strcmp(s, "TERM") == 0)
v = display ? d_termname : "unknown";
else if (strcmp(s, "COLUMNS") == 0)
sprintf(xbuf, "%d", display ? d_width : -1);
else if (strcmp(s, "LINES") == 0)
sprintf(xbuf, "%d", display ? d_height : -1);
else
v = getenv(s);
}
else
v = gettermcapstring(s);
if (v)
{
debug2("exp: $'%s'='%s'\n", s, v);
while (*v && esize-- > 0)
*e++ = *v++;
}
else
debug1("exp: '%s' not env\n", s); /* {-: */
if ((*p = c) == '}' || c == ':')
p++;
s = p;
}
else
{
/*
* \$, \\$, \\, \\\, \012 are reduced here,
* d_other sequences starting whith \ are passed through.
*/
if (s[0] == '\\' && !quofl)
{
if (s[1] >= '0' && s[1] <= '7')
{
int i;
s++;
i = *s - '0';
s++;
if (*s >= '0' && *s <= '7')
{
i = i * 8 + *s - '0';
s++;
if (*s >= '0' && *s <= '7')
{
i = i * 8 + *s - '0';
s++;
}
}
debug2("expandvars: octal coded character %o (%d)\n", i, i);
*e++ = i;
}
else
{
if (s[1] == '$' ||
(s[1] == '\\' && s[2] == '$') ||
s[1] == '\'' ||
(s[1] == '\\' && s[2] == '\''))
s++;
}
}
*e++ = *s++;
esize--;
}
}
if (esize <= 0)
Msg(0, "expand_vars: buffer overflow\n");
*e = '\0';
return ebuf;
}
void
RcLine(ubuf)
char *ubuf;
{
char *args[MAXARGS], *buf;
struct action act;
buf = expand_vars(ubuf);
if (Parse(buf, args) <= 0)
return;
if ((act.nr = FindCommnr(*args)) == RC_ILLEGAL)
{
Msg(0, "%s: unknown command '%s'", rc_name, *args);
return;
}
act.args = args + 1;
DoAction(&act, -1);
}
void
WriteFile(dump)
int dump;
{
/* dump==0: create .termcap,
* dump==1: hardcopy,
* #ifdef COPY_PASTE
* dump==2: BUFFERFILE
* #endif COPY_PASTE
*/
register int i, j, k;
register char *p;
register FILE *f;
char fn[1024];
char *mode = "w";
switch (dump)
{
case DUMP_TERMCAP:
i = SockNamePtr - SockPath;
strncpy(fn, SockPath, i);
strcpy(fn + i, ".termcap");
break;
case DUMP_HARDCOPY:
if (hardcopydir)
sprintf(fn, "%s/hardcopy.%d", hardcopydir, fore->w_number);
else
sprintf(fn, "hardcopy.%d", fore->w_number);
if (hardcopy_append && !access(fn, W_OK))
mode = "a";
break;
#ifdef COPY_PASTE
case DUMP_EXCHANGE:
sprintf(fn, "%s", BufferFile);
umask(0);
break;
#endif
}
debug2("WriteFile(%d) %s\n", dump, fn);
if (UserContext() > 0)
{
debug("Writefile: usercontext\n");
if ((f = fopen(fn, mode)) == NULL)
{
debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
UserReturn(0);
}
else
{
switch (dump)
{
case DUMP_HARDCOPY:
if (*mode == 'a')
{
putc('>', f);
for (j = d_width - 2; j > 0; j--)
putc('=', f);
fputs("<\n", f);
}
for (i = 0; i < d_height; i++)
{
p = fore->w_image[i];
for (k = d_width - 1; k >= 0 && p[k] == ' '; k--)
;
for (j = 0; j <= k; j++)
putc(p[j], f);
putc('\n', f);
}
break;
case DUMP_TERMCAP:
if ((p = index(MakeTermcap(fore->w_aflag), '=')) != NULL)
{
fputs(++p, f);
putc('\n', f);
}
break;
#ifdef COPY_PASTE
case DUMP_EXCHANGE:
p = d_copybuffer;
for (i = 0; i < d_copylen; i++)
putc(*p++, f);
break;
#endif
}
(void) fclose(f);
UserReturn(1);
}
}
if (UserStatus() <= 0)
Msg(0, "Cannot open \"%s\"", fn);
else
{
switch (dump)
{
case DUMP_TERMCAP:
Msg(0, "Termcap entry written to \"%s\".", fn);
break;
case DUMP_HARDCOPY:
Msg(0, "Screen image %s to \"%s\".",
(*mode == 'a') ? "appended" : "written", fn);
break;
#ifdef COPY_PASTE
case DUMP_EXCHANGE:
Msg(0, "Copybuffer written to \"%s\".", fn);
#endif
}
}
}
#ifdef COPY_PASTE
void
ReadFile()
{
int i, l, size;
char fn[1024], c;
struct stat stb;
sprintf(fn, "%s", BufferFile);
debug1("ReadFile(%s)\n", fn);
if ((i = secopen(fn, O_RDONLY, 0)) < 0)
{
Msg(errno, "no %s -- no slurp", fn);
return;
}
if (fstat(i, &stb))
{
Msg(errno, "no good %s -- no slurp", fn);
close(i);
return;
}
size = stb.st_size;
if (d_copybuffer)
free(d_copybuffer);
d_copylen = 0;
if ((d_copybuffer = malloc(size)) == NULL)
{
close(i);
Msg(0, strnomem);
return;
}
errno = 0;
if ((l = read(i, d_copybuffer, size)) != size)
{
d_copylen = (l > 0) ? l : 0;
#ifdef NETHACK
if (nethackflag)
Msg(errno, "You choke on your food: %d bytes", d_copylen);
else
#endif
Msg(errno, "Got only %d bytes from %s", d_copylen, fn);
close(i);
return;
}
d_copylen = l;
if (read(i, &c, 1) > 0)
Msg(0, "Slurped only %d characters into buffer - try again", d_copylen);
else
Msg(0, "Slurped %d characters into buffer", d_copylen);
close(i);
return;
}
void
KillBuffers()
{
char fn[1024];
sprintf(fn, "%s", BufferFile);
errno = 0;
#ifndef NOREUID
setreuid(eff_uid, real_uid);
setregid(eff_gid, real_gid);
#else
if (access(fn, W_OK) == -1)
{
Msg(errno, "%s not removed", fn);
return;
}
#endif
unlink(fn);
Msg(errno, "%s removed", fn);
#ifndef NOREUID
setreuid(real_uid, eff_uid);
setregid(real_gid, eff_gid);
#endif
}
#endif /* COPY_PASTE */
/*
* (Almost) secure open and fopen...
*/
FILE *
secfopen(name, mode)
char *name;
char *mode;
{
FILE *fi;
#ifdef NOREUID
int flags, fd;
#endif
debug2("secfopen(%s, %s)\n", name, mode);
#ifndef NOREUID
setreuid(eff_uid, real_uid);
setregid(eff_gid, real_gid);
fi = fopen(name, mode);
setreuid(real_uid, eff_uid);
setregid(real_gid, eff_gid);
return fi;
#else
if (eff_uid == real_uid)
return(fopen(name, mode));
if (mode[0] && mode[1] == '+')
flags = O_RDWR;
else
flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
if (mode[0] == 'w')
flags |= O_CREAT | O_TRUNC;
else if (mode[0] == 'a')
flags |= O_CREAT | O_APPEND;
else if (mode[0] != 'r')
{
errno = EINVAL;
return(0);
}
if ((fd = secopen(name, flags, 0666)) < 0)
return(0);
if ((fi = fdopen(fd, mode)) == 0)
{
close(fd);
return(0);
}
return(fi);
#endif
}
int
secopen(name, flags, mode)
char *name;
int flags;
int mode;
{
int fd;
#ifdef NOREUID
int q;
struct stat stb;
#endif
debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
#ifndef NOREUID
setreuid(eff_uid, real_uid);
setregid(eff_gid, real_gid);
fd = open(name, flags, mode);
setreuid(real_uid, eff_uid);
setregid(real_gid, eff_gid);
return fd;
#else
if (eff_uid == real_uid)
return(open(name, flags, mode));
/* Truncation/creation is done in UserContext */
if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
{
if (UserContext() > 0)
{
if ((fd = open(name, flags, mode)) >= 0)
{
close(fd);
UserReturn(0);
}
if (errno == 0)
errno = EACCES;
UserReturn(errno);
}
if (q = UserStatus())
{
if (q > 0)
errno = q;
return(-1);
}
}
if (access(name, F_OK))
return(-1);
if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
return(-1);
debug("open successful\n");
if (fstat(fd, &stb))
{
close(fd);
return(-1);
}
debug("fstat successful\n");
if (stb.st_uid != real_uid)
{
switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
{
case O_RDONLY:
q = 0004;
break;
case O_WRONLY:
q = 0002;
break;
default:
q = 0006;
break;
}
if ((stb.st_mode & q) != q)
{
debug("secopen: permission denied\n");
close(fd);
errno = EACCES;
return(-1);
}
}
debug1("secopen ok - returning %d\n", fd);
return(fd);
#endif
}