diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:21 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:21 +0200 |
commit | 14a4b00c9ef680b78469333291270e4c276f100d (patch) | |
tree | 6479193bac66d70af7f7b8133498b4d61a0fd29b | |
parent | 0636e9ecb5a32db4d4520f50a20652faa825feaf (diff) | |
download | screen-14a4b00c9ef680b78469333291270e4c276f100d.tar.gz |
Imported Upstream version 3.7.4upstream/3.7.4
-rw-r--r-- | acls.c | 610 | ||||
-rw-r--r-- | acls.h | 21 | ||||
-rw-r--r-- | ansi.c | 24 | ||||
-rw-r--r-- | attacher.c | 25 | ||||
-rw-r--r-- | comm.c | 4 | ||||
-rw-r--r-- | config.h.in | 10 | ||||
-rwxr-xr-x | configure | 54 | ||||
-rw-r--r-- | configure.in | 6 | ||||
-rw-r--r-- | display.c | 16 | ||||
-rw-r--r-- | doc/Makefile.in | 2 | ||||
-rw-r--r-- | doc/screen.1 | 1 | ||||
-rw-r--r-- | etc/etcscreenrc | 4 | ||||
-rw-r--r-- | etc/screenrc | 12 | ||||
-rw-r--r-- | extern.h | 26 | ||||
-rw-r--r-- | fileio.c | 160 | ||||
-rw-r--r-- | help.c | 22 | ||||
-rw-r--r-- | input.c | 155 | ||||
-rw-r--r-- | kmapdef.c.dist | 20 | ||||
-rw-r--r-- | mark.c | 12 | ||||
-rw-r--r-- | misc.c | 303 | ||||
-rw-r--r-- | os.h | 14 | ||||
-rw-r--r-- | osdef.h.in | 1 | ||||
-rw-r--r-- | patchlevel.h | 18 | ||||
-rw-r--r-- | process.c | 299 | ||||
-rw-r--r-- | screen.c | 110 | ||||
-rw-r--r-- | screen.h | 4 | ||||
-rw-r--r-- | search.c | 26 | ||||
-rw-r--r-- | socket.c | 147 | ||||
-rw-r--r-- | tek.patch | 27 | ||||
-rw-r--r-- | term.c | 22 | ||||
-rw-r--r-- | term.h.dist | 16 | ||||
-rw-r--r-- | termcap.c | 16 | ||||
-rw-r--r-- | tty.c.dist | 5 | ||||
-rw-r--r-- | tty.sh | 5 | ||||
-rw-r--r-- | utmp.c | 7 | ||||
-rw-r--r-- | window.c | 64 | ||||
-rw-r--r-- | window.h | 2 |
37 files changed, 1588 insertions, 682 deletions
@@ -36,34 +36,38 @@ RCS_ID("$Id: acls.c,v 1.12 1994/05/31 12:31:21 mlschroe Exp $ FAU") extern struct comm comms[]; extern struct win *windows, *wtab[]; +extern char NullStr[]; extern struct display *display, *displays; struct user *users; #ifdef MULTIUSER +int maxusercount = 0; /* used in process.c: RC_MONITOR, RC_SILENCE */ + /* record given user ids here */ static AclBits userbits; -/* rights a new unknown user will have on windows and cmds */ +/* + * rights a new unknown user will have on windows and cmds. + * These are changed by a "umask ?-..." command: + */ static char default_w_bit[ACL_BITS_PER_WIN] = { - 1, /* EXEC */ - 1, /* WRITE */ - 1 /* READ */ + 0, /* EXEC */ + 0, /* WRITE */ + 0 /* READ */ }; static char default_c_bit[ACL_BITS_PER_CMD] = { - 1 /* EXEC */ + 0 /* EXEC */ }; /* rights of all users per newly created window */ -static AclBits default_w_userbits[ACL_BITS_PER_WIN]; - /* -static AclBits default_c_userbits[ACL_BITS_PER_CMD]; -*/ - -static int maxusercount = 0; + * are now stored per user (umask) + * static AclBits default_w_userbits[ACL_BITS_PER_WIN]; + * static AclBits default_c_userbits[ACL_BITS_PER_CMD]; + */ static int GrowBitfield __P((AclBits *, int, int, int)); @@ -108,30 +112,40 @@ char *name; break; #ifdef MULTIUSER debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ", - (*u)?(*u)->id:-1); -#else + (*u)?(*u)->u_id:-1); +#else /* MULTIUSER */ debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not "); -#endif +#endif /* MULTIUSER */ return u; } -int DefaultEsc = Ctrl('a'); -int DefaultMetaEsc = 'a'; +int DefaultEsc = -1; /* initialised by screen.c:main() */ +int DefaultMetaEsc = -1; /* - * Add a new user. His password may be NULL or "" if none. - * He has no rights. + * Add a new user. His password may be NULL or "" if none. His name must not + * be "none", as this represents the NULL-pointer when dealing with groups. + * He has default rights, determined by umask. */ int UserAdd(name, pass, up) char *name, *pass; struct user **up; { +#ifdef MULTIUSER + int j; +#endif + if (!up) up = FindUserPtr(name); if (*up) - return 1; /* he is already there */ - *up = (struct user *)calloc(1, sizeof(struct user)); + { + if (pass) + (*up)->u_password = SaveStr(pass); + return 1; /* he is already there */ + } + if (strcmp("none", name)) /* "none" is a reserved word */ + *up = (struct user *)calloc(1, sizeof(struct user)); if (!*up) return -1; /* he still does not exist */ #ifdef COPY_PASTE @@ -141,19 +155,24 @@ struct user **up; (*up)->u_Esc = DefaultEsc; (*up)->u_MetaEsc = DefaultMetaEsc; strncpy((*up)->u_name, name, 20); + (*up)->u_password = NULL; if (pass) - strncpy((*up)->u_password, pass, 20); + (*up)->u_password = SaveStr(pass); + if (!(*up)->u_password) + (*up)->u_password = NullStr; #ifdef MULTIUSER + (*up)->u_group = NULL; /* now find an unused index */ - for ((*up)->id = 0; (*up)->id < maxusercount; (*up)->id++) - if (!(ACLBIT((*up)->id) & ACLBYTE(userbits, (*up)->id))) + for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++) + if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id))) break; - debug2("UserAdd %s id %d\n", name, (*up)->id); - if ((*up)->id == maxusercount) + debug2("UserAdd %s id %d\n", name, (*up)->u_id); + if ((*up)->u_id == maxusercount) { - int i, j; + int j; struct win *w; + struct user *u; debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK); /* the bitfields are full, grow a chunk */ @@ -173,55 +192,89 @@ struct user **up; } */ /* third, the bits for each commands */ - for (i = 0; i <= RC_LAST; i++) - for (j = 0; j < ACL_BITS_PER_CMD; j++) - if (GrowBitfield(&comms[i].userbits[j], maxusercount, USER_CHUNK, - default_c_bit[j])) + for (j = 0; j <= RC_LAST; j++) + { + int i; + + for (i = 0; i < ACL_BITS_PER_CMD; i++) + if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK, + default_c_bit[i])) + { + free((char *)*up); *up = NULL; return -1; + } + } + /* fourth, default window creation bits per user */ + for (u = users; u != *up; u = u->u_next) + { + for (j = 0; j < ACL_BITS_PER_WIN; j++) { - free((char *)*up); *up = NULL; return -1; + if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK, + default_w_bit[j])) + { + free((char *)*up); *up = NULL; return -1; + } } - /* fourth, default window and bits */ - for (j = 0; j < ACL_BITS_PER_WIN; j++) - if (GrowBitfield(&default_w_userbits[j], maxusercount, USER_CHUNK, - default_w_bit[j])) - { - free((char *)*up); *up = NULL; return -1; - } + } + /* fifth, the bits for each window */ + /* keep these in sync with NewWindowAcl() */ for (w = windows; w; w = w->w_next) - for (j = 0; j < ACL_BITS_PER_WIN; j++) - if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK, - default_w_bit[j])) - { - free((char *)*up); *up = NULL; return -1; + { + /* five a: the access control list */ + for (j = 0; j < ACL_BITS_PER_WIN; j++) + if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK, + default_w_bit[j])) + { + free((char *)*up); *up = NULL; return -1; + } + /* five b: the activity notify list */ + /* five c: the silence notify list */ + if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) || + GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0)) + { + free((char *)*up); *up = NULL; return -1; } + } maxusercount += USER_CHUNK; } - ACLBYTE(userbits, (*up)->id) |= ACLBIT((*up)->id); + + /* mark the user-entry as "in-use" */ + ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id); + /* user id 0 is the session creator, he has all rights */ - if ((*up)->id == 0) - AclSetPerm(*up, "+rwx", "#?"); + if ((*up)->u_id == 0) + AclSetPerm(NULL, *up, "+a", "#?"); + + /* user nobody has a fixed set of rights: */ + if (!strcmp((*up)->u_name, "nobody")) + { + AclSetPerm(NULL, *up, "-rwx", "#?"); + AclSetPerm(NULL, *up, "+x", "su"); + AclSetPerm(NULL, *up, "+x", "detach"); + AclSetPerm(NULL, *up, "+x", "displays"); + AclSetPerm(NULL, *up, "+x", "version"); + } + + /* + * Create his umask: + * Give default_w_bit's for all users, + * but allow himself everything on "his" windows. + */ + for (j = 0; j < ACL_BITS_PER_WIN; j++) + { + if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount, + default_w_bit[j])) + { + free((char *)*up); *up = NULL; return -1; + } + ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id); + } #else /* MULTIUSER */ debug1("UserAdd %s\n", name); #endif /* MULTIUSER */ return 0; } -/* change user's password */ -int -UserSetPass(name, pass, up) -char *name, *pass; -struct user **up; -{ - if (!up) - up = FindUserPtr(name); - if (!*up) - return UserAdd(name, pass, up); - strncpy((*up)->u_password, pass ? pass : "", 20); - (*up)->u_password[20] = '\0'; - return 0; -} - /* * Remove a user from the list. * Destroy all his permissions and completely detach him from the session. @@ -232,37 +285,66 @@ char *name; struct user **up; { struct user *u; +#ifdef MULTIUSER + int i; +#endif struct display *old, *next; if (!up) up = FindUserPtr(name); - if ((u = *up) == 0) + if (!(u = *up)) return -1; /* he who does not exist cannot be removed */ old = display; for (display = displays; display; display = next) { - next = display->d_next; + next = display->d_next; /* read the next ptr now, Detach may zap it. */ if (D_user != u) continue; if (display == old) - old = 0; + old = NULL; Detach(D_REMOTE); } display = old; *up = u->u_next; + #ifdef MULTIUSER - ACLBYTE(userbits, u->id) &= ~ACLBIT(u->id); + for (up = &users; *up; up = &(*up)->u_next) + { + /* unlink all group references to this user */ + struct usergroup **g = &(*up)->u_group; + + while (*g) + { + if ((*g)->u == u) + { + struct usergroup *next = (*g)->next; + + free((char *)(*g)); + *g = next; + } + else + g = &(*g)->next; + } + } + ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id); /* restore the bits in his slot to default: */ - AclSetPerm(u, default_w_bit[ACL_READ] ? "+r" : "-r", "#"); - AclSetPerm(u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#"); - AclSetPerm(u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#"); - AclSetPerm(u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?"); -#endif + AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#"); + AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#"); + AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#"); + AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?"); + for (i = 0; i < ACL_BITS_PER_WIN; i++) + free((char *)u->u_umask_w_bits[i]); +#endif /* MULTIUSER */ debug1("FREEING user structure for %s\n", u->u_name); #ifdef COPY_PASTE UserFreeCopyBuffer(u); #endif free((char *)u); + if (!users) + { + debug("Last user deleted. Feierabend.\n"); + Finit(0); /* Destroying whole session. Noone could ever attach again. */ + } return 0; } @@ -287,18 +369,17 @@ struct user *u; w->w_pasteptr - u->u_copybuffer < u->u_copylen) { if (w->w_pastebuf) - free(w->w_pastebuf); + free((char *)w->w_pastebuf); w->w_pastebuf = 0; w->w_pasteptr = 0; w->w_pastelen = 0; } } - free(u->u_copybuffer); - D_user->u_copylen = 0; + free((char *)u->u_copybuffer); + u->u_copylen = 0; u->u_copybuffer = NULL; return 0; } - #endif /* COPY_PASTE */ /************************************************************************ @@ -308,16 +389,21 @@ struct user *u; #ifdef MULTIUSER -extern char *multi; /* username */ - -/* This gives the users default rights to the new window */ +/* This gives the users default rights to the new window w created by u */ int -NewWindowAcl(w) +NewWindowAcl(w, u) struct win *w; +struct user *u; { int i, j; - debug1("NewWindowAcl default_w_userbits for window %d\n", w->w_number); + debug2("NewWindowAcl %s's umask_w_bits for window %d\n", + u ? u->u_name : "everybody", w->w_number); + + /* keep these in sync with UserAdd part five. */ + if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) || + GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0)) + return -1; for (j = 0; j < ACL_BITS_PER_WIN; j++) { /* we start with len 0 for the new bitfield size and add maxusercount */ @@ -328,27 +414,30 @@ struct win *w; return -1; } for (i = 0; i < maxusercount; i++) - if (ACLBIT(i) & ACLBYTE(default_w_userbits[j], i)) + if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) : + default_w_bit[j]) ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i); } return 0; } /* if mode starts with '-' we remove the users exec bit for cmd */ -int +/* + * NOTE: before you make this function look the same as + * AclSetPermWin, try to merge both functions. + */ +static int AclSetPermCmd(u, mode, cmd) struct user *u; char *mode; struct comm *cmd; { int neg = 0; + char *m = mode; - if (!multi) - return 0; - debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); - while (*mode) + while (*m) { - switch (*mode++) + switch (*m++) { case '-': neg = 1; @@ -356,12 +445,14 @@ struct comm *cmd; case '+': neg = 0; continue; + case 'a': case 'e': case 'x': +/* debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); */ if (neg) - ACLBYTE(cmd->userbits[ACL_EXEC], u->id) &= ~ACLBIT(u->id); + ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id); else - ACLBYTE(cmd->userbits[ACL_EXEC], u->id) |= ACLBIT(u->id); + ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->u_id); break; case 'r': case 'w': @@ -377,22 +468,35 @@ struct comm *cmd; /* * aclchg nerd -w+w 2 * releases a writelock on window 2 held by user nerd. + * Letter n allows network access on a window. + * uu should be NULL, except if you want to change his umask. */ -int -AclSetPermWin(u, mode, win) -struct user *u; +static int +AclSetPermWin(uu, u, mode, win) +struct user *u, *uu; char *mode; struct win *win; { int neg = 0; - int bit; + int bit, bits; + AclBits *bitarray; + char *m = mode; + + if (uu) + { + debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode); + bitarray = uu->u_umask_w_bits; + } + else + { + ASSERT(win); + bitarray = win->w_userbits; + debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number); + } - if (!multi) - return 0; - debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number); - while (*mode) + while (*m) { - switch (*mode++) + switch (*m++) { case '-': neg = 1; @@ -401,67 +505,114 @@ struct win *win; neg = 0; continue; case 'r': - bit = ACL_READ; + bits = (1 << ACL_READ); break; case 'w': - bit = ACL_WRITE; + bits = (1 << ACL_WRITE); break; case 'x': - bit = ACL_EXEC; + bits = (1 << ACL_EXEC); + break; + case 'a': + bits = (1 << ACL_BITS_PER_WIN) - 1; break; default: return -1; } - if (neg) - ACLBYTE(win->w_userbits[bit], u->id) &= ~ACLBIT(u->id); - else - ACLBYTE(win->w_userbits[bit], u->id) |= ACLBIT(u->id); - if ((win->w_wlockuser == u) && neg && (bit == ACL_WRITE)) + for (bit = 0; bit < ACL_BITS_PER_WIN; bit++) + { + if (!(bits & (1 << bit))) + continue; + if (neg) + ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id); + else + ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id); + if (!uu && (win->w_wlockuser == u) && neg && (bit == ACL_WRITE)) + { + debug2("%s lost writelock on win %d\n", u->u_name, win->w_number); + win->w_wlockuser = NULL; + if (win->w_wlock == WLOCK_ON) + win->w_wlock = WLOCK_AUTO; + } + } + } + if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0') + { + /* + * It is Mr. '?', the unknown user. He deserves special treatment as + * he defines the defaults. Sorry, this is global, not per user. + */ + if (win) { - debug2("%s lost writelock on win %d\n", u->u_name, win->w_number); - win->w_wlockuser = NULL; - if (win->w_wlock == WLOCK_ON) - win->w_wlock = WLOCK_AUTO; - } + debug1("AclSetPermWin: default_w_bits '%s'.\n", mode); + for (bit = 0; bit < ACL_BITS_PER_WIN; bit++) + default_w_bit[bit] = + (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0; + } + else + { + /* + * Hack. I do not want to duplicate all the above code for + * AclSetPermCmd. This asumes that there are not more bits + * per cmd than per win. + */ + debug1("AclSetPermWin: default_c_bits '%s'.\n", mode); + for (bit = 0; bit < ACL_BITS_PER_CMD; bit++) + default_c_bit[bit] = + (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0; + } + UserDel(u->u_name, NULL); } return 0; } -/* string is broken down into comand and window names, mode applies */ +/* + * String is broken down into comand and window names, mode applies + * A command name matches first, so do not use these as window names. + * uu should be NULL, except if you want to change his umask. + */ int -AclSetPerm(u, mode, s) -struct user *u; +AclSetPerm(uu, u, mode, s) +struct user *uu, *u; char *mode, *s; { struct win *w; int i; char *p, ch; + debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n", + u->u_name, mode, s); while (*s) { switch (*s) { - case '*': /* all windows and all commands */ - return AclSetPerm(u, mode, "#?"); - case '#': /* all windows */ - for (w = windows; w; w = w->w_next) - AclSetPermWin(u, mode, w); + case '*': /* all windows and all commands */ + return AclSetPerm(uu, u, mode, "#?"); + case '#': + if (uu) /* window umask or .. */ + AclSetPermWin(uu, u, mode, (struct win *)1); + else /* .. or all windows */ + for (w = windows; w; w = w->w_next) + AclSetPermWin(NULL, u, mode, w); s++; break; - case '?': /* all commands */ - for (i = 0; i <= RC_LAST; i++) - AclSetPermCmd(u, mode, &comms[i]); + case '?': + if (uu) /* command umask or .. */ + AclSetPermWin(uu, u, mode, (struct win *)0); + else /* .. or all commands */ + for (i = 0; i <= RC_LAST; i++) + AclSetPermCmd(u, mode, &comms[i]); s++; break; default: for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++) ; - if ((ch = *p) != 0) + if ((ch = *p)) *p++ = '\0'; if ((i = FindCommnr(s)) != RC_ILLEGAL) AclSetPermCmd(u, mode, &comms[i]); else if (((i = WindowByNoN(s)) >= 0) && wtab[i]) - AclSetPermWin(u, mode, wtab[i]); + AclSetPermWin(NULL, u, mode, wtab[i]); else /* checking group name */ return -1; @@ -473,6 +624,156 @@ char *mode, *s; return 0; } +/* + * Generic ACL Manager: + * + * This handles acladd and aclchg identical. + * With 2 or 4 parameters, the second parameter is a password. + * With 3 or 4 parameters the last two parameters specify the permissions + * else user is added with full permissions. + * With 1 parameter the users permissions are copied from user *argv. + * Unlike the other cases, u->u_name should not match *argv here. + * uu should be NULL, except if you want to change his umask. + */ +static int +UserAcl(uu, u, argc, argv) +struct user *uu, **u; +int argc; +char **argv; +{ + if ((*u && !strcmp((*u)->u_name, "nobody")) || + (argc > 1 && !strcmp(argv[0], "nobody"))) + return -1; /* do not change nobody! */ + + switch (argc) + { + case 1+1+2: + debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]); + return (UserAdd(argv[0], argv[1], u) < 0) || + AclSetPerm(uu, *u, argv[2], argv[3]); + case 1+2: + debug1("UserAcl: user '%s', no password:", argv[0]); + return (UserAdd(argv[0], NULL, u) < 0) || + AclSetPerm(uu, *u, argv[1], argv[2]); + case 1+1: + debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]); + return UserAdd(argv[0], argv[1], u) < 0; + case 1: + debug1("UserAcl: user '%s', no password:", argv[0]); + return (UserAdd(argv[0], NULL, u) < 0) || + AclSetPerm(uu, *u, "+a", "#?"); + default: + return -1; + } +} + +static int +UserAclCopy(to_up, from_up) +struct user **to_up, **from_up; +{ + struct win *w; + int i, j, to_id, from_id; + + if (!*to_up || !*from_up) + return -1; + debug2("UserAclCopy: from user '%s' to user '%s'\n", + (*from_up)->u_name, (*to_up)->u_name); + if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id)) + return -1; + for (w = windows; w; w = w->w_next) + { + for (i = 0; i < ACL_BITS_PER_WIN; i++) + { + if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id)) + ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id); + else + { + ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id); + if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE)) + { + debug2("%s lost wlock on win %d\n", + (*to_up)->u_name, w->w_number); + w->w_wlockuser = NULL; + if (w->w_wlock == WLOCK_ON) + w->w_wlock = WLOCK_AUTO; + } + } + } + } + for (j = 0; j <= RC_LAST; j++) + { + for (i = 0; i < ACL_BITS_PER_CMD; i++) + { + if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id)) + ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id); + else + ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id); + } + } + + return 0; +} + +/* + * Syntax: + * user [password] [+rwx #?] + * * [password] [+rwx #?] + * user1,user2,user3 [password] [+rwx #?] + * user1,user2,user3=user + * uu should be NULL, except if you want to change his umask. + */ +int +UsersAcl(uu, argc, argv) +struct user *uu; +int argc; +char **argv; +{ + char *s; + int r; + struct user **cf_u = NULL; + + if (argc == 1) + { + char *p = NULL; + + s = argv[0]; + while (*s) + if (*s++ == '=') p = s; + if (p) + { + p[-1] = '\0'; + cf_u = FindUserPtr(p); + } + } + + if (argv[0][0] == '*' && argv[0][1] == '\0') + { + struct user **u; + + debug("all users acls.\n"); + for (u = &users; *u; u = &(*u)->u_next) + if (strcmp("nobody", (*u)->u_name) && + ((cf_u) ? + ((r = UserAclCopy(u, cf_u)) < 0) : + ((r = UserAcl(uu, u, argc, argv)) < 0))) + return -1; + return 0; + } + + do + { + for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++) + ; + *s ? (*s++ = '\0') : (*s = '\0'); + debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc); + if ((cf_u) ? + ((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) : + ((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0)) + return -1; + } while (*(argv[0] = s)); + return 0; +} + #if 0 void AclWinSwap(a, b) @@ -512,19 +813,44 @@ int a, b; } #endif +struct user *EffectiveAclUser = NULL; /* hook for AT command permission */ + int AclCheckPermWin(u, mode, w) struct user *u; int mode; struct win *w; { - if (!multi) - return 0; + int ok; + if (mode < 0 || mode >= ACL_BITS_PER_WIN) return -1; + if (EffectiveAclUser) + { + debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name); + u = EffectiveAclUser; + } + ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id); debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number); - debug1("%d\n", !(ACLBYTE(w->w_userbits[mode], u->id) & ACLBIT(u->id))); - return !(ACLBYTE(w->w_userbits[mode], u->id) & ACLBIT(u->id)); + + if (!ok) + { + struct usergroup **g = &u->u_group; + struct user *saved_eff = EffectiveAclUser; + + EffectiveAclUser = NULL; + while (*g) + { + if (!AclCheckPermWin((*g)->u, mode, w)) + break; + g = &(*g)->next; + } + EffectiveAclUser = saved_eff; + if (*g) + ok = 1; + } + debug1("%d\n", !ok); + return !ok; } int @@ -533,13 +859,35 @@ struct user *u; int mode; struct comm *c; { - if (!multi) - return 0; + int ok; + if (mode < 0 || mode >= ACL_BITS_PER_CMD) return -1; + if (EffectiveAclUser) + { + debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name); + u = EffectiveAclUser; + } + ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id); debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name); - debug1("%d\n", !(ACLBYTE(c->userbits[mode], u->id) & ACLBIT(u->id))); - return !(ACLBYTE(c->userbits[mode], u->id) & ACLBIT(u->id)); + if (!ok) + { + struct usergroup **g = &u->u_group; + struct user *saved_eff = EffectiveAclUser; + + EffectiveAclUser = NULL; + while (*g) + { + if (!AclCheckPermCmd((*g)->u, mode, c)) + break; + g = &(*g)->next; + } + EffectiveAclUser = saved_eff; + if (*g) + ok = 1; + } + debug1("%d\n", !ok); + return !ok; } #endif /* MULTIUSER */ @@ -58,7 +58,16 @@ typedef struct grouplist struct grouplist *next; } AclGroupList; -#endif +/* + * How a user joins a group. + * Here is the node to construct one list per user. + */ +struct usergroup +{ + struct user *u; /* the user who borrows us his rights */ + struct usergroup *next; +}; +#endif /* MULTIUSER */ /*************** * ==> user.h @@ -71,17 +80,21 @@ typedef struct grouplist */ typedef struct user { - struct user *u_next; + struct user *u_next; /* continue the main user list */ char u_name[20+1]; /* login name how he showed up */ - char u_password[20+1]; /* his password (may be zero length). */ + char *u_password; /* his password (may be NullStr). */ + int u_checkpassword; /* nonzero if this u_password is valid */ int u_detachwin; /* the window where he last detached */ + int u_detachotherwin; /* window that was "other" when he detached */ int u_Esc, u_MetaEsc; /* the users screen escape character */ #ifdef COPY_PASTE char *u_copybuffer; int u_copylen; #endif #ifdef MULTIUSER - int id; /* a uniq index in the bitfields. */ + int u_id; /* a uniq index in the bitfields. */ + AclBits u_umask_w_bits[ACL_BITS_PER_WIN]; /* his window create umask */ + struct usergroup *u_group; /* linked list of pointers to other users */ #endif } User; @@ -415,7 +415,7 @@ register struct win *p; #ifdef KANJI static char *kanjicharsets[3] = { "BBBB02", /* jis */ - "\002IBB01", /* euc */ + "B\002IB01", /* euc */ "BIBB01" /* sjis */ }; #endif @@ -955,6 +955,16 @@ skip: if (--len == 0) if (font != KANJI) { debug2("SJIS !! %x %x\n", c, t); + /* + * SJIS -> EUC mapping: + * First byte: + * 81,82...9f -> 21,23...5d + * e0,e1...ef -> 5f,61...7d + * Second byte: + * 40-7e -> 21-5f + * 80-9e -> 60-7e + * 9f-fc -> 21-7e (increment first byte!) + */ if (0x40 <= t && t <= 0xfc && t != 0x7f) { if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21; @@ -1424,8 +1434,14 @@ int c, intermediate; ASetMode(0); break; case 'i': - if (display && a1 == 5) - PrintStart(); + { + struct display *odisplay = display; + if (display == 0 && displays && displays->d_next == 0) + display = displays; + if (display && a1 == 5) + PrintStart(); + display = odisplay; + } break; case 'n': if (a1 == 5) /* Report terminal status */ @@ -2464,7 +2480,7 @@ char *fmt; int n1, n2; { register int len; - char rbuf[40]; + char rbuf[40]; /* enough room for all replys */ sprintf(rbuf, fmt, n1, n2); len = strlen(rbuf); @@ -164,7 +164,8 @@ int how; bzero((char *) &m, sizeof(m)); m.type = how; - strcpy(m.m_tty, attach_tty); + strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); + m.m_tty[sizeof(m.m_tty) - 1] = 0; if (how == MSG_WINCH) { @@ -186,7 +187,7 @@ int how; } else { - n = FindSocket(&lasts, (int *)0, SockMatch); + n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch); switch (n) { case 0: @@ -225,7 +226,7 @@ int how; eff_uid = real_uid; eff_gid = real_gid; - debug2("Attach: uid %d euid %d\n", getuid(), geteuid()); + debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid()); MasterPid = 0; for (s = SockName; *s; s++) { @@ -238,7 +239,7 @@ int how; if (stat(SockPath, &st) == -1) Panic(errno, "stat %s", SockPath); if ((st.st_mode & 0600) != 0600) - Panic(0, "Socket is in wrong mode (%03o)", st.st_mode); + Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode); if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600)) Panic(0, "That screen is %sdetached.", dflag ? "already " : "not "); #ifdef REMOTE_DETACH @@ -266,7 +267,8 @@ int how; } #endif ASSERT(how == MSG_ATTACH || how == MSG_CONT); - strcpy(m.m.attach.envterm, attach_term); + strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1); + m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0; debug1("attach: sending %d bytes... ", (int)sizeof(m)); strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1); @@ -349,7 +351,7 @@ char *pwto; sighup = signal(SIG_PW_FAIL, trysendfail); for (tries = 0; ; ) { - strcpy(pwto, screenpw); + strncpy(pwto, screenpw, 9); trysendstatok = trysendstatfail = 0; if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m)) Panic(errno, "write"); @@ -423,7 +425,8 @@ AttacherFinit SIGDEFARG { debug("Detaching backend!\n"); bzero((char *) &m, sizeof(m)); - strcpy(m.m_tty, attach_tty); + strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); + m.m_tty[sizeof(m.m_tty) - 1] = 0; debug1("attach_tty is %s\n", attach_tty); m.m.detach.dpid = getpid(); m.type = MSG_HANGUP; @@ -726,7 +729,7 @@ LockTerminal() static void screen_builtin_lck() { - char fullname[100], *cp1, message[BUFSIZ]; + char fullname[100], *cp1, message[100 + 100]; char *pass, mypass[9]; #ifdef undef @@ -773,12 +776,14 @@ screen_builtin_lck() } debug("screen_builtin_lck looking in gcos field\n"); - strcpy(fullname, ppp->pw_gecos); + strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9); + fullname[sizeof(fullname) - 9] = 0; if ((cp1 = index(fullname, ',')) != NULL) *cp1 = '\0'; if ((cp1 = index(fullname, '&')) != NULL) { - sprintf(cp1, "%s", ppp->pw_name); + strncpy(cp1, ppp->pw_name, 8); + cp1[8] = 0; if (*cp1 >= 'a' && *cp1 <= 'z') *cp1 -= 'a' - 'A'; } @@ -63,12 +63,12 @@ struct comm comms[RC_LAST + 1] = #ifdef MULTI { "clone", NEED_DISPLAY|ARGS_ONE|ARGS_ORMORE }, #endif - { "colon", NEED_DISPLAY|ARGS_ZERO }, + { "colon", NEED_DISPLAY|ARGS_ZEROONE }, { "command", NEED_DISPLAY|ARGS_ZERO }, { "console", NEED_FORE|ARGS_ZEROONE }, #ifdef COPY_PASTE { "copy", NEED_FORE|ARGS_ZERO }, - { "crlf", ARGS_ONE }, + { "crlf", ARGS_ZEROONE }, #endif { "debug", ARGS_ZEROONE }, #ifdef AUTO_NUKE diff --git a/config.h.in b/config.h.in index 2d79d57..4ed1791 100644 --- a/config.h.in +++ b/config.h.in @@ -449,6 +449,16 @@ #undef HAVE_LSTAT /* + * define HAVE_UTIMES if your system has the utimes() call. + */ +#undef HAVE_UTIMES + +/* + * define HAVE_VSNPRINTF if your system has vsnprintf() (GNU lib). + */ +#undef HAVE_VSNPRINTF + +/* * define HAVE_DEV_PTC if you have a /dev/ptc character special * device. */ @@ -2622,10 +2622,10 @@ rm -f /tmp/conftest* test -n "$silent" || echo "checking for vsprintf" cat > conftest.${ac_ext} <<EOF #include "confdefs.h" -#include <varargs.h> + #include <stdio.h> int main() { return 0; } -int t() { vsprintf();; return 0; } +int t() { vsprintf(0,0,0);; return 0; } EOF if eval $ac_compile; then rm -rf conftest* @@ -2964,6 +2964,56 @@ ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_STRERROR\${ac_dB}HAVE_STRERROR\${ac_dC} fi rm -f conftest* +test -n "$silent" || echo "checking for utimes" +cat > conftest.${ac_ext} <<EOF +#include "confdefs.h" + +int main() { return 0; } +int t() { utimes(0,0);; return 0; } +EOF +if eval $ac_compile; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining HAVE_UTIMES" +echo "#define" HAVE_UTIMES "1" >> confdefs.h +DEFS="$DEFS -DHAVE_UTIMES=1" +ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_UTIMES\${ac_dB}HAVE_UTIMES\${ac_dC}1\${ac_dD} +\${ac_uA}HAVE_UTIMES\${ac_uB}HAVE_UTIMES\${ac_uC}1\${ac_uD} +\${ac_eA}HAVE_UTIMES\${ac_eB}HAVE_UTIMES\${ac_eC}1\${ac_eD} +" +} + + +fi +rm -f conftest* + +test -n "$silent" || echo "checking for vsnprintf" +cat > conftest.${ac_ext} <<EOF +#include "confdefs.h" + +int main() { return 0; } +int t() { vsnprintf(0,0,0);; return 0; } +EOF +if eval $ac_compile; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining HAVE_VSNPRINTF" +echo "#define" HAVE_VSNPRINTF "1" >> confdefs.h +DEFS="$DEFS -DHAVE_VSNPRINTF=1" +ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_VSNPRINTF\${ac_dB}HAVE_VSNPRINTF\${ac_dC}1\${ac_dD} +\${ac_uA}HAVE_VSNPRINTF\${ac_uB}HAVE_VSNPRINTF\${ac_uC}1\${ac_uD} +\${ac_eA}HAVE_VSNPRINTF\${ac_eB}HAVE_VSNPRINTF\${ac_eC}1\${ac_eD} +" +} + + +fi +rm -f conftest* + test -n "$seqptx" && LIBS="-ltermcap -lc -lsocket -linet -lsec -lseq" diff --git a/configure.in b/configure.in index a655f0a..92c4c58 100644 --- a/configure.in +++ b/configure.in @@ -978,8 +978,8 @@ else AC_DEFINE(NAME_MAX, 14) fi rm -f /tmp/conftest* -AC_COMPILE_CHECK(vsprintf, [#include <varargs.h> -#include <stdio.h>], [vsprintf();], AC_DEFINE(USEVARARGS)) +AC_COMPILE_CHECK(vsprintf, [ +#include <stdio.h>], [vsprintf(0,0,0);], AC_DEFINE(USEVARARGS)) AC_DIR_HEADER AC_XENIX_DIR @@ -993,6 +993,8 @@ AC_COMPILE_CHECK(rename, , [rename(0,0);], , AC_DEFINE(NEED_RENAME)) AC_COMPILE_CHECK(_exit, , [_exit(0);], AC_DEFINE(HAVE__EXIT)) AC_COMPILE_CHECK(lstat, , [lstat(0,0);], AC_DEFINE(HAVE_LSTAT)) AC_COMPILE_CHECK(strerror, ,[strerror(0);], AC_DEFINE(HAVE_STRERROR)) +AC_COMPILE_CHECK(utimes, ,[utimes(0,0);], AC_DEFINE(HAVE_UTIMES)) +AC_COMPILE_CHECK(vsnprintf, ,[vsnprintf(0,0,0);], AC_DEFINE(HAVE_VSNPRINTF)) dnl dnl **** the end **** @@ -269,9 +269,10 @@ struct mode *Mode; D_dospeed = (short) D_OldMode.m_ttyb.sg_ospeed; #endif /* POSIX || TERMIO */ debug1("New displays ospeed = %d\n", D_dospeed); - strcpy(D_usertty, utty); - strcpy(D_termname, term); - + strncpy(D_usertty, utty, sizeof(D_usertty) - 1); + D_usertty[sizeof(D_usertty) - 1] = 0; + strncpy(D_termname, term, sizeof(D_termname) - 1); + D_termname[sizeof(D_termname) - 1] = 0; D_user = *u; D_lay = &BlankLayer; D_layfn = BlankLayer.l_layfn; @@ -477,7 +478,7 @@ int c; else if (D_kanji == SJIS) { t += (c & 1) ? ((t <= 0x5f) ? 0x1f : 0x20) : 0x7e; - c = (c - 0x21) / 2 + ((c < 0x5e) ? 0x81 : 0xc1); + c = (c - 0x21) / 2 + ((c < 0x5f) ? 0x81 : 0xc1); } D_mbcs = t; } @@ -1887,7 +1888,12 @@ NukePending() PutStr(D_EI); D_insert = 0; /* Check for toggle */ -#ifndef MAPKEYS +#ifdef MAPKEYS + if (D_KS && strcmp(D_KS, D_KE)) + PutStr(D_KS); + if (D_CCS && strcmp(D_CCS, D_CCE)) + PutStr(D_CCS); +#else if (D_KS && strcmp(D_KS, D_KE)) PutStr(D_KE); D_keypad = 0; diff --git a/doc/Makefile.in b/doc/Makefile.in index ce1930b..74dcc37 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -29,7 +29,7 @@ install: installdirs if test -f $$d/screen.info; then \ for f in $$d/screen.info*; do $(INSTALL_DATA) $$f $(infodir);done; \ if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ - install-info --infodir=$(infodir) $$d/screen.info; \ + install-info --info-dir=$(infodir) $$d/screen.info; \ else true; fi; \ fi diff --git a/doc/screen.1 b/doc/screen.1 index 558e314..d30e94e 100644 --- a/doc/screen.1 +++ b/doc/screen.1 @@ -859,6 +859,7 @@ Clears the current window and saves its image to the scrollback buffer. .sp .ne 3 .B colon +.RI [ prefix ] .PP Allows you to enter \*Q.screenrc\*U command lines. Useful for on-the-fly modification of key bindings, diff --git a/etc/etcscreenrc b/etc/etcscreenrc index 301d6b9..7c6aa42 100644 --- a/etc/etcscreenrc +++ b/etc/etcscreenrc @@ -93,3 +93,7 @@ bind 'K' kill bind 'I' login on bind 'O' login off bind '}' history + +# colon takes a parameter since screen-3.8.6 +bind 'R' colon "screen -ln rlogin faui -8^b^b^b" +bind 'P' colon "^p" diff --git a/etc/screenrc b/etc/screenrc index 839ad8c..76fc888 100644 --- a/etc/screenrc +++ b/etc/screenrc @@ -32,6 +32,8 @@ pow_detach_msg "Screen session of \$LOGNAME \$:cr:\$:nl:ended." defscrollback 1000 +# don't kill window after the process died +# zombie "^[" ################ # @@ -55,7 +57,7 @@ termcapinfo xterm* OL=10000 # keys. termcapinfo xterm 'VR=\E[?5h:VN=\E[?5l' termcapinfo xterm 'k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~' -termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[5~:kN=\E[6~' +termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[H:kN=\E[6~' # special xterm hardstatus: use the window title. termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]0;screen\007' @@ -122,3 +124,11 @@ register [ "\033:se noai\015a" register ] "\033:se ai\015a" bind ^] paste [.] +################ +# +# default windows +# + +# screen -t local 0 +# screen -t mail 1 elm +# screen -t 40 2 rlogin faui40 @@ -24,7 +24,7 @@ /* screen.c */ -extern void main __P((int, char **)); +extern int main __P((int, char **)); extern sigret_t SigHup __P(SIGPROTOARG); extern void eexit __P((int)); extern void Detach __P((int)); @@ -69,7 +69,7 @@ extern int secopen __P((char *, int, int)); extern void WriteFile __P((int)); extern char *ReadFile __P((char *, int *)); extern void KillBuffers __P((void)); -extern char *expand_vars __P((char *)); +extern char *expand_vars __P((char *, struct display *)); /* tty.c */ extern int OpenTTY __P((char *)); @@ -99,10 +99,11 @@ extern void ISearch __P((int)); /* input.c */ extern void inp_setprompt __P((char *, char *)); -extern void Input __P((char *, int, void (*)(), int)); +extern void Input __P((char *, int, int, void (*)(), char *)); +extern int InInput __P((void)); /* help.c */ -extern void exit_with_usage __P((char *)); +extern void exit_with_usage __P((char *, char *, char *)); extern void display_help __P((void)); extern void display_copyright __P((void)); extern void display_displays __P((void)); @@ -161,7 +162,7 @@ extern int IsNumColon __P((char *, int, char *, int)); extern void ShowWindows __P((void)); extern int WindowByNoN __P((char *)); #ifdef COPY_PASTE -extern int CompileKeys __P((char *, char *)); +extern int CompileKeys __P((char *, unsigned char *)); #endif /* termcap.c */ @@ -247,7 +248,7 @@ extern void DoResize __P((int, int)); extern char *xrealloc __P((char *, int)); /* socket.c */ -extern int FindSocket __P((int *, int *, char *)); +extern int FindSocket __P((int *, int *, int *, char *)); extern int MakeClientSocket __P((int)); extern int MakeServerSocket __P((void)); extern int RecoverSocket __P((void)); @@ -292,6 +293,14 @@ extern void xsetegid __P((int)); #endif extern int AddXChar __P((char *, int)); extern int AddXChars __P((char *, int, char *)); +extern void opendebug __P((int, int)); +#ifdef USEVARARGS +# ifndef HAVE_VSNPRINTF +extern int xvsnprintf __P((char *, int, char *, va_list)); +# endif +#else +extern int xsnprintf __P(()); +#endif /* acl.c */ #ifdef MULTIUSER @@ -306,9 +315,10 @@ extern int AclUserAddGroup __P((char *, char *)); extern int AclUserDelGroup __P((char *, char *)); extern int AclCheckPermWin __P((struct user *, int, struct win *)); extern int AclCheckPermCmd __P((struct user *, int, struct comm *)); -extern int AclSetPerm __P((struct user *, char *, char *)); +extern int AclSetPerm __P((struct user *, struct user *, char *, char *)); +extern int UsersAcl __P((struct user *, int, char **)); extern void AclWinSwap __P((int, int)); -extern int NewWindowAcl __P((struct win *)); +extern int NewWindowAcl __P((struct win *, struct user *)); #endif /* MULTIUSER */ extern struct user **FindUserPtr __P((char *)); extern int UserAdd __P((char *, char *, struct user **)); @@ -121,7 +121,7 @@ char *rcfile; else { debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n"); - if (strlen(home) > 244) + if (strlen(home) > sizeof(buf) - 12) Panic(0, "Rc: home too large"); sprintf(buf, "%s/.iscreenrc", home); if (access(buf, R_OK)) @@ -176,7 +176,7 @@ char *rcfilename; { if ((p = rindex(buf, '\n')) != NULL) *p = '\0'; - if ((argc = Parse(expand_vars(buf), args)) == 0) + if ((argc = Parse(expand_vars(buf, display), args)) == 0) continue; if (strcmp(args[0], "echo") == 0) { @@ -279,160 +279,13 @@ char *rcfilename; 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); + buf = expand_vars(ubuf, display); if (Parse(buf, args) <= 0) return; DoCommand(args); @@ -458,11 +311,13 @@ int dump; { case DUMP_TERMCAP: i = SockName - SockPath; + if (i > sizeof(fn) - 9) + i = 0; strncpy(fn, SockPath, i); strcpy(fn + i, ".termcap"); break; case DUMP_HARDCOPY: - if (hardcopydir) + if (hardcopydir && strlen(hardcopydir) < sizeof(fn) - 21) sprintf(fn, "%s/hardcopy.%d", hardcopydir, fore->w_number); else sprintf(fn, "hardcopy.%d", fore->w_number); @@ -471,7 +326,8 @@ int dump; break; #ifdef COPY_PASTE case DUMP_EXCHANGE: - sprintf(fn, "%s", BufferFile); + strncpy(fn, BufferFile, sizeof(fn) - 1); + fn[sizeof(fn) - 1] = 0; umask(0); break; #endif @@ -39,8 +39,8 @@ extern struct mchar mchar_null; void -exit_with_usage(myname) -char *myname; +exit_with_usage(myname, message, arg) +char *myname, *message, *arg; { printf("Use: %s [-opts] [cmd [args]]\n", myname); printf(" or: %s -r [host.tty]\n\nOptions:\n", myname); @@ -74,6 +74,12 @@ char *myname; #ifdef MULTI printf("-x Attach to a not detached screen. (Multi display mode).\n"); #endif /* MULTI */ + if (message && *message) + { + printf("\nError: "); + printf(message, arg); + printf("\n"); + } exit(1); } @@ -287,7 +293,8 @@ helppage() debug1("help: searching key %d\n", n); buf[0] = '\0'; for (key = 0; key < 256; key++) - if (ktab[key].nr == n && ktab[key].args == noargs) + if (ktab[key].nr == n && ktab[key].args == noargs && strlen(buf) < sizeof(buf) - 7) + { strcat(buf, " "); add_key_to_buf(buf, key); @@ -360,7 +367,7 @@ int fr; *bp++ = del = '\''; } while (*cp && bp < buf + 250) - bp += AddXChar(bp, *cp++); + bp += AddXChar(bp, *(unsigned char *)cp++); if (del) *bp++ = del; *bp = 0; @@ -389,10 +396,11 @@ int key; debug1("help: key found: %c\n", key); buf += strlen(buf); if (key < 0) - sprintf(buf, "unset"); + strcpy(buf, "unset"); else if (key == ' ') - sprintf(buf, "sp"); - else buf[AddXChar(buf, key)] = 0; + strcpy(buf, "sp"); + else + buf[AddXChar(buf, key)] = 0; } @@ -37,15 +37,25 @@ static void InpSetCursor __P((void)); extern struct display *display; extern struct mchar mchar_blank, mchar_so; +struct inpline +{ + char buf[101]; /* text buffer */ + int len; /* length of the editible string */ + int pos; /* cursor position in editable string */ +}; + +static struct inpline inphist; /* XXX: should be a dynamic list */ + + struct inpdata { - char inpbuf[101]; - int inplen; - int inpmaxlen; - char *inpstring; - int inpstringlen; - int inpmode; - void (*inpfinfunc)(); + struct inpline inp; + int inpmaxlen; /* 100, or less, if caller has shorter buffer */ + char *inpstring; /* the prompt */ + int inpstringlen; /* length of the prompt */ + int inpmode; /* INP_NOECHO, INP_RAW, INP_EVERY */ + void (*inpfinfunc) __P((char *buf, int len, char *priv)); + char *priv; }; static struct LayFuncs InpLf = @@ -78,9 +88,10 @@ char *p, *s; } if (s) { - strncpy(inpdata->inpbuf, s, sizeof(inpdata->inpbuf) - 1); - inpdata->inpbuf[sizeof(inpdata->inpbuf) - 1] = 0; - inpdata->inplen = strlen(inpdata->inpbuf); + if (s != inpdata->inp.buf) + strncpy(inpdata->inp.buf, s, sizeof(inpdata->inp.buf) - 1); + inpdata->inp.buf[sizeof(inpdata->inp.buf) - 1] = 0; + inpdata->inp.pos = inpdata->inp.len = strlen(inpdata->inp.buf); } RefreshLine(STATLINE, 0, D_width - 1, 0); } @@ -93,13 +104,15 @@ char *p, *s; * mode is an OR of * INP_NOECHO == suppress echoing of characters. * INP_RAW == raw mode. call finfunc after each character typed. + * INP_EVERY == digraph mode. */ void -Input(istr, len, finfunc, mode) +Input(istr, len, mode, finfunc, data) char *istr; int len; -void (*finfunc)(); int mode; +void (*finfunc) __P((char *buf, int len, char *data)); +char *data; { int maxlen; struct inpdata *inpdata; @@ -129,8 +142,9 @@ int mode; inpdata = (struct inpdata *)D_lay->l_data; inpdata->inpmaxlen = len; inpdata->inpfinfunc = finfunc; - inpdata->inplen = 0; + inpdata->inp.pos = inpdata->inp.len = 0; inpdata->inpmode = mode; + inpdata->priv = data; inp_setprompt(istr, (char *)NULL); } @@ -140,7 +154,7 @@ InpSetCursor() struct inpdata *inpdata; inpdata = (struct inpdata *)D_lay->l_data; - GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inplen), STATLINE); + GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos), STATLINE); } static void @@ -155,70 +169,134 @@ int *plen; inpdata = (struct inpdata *)D_lay->l_data; - GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inplen), STATLINE); + GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos), STATLINE); if (ppbuf == 0) { InpAbort(); return; } - x = inpdata->inpstringlen + inpdata->inplen; + x = inpdata->inpstringlen + inpdata->inp.pos; len = *plen; pbuf = *ppbuf; while (len) { + char *p = inpdata->inp.buf + inpdata->inp.pos; + ch = *pbuf++; len--; if (inpdata->inpmode & INP_EVERY) { - inpdata->inpbuf[inpdata->inplen] = ch; - inpdata->inpbuf[inpdata->inplen + 1] = ch; /* gross */ - (*inpdata->inpfinfunc)(inpdata->inpbuf, inpdata->inplen); - ch = inpdata->inpbuf[inpdata->inplen]; + inpdata->inp.buf[inpdata->inp.len] = ch; + inpdata->inp.buf[inpdata->inp.len + 1] = ch; /* gross */ + (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv); + ch = inpdata->inp.buf[inpdata->inp.len]; } else if (inpdata->inpmode & INP_RAW) { - (*inpdata->inpfinfunc)(&ch, 1); /* raw */ + (*inpdata->inpfinfunc)(&ch, 1, inpdata->priv); /* raw */ if (ch) continue; } - if ((unsigned char)ch >= ' ' && ch != 0177 && inpdata->inplen < inpdata->inpmaxlen) + if (((unsigned char)ch & 0177) >= ' ' && ch != 0177 && inpdata->inp.len < inpdata->inpmaxlen) { - inpdata->inpbuf[inpdata->inplen++] = ch; + if (inpdata->inp.len > inpdata->inp.pos) + bcopy(p, p+1, inpdata->inp.len - inpdata->inp.pos); + inpdata->inp.len++; + inpdata->inp.buf[inpdata->inp.pos++] = ch; + if (!(inpdata->inpmode & INP_NOECHO)) { GotoPos(x, STATLINE); SetRendition(&mchar_so); - PUTCHAR(ch); + PUTCHAR(*p++); x++; + if (p < inpdata->inp.buf+inpdata->inp.len) + { + while (p < inpdata->inp.buf+inpdata->inp.len) + PUTCHAR(*p++); + GotoPos(x, STATLINE); + } } } - else if ((ch == '\b' || ch == 0177) && inpdata->inplen > 0) + else if ((ch == '\b' || ch == 0177) && inpdata->inp.pos > 0) { - inpdata->inplen--; + if (inpdata->inp.len > inpdata->inp.pos) + bcopy(p, p-1, inpdata->inp.len - inpdata->inp.pos); + inpdata->inp.len--; + inpdata->inp.pos--; + p--; if (!(inpdata->inpmode & 1)) { x--; GotoPos(x, STATLINE); + SetRendition(&mchar_so); + while (p < inpdata->inp.buf+inpdata->inp.len) + PUTCHAR(*p++); SetRendition(&mchar_blank); PUTCHAR(' '); GotoPos(x, STATLINE); } } + else if (ch == '\001' || (unsigned char)ch == 0201) /* CTRL-A */ + { + GotoPos(x -= inpdata->inp.pos, STATLINE); + inpdata->inp.pos = 0; + } + else if ((ch == '\002' || (unsigned char)ch == 0202) && inpdata->inp.pos > 0) /* CTRL-B */ + { + GotoPos(--x, STATLINE); + inpdata->inp.pos--; + } + else if (ch == '\005' || (unsigned char)ch == 0205) /* CTRL-E */ + { + GotoPos(x += inpdata->inp.len - inpdata->inp.pos, STATLINE); + inpdata->inp.pos = inpdata->inp.len; + } + else if ((ch == '\006' || (unsigned char)ch == 0206) && inpdata->inp.pos < inpdata->inp.len) /* CTRL-F */ + { + GotoPos(++x, STATLINE); + inpdata->inp.pos++; + } + else if (ch == '\020' || (unsigned char)ch == 0220) /* CTRL-P */ + { + p = inpdata->inp.buf; + GotoPos(inpdata->inpstringlen, STATLINE); + SetRendition(&mchar_blank); + while (p++ < inpdata->inp.buf+inpdata->inp.len) + PUTCHAR(' '); + + inpdata->inp = inphist; /* structure copy */ + if (inpdata->inp.len > inpdata->inpmaxlen) + inpdata->inp.len = inpdata->inpmaxlen; + if (inpdata->inp.pos > inpdata->inp.len) + inpdata->inp.pos = inpdata->inp.len; + x = inpdata->inpstringlen + inpdata->inp.pos; + + p = inpdata->inp.buf; + GotoPos(inpdata->inpstringlen, STATLINE); + SetRendition(&mchar_so); + while (p < inpdata->inp.buf+inpdata->inp.len) + PUTCHAR(*p++); + GotoPos(x, STATLINE); + } else if (ch == '\004' || ch == '\003' || ch == '\007' || ch == '\033' || ch == '\000' || ch == '\n' || ch == '\r') { - if (ch != '\033' && ch != '\n' && ch != '\r') - inpdata->inplen = 0; - inpdata->inpbuf[inpdata->inplen] = 0; + if (ch != '\004' && ch != '\n' && ch != '\r') + inpdata->inp.len = 0; + inpdata->inp.buf[inpdata->inp.len] = 0; + + if (inpdata->inp.len) + inphist = inpdata->inp; /* structure copy */ D_lay->l_data = 0; InpAbort(); /* redisplays... */ *ppbuf = pbuf; *plen = len; if ((inpdata->inpmode & INP_RAW) == 0) - (*inpdata->inpfinfunc)(inpdata->inpbuf, inpdata->inplen); + (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv); else - (*inpdata->inpfinfunc)(pbuf - 1, 0); + (*inpdata->inpfinfunc)(pbuf - 1, 0, inpdata->priv); free((char *)inpdata); return; } @@ -248,7 +326,7 @@ int y, xs, xe, isblank; LAY_CALL_UP(RefreshLine(y, xs, xe, isblank)); return; } - inpdata->inpbuf[inpdata->inplen] = 0; + inpdata->inp.buf[inpdata->inp.len] = 0; GotoPos(xs, y); q = xs; v = xe - xs + 1; @@ -265,14 +343,14 @@ int y, xs, xe, isblank; v -= l; } s = r; - r += inpdata->inplen; + r += inpdata->inp.len; if (!(inpdata->inpmode & INP_NOECHO) && v > 0 && q < r) { SetRendition(&mchar_so); l = v; if (l > r-q) l = r-q; - AddStrn(inpdata->inpbuf + q - s, l); + AddStrn(inpdata->inp.buf + q - s, l); q += l; v -= l; } @@ -289,3 +367,12 @@ int y, xs, xe, isblank; } SetLastPos(q, y); } + +int +InInput() +{ + if (display && D_layfn->LayProcess == InpProcess) + return 1; + return 0; +} + diff --git a/kmapdef.c.dist b/kmapdef.c.dist index 943c600..fef98ed 100644 --- a/kmapdef.c.dist +++ b/kmapdef.c.dist @@ -20,6 +20,14 @@ char *kmapdef[] = { "\033[21~", "\033[23~", "\033[24~", +0, +0, +0, +0, +0, +0, +0, +0, "\010", "\033[1~", 0, @@ -96,7 +104,7 @@ char *kmapadef[] = { }; char *kmapmdef[] = { -"g", +"\201", 0, 0, 0, @@ -109,7 +117,7 @@ char *kmapmdef[] = { 0, 0, "\004", -"G", +"\205", 0, 0, 0, @@ -121,10 +129,10 @@ char *kmapmdef[] = { 0, 0, 0, -"k", -"j", -"l", -"h" +"\220", +"\216", +"\206", +"\202" }; #endif @@ -73,7 +73,7 @@ static struct LayFuncs MarkLf = }; int join_with_cr = 0; -char mark_key_tab[256]; /* this array must be initialised first! */ +unsigned char mark_key_tab[256]; /* this array must be initialised first! */ static struct markdata *markdata; @@ -528,7 +528,7 @@ int *inlenp; else */ { - od = mark_key_tab[(unsigned int)*pt++]; + od = mark_key_tab[(int)(unsigned char)*pt++]; inlen--; } rep_cnt = markdata->rep_cnt; @@ -567,12 +567,14 @@ int *inlenp; Redisplay(0); GotoPos(cx, W2D(cy)); break; + case 0202: /* M-C-b */ case '\010': /* CTRL-H Backspace */ case 'h': if (rep_cnt == 0) rep_cnt = 1; revto(cx - rep_cnt, cy); break; + case 0216: /* M-C-p */ case '\016': /* CTRL-N */ case 'j': if (rep_cnt == 0) @@ -601,12 +603,14 @@ int *inlenp; case '\n': revto(markdata->left_mar, cy + 1); break; - case 'k': + case 0220: /* M-C-p */ case '\020': /* CTRL-P */ + case 'k': if (rep_cnt == 0) rep_cnt = 1; revto(cx, cy - rep_cnt); break; + case 0206: /* M-C-f */ case 'l': if (rep_cnt == 0) rep_cnt = 1; @@ -687,9 +691,11 @@ int *inlenp; rep_cnt = 100; revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + D_height)) / 100, (D_height - 1) / 2); break; + case 0201: case 'g': rep_cnt = 1; /* FALLTHROUGH */ + case 0205: case 'G': /* rep_cnt is here the WIN line number */ if (rep_cnt == 0) @@ -25,6 +25,7 @@ RCS_ID("$Id: misc.c,v 1.5 1994/05/31 12:32:19 mlschroe Exp $ FAU") #include <sys/types.h> +#include <sys/stat.h> /* mkdir() declaration */ #include <signal.h> #include "config.h" @@ -196,7 +197,7 @@ int egid; Panic(errno, "setegid"); } -#else +#else /* HAVE_SETEUID */ # ifdef HAVE_SETREUID void @@ -229,8 +230,8 @@ int egid; Panic(errno, "setregid"); } -# endif -#endif +# endif /* HAVE_SETREUID */ +#endif /* HAVE_SETEUID */ @@ -293,8 +294,6 @@ int except; close(f); } - - /* * Security - switch to real uid */ @@ -427,6 +426,11 @@ int len; { char *p; + if (str == 0) + { + *buf = 0; + return 0; + } len -= 4; /* longest sequence produced by AddXChar() */ for (p = buf; p < buf + len && *str; str++) { @@ -439,6 +443,181 @@ int len; return p - buf; } +#ifdef DEBUG +void +opendebug(new, shout) +int new, shout; +{ + char buf[256]; + +#ifdef _MODE_T + mode_t oumask = umask(0); +#else + int oumask = umask(0); +#endif + + ASSERT(!dfp); + + (void) mkdir(DEBUGDIR, 0777); + sprintf(buf, shout ? "%s/SCREEN.%d" : "%s/screen.%d", DEBUGDIR, getpid()); + if (!(dfp = fopen(buf, new ? "w" : "a"))) + dfp = stderr; + else + (void)chmod(buf, 0666); + + (void)umask(oumask); + debug("opendebug: done.\n"); +} +#endif /* DEBUG */ + +/* + * "$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" + * + * display == NULL is valid here! + */ +char * +expand_vars(ss, d) +char *ss; +struct display *d; +{ + 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 = d ? d->d_termname : "unknown"; + else if (strcmp(s, "COLUMNS") == 0) + sprintf(xbuf, "%d", d ? d->d_width : -1); + else if (strcmp(s, "LINES") == 0) + sprintf(xbuf, "%d", d ? d->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'; + return ebuf; +} #ifdef TERMINFO /* @@ -466,3 +645,117 @@ int (*outc)(); } #endif + +#ifndef USEVARARGS + +# define xva_arg(s, t, tn) (*(t *)(s += xsnoff(tn, 0, 0), s - xsnoff(tn, 0, 0))) +# define xva_list char * + +static int +xsnoff(a, b, c) +int a; +char *b; +int c; +{ + return a ? (char *)&c - (char *)&b : (char *)&b - (char *)&a; +} + +int +xsnprintf(s, n, fmt, p1, p2, p3, p4, p5, p6) +char *s; +int n; +char *fmt; +unsigned long p1, p2, p3, p4, p5, p6; +{ + int xvsnprintf __P((char *, int, char *, xva_list)); + return xvsnprintf(s, n, fmt, (char *)&fmt + xsnoff(1, 0, 0)); +} + +#else + +# define xva_arg(s, t, tn) va_arg(s, t) +# define xva_list va_list + +#endif + + +#if !defined(USEVARARGS) || !defined(HAVE_VSNPRINTF) + +int +xvsnprintf(s, n, fmt, stack) +char *s; +int n; +char *fmt; +xva_list stack; +{ + char *f, *sf = 0; + int i, on, argl = 0; + char myf[10], buf[20]; + char *arg, *myfp; + + on = n; + f = fmt; + arg = 0; + while(arg || (sf = index(f, '%')) || (sf = f + strlen(f))) + { + if (arg == 0) + { + arg = f; + argl = sf - f; + } + if (argl) + { + i = argl > n - 1 ? n - 1 : argl; + strncpy(s, arg, i); + s += i; + n -= i; + if (i < argl) + { + *s = 0; + return on; + } + } + arg = 0; + if (sf == 0) + continue; + f = sf; + sf = 0; + if (!*f) + break; + myfp = myf; + *myfp++ = *f++; + while (((*f >= '0' && *f <='9') || *f == '#') && myfp - myf < 8) + *myfp++ = *f++; + *myfp++ = *f; + *myfp = 0; + if (!*f++) + break; + switch(f[-1]) + { + case '%': + arg = "%"; + break; + case 'c': + case 'o': + case 'd': + case 'x': + i = xva_arg(stack, int, 0); + sprintf(buf, myf, i); + arg = buf; + break; + case 's': + arg = xva_arg(stack, char *, 1); + if (arg == 0) + arg = "NULL"; + break; + default: + arg = ""; + break; + } + argl = strlen(arg); + } + *s = 0; + return on - n; +} + +#endif @@ -27,6 +27,11 @@ #include <sys/param.h> +/* In strict ANSI mode, HP-UX machines define __hpux but not hpux */ +#if defined(__hpux) && !defined(hpux) +# define hpux +#endif + #if defined(BSDI) || defined(__386BSD__) || defined(_CX_UX) || defined(hpux) # include <signal.h> #endif /* BSDI || __386BSD__ || _CX_UX */ @@ -137,7 +142,14 @@ extern int errno; #endif #if !defined(HAVE__EXIT) && !defined(_exit) -#define _exit(x) exit(x) +# define _exit(x) exit(x) +#endif + +#ifndef HAVE_UTIMES +# define utimes utime +#endif +#ifndef HAVE_VSNPRINTF +# define vsnprintf xvsnprintf #endif /***************************************************************** @@ -161,6 +161,7 @@ extern int vsprintf __P((char *, char *, va_list)); #endif struct timeval; /* for select __P */ extern int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); +extern int utimes __P((char *, struct timeval *)); extern void unsetenv __P((char *)); diff --git a/patchlevel.h b/patchlevel.h index e7bd579..f25e500 100644 --- a/patchlevel.h +++ b/patchlevel.h @@ -227,11 +227,25 @@ * linux: elf, but no SVR4, check for utmpx. * hpux10.10 libcurses breaks select()! * -- DISTRIBUTED + * 27.09.96 -- 3.07.03 ncurses tgetflag returns -1 if cap not valid. + * autonuke fix: reset application mode. An init + * string may have cleared it. + * Small UTMPOK patch from Douglas B. Jones. + * 23.06.97 -- 3.07.04 Some bugfixes. Kanji fixed. + * Code update from 3.8.6: Colon line editing added. + * Digraph made line-editing resistant. + * DEC ALPHA ut_user[0] = 0; + * Added error messages to exit_with_usage. + * FindSocket code improved (the MULTIUSER part). + * Use utimes() if available. Power-detached start. + * vsnprintf() support. exit -> _exit in window.c. + * AddXChars now tolerates NULL string. + * -- DISTRIBUTED */ #define ORIGIN "FAU" #define REV 3 #define VERS 7 -#define PATCHLEVEL 2 -#define DATE "1-Sep-96" +#define PATCHLEVEL 4 +#define DATE "23-Jun-97" #define STATE "" @@ -69,7 +69,7 @@ extern int intrc, origintrc; /* display? */ extern struct NewWindow nwin_default, nwin_undef; #ifdef COPY_PASTE extern int join_with_cr, pastefont; -extern char mark_key_tab[]; +extern unsigned char mark_key_tab[]; extern char *BufferFile; #endif #ifdef POW_DETACH @@ -107,25 +107,27 @@ static int ParseWinNum __P((struct action *act, int *)); static int ParseBase __P((struct action *act, char *, int *, int, char *)); static char *ParseChar __P((char *, char *)); static int IsNum __P((char *, int)); -static void InputColon __P((void)); -static void Colonfin __P((char *, int)); +static void Colonfin __P((char *, int, char *)); static void InputSelect __P((void)); static void InputSetenv __P((char *)); static void InputAKA __P((void)); -static void AKAfin __P((char *, int)); +static void AKAfin __P((char *, int, char *)); #ifdef COPY_PASTE -static void copy_reg_fn __P((char *, int)); -static void ins_reg_fn __P((char *, int)); +static void copy_reg_fn __P((char *, int, char *)); +static void ins_reg_fn __P((char *, int, char *)); #endif -static void process_fn __P((char *, int)); +static void process_fn __P((char *, int, char *)); #ifdef PASSWORD -static void pass1 __P((char *, int)); -static void pass2 __P((char *, int)); +static void pass1 __P((char *, int, char *)); +static void pass2 __P((char *, int, char *)); #endif #ifdef POW_DETACH -static void pow_detach_fn __P((char *, int)); +static void pow_detach_fn __P((char *, int, char *)); +#endif +static void digraph_fn __P((char *, int, char *)); +#ifdef MAPKEYS +static int StuffKey __P((int)); #endif -static void digraph_fn __P((char *, int)); @@ -150,7 +152,9 @@ struct win *wtab[MAXWIN]; /* window table, should be dynamic */ #ifdef MULTIUSER extern char *multi; +extern int maxusercount; #endif +char NullStr[] = ""; /* not really used */ #ifdef PASSWORD int CheckPassword; char Password[30]; @@ -462,17 +466,16 @@ char *ibuf; int ilen; { int ch, slen; - char *s; - struct action *act; + unsigned char *s; int i, l; if (display == 0 || ilen == 0) return; slen = ilen; - s = ibuf; + s = (unsigned char *)ibuf; while(ilen-- > 0) { - ch = *(unsigned char *)s++; + ch = *s++; if (D_dontmap) D_dontmap = 0; else if (D_nseqs) @@ -503,7 +506,7 @@ int ilen; ProcessInput2(ibuf, slen); D_seqruns = 0; } - ibuf = s; + ibuf = (char *)s; slen = ilen; ch = -1; if (*++D_seqp == 0) @@ -511,29 +514,7 @@ int ilen; i = (struct kmap *)(D_seqp - D_seql - KMAP_SEQ) - D_kmaps; debug1("Mapping #%d", i); i = D_kmaps[i].nr & ~KMAP_NOTIMEOUT; -#ifdef DEBUG - if (i < KMAP_KEYS) - debug1(" - %s", term[i + T_CAPS].tcname); -#endif - if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys) - i += T_OCAPS - T_CURSOR; - else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad) - i += T_OCAPS - T_CURSOR; - debug1(" - action %d\n", i); - fore = D_fore; - act = 0; -#ifdef COPY_PASTE - if (InMark()) - act = &mmtab[i]; -#endif - if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault) - act = &umtab[i]; - D_mapdefault = 0; - if (!act || act->nr == RC_ILLEGAL) - act = &dmtab[i]; - if (act && act->nr != RC_ILLEGAL) - DoAction(act, 0); - else + if (StuffKey(i)) { D_seqp -= D_seql; ProcessInput2(D_seqp, D_seql); @@ -604,7 +585,7 @@ int ilen; if (ch >= 0) DoAction(&ktab[ch], ch); - ibuf = s + 1; + ibuf = (char *)(s + 1); ilen--; } } @@ -821,7 +802,7 @@ int key; static char buf[2]; buf[0] = key; - Input(buf, 1, pow_detach_fn, INP_RAW); + Input(buf, 1, INP_RAW, pow_detach_fn, NULL); } else Detach(D_POWER); /* detach and kill Attacher's parent */ @@ -845,14 +826,7 @@ int key; dfp = NULL; } if (strcmp("off", *args)) - { - char buf[255]; - - sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, getpid()); - if ((dfp = fopen(buf, "a")) == NULL) - dfp = stderr; - debug("debug: opening debug file.\n"); - } + opendebug(0, 1); #else Msg(0, "Sorry, screen was compiled without -DDEBUG option."); #endif @@ -1045,7 +1019,7 @@ int key; */ if ((s = *args) == NULL) { - Input("Copy to register:", 1, copy_reg_fn, INP_RAW); + Input("Copy to register:", 1, INP_RAW, copy_reg_fn, NULL); break; } if (((s = ParseChar(s, &ch)) == NULL) || *s) @@ -1075,7 +1049,7 @@ int key; * This could be done with RC_PASTE too, but is here to be consistent * with the zero argument call. */ - copy_reg_fn(&ch, 0); + copy_reg_fn(&ch, 0, NULL); break; #endif case RC_REGISTER: @@ -1095,7 +1069,7 @@ int key; case RC_PROCESS: if ((s = *args) == NULL) { - Input("Process register:", 1, process_fn, INP_RAW); + Input("Process register:", 1, INP_RAW, process_fn, NULL); break; } if ((s = ParseChar(s, &ch)) == NULL || *s) @@ -1104,7 +1078,7 @@ int key; rc_name); break; } - process_fn(&ch, 0); + process_fn(&ch, 0, NULL); break; case RC_STUFF: s = *args; @@ -1245,7 +1219,13 @@ int key; ChangeAKA(fore, *args, 20); break; case RC_COLON: - InputColon(); + Input(":", 100, INP_COOKED, Colonfin, NULL); + if (*args && **args) + { + s = *args; + n = strlen(s); + Process(&s, &n); + } break; case RC_LASTMSG: if (D_status_lastmsg) @@ -1399,7 +1379,7 @@ int key; */ if ((s = *args) == NULL) { - Input("Paste from register:", 1, ins_reg_fn, INP_RAW); + Input("Paste from register:", 1, INP_RAW, ins_reg_fn, NULL); break; } /* @@ -1833,6 +1813,14 @@ int key; break; if (n) { +#ifdef MULTIUSER + if (display) /* we tell only this user */ + ACLBYTE(fore->w_lio_notify, D_user->u_id) |= ACLBIT(D_user->u_id); + else + for (i = 0; i < maxusercount; i++) + ACLBYTE(fore->w_mon_notify, i) |= ACLBIT(i); + if (!fore->w_tstamp.seconds) +#endif fore->w_tstamp.lastio = time(0); fore->w_tstamp.seconds = i; if (!msgok) @@ -1848,8 +1836,22 @@ int key; } else { - fore->w_tstamp.lastio = (time_t)0; - fore->w_tstamp.seconds = 0; +#ifdef MULTIUSER + if (display) /* we remove only this user */ + ACLBYTE(fore->w_lio_notify, D_user->u_id) + &= ~ACLBIT(D_user->u_id); + else + for (i = 0; i < maxusercount; i++) + ACLBYTE(fore->w_lio_notify, i) &= ~ACLBIT(i); + for (i = maxusercount - 1; i >= 0; i--) + if (ACLBYTE(fore->w_lio_notify, i)) + break; + if (i < 0) +#endif + { + fore->w_tstamp.lastio = (time_t)0; + fore->w_tstamp.seconds = 0; + } if (!msgok) break; #ifdef NETHACK @@ -1882,13 +1884,13 @@ int key; s = NULL; if (ParseSaveStr(act, &s)) break; - if (!*s || strlen(s) > MAXPATHLEN - 13) + if (!*s || strlen(s) + (SockName - SockPath) > MAXPATHLEN - 13) { Msg(0, "%s: bad session name '%s'\n", rc_name, s); free(s); break; } - sprintf(buf, "%s", SockPath); + strncpy(buf, SockPath, SockName - SockPath); sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s); free(s); if ((access(buf, F_OK) == 0) || (errno != ENOENT)) @@ -1902,7 +1904,7 @@ int key; break; } debug2("rename(%s, %s) done\n", SockPath, buf); - sprintf(SockPath, "%s", buf); + strcpy(SockPath, buf); MakeNewEnv(); } break; @@ -1980,7 +1982,7 @@ int key; Msg(0, "Will %spaste font settings", pastefont ? "" : "not "); break; case RC_CRLF: - (void)ParseOnOff(act, &join_with_cr); + (void)ParseSwitch(act, &join_with_cr); break; #endif #ifdef NETHACK @@ -2036,8 +2038,8 @@ int key; debug("prompting for password on no display???\n"); break; } - Input("New screen password:", sizeof(Password) - 1, pass1, - INP_NOECHO); + Input("New screen password:", sizeof(Password) - 1, INP_NOECHO, + pass1, NULL); } break; #endif /* PASSWORD */ @@ -2103,7 +2105,7 @@ int key; if (*args == 0) { if (mf) - display_bindkey("Copy mode", mmtab); + display_bindkey("Edit mode", mmtab); else if (df) display_bindkey("Default", dmtab); else @@ -2216,39 +2218,18 @@ int key; #ifdef MULTIUSER case RC_ACLCHG: case RC_ACLADD: - { - struct user **u; - - if (args[0][0] == '*' && args[0][1] == '\0' && args[1] && args[2]) - { - for (u = &users; *u; u = &(*u)->u_next) - AclSetPerm(*u, args[1], args[2]); - break; - } - do - { - for (s = args[0]; *s && *s != ' ' && *s != '\t' && *s != ','; s++) - ; - *s ? (*s++ = '\0') : (*s = '\0'); - u = FindUserPtr(args[0]); - UserAdd(args[0], (char *)0, u); - if (args[1] && args[2]) - AclSetPerm(*u, args[1], args[2]); - else - AclSetPerm(*u, "+rwx", "#?"); - } while (*(args[0] = s)); - break; - } + for (n = 0; args[n]; n++) + ; + UsersAcl(NULL, n, args); + break; case RC_ACLDEL: - { - if (UserDel(args[0], (struct user **)0)) - break; - if (msgok) - Msg(0, "%s removed from acl database", args[0]); - break; - } + if (UserDel(args[0], NULL)) + break; + if (msgok) + Msg(0, "%s removed from acl database", args[0]); + break; case RC_ACLGRP: - { + { break; } case RC_MULTIUSER: @@ -2334,7 +2315,7 @@ int key; Msg(0, "using termcap entries for printing"); break; case RC_DIGRAPH: - Input("Enter digraph: ", 10, digraph_fn, INP_EVERY); + Input("Enter digraph: ", 10, INP_EVERY, digraph_fn, NULL); if (*args && **args) { s = *args; @@ -2462,6 +2443,15 @@ char **args; return ap; } +/* + * buf is split into argument vector args. + * leading whitespace is removed. + * @!| abbreviations are expanded. + * the end of buffer is recognized by '\0' or an un-escaped '#'. + * " and ' are interpreted. + * + * argc is returned. + */ int Parse(buf, args) char *buf, **args; @@ -2797,6 +2787,13 @@ char *bname; return 0; } +/* + * Interprets ^?, ^@ and other ^-control-char notation. + * Interprets \ddd octal notation + * + * The result is placed in *cp, p is advanced behind the parsed expression and + * returned. + */ static char * ParseChar(p, cp) char *p, *cp; @@ -3132,7 +3129,7 @@ ShowWindows() continue; cmd = p->w_title; - if (s - buf + strlen(cmd) > sizeof(buf) - 6) + if (s - buf + strlen(cmd) > sizeof(buf) - 24) break; if (s > buf) { @@ -3276,9 +3273,10 @@ ShowInfo() static void -AKAfin(buf, len) +AKAfin(buf, len, data) char *buf; int len; +char *data; /* dummy */ { ASSERT(display); if (len && fore) @@ -3288,28 +3286,24 @@ int len; static void InputAKA() { - Input("Set window's title to: ", 20, AKAfin, INP_COOKED); + Input("Set window's title to: ", 20, INP_COOKED, AKAfin, NULL); } static void -Colonfin(buf, len) +Colonfin(buf, len, data) char *buf; int len; +char *data; /* dummy */ { if (len) RcLine(buf); } static void -InputColon() -{ - Input(":", 100, Colonfin, INP_COOKED); -} - -static void -SelectFin(buf, len) +SelectFin(buf, len, data) char *buf; int len; +char *data; /* dummy */ { int n; @@ -3323,16 +3317,17 @@ int len; static void InputSelect() { - Input("Switch to window: ", 20, SelectFin, INP_COOKED); + Input("Switch to window: ", 20, INP_COOKED, SelectFin, NULL); } static char setenv_var[31]; static void -SetenvFin1(buf, len) +SetenvFin1(buf, len, data) char *buf; int len; +char *data; /* dummy */ { if (!len || !display) return; @@ -3340,9 +3335,10 @@ int len; } static void -SetenvFin2(buf, len) +SetenvFin2(buf, len, data) char *buf; int len; +char *data; /* dummy */ { struct action act; char *args[3]; @@ -3362,18 +3358,25 @@ static void InputSetenv(arg) char *arg; { - static char setenv_buf[80]; /* need to be static here, cannot be freed */ + static char setenv_buf[50 + sizeof(setenv_var)]; /* need to be static here, cannot be freed */ if (arg) { - strncpy(setenv_var, arg, 30); - sprintf(setenv_buf, "Enter value for %s: ", arg); - Input(setenv_buf, 30, SetenvFin2, INP_COOKED); + strncpy(setenv_var, arg, sizeof(setenv_var) - 1); + sprintf(setenv_buf, "Enter value for %s: ", setenv_var); + Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL); } else - Input("Setenv: Enter variable name: ", 30, SetenvFin1, INP_COOKED); + Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL); } +/* + * the following options are understood by this parser: + * -f, -f0, -f1, -fy, -fa + * -t title, -T terminal-type, -h height-of-scrollback, + * -ln, -l0, -ly, -l1, -l + * -a, -M, -L + */ void DoScreen(fn, av) char *fn, **av; @@ -3503,7 +3506,8 @@ char *fn, **av; */ int CompileKeys(s, array) -char *s, *array; +char *s; +unsigned char *array; { int i; unsigned char key, value; @@ -3541,11 +3545,12 @@ char *s, *array; * Asynchronous input functions */ -#ifdef POW_DETACH +#if defined(POW_DETACH) static void -pow_detach_fn(buf, len) +pow_detach_fn(buf, len, data) char *buf; int len; +char *data; /* dummy */ { if (len) { @@ -3568,9 +3573,10 @@ int len; #ifdef COPY_PASTE static void -copy_reg_fn(buf, len) +copy_reg_fn(buf, len, data) char *buf; int len; +char *data; /* dummy */ { struct plop *pp = plop_tab + (int)(unsigned char)*buf; @@ -3592,9 +3598,10 @@ int len; } static void -ins_reg_fn(buf, len) +ins_reg_fn(buf, len, data) char *buf; int len; +char *data; /* dummy */ { struct plop *pp = plop_tab + (int)(unsigned char)*buf; @@ -3627,9 +3634,10 @@ int len; #endif /* COPY_PASTE */ static void -process_fn(buf, len) +process_fn(buf, len, data) char *buf; int len; +char *data; /* dummy */ { struct plop *pp = plop_tab + (int)(unsigned char)*buf; @@ -3656,19 +3664,21 @@ int len; /* ARGSUSED */ static void -pass1(buf, len) +pass1(buf, len, data) char *buf; int len; +char *data; { strncpy(Password, buf, sizeof(Password) - 1); - Input("Retype new password:", sizeof(Password) - 1, pass2, 1); + Input("Retype new password:", sizeof(Password) - 1, INP_NOECHO, pass2, NULL); } /* ARGSUSED */ static void -pass2(buf, len) +pass2(buf, len, data) char *buf; int len; +char *data; { int st; char salt[2]; @@ -3717,9 +3727,10 @@ int len; #endif /* PASSWORD */ static void -digraph_fn(buf, len) +digraph_fn(buf, len, data) char *buf; int len; +char *data; /* dummy */ { int ch, i, x; @@ -3732,7 +3743,7 @@ int len; { if (ch < '0' || ch > '7') { - buf[len] = '\001'; /* ignore */ + buf[len] = '\034'; /* ^] is ignored by Input() */ return; } if (len == 3) @@ -3775,3 +3786,39 @@ int len; while(i) Process(&buf, &i); } + +#ifdef MAPKEYS +static int +StuffKey(i) +int i; +{ + struct action *act; + + debug1("StuffKey #%d", i); +#ifdef DEBUG + if (i < KMAP_KEYS) + debug1(" - %s", term[i + T_CAPS].tcname); +#endif + if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys) + i += T_OCAPS - T_CURSOR; + else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad) + i += T_OCAPS - T_CURSOR; + debug1(" - action %d\n", i); + fore = D_fore; + act = 0; +#ifdef COPY_PASTE + if (InMark() || InInput()) + act = &mmtab[i]; +#endif + if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault) + act = &umtab[i]; + D_mapdefault = 0; + if (!act || act->nr == RC_ILLEGAL) + act = &dmtab[i]; + if (act == 0 || act->nr == RC_ILLEGAL) + return -1; + DoAction(act, 0); + return 0; +} +#endif + @@ -106,7 +106,7 @@ extern int intrc; extern int use_hardstatus; #ifdef COPY_PASTE -extern char mark_key_tab[]; +extern unsigned char mark_key_tab[]; #endif extern char version[]; extern char DefaultShell[]; @@ -135,7 +135,7 @@ char *attach_term; char *LoginName; struct mode attach_Mode; -char SockPath[MAXPATHLEN]; +char SockPath[MAXPATHLEN + 2 * MAXSTR]; char *SockName, *SockMatch; /* SockName is pointer in SockPath */ int ServerSocket = -1; @@ -313,7 +313,7 @@ fd_set *rp, *wp; FD_SET(ServerSocket, rp); } -void +int main(ac, av) int ac; char **av; @@ -367,16 +367,7 @@ char **av; */ closeallfiles(0); #ifdef DEBUG - { - char buf[255]; - - sprintf(buf, "%s/screen.%d", DEBUGDIR, getpid()); - (void) mkdir(DEBUGDIR, 0777); - if ((dfp = fopen(buf, "w")) == NULL) - dfp = stderr; - else - (void) chmod(buf, 0666); - } + opendebug(1, 0); #endif sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS, PATCHLEVEL, STATE, ORIGIN, DATE); @@ -490,7 +481,7 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify an alternate rc-filename with -c", NULL); RcFileName = *++av; } break; @@ -500,11 +491,12 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify command escape characters with -e", NULL); ap = *++av; } if (ParseEscape((struct user *)0, ap)) - Panic(0, "Two characters are required with -e option."); + Panic(0, "Two characters are required with -e option, not '%s'", ap); + ap = NULL; break; case 'f': switch (ap[2]) @@ -522,7 +514,7 @@ char **av; nwin_options.flowflag = FLOW_AUTOFLAG; break; default: - exit_with_usage(myname); + exit_with_usage(myname, "Unknown flow option -%s", --ap); } break; case 'h': @@ -531,23 +523,23 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, NULL, NULL); nwin_options.histheight = atoi(*++av); } if (nwin_options.histheight < 0) - exit_with_usage(myname); + exit_with_usage(myname, "-h %s: negative scrollback size?",*av); break; case 'i': iflag = 1; break; - case 't': /* title is a synonym for AkA */ - case 'k': + case 't': + case 'k': /* obsolete */ if (ap[2]) nwin_options.aka = ap + 2; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify a new window-name with -t", NULL); nwin_options.aka = *++av; } break; @@ -573,7 +565,7 @@ char **av; } break; default: - exit_with_usage(myname); + exit_with_usage(myname, "%s: Unknown suboption to -l", ap); } break; case 'w': @@ -598,7 +590,7 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify terminal-type with -T", NULL); if (strlen(*++av) < 20) strcpy(screenterm, *av); } @@ -616,7 +608,7 @@ char **av; { SockMatch = ap + 2; if (ac != 1) - exit_with_usage(myname); + exit_with_usage(myname, "must have exact one parameter after %s", ap); } else if (ac > 1 && *av[1] != '-') { @@ -659,7 +651,7 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify shell with -s", NULL); if (ShellProg) free(ShellProg); ShellProg = SaveStr(*++av); @@ -672,22 +664,24 @@ char **av; else { if (--ac == 0) - exit_with_usage(myname); + exit_with_usage(myname, "Specify session-name with -S", NULL); SockMatch = *++av; if (!*SockMatch) - exit_with_usage(myname); + exit_with_usage(myname, "-S: Empty session-name?", NULL); } break; case 'v': Panic(0, "Screen version %s", version); /* NOTREACHED */ default: - exit_with_usage(myname); + exit_with_usage(myname, "Unknown option %s", ap); } } else break; } + if (SockMatch && strlen(SockMatch) >= MAXSTR) + Panic(0, "Ridiculously long socketname - try again."); if (dflag && mflag && SockMatch && !(rflag || xflag)) detached = 1; nwin = nwin_options; @@ -754,6 +748,8 @@ char **av; Panic(0, "Cannot identify account '%s'.", multi); multi_uid = mppp->pw_uid; multi_home = SaveStr(mppp->pw_dir); + if (strlen(multi_home) > MAXPATHLEN - 10) + Panic(0, "home directory path too long"); # ifdef MULTI if (rflag || lsflag) { @@ -842,6 +838,10 @@ pw_try_again: home = ppp->pw_dir; if (strlen(LoginName) > 20) Panic(0, "LoginName too long - sorry."); +#ifdef MULTIUSER + if (multi && strlen(multi) > 20) + Panic(0, "Screen owner name too long - sorry."); +#endif if (strlen(home) > MAXPATHLEN - 25) Panic(0, "$HOME too long - sorry."); @@ -866,7 +866,7 @@ pw_try_again: tty_mode = st.st_mode & 0777; #endif if ((n = secopen(attach_tty, O_RDWR, 0)) < 0) - Panic(0, "Cannot open '%s' - please check.", attach_tty); + Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty); close(n); debug1("attach_tty is %s\n", attach_tty); if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0) @@ -1001,7 +1001,7 @@ pw_try_again: if (lsflag) { - int i, fo; + int i, fo, oth; #ifdef MULTIUSER if (multi) @@ -1011,9 +1011,9 @@ pw_try_again: setgid(real_gid); eff_uid = real_uid; eff_gid = real_gid; - i = FindSocket((int *)NULL, &fo, SockMatch); + i = FindSocket((int *)NULL, &fo, &oth, SockMatch); if (quietflag) - exit(10 + i); + exit(8 + (fo ? ((oth || i) ? 2 : 1) : 0) + i); if (fo == 0) { #ifdef NETHACK @@ -1061,7 +1061,18 @@ pw_try_again: } } nwin_compose(&nwin_default, &nwin_options, &nwin_default); - switch (MasterPid = fork()) + + if (DefaultEsc == -1) + DefaultEsc = Ctrl('a'); + if (DefaultMetaEsc == -1) + DefaultMetaEsc = 'a'; + + if (!detached || dflag != 2) + MasterPid = fork(); + else + MasterPid = 0; + + switch (MasterPid) { case -1: Panic(errno, "fork"); @@ -1117,7 +1128,7 @@ pw_try_again: if (dfp && dfp != stderr) fclose(dfp); - sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, getpid()); + sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, (int)getpid()); if ((dfp = fopen(buf, "w")) == NULL) dfp = stderr; else @@ -1247,7 +1258,7 @@ pw_try_again: #endif FinishRc(RcFileName); - debug2("UID %d EUID %d\n", getuid(), geteuid()); + debug2("UID %d EUID %d\n", (int)getuid(), (int)geteuid()); if (windows == NULL) { debug("We open one default window, as screenrc did not specify one.\n"); @@ -1633,6 +1644,11 @@ pw_try_again: { if (errno == EINTR) continue; +#ifdef EAGAIN + /* IBM's select() doesn't always tell the truth */ + if (errno == EAGAIN) + continue; +#endif debug1("Read error: %d - SigHup()ing!\n", errno); SigHup(SIGARG); sleep(1); @@ -1829,14 +1845,20 @@ struct win *p; debug3("window %d (%s) going into zombie state fd %d", p->w_number, p->w_title, p->w_ptyfd); #ifdef UTMPOK - RemoveUtmp(p); + if (p->w_slot != (slot_t)0 && p->w_slot != (slot_t)-1) + { + RemoveUtmp(p); + p->w_slot = 0; /* "detached" */ + } #endif (void) chmod(p->w_tty, 0666); (void) chown(p->w_tty, 0, 0); close(p->w_ptyfd); p->w_ptyfd = -1; +#ifdef UTMPOK /* zap saved utmp as the slot may change */ bzero((char *)&p->w_savut, sizeof(p->w_savut)); +#endif p->w_pid = 0; ResetWindow(p); p->w_y = p->w_bot; @@ -1871,7 +1893,7 @@ SigChldHandler() debug1("'%s' reconstructed\n", SockPath); } else - debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode); + debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, (int)st.st_mode); } static sigret_t @@ -2180,7 +2202,7 @@ int mode; AddStr("[power detached]\r\n"); if (PowDetachString) { - AddStr(expand_vars(PowDetachString)); + AddStr(expand_vars(PowDetachString, display)); AddStr("\r\n"); } sign = SIG_POWER_BYE; @@ -2190,7 +2212,7 @@ int mode; AddStr("[remote power detached]\r\n"); if (PowDetachString) { - AddStr(expand_vars(PowDetachString)); + AddStr(expand_vars(PowDetachString, display)); AddStr("\r\n"); } sign = SIG_POWER_BYE; @@ -2340,10 +2362,10 @@ unsigned long p1, p2, p3, p4, p5, p6; # else /* __STDC__ */ va_start(ap); # endif /* __STDC__ */ - (void) vsprintf(p, fmt, ap); + (void) vsnprintf(p, sizeof(buf) - 100, fmt, ap); va_end(ap); #else /* USEVARARRGS */ - sprintf(p, fmt, p1, p2, p3, p4, p5, p6); + xsnprintf(p, sizeof(buf) - 100, fmt, p1, p2, p3, p4, p5, p6); #endif /* USEVARARRGS */ if (err) { @@ -2392,10 +2414,10 @@ unsigned long p1, p2, p3, p4, p5, p6; # else /* __STDC__ */ va_start(ap); # endif /* __STDC__ */ - (void) vsprintf(p, fmt, ap); + (void) vsnprintf(p, sizeof(buf) - 100, fmt, ap); va_end(ap); #else /* USEVARARRGS */ - sprintf(p, fmt, p1, p2, p3, p4, p5, p6); + xsnprintf(p, sizeof(buf) - 100, fmt, p1, p2, p3, p4, p5, p6); #endif /* USEVARARRGS */ if (err) { @@ -64,9 +64,9 @@ #ifndef NOASSERT # if defined(__STDC__) -# define ASSERT(lousy_cpp) {if (!(lousy_cpp)) {debug2("ASSERT("#lousy_cpp")ion failed file %s line %d\n", __FILE__, __LINE__);abort();}} +# define ASSERT(lousy_cpp) do {if (!(lousy_cpp)) {if (!dfp) opendebug(0, 1);debug2("ASSERT("#lousy_cpp") failed file %s line %d\n", __FILE__, __LINE__);abort();}} while (0) # else -# define ASSERT(lousy_cpp) {if (!(lousy_cpp)) {debug2("ASSERT(lousy_cpp)ion failed file %s line %d\n", __FILE__, __LINE__);abort();}} +# define ASSERT(lousy_cpp) do {if (!(lousy_cpp)) {if (!dfp) opendebug(0, 1);debug2("ASSERT(lousy_cpp) failed file %s line %d\n", __FILE__, __LINE__);abort();}} while (0) # endif #else # define ASSERT(lousy_cpp) {;} @@ -41,8 +41,8 @@ extern struct display *display; */ static int matchword __P((char *, int, int, int)); -static void searchend __P((char *, int)); -static void backsearchend __P((char *, int)); +static void searchend __P((char *, int, char *)); +static void backsearchend __P((char *, int, char *)); void Search(dir) @@ -53,20 +53,22 @@ int dir; { markdata = (struct markdata *)D_lay->l_data; if (markdata->isdir > 0) - searchend((char *)0, 0); + searchend(0, 0, NULL); else if (markdata->isdir < 0) - backsearchend((char *)0, 0); + backsearchend(0, 0, NULL); else Msg(0, "No previous pattern"); } else - Input((dir > 0 ? "/" : "?"), sizeof(markdata->isstr)-1, (dir > 0 ? searchend : backsearchend), INP_COOKED); + Input((dir > 0 ? "/" : "?"), sizeof(markdata->isstr)-1, INP_COOKED, + (dir > 0 ? searchend : backsearchend), NULL); } static void -searchend(buf, len) +searchend(buf, len, data) char *buf; int len; +char *data; /* dummy */ { int x = 0, sx, ex, y; struct markdata *markdata; @@ -92,9 +94,10 @@ int len; } static void -backsearchend(buf, len) +backsearchend(buf, len, data) char *buf; int len; +char *data; /* dummy */ { int sx, ex, x = -1, y; struct markdata *markdata; @@ -157,7 +160,7 @@ static char *isprompts[] = { static int is_redo __P((struct markdata *)); -static void is_process __P((char *, int)); +static void is_process __P((char *, int, char *)); static int is_bm __P((char *, int, int, int, int)); @@ -209,9 +212,10 @@ int l, p, end, dir; /*ARGSUSED*/ static void -is_process(p, n) +is_process(p, n, data) /* i-search */ char *p; int n; +char *data; /* dummy */ { int pos, x, y, dir; struct markdata *markdata; @@ -323,13 +327,15 @@ ISearch(dir) int dir; { struct markdata *markdata; + markdata = (struct markdata *)D_lay->l_data; markdata->isdir = markdata->isstartdir = dir; markdata->isstartpos = markdata->cx + markdata->cy * D_width; markdata->isistrl = markdata->isstrl = 0; if (W2D(markdata->cy) == STATLINE) revto_line(markdata->cx, markdata->cy, STATLINE > 0 ? STATLINE - 1 : 1); - Input(isprompts[dir + 1], sizeof(markdata->isstr) - 1, is_process, INP_RAW); + Input(isprompts[dir + 1], sizeof(markdata->isstr) - 1, INP_RAW, + is_process, NULL); GotoPos(markdata->cx, W2D(markdata->cy)); } @@ -93,19 +93,20 @@ extern char SockPath[]; * match: string to match socket name. * * The socket directory must be in SockPath! - * - * Returns: number of good sockets. + * The global variables LoginName, multi, rflag, xflag, dflag, quietflag, + * nethackflag, SockPath are used. * * The first good socket is stored in fdp and its name is * appended to SockPath. * If none exists or fdp is NULL SockPath is not changed. * + * Returns: number of good sockets. */ int -FindSocket(fdp, nfoundp, match) +FindSocket(fdp, nfoundp, notherp, match) int *fdp; -int *nfoundp; +int *nfoundp, *notherp; char *match; { DIR *dirp; @@ -115,9 +116,9 @@ char *match; int sdirlen; int matchlen = 0; char *name, *n; - int firsts = -1, s; + int firsts = -1, sockfd; char *firstn = 0; - int nfound = 0, ngood = 0, ndead = 0, nwipe = 0; + int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0; struct sent { struct sent *next; @@ -155,7 +156,7 @@ char *match; { name = dp->d_name; debug1("- %s\n", name); - if (*name == 0 || *name == '.') + if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR) continue; if (matchlen) { @@ -177,8 +178,15 @@ char *match; } sprintf(SockPath + sdirlen, "/%s", name); + debug1("stat %s\n", SockPath); + errno = 0; + debug2("uid = %d, gid = %d\n", (int)getuid(), (int)getgid()); + debug2("euid = %d, egid = %d\n", (int)geteuid(), (int)getegid()); if (stat(SockPath, &st)) - continue; + { + debug1("errno = %d\n", errno); + continue; + } #ifndef SOCK_NOT_IN_FS # ifdef NAMEDPIPE @@ -194,13 +202,25 @@ char *match; # endif #endif + debug2("st.st_uid = %d, real_uid = %d\n", (int)st.st_uid, real_uid); if (st.st_uid != real_uid) continue; mode = st.st_mode & 0777; debug1(" has mode 0%03o\n", mode); #ifdef MULTIUSER if (multi && ((mode & 0677) != 0601)) - continue; + { + debug(" is not a MULTI-USER session"); + if (strcmp(multi, LoginName)) + { + debug(" and we are in a foreign directory.\n"); + mode = -4; + } + else + { + debug(", but it is our own session.\n"); + } + } #endif debug(" store it.\n"); if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0) @@ -211,14 +231,16 @@ char *match; *slisttail = sent; slisttail = &sent->next; nfound++; - s = MakeClientSocket(0); + sockfd = MakeClientSocket(0); #ifdef USE_SETEUID /* MakeClientSocket sets ids back to eff */ xseteuid(real_uid); xsetegid(real_gid); #endif - if (s == -1) + if (sockfd == -1) { + debug2(" MakeClientSocket failed, unreachable? %d %d\n", + matchlen, wipeflag); sent->mode = -3; /* Unreachable - it is dead if we detect that it's local * or we specified a match @@ -239,37 +261,47 @@ char *match; } } } + npriv++; continue; } - /* Shall we connect ? */ + mode &= 0776; + /* Shall we connect ? */ + debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag); + debug2("xflag=%d, dflag=%d ?\n", xflag, dflag); - /* - * mode 600: socket is detached. - * mode 700: socket is attached. - * xflag implies rflag here. - * - * fail, when socket mode mode is not 600 or 700 - * fail, when we want to detach, but it already is. - * fail, when we only want to attach, but mode 700 and not xflag. - * fail, if none of dflag, rflag, xflag is set. - */ - if ((mode != 0700 && mode != 0600) || - (dflag && mode == 0600) || - (!dflag && rflag && mode == 0700 && !xflag) || - (!dflag && !rflag && !xflag)) + /* + * mode 600: socket is detached. + * mode 700: socket is attached. + * xflag implies rflag here. + * + * fail, when socket mode is not 600 or 700 + * fail, when we want to detach w/o reattach, but it already is detached. + * fail, when we only want to attach, but mode 700 and not xflag. + * fail, if none of dflag, rflag, xflag is set. + */ + if ((mode != 0700 && mode != 0600) || + (dflag && !rflag && mode == 0600) || + (!dflag && rflag && mode == 0700 && !xflag) || + (!dflag && !rflag && !xflag)) { - close(s); + close(sockfd); + debug(" no!\n"); + npriv++; /* a good socket that was not for us */ continue; } ngood++; if (fdp && firsts == -1) { - firsts = s; + firsts = sockfd; firstn = sent->name; + debug(" taken\n"); } else - close(s); + { + debug(" discarded.\n"); + close(sockfd); + } } (void)closedir(dirp); if (nfound && (lsflag || ngood != 1) && !quietflag) @@ -319,14 +351,16 @@ char *match; break; #endif case -1: - /* No trigraphs, please */ + /* No trigraphs here! */ printf("\t%s\t(Dead ?%c?)\n", sent->name, '?'); break; case -2: printf("\t%s\t(Removed)\n", sent->name); break; case -3: - printf("\t%s\t(Unreachable)\n", sent->name); + printf("\t%s\t(Remote or dead)\n", sent->name); + case -4: + printf("\t%s\t(Private)\n", sent->name); break; } } @@ -371,6 +405,8 @@ char *match; xseteuid(eff_uid); xsetegid(eff_gid); #endif + if (notherp) + *notherp = npriv; if (nfoundp) *nfoundp = nfound - nwipe; return ngood; @@ -477,7 +513,8 @@ MakeServerSocket() if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) Panic(errno, "socket"); a.sun_family = AF_UNIX; - strcpy(a.sun_path, SockPath); + strncpy(a.sun_path, SockPath, sizeof(a.sun_path)); + a.sun_path[sizeof(a.sun_path) - 1] = 0; # ifdef USE_SETEUID xseteuid(real_uid); xsetegid(real_gid); @@ -549,7 +586,8 @@ int err; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) Panic(errno, "socket"); a.sun_family = AF_UNIX; - strcpy(a.sun_path, SockPath); + strncpy(a.sun_path, SockPath, sizeof(a.sun_path)); + a.sun_path[sizeof(a.sun_path) - 1] = 0; # ifdef USE_SETEUID xseteuid(real_uid); xsetegid(real_gid); @@ -601,25 +639,28 @@ struct NewWindow *nwin; if (strlen(sty) > NAME_MAX) sty[NAME_MAX] = 0; #endif + if (strlen(sty) > 2 * MAXSTR - 1) + sty[2 * MAXSTR - 1] = 0; sprintf(SockPath + strlen(SockPath), "/%s", sty); if ((s = MakeClientSocket(1)) == -1) exit(1); debug1("SendCreateMsg() to '%s'\n", SockPath); bzero((char *)&m, sizeof(m)); m.type = MSG_CREATE; - strcpy(m.m_tty, attach_tty); + strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); + m.m_tty[sizeof(m.m_tty) - 1] = 0; p = m.m.create.line; n = 0; if (nwin->args != nwin_undef.args) for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n) { len = strlen(*av) + 1; - if (p + len >= m.m.create.line + MAXPATHLEN - 1) + if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1) break; strcpy(p, *av); p += len; } - if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + MAXPATHLEN) + if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line)) strcpy(p, nwin->aka); else *p = '\0'; @@ -670,17 +711,18 @@ unsigned long p1, p2, p3, p4, p5, p6; # else /* __STDC__ */ va_start(ap); # endif /* __STDC__ */ - (void) vsprintf(m.m.message, fmt, ap); + (void) vsnprintf(m.m.message, sizeof(m.m.message), fmt, ap); va_end(ap); #else /* USEVARARGS */ - sprintf(m.m.message, fmt, p1, p2, p3, p4, p5, p6); + xsnprintf(m.m.message, sizeof(m.m.message), fmt, p1, p2, p3, p4, p5, p6); #endif /* USEVARARGS */ debug1("SendErrorMsg: '%s'\n", m.m.message); if (display == 0) return; s = MakeClientSocket(0); m.type = MSG_ERROR; - strcpy(m.m_tty, D_usertty); + strncpy(m.m_tty, D_usertty, sizeof(m.m_tty) - 1); + m.m_tty[sizeof(m.m_tty) - 1] = 0; debug1("SendErrorMsg(): writing to '%s'\n", SockPath); (void) write(s, (char *) &m, sizeof m); close(s); @@ -701,10 +743,10 @@ char *pwd, *utty; { # ifdef NETHACK if (nethackflag) - Msg(0, "'%s' tries to explode in the sky, but fails. (%s)", utty, pwd); + Msg(0, "'%s' tries to explode in the sky, but fails.", utty); else # endif /* NETHACK */ - Msg(0, "Illegal reattach attempt from terminal %s, \"%s\"", utty, pwd); + Msg(0, "Illegal reattach attempt from terminal %s.", utty); } debug1("CheckPass() wrong password kill(%d, SIG_PW_FAIL)\n", pid); Kill(pid, SIG_PW_FAIL); @@ -882,6 +924,7 @@ ReceiveMsg() if (TTYCMP(D_usertty, m.m_tty) == 0) break; debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not "); + wi = 0; if (!display) { for (wi = windows; wi; wi = wi->w_next) @@ -946,12 +989,12 @@ ReceiveMsg() Kill(m.m.attach.apid, SIGCONT); # endif #endif /* PASSWORD */ - if (display) + if (display || wi) { - write(i, "Attaching to a not detached screen?\n", 36); + write(i, "Attaching from inside of screen?\n", 33); close(i); Kill(m.m.attach.apid, SIG_BYE); - Msg(0, "Attach msg ignored: We are not detached."); + Msg(0, "Attach msg ignored: coming from inside."); break; } @@ -1045,15 +1088,24 @@ ReceiveMsg() RemoveLoginSlot(); if (displays->d_next == 0) for (wi = windows; wi; wi = wi->w_next) - if (wi->w_slot != (slot_t) -1) + if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1) SetUtmp(wi); #endif SetMode(&D_OldMode, &D_NewMode); SetTTY(D_userfd, &D_NewMode); D_fore = NULL; + /* there may be a window that we remember from last detach: */ if (D_user->u_detachwin >= 0) fore = wtab[D_user->u_detachwin]; + /* Wayne wants us to restore the other window too. */ + if (D_user->u_detachotherwin >= 0) + D_other = wtab[D_user->u_detachotherwin]; + /* + * We want a window to start with. + * It is the window we left from, which is not occupied and + * grants us full read/write permissions. + */ #ifdef MULTIUSER if (!fore || fore->w_display || AclCheckPermWin(D_user, ACL_WRITE, fore)) #else @@ -1092,7 +1144,8 @@ ReceiveMsg() Msg(0, "%s", m.m.message); break; case MSG_HANGUP: - SigHup(SIGARG); + if (!wi) /* ignore hangups from inside */ + SigHup(SIGARG); break; #ifdef REMOTE_DETACH case MSG_DETACH: @@ -1160,7 +1213,7 @@ chsock() * may be happy to remove old files. We manually prevent the socket * from becoming old. (chmod does not touch mtime). */ - (void)utime(SockPath, NULL); + (void)utimes(SockPath, NULL); if (euid != real_uid) UserReturn(r); @@ -1,14 +1,5 @@ -Zhang has developed a patch to the "screen" VT100 terminal emulation program -that allows one to perform tektronics "tek40xx" style graphics in a -screen window. I've tested it with gnuplot and it works quite well. - -Send flames or technical inquries to the patch author Xiaoguang -Zhang (zhang@gmsds.ms.ornl.gov) and to screen@uni-erlangen.de - -===================================================================== - -*** ./ansi.h.orig Fri Jan 2 19:12:05 1970 ---- ./ansi.h Wed Nov 15 19:25:11 1995 +*** ./ansi.h.orig Tue Jan 9 19:16:35 1996 +--- ./ansi.h Sat Jun 14 22:38:37 1997 *************** *** 56,62 **** PRIN, /* Printer mode */ @@ -29,11 +20,11 @@ Zhang (zhang@gmsds.ms.ornl.gov) and to screen@uni-erlangen.de }; enum string_t -*** ./ansi.c.orig Sun Oct 29 16:01:26 1995 ---- ./ansi.c Wed Nov 15 19:25:11 1995 +*** ./ansi.c.orig Thu May 1 17:33:31 1997 +--- ./ansi.c Sat Jun 14 22:38:37 1997 *************** -*** 805,810 **** ---- 805,815 ---- +*** 813,818 **** +--- 813,823 ---- case 'k': StartString(AKA); break; @@ -46,8 +37,8 @@ Zhang (zhang@gmsds.ms.ornl.gov) and to screen@uni-erlangen.de if (Special(c)) { *************** -*** 868,873 **** ---- 873,899 ---- +*** 876,881 **** +--- 881,907 ---- goto tryagain; } } @@ -75,5 +66,3 @@ Zhang (zhang@gmsds.ms.ornl.gov) and to screen@uni-erlangen.de break; case LIT: default: - -===================================================================== @@ -184,8 +184,18 @@ struct term term[T_N] = { "k;", T_STR }, KMAPDEF("\033[21~") { "F1", T_STR }, KMAPDEF("\033[23~") { "F2", T_STR }, KMAPDEF("\033[24~") + /* extra keys for vt220 (David.Leonard@it.uq.edu.au) */ + { "F3", T_STR }, + { "F4", T_STR }, + { "F5", T_STR }, + { "F6", T_STR }, + { "F7", T_STR }, + { "F8", T_STR }, + { "F9", T_STR }, + { "FA", T_STR }, + { "kb", T_STR }, KMAPDEF("\010") - { "kh", T_STR }, KMAPDEF("\033[1~") KMAPMDEF("g") + { "kh", T_STR }, KMAPDEF("\033[1~") KMAPMDEF("\201") { "K1", T_STR }, { "K2", T_STR }, { "K3", T_STR }, @@ -199,7 +209,7 @@ struct term term[T_N] = { "kD", T_STR }, KMAPDEF("\033[3~") { "kE", T_STR }, { "kF", T_STR }, KMAPMDEF("\004") - { "kH", T_STR }, KMAPDEF("\033[4~") KMAPMDEF("G") + { "kH", T_STR }, KMAPDEF("\033[4~") KMAPMDEF("\205") { "kI", T_STR }, KMAPDEF("\033[2~") { "kL", T_STR }, { "kM", T_STR }, @@ -213,10 +223,10 @@ struct term term[T_N] = { "@7", T_STR }, /* keys that can have two bindings */ /* define T_CURSOR */ - { "ku", T_STR }, KMAPDEF("\033[A") KMAPADEF("\033OA") KMAPMDEF("k") - { "kd", T_STR }, KMAPDEF("\033[B") KMAPADEF("\033OB") KMAPMDEF("j") - { "kr", T_STR }, KMAPDEF("\033[C") KMAPADEF("\033OC") KMAPMDEF("l") - { "kl", T_STR }, KMAPDEF("\033[D") KMAPADEF("\033OD") KMAPMDEF("h") + { "ku", T_STR }, KMAPDEF("\033[A") KMAPADEF("\033OA") KMAPMDEF("\220") + { "kd", T_STR }, KMAPDEF("\033[B") KMAPADEF("\033OB") KMAPMDEF("\216") + { "kr", T_STR }, KMAPDEF("\033[C") KMAPADEF("\033OC") KMAPMDEF("\206") + { "kl", T_STR }, KMAPDEF("\033[D") KMAPADEF("\033OD") KMAPMDEF("\202") /* define T_KEYPAD */ { "f0", T_STR }, KMAPDEF("0") KMAPADEF("\033Op") { "f1", T_STR }, KMAPDEF("1") KMAPADEF("\033Oq") diff --git a/term.h.dist b/term.h.dist index 73f021d..7dd41b8 100644 --- a/term.h.dist +++ b/term.h.dist @@ -221,17 +221,17 @@ union tcu #define d_CXC d_tcs[99].str #define D_CXC (D_tcs[99].str) #define T_CAPS 100 -#define T_CURSOR 139 -#define T_KEYPAD 143 -#define T_OCAPS 161 -#define T_ECAPS 174 -#define T_N 174 +#define T_CURSOR 147 +#define T_KEYPAD 151 +#define T_OCAPS 169 +#define T_ECAPS 182 +#define T_N 182 #ifdef MAPKEYS # define KMAPDEFSTART 100 -# define NKMAPDEF 61 -# define KMAPADEFSTART 139 +# define NKMAPDEF 69 +# define KMAPADEFSTART 147 # define NKMAPADEF 22 -# define KMAPMDEFSTART 114 +# define KMAPMDEFSTART 122 # define NKMAPMDEF 29 #endif @@ -677,21 +677,21 @@ int aflag; if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE) { sprintf(Termcap, "TERMCAP=%s", s); - sprintf(Term, "TERM=screen"); + strcpy(Term, "TERM=screen"); debug("getenvSCREENCAP o.k.\n"); return Termcap; } Termcaplen = 0; debug1("MakeTermcap screenterm='%s'\n", screenterm); debug1("MakeTermcap termname='%s'\n", tname); - if (*screenterm == '\0') + if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3) { debug("MakeTermcap sets screenterm=screen\n"); strcpy(screenterm, "screen"); } do { - sprintf(Term, "TERM="); + strcpy(Term, "TERM="); p = Term + 5; if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1) { @@ -705,10 +705,10 @@ int aflag; if (tgetent(buf, p) == 1) break; } - sprintf(p, "%s", screenterm); + strcpy(p, screenterm); if (tgetent(buf, p) == 1) break; - sprintf(p, "vt100"); + strcpy(p, "vt100"); } while (0); /* Goto free programming... */ @@ -726,6 +726,8 @@ int aflag; } tcLineLen = 100; /* Force NL */ + if (strlen(Term) > TERMCAP_BUFSIZE - 40) + strcpy(Term, "too_long"); sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal", Term + 5); Termcaplen = strlen(Termcap); @@ -928,7 +930,7 @@ char *s; *p++ = 'E'; break; case ':': - sprintf(p, "\\072"); + strcpy(p, "\\072"); p += 4; break; case '^': @@ -1243,7 +1245,7 @@ char *cap; bufp = buf; if ((tep = findcap(cap, &bufp, 2))) return (*tep == '@') ? 0 : 1; - return tgetflag(cap); + return tgetflag(cap) > 0; } static int @@ -107,8 +107,9 @@ char *line; */ #ifdef TIOCEXCL errno = 0; - ioctl(f, TIOCEXCL, (char *) 0); - debug3("%d %d %d\n", getuid(), geteuid(), getpid()); + if (ioctl(f, TIOCEXCL, (char *) 0) < 0) + Msg(errno, "%s: ioctl TIOCEXCL failed", line); + debug3("%d %d %d\n", (int)getuid(), (int)geteuid(), (int)getpid()); debug2("%s TIOCEXCL errno %d\n", line, errno); #endif /* TIOCEXCL */ /* @@ -124,8 +124,9 @@ char *line; */ #ifdef TIOCEXCL errno = 0; - ioctl(f, TIOCEXCL, (char *) 0); - debug3("%d %d %d\n", getuid(), geteuid(), getpid()); + if (ioctl(f, TIOCEXCL, (char *) 0) < 0) + Msg(errno, "%s: ioctl TIOCEXCL failed", line); + debug3("%d %d %d\n", (int)getuid(), (int)geteuid(), (int)getpid()); debug2("%s TIOCEXCL errno %d\n", line, errno); #endif /* TIOCEXCL */ /* @@ -279,7 +279,14 @@ RemoveLoginSlot() if (ut_delete_user(D_loginslot, uu->ut_pid, 0, 0) == 0) # else /* _SEQUENT_ */ u = *uu; + /* + * Ed Hill (ed-hill@uiowa.edu) screen-3.5.2 under AIX 3.2.5 + * when you are down to a single screen, and you log out of it (thus exiting + * screen), it leaves a stray entry in the utmp file. Seems better: + * u.ut_type = EMPTY; + */ u.ut_type = DEAD_PROCESS; + u.ut_user[0] = '\0'; /* for Digital UNIX 3.2C, kilbi@rad.rwth-aachen.de */ u.ut_exit.e_termination = 0; u.ut_exit.e_exit= 0; if (pututline(&u) == 0) @@ -121,6 +121,9 @@ struct NewWindow *newwin; struct NewWindow nwin; int ttyflag; char *TtyName; +#ifdef MULTIUSER + extern struct user *users; +#endif debug1("NewWindow: StartAt %d\n", newwin->StartAt); debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL"); @@ -175,7 +178,12 @@ struct NewWindow *newwin; p->w_cmdargs[i] = 0; #ifdef MULTIUSER - if (NewWindowAcl(p)) + /* + * This is dangerous: without a display we use creators umask + * This is intended to be usefull for detached startup. + * But is still better than default bits with a NULL user. + */ + if (NewWindowAcl(p, display ? D_user : users)) { free((char *)p); close(f); @@ -324,16 +332,8 @@ struct win *p; } #ifdef UTMPOK - p->w_slot = (slot_t) -1; - debug1("RemakeWindow will %slog in.\n", lflag ? "" : "not "); -# ifdef LOGOUTOK - if (lflag) -# endif - { - p->w_slot = (slot_t) 0; - if (display) - SetUtmp(p); - } + if (display && p->w_slot == (slot_t)0) + SetUtmp(p); #endif return p->w_number; } @@ -488,6 +488,8 @@ struct win *win; args = ShellArgs; proc = *args; } + fflush(stdout); + fflush(stderr); switch (pid = fork()) { case -1: @@ -513,14 +515,14 @@ struct win *win; if (setuid(real_uid) || setgid(real_gid)) { SendErrorMsg("Setuid/gid: %s", strerror(errno)); - exit(1); + _exit(1); } eff_uid = real_uid; eff_gid = real_gid; if (dir && *dir && chdir(dir) == -1) { SendErrorMsg("Cannot chdir to %s: %s", dir, strerror(errno)); - exit(1); + _exit(1); } if (display) @@ -553,7 +555,7 @@ struct win *win; else (void) chmod(buf, 0666); } - debug1("=== ForkWindow: pid %d\n", getpid()); + debug1("=== ForkWindow: pid %d\n", (int)getpid()); #endif /* Close the three /dev/null descriptors */ close(0); @@ -576,7 +578,7 @@ struct win *win; if ((newfd = open(ttyn, O_RDWR)) < 0) { SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno)); - exit(1); + _exit(1); } } else @@ -602,7 +604,7 @@ struct win *win; if ((newfd = open(ttyn, O_RDWR)) != 0) { SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno)); - exit(1); + _exit(1); } dup(0); dup(0); @@ -619,17 +621,17 @@ struct win *win; if (ioctl(newfd, I_PUSH, "ptem")) { SendErrorMsg("Cannot I_PUSH ptem %s %s", ttyn, strerror(errno)); - exit(1); + _exit(1); } if (ioctl(newfd, I_PUSH, "ldterm")) { SendErrorMsg("Cannot I_PUSH ldterm %s %s", ttyn, strerror(errno)); - exit(1); + _exit(1); } if (ioctl(newfd, I_PUSH, "ttcompat")) { SendErrorMsg("Cannot I_PUSH ttcompat %s %s", ttyn, strerror(errno)); - exit(1); + _exit(1); } #endif if (fgtty(newfd)) @@ -687,8 +689,8 @@ struct win *win; NewEnv[2] = Termcap; #endif strcpy(shellbuf, "SHELL="); - strncpy(shellbuf + 6, ShellProg, MAXPATHLEN); - shellbuf[MAXPATHLEN + 6] = 0; + strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7); + shellbuf[sizeof(shellbuf) - 1] = 0; NewEnv[4] = shellbuf; debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf); if (term && *term && strcmp(screenterm, term) && @@ -723,7 +725,7 @@ struct win *win; execvpe(proc, args, NewEnv); debug1("exec error: %d\n", errno); SendErrorMsg("Cannot exec '%s': %s", proc, strerror(errno)); - exit(1); + _exit(1); default: break; } @@ -749,11 +751,13 @@ char *prog, **args, **env; path = DefaultPath; do { - p = buf; - while (*path && *path != ':') - *p++ = *path++; + for (p = buf; *path && *path != ':'; path++) + if (p - buf < sizeof(buf) - 2) + *p++ = *path; if (p > buf) *p++ = '/'; + if (p - buf + strlen(prog) >= sizeof(buf) - 1) + continue; strcpy(p, prog); execve(buf, args, env); switch (errno) @@ -984,6 +988,8 @@ char **av; SetMode(&D_OldMode, &D_NewMode); SetTTY(f, &D_NewMode); + fflush(stdout); + fflush(stderr); switch (fork()) { case -1: @@ -998,7 +1004,7 @@ char **av; if (setuid(real_uid) || setgid(real_gid)) { SendErrorMsg("Setuid/gid: %s", strerror(errno)); - exit(1); + _exit(1); } eff_uid = real_uid; eff_gid = real_gid; @@ -1016,7 +1022,7 @@ char **av; else (void) chmod(buf, 0666); } - debug1("=== Clone: pid %d\n", getpid()); + debug1("=== Clone: pid %d\n", (int)getpid()); #endif for (avp = av; *avp; avp++) { @@ -1025,7 +1031,7 @@ char **av; if (strcmp(*avp, "%X") == 0) *avp = specialbuf; } - sprintf(specialbuf, "-SXX1"); + strcpy(specialbuf, "-SXX1"); namep += strlen(namep); specialbuf[3] = *--namep; specialbuf[2] = *--namep; @@ -1037,7 +1043,7 @@ char **av; #endif execvpe(*av, av, environ); SendErrorMsg("Cannot exec '%s': %s", *av, strerror(errno)); - exit(1); + _exit(1); default: break; } @@ -200,6 +200,8 @@ struct win struct user *w_wlockuser; /* NULL when unlocked or user who writes */ #ifdef MULTIUSER AclBits w_userbits[ACL_BITS_PER_WIN]; + AclBits w_lio_notify; /* whom to tell when lastio+seconds < time() */ + AclBits w_mon_notify; /* whom to tell monitor statis */ #endif }; |