diff options
author | Sadrul Habib Chowdhury <sadrul@users.sourceforge.net> | 2010-02-16 11:37:14 -0500 |
---|---|---|
committer | Sadrul Habib Chowdhury <sadrul@users.sourceforge.net> | 2010-02-16 11:37:14 -0500 |
commit | 5275b7c42a4eb590249b1fca47ce184fe2ba69f9 (patch) | |
tree | 9caa1b77e863fe2b314ba34fbf4a4befd5b95b3f | |
parent | 97059b7ad521cf796daee07397c658d9716dd1e7 (diff) | |
parent | 2f39e64a76b2db7ce5ae88b6c087b8e60a47ce06 (diff) | |
download | screen-5275b7c42a4eb590249b1fca47ce184fe2ba69f9.tar.gz |
Merge branch 'query-result'
-rw-r--r-- | src/attacher.c | 78 | ||||
-rw-r--r-- | src/comm.c | 14 | ||||
-rw-r--r-- | src/comm.sh | 2 | ||||
-rw-r--r-- | src/doc/screen.1 | 17 | ||||
-rw-r--r-- | src/doc/screen.texinfo | 16 | ||||
-rw-r--r-- | src/extern.h | 2 | ||||
-rw-r--r-- | src/process.c | 45 | ||||
-rw-r--r-- | src/screen.c | 10 | ||||
-rw-r--r-- | src/screen.h | 3 | ||||
-rw-r--r-- | src/socket.c | 54 |
10 files changed, 218 insertions, 23 deletions
diff --git a/src/attacher.c b/src/attacher.c index 1bba70f..ef3ce8b 100644 --- a/src/attacher.c +++ b/src/attacher.c @@ -83,6 +83,21 @@ AttachSigCont SIGDEFARG SIGRETURN; } +static int QueryResult; + +static sigret_t +QueryResultSuccess SIGDEFARG +{ + QueryResult = 1; + SIGRETURN; +} + +static sigret_t +QueryResultFail SIGDEFARG +{ + QueryResult = 2; + SIGRETURN; +} /* * Send message to a screen backend. @@ -923,10 +938,11 @@ screen_builtin_lck() void -SendCmdMessage(sty, match, av) +SendCmdMessage(sty, match, av, query) char *sty; char *match; char **av; +int query; { int i, s; struct msg m; @@ -954,7 +970,7 @@ char **av; exit(1); } bzero((char *)&m, sizeof(m)); - m.type = MSG_COMMAND; + m.type = query ? MSG_QUERY : MSG_COMMAND; if (attach_tty) { strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); @@ -979,7 +995,59 @@ char **av; m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0; m.m.command.apid = getpid(); debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd); - if (WriteMessage(s, &m)) - Msg(errno, "write"); - close(s); + if (query) + { + /* Create a server socket so we can get back the result */ + char *sp = SockPath + strlen(SockPath); + char query[] = "-queryX"; + char c; + int r = -1; + for (c = 'A'; c <= 'Z'; c++) + { + query[6] = c; + strcpy(sp, query); /* XXX: strncpy? */ + if ((r = MakeServerSocket()) >= 0) + break; + } + if (r < 0) + { + for (c = '0'; c <= '9'; c++) + { + query[6] = c; + strcpy(sp, query); + if ((r = MakeServerSocket()) >= 0) + break; + } + } + + if (r < 0) + Panic(0, "Could not create a listening socket to read the results."); + + strncpy(m.m.command.writeback, SockPath, sizeof(m.m.command.writeback) - 1); + m.m.command.writeback[sizeof(m.m.command.writeback) - 1] = '\0'; + + /* Send the message, then wait for a response */ + signal(SIGCONT, QueryResultSuccess); + signal(SIG_BYE, QueryResultFail); + if (WriteMessage(s, &m)) + Msg(errno, "write"); + close(s); + while (!QueryResult) + pause(); + signal(SIGCONT, SIG_DFL); + signal(SIG_BYE, SIG_DFL); + + /* Read the result and spit it out to stdout */ + ReceiveRaw(r); + unlink(SockPath); + if (QueryResult == 2) /* An error happened */ + exit(1); + } + else + { + if (WriteMessage(s, &m)) + Msg(errno, "write"); + close(s); + } } + @@ -180,7 +180,7 @@ struct comm comms[RC_LAST + 1] = { "dinfo", NEED_DISPLAY|ARGS_0 }, { "displays", NEED_LAYER|ARGS_0 }, { "dumptermcap", NEED_FORE|ARGS_0 }, - { "echo", ARGS_12 }, + { "echo", CAN_QUERY|ARGS_12 }, #ifdef ENCODINGS { "encoding", ARGS_12 }, #endif @@ -207,12 +207,12 @@ struct comm comms[RC_LAST + 1] = { "hstatus", NEED_FORE|ARGS_1 }, { "idle", ARGS_0|ARGS_ORMORE }, { "ignorecase", ARGS_01 }, - { "info", NEED_LAYER|ARGS_0 }, + { "info", CAN_QUERY|NEED_LAYER|ARGS_0 }, #ifdef ENCODINGS { "kanji", NEED_FORE|ARGS_12 }, #endif { "kill", NEED_FORE|ARGS_0 }, - { "lastmsg", NEED_DISPLAY|ARGS_0 }, + { "lastmsg", CAN_QUERY|NEED_DISPLAY|ARGS_0 }, { "layout", ARGS_1|ARGS_ORMORE}, { "license", NEED_LAYER|ARGS_0 }, #ifdef LOCK @@ -286,7 +286,7 @@ struct comm comms[RC_LAST + 1] = #ifdef COPY_PASTE { "scrollback", NEED_FORE|ARGS_1 }, #endif - { "select", ARGS_01 }, + { "select", CAN_QUERY|ARGS_01 }, { "sessionname", ARGS_01 }, { "setenv", ARGS_012 }, { "setsid", ARGS_1 }, @@ -311,8 +311,8 @@ struct comm comms[RC_LAST + 1] = { "termcap", ARGS_23 }, { "termcapinfo", ARGS_23 }, { "terminfo", ARGS_23 }, - { "time", ARGS_01 }, - { "title", NEED_FORE|ARGS_01 }, + { "time", CAN_QUERY|ARGS_01 }, + { "title", CAN_QUERY|NEED_FORE|ARGS_01 }, { "umask", ARGS_1|ARGS_ORMORE }, { "unbindall", ARGS_0 }, { "unsetenv", ARGS_1 }, @@ -327,7 +327,7 @@ struct comm comms[RC_LAST + 1] = { "wall", NEED_DISPLAY|ARGS_1}, { "width", ARGS_0123 }, { "windowlist", ARGS_012 }, - { "windows", NEED_DISPLAY|ARGS_0 }, + { "windows", CAN_QUERY|ARGS_0 }, { "wrap", NEED_FORE|ARGS_01 }, #ifdef COPY_PASTE { "writebuf", ARGS_0123 }, diff --git a/src/comm.sh b/src/comm.sh index a4b06e7..4fc8cb2 100644 --- a/src/comm.sh +++ b/src/comm.sh @@ -43,6 +43,8 @@ struct comm #define NEED_FORE (1<<6) /* this command needs a fore window */ #define NEED_DISPLAY (1<<7) /* this command needs a display */ #define NEED_LAYER (1<<8) /* this command needs a layer */ +#define CAN_QUERY (1<<9) /* this command can be queried, i.e. used with -Q to + get back a result to stdout */ #define ARGS_01 (ARGS_0 | ARGS_PLUS1) #define ARGS_02 (ARGS_0 | ARGS_PLUS2) diff --git a/src/doc/screen.1 b/src/doc/screen.1 index 3ac5571..c26bbc8 100644 --- a/src/doc/screen.1 +++ b/src/doc/screen.1 @@ -305,6 +305,22 @@ there is no session to resume. 12 (or more) indicates that there are 2 (or more) sessions to resume and you should specify which one to choose. In all other cases \*Q-q\*U has no effect. .TP 5 +.B \-Q +Some commands now can be queried from a remote session using this +flag, e.g. 'screen -Q windows'. The commands will send the +response to the stdout of the querying process. If there was an +error in the command, then the querying process will exit with +a non-zero status. + +The commands that can be queried now are: + \fBecho\fP + \fBinfo\fP + \fBlastmsg\fP + \fBselect\fP + \fBtime\fP + \fBtitle\fP + \fBwindows\fP +.TP 5 .BR \-r " [" \fIpid.tty.host ] .PD 0 .TP 5 @@ -376,7 +392,6 @@ the \fB-d\fP or \fB-r\fP option to tell screen to look only for attached or detached screen sessions. Note that this command doesn't work if the session is password protected. - .SH "DEFAULT KEY BINDINGS" .ta 12n 26n As mentioned, each diff --git a/src/doc/screen.texinfo b/src/doc/screen.texinfo index 44d233e..f7371e1 100644 --- a/src/doc/screen.texinfo +++ b/src/doc/screen.texinfo @@ -374,6 +374,22 @@ there is no session to resume. 12 (or more) indicates that there are 2 (or more) sessions to resume and you should specify which one to choose. In all other cases @samp{-q} has no effect. +@item -Q +Some commands now can be queried from a remote session using this +flag, e.g. 'screen -Q windows'. The commands will send the +response to the stdout of the querying process. If there was an +error in the command, then the querying process will exit with +a non-zero status. + +The commands that can be queried now are: + @code{echo} + @code{info} + @code{lastmsg} + @code{select} + @code{time} + @code{title} + @code{windows} + @item -r [@var{pid.sessionname}] @itemx -r @var{sessionowner}/[@var{pid.sessionname}] Resume a detached @code{screen} session. No other options (except diff --git a/src/extern.h b/src/extern.h index 38a8d6e..dc5857e 100644 --- a/src/extern.h +++ b/src/extern.h @@ -241,7 +241,7 @@ extern void FreeTransTable __P((void)); extern int Attach __P((int)); extern void Attacher __P((void)); extern sigret_t AttacherFinit __P(SIGPROTOARG); -extern void SendCmdMessage __P((char *, char *, char **)); +extern void SendCmdMessage __P((char *, char *, char **, int)); /* display.c */ extern struct display *MakeDisplay __P((char *, char *, char *, int, int, struct mode *)); diff --git a/src/process.c b/src/process.c index 128b0e2..34ed63d 100644 --- a/src/process.c +++ b/src/process.c @@ -59,6 +59,7 @@ extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[]; extern char *hstatusstring, *captionstring, *timestring; extern char *wliststr, *wlisttit; extern int captionalways; +extern int queryflag; extern char *hardcopydir, *screenlogfile, *logtstamp_string; extern int log_flush, logtstamp_on, logtstamp_after; extern char *VisualBellString; @@ -1147,19 +1148,35 @@ int key; return; } n = comms[nr].flags; + /* Commands will have a CAN_QUERY flag, depending on whether they have + * something to return on a query. For example, 'windows' can return a result, + * but 'other' cannot. + * If some command causes an error, then it should reset queryflag to -1, so that + * the process requesting the query can be notified that an error happened. + */ + if (!(n & CAN_QUERY) && queryflag >= 0) + { + /* Query flag is set, but this command cannot be queried. */ + Msg(0, "%s command cannot be queried.", comms[nr].name); + queryflag = -1; + return; + } if ((n & NEED_DISPLAY) && display == 0) { Msg(0, "%s: %s: display required", rc_name, comms[nr].name); + queryflag = -1; return; } if ((n & NEED_FORE) && fore == 0) { Msg(0, "%s: %s: window required", rc_name, comms[nr].name); + queryflag = -1; return; } if ((n & NEED_LAYER) && flayer == 0) { Msg(0, "%s: %s: display or window required", rc_name, comms[nr].name); + queryflag = -1; return; } if ((argc = CheckArgNum(nr, args)) < 0) @@ -1171,6 +1188,7 @@ int key; { Msg(0, "%s: %s: permission denied (user %s)", rc_name, comms[nr].name, (EffectiveAclUser ? EffectiveAclUser : D_user)->u_name); + queryflag = -1; return; } } @@ -1190,7 +1208,10 @@ int key; else if (args[0][0] == '.' && !args[0][1]) { if (!fore) - Msg(0, "select . needs a window"); + { + Msg(0, "select . needs a window"); + queryflag = -1; + } else { SetForeWindow(fore); @@ -1199,6 +1220,8 @@ int key; } else if (ParseWinNum(act, &n) == 0) SwitchWindow(n); + else if (queryflag >= 0) + queryflag = -1; /* ParseWinNum already prints out an appropriate error message. */ break; #ifdef AUTO_NUKE case RC_DEFAUTONUKE: @@ -2026,6 +2049,13 @@ int key; } break; case RC_TITLE: + if (queryflag >= 0) + { + if (fore) + Msg(0, "%s", fore->w_title); + else + queryflag = -1; + } if (*args == 0) InputAKA(); else @@ -2635,7 +2665,10 @@ int key; if (s) Msg(0, "%s", s); else - Msg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name); + { + Msg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name); + queryflag = -1; + } break; case RC_BELL: case RC_BELL_MSG: @@ -5318,7 +5351,7 @@ int where; continue; if ((flags & 1) && display && p == D_fore) continue; - if (D_fore && D_fore->w_group != p->w_group) + if (display && D_fore && D_fore->w_group != p->w_group) continue; cmd = p->w_title; @@ -5460,13 +5493,11 @@ int where; char buf[1024]; char *s, *ss; - if (!display) - return; - if (where == -1 && D_fore) + if (display && where == -1 && D_fore) where = D_fore->w_number; ss = AddWindows(buf, sizeof(buf), 0, where); s = buf + strlen(buf); - if (ss - buf > D_width / 2) + if (display && ss - buf > D_width / 2) { ss -= D_width / 2; if (s - ss < D_width) diff --git a/src/screen.c b/src/screen.c index 92b2001..67cddbc 100644 --- a/src/screen.c +++ b/src/screen.c @@ -207,6 +207,7 @@ char *wlisttit; int auto_detach = 1; int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag; int cmdflag; +int queryflag = -1; int adaptflag; #ifdef MULTIUSER @@ -680,6 +681,10 @@ char **av; case 'q': quietflag = 1; break; + case 'Q': + queryflag = 1; + cmdflag = 1; + break; case 'r': case 'R': #ifdef MULTI @@ -1176,7 +1181,7 @@ char **av; if (!*av) Panic(0, "Please specify a command."); SET_GUID(); - SendCmdMessage(sty, SockMatch, av); + SendCmdMessage(sty, SockMatch, av, queryflag >= 0); exit(0); } else if (rflag || xflag) @@ -2105,6 +2110,9 @@ VA_DECL } else printf("%s\r\n", buf); + + if (queryflag >= 0) + write(queryflag, buf, strlen(buf)); } /* diff --git a/src/screen.h b/src/screen.h index a151e38..fa4cc82 100644 --- a/src/screen.h +++ b/src/screen.h @@ -173,6 +173,7 @@ struct mode #define MSG_WINCH 6 #define MSG_HANGUP 7 #define MSG_COMMAND 8 +#define MSG_QUERY 9 /* * versions of struct msg: @@ -227,6 +228,8 @@ struct msg char cmd[MAXPATHLEN]; /* command */ int apid; /* pid of frontend */ char preselect[20]; + char writeback[MAXPATHLEN]; /* The socket to write the result. + Only used for MSG_QUERY */ } command; char message[MAXPATHLEN * 2]; diff --git a/src/socket.c b/src/socket.c index a174b72..70b57db 100644 --- a/src/socket.c +++ b/src/socket.c @@ -65,6 +65,7 @@ static void AskPassword __P((struct msg *)); extern char *RcFileName, *extra_incap, *extra_outcap; extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid; extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag; +extern int queryflag; extern char *attach_tty, *LoginName, HostName[]; extern struct display *display, *displays; extern struct win *fore, **wtab, *console_window, *windows; @@ -1170,6 +1171,26 @@ ReceiveMsg() FinishDetach(&m); break; #endif + case MSG_QUERY: + { + char *oldSockPath = SaveStr(SockPath); + strcpy(SockPath, m.m.command.writeback); + int s = MakeClientSocket(0); + strcpy(SockPath, oldSockPath); + Free(oldSockPath); + if (s >= 0) + { + queryflag = s; + DoCommandMsg(&m); + close(s); + } + else + queryflag = -1; + + Kill(m.m.command.apid, (queryflag >= 0) ? SIGCONT : SIG_BYE); /* Send SIG_BYE if an error happened */ + queryflag = -1; + } + break; case MSG_COMMAND: DoCommandMsg(&m); break; @@ -1178,6 +1199,32 @@ ReceiveMsg() } } +void +ReceiveRaw(s) +int s; +{ + char rd[256]; + int len = 0; +#ifdef NAMEDPIPE + if (fcntl(s, F_SETFL, 0) == -1) + Panic(errno, "BLOCK fcntl"); +#else + struct sockaddr_un a; + len = sizeof(a); + if ((s = accept(s, (struct sockaddr *) &a, (void *)&len)) < 0) + { + Msg(errno, "accept"); + return; + } +#endif + while ((len = read(s, rd, 255)) > 0) + { + rd[len] = 0; + printf("%s", rd); + } + close(s); +} + #if defined(_SEQUENT_) && !defined(NAMEDPIPE) #undef connect /* @@ -1605,12 +1652,16 @@ struct msg *mp; if (fc != fullcmd) *--fc = 0; if (Parse(fullcmd, fc - fullcmd, args, argl) <= 0) - return; + { + /* XXX: Return some useful message back if MSG_QUERY */ + return; + } #ifdef MULTIUSER user = *FindUserPtr(mp->m.attach.auser); if (user == 0) { Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser); + /* XXX: Return some useful message back if MSG_QUERY */ return; } #else @@ -1620,6 +1671,7 @@ struct msg *mp; if (user->u_password && *user->u_password) { Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser); + /* XXX: Return some useful message back if MSG_QUERY */ return; } #endif |