Add readine-like behaviour for \x17, \x04 in input layer.
[screen-lua.git] / src / fileio.c
blob0ffba66cdd552111033b2f3c8f49922f00d7579f
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
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 2, or (at your option)
9 * any later version.
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.
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.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
28 #ifndef SIGINT
29 # include <signal.h>
30 #endif
32 #include "config.h"
33 #include "screen.h"
34 #include "extern.h"
36 extern struct display *display, *displays;
37 extern struct win *fore;
38 extern struct layer *flayer;
39 extern int real_uid, eff_uid;
40 extern int real_gid, eff_gid;
41 extern char *extra_incap, *extra_outcap;
42 extern char *home, *RcFileName;
43 extern char SockPath[], *SockName;
44 #ifdef COPY_PASTE
45 extern char *BufferFile;
46 #endif
47 extern int hardcopy_append;
48 extern char *hardcopydir;
50 static char *CatExtra __P((char *, char *));
51 static char *findrcfile __P((char *));
54 char *rc_name = "";
55 int rc_recursion = 0;
57 static char *
58 CatExtra(str1, str2)
59 register char *str1, *str2;
61 register char *cp;
62 register int len1, len2, add_colon;
64 len1 = strlen(str1);
65 if (len1 == 0)
66 return str2;
67 add_colon = (str1[len1 - 1] != ':');
68 if (str2)
70 len2 = strlen(str2);
71 if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
72 Panic(0, strnomem);
73 bcopy(cp, cp + len1 + add_colon, len2 + 1);
75 else
77 if (len1 == 0)
78 return 0;
79 if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
80 Panic(0, strnomem);
81 cp[len1 + add_colon] = '\0';
83 bcopy(str1, cp, len1);
84 if (add_colon)
85 cp[len1] = ':';
87 return cp;
90 static char *
91 findrcfile(rcfile)
92 char *rcfile;
94 char buf[256];
95 char *p;
97 if (rcfile)
99 char *rcend = rindex(rc_name, '/');
100 if (*rcfile != '/' && rcend && (rcend - rc_name) + strlen(rcfile) + 2 < sizeof(buf))
102 strncpy(buf, rc_name, rcend - rc_name + 1);
103 strcpy(buf + (rcend - rc_name) + 1, rcfile);
104 if (access(buf, R_OK) == 0)
105 return SaveStr(buf);
107 debug1("findrcfile: you specified '%s'\n", rcfile);
108 return SaveStr(rcfile);
110 debug("findrcfile: you specified nothing...\n");
111 if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
113 debug1(" $SCREENRC has: '%s'\n", p);
114 return SaveStr(p);
116 else
118 debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
119 if (strlen(home) > sizeof(buf) - 12)
120 Panic(0, "Rc: home too large");
121 sprintf(buf, "%s/.screenrc", home);
122 return SaveStr(buf);
127 * this will be called twice:
128 * 1) rcfilename = "/etc/screenrc"
129 * 2) rcfilename = RcFileName
132 StartRc(rcfilename, nopanic)
133 char *rcfilename;
134 int nopanic;
136 register int argc, len;
137 register char *p, *cp;
138 char buf[2048];
139 char *args[MAXARGS];
140 int argl[MAXARGS];
141 FILE *fp;
142 char *oldrc_name = rc_name;
144 /* always fix termcap/info capabilities */
145 extra_incap = CatExtra("TF", extra_incap);
147 /* Special settings for vt100 and others */
148 if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", 5)))
149 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);
151 rc_name = findrcfile(rcfilename);
153 if ((fp = secfopen(rc_name, "r")) == NULL)
155 if (!rc_recursion && RcFileName && !strcmp(RcFileName, rc_name))
158 * User explicitly gave us that name,
159 * this is the only case, where we get angry, if we can't read
160 * the file.
162 debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
163 if (!nopanic) Panic(0, "Unable to open \"%s\".", rc_name);
164 /* possibly NOTREACHED */
166 debug1("StartRc: '%s' no good. ignored\n", rc_name);
167 Free(rc_name);
168 rc_name = oldrc_name;
169 return 1;
171 while (fgets(buf, sizeof buf, fp) != NULL)
173 if ((p = rindex(buf, '\n')) != NULL)
174 *p = '\0';
175 if ((argc = Parse(buf, sizeof buf, args, argl)) == 0)
176 continue;
177 if (strcmp(args[0], "echo") == 0)
179 if (!display)
180 continue;
181 if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
183 Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
184 continue;
186 AddStr(args[argc - 1]);
187 if (argc != 3)
189 AddStr("\r\n");
190 Flush();
193 else if (strcmp(args[0], "sleep") == 0)
195 if (!display)
196 continue;
197 debug("sleeeeeeep\n");
198 if (argc != 2)
200 Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
201 continue;
203 DisplaySleep1000(1000 * atoi(args[1]), 1);
205 #ifdef TERMINFO
206 else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo"))
207 #else
208 else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap"))
209 #endif
211 if (!display)
212 continue;
213 if (argc < 3 || argc > 4)
215 Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
216 continue;
218 for (p = args[1]; p && *p; p = cp)
220 if ((cp = index(p, '|')) != 0)
221 *cp++ = '\0';
222 len = strlen(p);
223 if (p[len - 1] == '*')
225 if (!(len - 1) || !strncmp(p, D_termname, len - 1))
226 break;
228 else if (!strcmp(p, D_termname))
229 break;
231 if (!(p && *p))
232 continue;
233 extra_incap = CatExtra(args[2], extra_incap);
234 if (argc == 4)
235 extra_outcap = CatExtra(args[3], extra_outcap);
237 else if (!strcmp(args[0], "source"))
239 if (rc_recursion <= 10)
241 rc_recursion++;
242 (void)StartRc(args[1], 0);
243 rc_recursion--;
247 fclose(fp);
248 Free(rc_name);
249 rc_name = oldrc_name;
250 return 0;
253 void
254 FinishRc(rcfilename)
255 char *rcfilename;
257 char buf[2048];
258 FILE *fp;
259 char *oldrc_name = rc_name;
261 rc_name = findrcfile(rcfilename);
263 if ((fp = secfopen(rc_name, "r")) == NULL)
265 if (rc_recursion)
266 Msg(errno, "%s: source %s", oldrc_name, rc_name);
267 else if (RcFileName && !strcmp(RcFileName, rc_name))
270 * User explicitly gave us that name,
271 * this is the only case, where we get angry, if we can't read
272 * the file.
274 debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
275 Panic(0, "Unable to open \"%s\".", rc_name);
276 /* NOTREACHED */
278 debug1("FinishRc: '%s' no good. ignored\n", rc_name);
279 Free(rc_name);
280 rc_name = oldrc_name;
281 return;
284 debug("finishrc is going...\n");
285 while (fgets(buf, sizeof buf, fp) != NULL)
286 RcLine(buf, sizeof buf);
287 (void) fclose(fp);
288 Free(rc_name);
289 rc_name = oldrc_name;
292 void
293 do_source(rcfilename)
294 char *rcfilename;
296 if (rc_recursion > 10)
298 Msg(0, "%s: source: recursion limit reached", rc_name);
299 return;
301 rc_recursion++;
302 FinishRc(rcfilename);
303 rc_recursion--;
308 * Running a Command Line in the environment determined by the display.
309 * The fore window is taken from the display as well as the user.
310 * This is bad when we run detached.
312 void
313 RcLine(ubuf, ubufl)
314 char *ubuf;
315 int ubufl;
317 char *args[MAXARGS];
318 int argl[MAXARGS];
319 #ifdef MULTIUSER
320 extern struct acluser *EffectiveAclUser; /* acl.c */
321 extern struct acluser *users; /* acl.c */
322 #endif
324 if (display)
326 fore = D_fore;
327 flayer = D_forecv->c_layer;
329 else
330 flayer = fore ? fore->w_savelayer : 0;
331 if (Parse(ubuf, ubufl, args, argl) <= 0)
332 return;
333 #ifdef MULTIUSER
334 if (!display)
336 /* the session owner does it, when there is no display here */
337 EffectiveAclUser = users;
338 debug("RcLine: WARNING, no display no user! Session owner executes command\n");
340 #endif
341 DoCommand(args, argl);
342 #ifdef MULTIUSER
343 EffectiveAclUser = 0;
344 #endif
348 * needs display for copybuffer access and termcap dumping
350 void
351 WriteFile(user, fn, dump)
352 struct acluser *user;
353 char *fn;
354 int dump;
356 /* dump==0: create .termcap,
357 * dump==1: hardcopy,
358 * #ifdef COPY_PASTE
359 * dump==2: BUFFERFILE
360 * #endif COPY_PASTE
361 * dump==1: scrollback,
363 register int i, j, k;
364 register char *p;
365 register FILE *f;
366 char fnbuf[1024];
367 char *mode = "w";
368 #ifdef COPY_PASTE
369 int public = 0;
370 # ifdef _MODE_T
371 mode_t old_umask;
372 # else
373 int old_umask;
374 # endif
375 # ifdef HAVE_LSTAT
376 struct stat stb, stb2;
377 int fd, exists = 0;
378 # endif
379 #endif
381 switch (dump)
383 case DUMP_TERMCAP:
384 if (fn == 0)
386 i = SockName - SockPath;
387 if (i > (int)sizeof(fnbuf) - 9)
388 i = 0;
389 strncpy(fnbuf, SockPath, i);
390 strcpy(fnbuf + i, ".termcap");
391 fn = fnbuf;
393 break;
394 case DUMP_HARDCOPY:
395 case DUMP_SCROLLBACK:
396 if (fn == 0)
398 if (fore == 0)
399 return;
400 if (hardcopydir && *hardcopydir && strlen(hardcopydir) < sizeof(fnbuf) - 21)
401 sprintf(fnbuf, "%s/hardcopy.%d", hardcopydir, fore->w_number);
402 else
403 sprintf(fnbuf, "hardcopy.%d", fore->w_number);
404 fn = fnbuf;
406 if (hardcopy_append && !access(fn, W_OK))
407 mode = "a";
408 break;
409 #ifdef COPY_PASTE
410 case DUMP_EXCHANGE:
411 if (fn == 0)
413 strncpy(fnbuf, BufferFile, sizeof(fnbuf) - 1);
414 fnbuf[sizeof(fnbuf) - 1] = 0;
415 fn = fnbuf;
417 public = !strcmp(fn, DEFAULT_BUFFERFILE);
418 # ifdef HAVE_LSTAT
419 exists = !lstat(fn, &stb);
420 if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1))
422 Msg(0, "No write to links, please.");
423 return;
425 # endif
426 break;
427 #endif
430 debug2("WriteFile(%d) %s\n", dump, fn);
431 if (UserContext() > 0)
433 debug("Writefile: usercontext\n");
434 #ifdef COPY_PASTE
435 if (dump == DUMP_EXCHANGE && public)
437 old_umask = umask(0);
438 # ifdef HAVE_LSTAT
439 if (exists)
441 if ((fd = open(fn, O_WRONLY, 0666)) >= 0)
443 if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino == stb2.st_ino)
444 ftruncate(fd, 0);
445 else
447 close(fd);
448 fd = -1;
452 else
453 fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666);
454 f = fd >= 0 ? fdopen(fd, mode) : 0;
455 # else
456 f = fopen(fn, mode);
457 # endif
458 umask(old_umask);
460 else
461 #endif /* COPY_PASTE */
462 f = fopen(fn, mode);
463 if (f == NULL)
465 debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
466 UserReturn(0);
468 else
470 switch (dump)
472 case DUMP_HARDCOPY:
473 case DUMP_SCROLLBACK:
474 if (!fore)
475 break;
476 if (*mode == 'a')
478 putc('>', f);
479 for (j = fore->w_width - 2; j > 0; j--)
480 putc('=', f);
481 fputs("<\n", f);
483 if (dump == DUMP_SCROLLBACK)
485 for (i = 0; i < fore->w_histheight; i++)
487 p = (char *)(WIN(i)->image);
488 for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
490 for (j = 0; j <= k; j++)
491 putc(p[j], f);
492 putc('\n', f);
495 for (i = 0; i < fore->w_height; i++)
497 p = (char *)fore->w_mlines[i].image;
498 for (k = fore->w_width - 1; k >= 0 && p[k] == ' '; k--)
500 for (j = 0; j <= k; j++)
501 putc(p[j], f);
502 putc('\n', f);
504 break;
505 case DUMP_TERMCAP:
506 if ((p = index(MakeTermcap(fore->w_aflag), '=')) != NULL)
508 fputs(++p, f);
509 putc('\n', f);
511 break;
512 #ifdef COPY_PASTE
513 case DUMP_EXCHANGE:
514 p = user->u_plop.buf;
515 for (i = user->u_plop.len; i-- > 0; p++)
516 if (*p == '\r' && (i == 0 || p[1] != '\n'))
517 putc('\n', f);
518 else
519 putc(*p, f);
520 break;
521 #endif
523 (void) fclose(f);
524 UserReturn(1);
527 if (UserStatus() <= 0)
528 Msg(0, "Cannot open \"%s\"", fn);
529 else if (display && !*rc_name)
531 switch (dump)
533 case DUMP_TERMCAP:
534 Msg(0, "Termcap entry written to \"%s\".", fn);
535 break;
536 case DUMP_HARDCOPY:
537 case DUMP_SCROLLBACK:
538 Msg(0, "Screen image %s to \"%s\".",
539 (*mode == 'a') ? "appended" : "written", fn);
540 break;
541 #ifdef COPY_PASTE
542 case DUMP_EXCHANGE:
543 Msg(0, "Copybuffer written to \"%s\".", fn);
544 #endif
549 #ifdef COPY_PASTE
552 * returns an allocated buffer which holds a copy of the file named fn.
553 * lenp (if nonzero) points to a location, where the buffer size should be
554 * stored.
556 char *
557 ReadFile(fn, lenp)
558 char *fn;
559 int *lenp;
561 int i, l, size;
562 char c, *bp, *buf;
563 struct stat stb;
565 ASSERT(lenp);
566 debug1("ReadFile(%s)\n", fn);
567 if ((i = secopen(fn, O_RDONLY, 0)) < 0)
569 Msg(errno, "no %s -- no slurp", fn);
570 return NULL;
572 if (fstat(i, &stb))
574 Msg(errno, "no good %s -- no slurp", fn);
575 close(i);
576 return NULL;
578 size = stb.st_size;
579 if ((buf = malloc(size)) == NULL)
581 close(i);
582 Msg(0, strnomem);
583 return NULL;
585 errno = 0;
586 if ((l = read(i, buf, size)) != size)
588 if (l < 0)
589 l = 0;
590 Msg(errno, "Got only %d bytes from %s", l, fn);
591 close(i);
593 else
595 if (read(i, &c, 1) > 0)
596 Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
597 l, size);
598 else
599 Msg(0, "Slurped %d characters into buffer", l);
601 close(i);
602 *lenp = l;
603 for (bp = buf; l-- > 0; bp++)
604 if (*bp == '\n' && (bp == buf || bp[-1] != '\r'))
605 *bp = '\r';
606 return buf;
609 void
610 KillBuffers()
612 if (UserContext() > 0)
613 UserReturn(unlink(BufferFile) ? errno : 0);
614 errno = UserStatus();
615 Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : "");
617 #endif /* COPY_PASTE */
621 * (Almost) secure open and fopen...
624 FILE *
625 secfopen(name, mode)
626 char *name;
627 char *mode;
629 FILE *fi;
630 #ifndef USE_SETEUID
631 int flags, fd;
632 #endif
634 debug2("secfopen(%s, %s)\n", name, mode);
635 #ifdef USE_SETEUID
636 xseteuid(real_uid);
637 xsetegid(real_gid);
638 fi = fopen(name, mode);
639 xseteuid(eff_uid);
640 xsetegid(eff_gid);
641 return fi;
642 #else
643 if (eff_uid == real_uid)
644 return fopen(name, mode);
645 if (mode[0] && mode[1] == '+')
646 flags = O_RDWR;
647 else
648 flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
649 if (mode[0] == 'w')
650 flags |= O_CREAT | O_TRUNC;
651 else if (mode[0] == 'a')
652 flags |= O_CREAT | O_APPEND;
653 else if (mode[0] != 'r')
655 errno = EINVAL;
656 return 0;
658 if ((fd = secopen(name, flags, 0666)) < 0)
659 return 0;
660 if ((fi = fdopen(fd, mode)) == 0)
662 close(fd);
663 return 0;
665 return fi;
666 #endif
671 secopen(name, flags, mode)
672 char *name;
673 int flags;
674 int mode;
676 int fd;
677 #ifndef USE_SETEUID
678 int q;
679 struct stat stb;
680 #endif
682 debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
683 #ifdef USE_SETEUID
684 xseteuid(real_uid);
685 xsetegid(real_gid);
686 fd = open(name, flags, mode);
687 xseteuid(eff_uid);
688 xsetegid(eff_gid);
689 return fd;
690 #else
691 if (eff_uid == real_uid)
692 return open(name, flags, mode);
693 /* Truncation/creation is done in UserContext */
694 if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
696 if (UserContext() > 0)
698 if ((fd = open(name, flags, mode)) >= 0)
700 close(fd);
701 UserReturn(0);
703 if (errno == 0)
704 errno = EACCES;
705 UserReturn(errno);
707 if ((q = UserStatus()))
709 if (q > 0)
710 errno = q;
711 return -1;
714 if (access(name, F_OK))
715 return -1;
716 if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
717 return -1;
718 debug("open successful\n");
719 if (fstat(fd, &stb))
721 close(fd);
722 return -1;
724 debug("fstat successful\n");
725 if (stb.st_uid != real_uid)
727 switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
729 case O_RDONLY:
730 q = 0004;
731 break;
732 case O_WRONLY:
733 q = 0002;
734 break;
735 default:
736 q = 0006;
737 break;
739 if ((stb.st_mode & q) != q)
741 debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777);
742 close(fd);
743 errno = EACCES;
744 return -1;
747 debug1("secopen ok - returning %d\n", fd);
748 return fd;
749 #endif
754 printpipe(p, cmd)
755 struct win *p;
756 char *cmd;
758 int pi[2];
759 if (pipe(pi))
761 WMsg(p, errno, "printing pipe");
762 return -1;
764 switch (fork())
766 case -1:
767 WMsg(p, errno, "printing fork");
768 return -1;
769 case 0:
770 display = p->w_pdisplay;
771 displays = 0;
772 #ifdef DEBUG
773 if (dfp && dfp != stderr)
774 fclose(dfp);
775 #endif
776 close(0);
777 dup(pi[0]);
778 closeallfiles(0);
779 if (setgid(real_gid) || setuid(real_uid))
780 Panic(errno, "printpipe setuid");
781 #ifdef SIGPIPE
782 signal(SIGPIPE, SIG_DFL);
783 #endif
784 execl("/bin/sh", "sh", "-c", cmd, (char *)0);
785 Panic(errno, "/bin/sh");
786 default:
787 break;
789 close(pi[0]);
790 return pi[1];
794 readpipe(cmdv)
795 char **cmdv;
797 int pi[2];
799 if (pipe(pi))
801 Msg(errno, "pipe");
802 return -1;
804 switch (fork())
806 case -1:
807 Msg(errno, "fork");
808 return -1;
809 case 0:
810 displays = 0;
811 #ifdef DEBUG
812 if (dfp && dfp != stderr)
813 fclose(dfp);
814 #endif
815 close(1);
816 if (dup(pi[1]) != 1)
818 close(pi[1]);
819 Panic(0, "dup");
821 closeallfiles(1);
822 if (setgid(real_gid) || setuid(real_uid))
824 close(1);
825 Panic(errno, "setuid/setgid");
827 #ifdef SIGPIPE
828 signal(SIGPIPE, SIG_DFL);
829 #endif
830 execvp(*cmdv, cmdv);
831 close(1);
832 Panic(errno, *cmdv);
833 default:
834 break;
836 close(pi[1]);
837 return pi[0];