diff options
Diffstat (limited to 'fileio.c')
-rw-r--r-- | fileio.c | 760 |
1 files changed, 760 insertions, 0 deletions
diff --git a/fileio.c b/fileio.c new file mode 100644 index 0000000..81d2e81 --- /dev/null +++ b/fileio.c @@ -0,0 +1,760 @@ +/* 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + **************************************************************** + */ + +#include "rcs.h" +RCS_ID("$Id: fileio.c,v 1.10 1994/05/31 12:32:01 mlschroe Exp $ FAU") + + +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> + +#ifndef SIGINT +# include <signal.h> +#endif + +#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[], *SockName; +#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]; + + + /* Special settings for vt100 and others */ + + if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", 5))) + extra_incap = CatExtra("xn:f0=\033Op:f1=\033Oq:f2=\033Or:f3=\033Os:f4=\033Ot:f5=\033Ou:f6=\033Ov:f7=\033Ow:f8=\033Ox:f9=\033Oy:f.=\033On:f,=\033Ol:fe=\033OM:f+=\033Ok:f-=\033Om:f*=\033Oj:f/=\033Oo:fq=\033OX", extra_incap); + + 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(expand_vars(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], "termcapinfo") || !strcmp(args[0], "terminfo")) +#else + else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap")) +#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" + * "^a" -> "\001" + */ +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]; + int i; + + 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 if (*s == '^' && !quofl) + { + s++; + i = *s++; + if (i == '?') + i = '\177'; + else + i &= 0x1f; + *e++ = i; + esize--; + } + else + { + /* + * \$, \\$, \\, \\\, \012 are reduced here, + * other sequences starting whith \ are passed through. + */ + if (s[0] == '\\' && !quofl) + { + if (s[1] >= '0' && s[1] <= '7') + { + 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; + esize--; + continue; + } + else + { + if (s[1] == '$' || + (s[1] == '\\' && s[2] == '$') || + 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'; + debug1("expand_var returns '%s'\n", ebuf); + return ebuf; +} + +void +RcLine(ubuf) +char *ubuf; +{ + char *args[MAXARGS], *buf; + + buf = expand_vars(ubuf); + if (Parse(buf, args) <= 0) + return; + DoCommand(args); +} + +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 = SockName - 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_mlines[i].image; + 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_user->u_copybuffer; + for (i = D_user->u_copylen; i-- > 0; p++) + if (*p == '\r' && (i == 0 || p[1] != '\n')) + putc('\n', f); + else + 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 + +/* + * returns an allocated buffer which holds a copy of the file named fn. + * lenp (if nonzero) points to a location, where the buffer size should be + * stored. + */ +char * +ReadFile(fn, lenp) +char *fn; +int *lenp; +{ + int i, l, size; + char c, *bp, *buf; + struct stat stb; + + ASSERT(lenp); + debug1("ReadFile(%s)\n", fn); + if ((i = secopen(fn, O_RDONLY, 0)) < 0) + { + Msg(errno, "no %s -- no slurp", fn); + return NULL; + } + if (fstat(i, &stb)) + { + Msg(errno, "no good %s -- no slurp", fn); + close(i); + return NULL; + } + size = stb.st_size; + if ((buf = malloc(size)) == NULL) + { + close(i); + Msg(0, strnomem); + return NULL; + } + errno = 0; + if ((l = read(i, buf, size)) != size) + { + if (l < 0) + l = 0; +#ifdef NETHACK + if (nethackflag) + Msg(errno, "You choke on your food: %d bytes from %s", l, fn); + else +#endif + Msg(errno, "Got only %d bytes from %s", l, fn); + close(i); + } + else + { + if (read(i, &c, 1) > 0) + Msg(0, "Slurped only %d characters (of %d) into buffer - try again", + l, size); + else + Msg(0, "Slurped %d characters into buffer", l); + } + close(i); + *lenp = l; + for (bp = buf; l-- > 0; bp++) + if (*bp == '\n' && (bp == buf || bp[-1] != '\r')) + *bp = '\r'; + return buf; +} + +void +KillBuffers() +{ + if (UserContext() > 0) + UserReturn(unlink(BufferFile) ? errno : 0); + errno = UserStatus(); + Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : ""); +} +#endif /* COPY_PASTE */ + + +/* + * (Almost) secure open and fopen... + */ + +FILE * +secfopen(name, mode) +char *name; +char *mode; +{ + FILE *fi; +#ifndef USE_SETEUID + int flags, fd; +#endif + + debug2("secfopen(%s, %s)\n", name, mode); +#ifdef USE_SETEUID + xseteuid(real_uid); + xsetegid(real_gid); + fi = fopen(name, mode); + xseteuid(eff_uid); + xsetegid(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; +#ifndef USE_SETEUID + int q; + struct stat stb; +#endif + + debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode); +#ifdef USE_SETEUID + xseteuid(real_uid); + xsetegid(real_gid); + fd = open(name, flags, mode); + xseteuid(eff_uid); + xsetegid(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) + { + debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777); + close(fd); + errno = EACCES; + return -1; + } + } + debug1("secopen ok - returning %d\n", fd); + return fd; +#endif +} |