comparison svr-chansession.c @ 130:154c8d5a6d1e private-rez

propagate of 82bb923d0154750ef716b66b498561f882891946 and f51a272341ee12268fe7028bc2f2bad66c603069 from branch 'matt.dbclient.work' to 'matt.dbclient.rez'
author Matt Johnston <matt@ucc.asn.au>
date Tue, 21 Sep 2004 10:08:21 +0000
parents 9ffe5a6dbf3f
children b4cfe976c8e1
comparison
equal deleted inserted replaced
129:66087d87c355 130:154c8d5a6d1e
66 /* required to clear environment */ 66 /* required to clear environment */
67 extern char** environ; 67 extern char** environ;
68 68
69 static int sesscheckclose(struct Channel *channel) { 69 static int sesscheckclose(struct Channel *channel) {
70 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; 70 struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
71 return chansess->exited; 71 return chansess->exit.exitpid >= 0;
72 } 72 }
73 73
74 /* handler for childs exiting, store the state for return to the client */ 74 /* Handler for childs exiting, store the state for return to the client */
75
76 /* There's a particular race we have to watch out for: if the forked child
77 * executes, exits, and this signal-handler is called, all before the parent
78 * gets to run, then the childpids[] array won't have the pid in it. Hence we
79 * use the svr_ses.lastexit struct to hold the exit, which is then compared by
80 * the parent when it runs. This work correctly at least in the case of a
81 * single shell spawned (ie the usual case) */
75 static void sesssigchild_handler(int UNUSED(dummy)) { 82 static void sesssigchild_handler(int UNUSED(dummy)) {
76 83
77 int status; 84 int status;
78 pid_t pid; 85 pid_t pid;
79 unsigned int i; 86 unsigned int i;
80 struct ChanSess * chansess;
81 struct sigaction sa_chld; 87 struct sigaction sa_chld;
88 struct exitinfo *exit = NULL;
82 89
83 TRACE(("enter sigchld handler")); 90 TRACE(("enter sigchld handler"));
84 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
85 /* find the corresponding chansess */ 92 /* find the corresponding chansess */
86 for (i = 0; i < svr_ses.childpidsize; i++) { 93 for (i = 0; i < svr_ses.childpidsize; i++) {
87 if (svr_ses.childpids[i].pid == pid) { 94 if (svr_ses.childpids[i].pid == pid) {
88 95
89 chansess = svr_ses.childpids[i].chansess; 96 exit = &svr_ses.childpids[i].chansess->exit;
90 chansess->exited = 1; 97 break;
91 if (WIFEXITED(status)) { 98 }
92 chansess->exitstatus = WEXITSTATUS(status); 99 }
93 } 100
94 if (WIFSIGNALED(status)) { 101 /* If the pid wasn't matched, then we might have hit the race mentioned
95 chansess->exitsignal = WTERMSIG(status); 102 * above. So we just store the info for the parent to deal with */
103 if (i == svr_ses.childpidsize) {
104 exit = &svr_ses.lastexit;
105 }
106
107 exit->exitpid = pid;
108 if (WIFEXITED(status)) {
109 exit->exitstatus = WEXITSTATUS(status);
110 }
111 if (WIFSIGNALED(status)) {
112 exit->exitsignal = WTERMSIG(status);
96 #if !defined(AIX) && defined(WCOREDUMP) 113 #if !defined(AIX) && defined(WCOREDUMP)
97 chansess->exitcore = WCOREDUMP(status); 114 exit->exitcore = WCOREDUMP(status);
98 #else 115 #else
99 chansess->exitcore = 0; 116 exit->exitcore = 0;
100 #endif 117 #endif
101 } else { 118 } else {
102 /* we use this to determine how pid exited */ 119 /* we use this to determine how pid exited */
103 chansess->exitsignal = -1; 120 exit->exitsignal = -1;
104 } 121 }
105 } 122 exit = NULL;
106 } 123 }
107 } 124
125
108 sa_chld.sa_handler = sesssigchild_handler; 126 sa_chld.sa_handler = sesssigchild_handler;
109 sa_chld.sa_flags = SA_NOCLDSTOP; 127 sa_chld.sa_flags = SA_NOCLDSTOP;
110 sigaction(SIGCHLD, &sa_chld, NULL); 128 sigaction(SIGCHLD, &sa_chld, NULL);
111 TRACE(("leave sigchld handler")); 129 TRACE(("leave sigchld handler"));
112 } 130 }
115 /* XXX server */ 133 /* XXX server */
116 static void send_exitsignalstatus(struct Channel *channel) { 134 static void send_exitsignalstatus(struct Channel *channel) {
117 135
118 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; 136 struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
119 137
120 if (chansess->exited) { 138 if (chansess->exit.exitpid >= 0) {
121 if (chansess->exitsignal > 0) { 139 if (chansess->exit.exitsignal > 0) {
122 send_msg_chansess_exitsignal(channel, chansess); 140 send_msg_chansess_exitsignal(channel, chansess);
123 } else { 141 } else {
124 send_msg_chansess_exitstatus(channel, chansess); 142 send_msg_chansess_exitstatus(channel, chansess);
125 } 143 }
126 } 144 }
128 146
129 /* send the exitstatus to the client */ 147 /* send the exitstatus to the client */
130 static void send_msg_chansess_exitstatus(struct Channel * channel, 148 static void send_msg_chansess_exitstatus(struct Channel * channel,
131 struct ChanSess * chansess) { 149 struct ChanSess * chansess) {
132 150
133 assert(chansess->exited); 151 assert(chansess->exit.exitpid != -1);
134 assert(chansess->exitsignal == -1); 152 assert(chansess->exit.exitsignal == -1);
135 153
136 CHECKCLEARTOWRITE(); 154 CHECKCLEARTOWRITE();
137 155
138 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); 156 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
139 buf_putint(ses.writepayload, channel->remotechan); 157 buf_putint(ses.writepayload, channel->remotechan);
140 buf_putstring(ses.writepayload, "exit-status", 11); 158 buf_putstring(ses.writepayload, "exit-status", 11);
141 buf_putbyte(ses.writepayload, 0); /* boolean FALSE */ 159 buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
142 buf_putint(ses.writepayload, chansess->exitstatus); 160 buf_putint(ses.writepayload, chansess->exit.exitstatus);
143 161
144 encrypt_packet(); 162 encrypt_packet();
145 163
146 } 164 }
147 165
150 struct ChanSess * chansess) { 168 struct ChanSess * chansess) {
151 169
152 int i; 170 int i;
153 char* signame = NULL; 171 char* signame = NULL;
154 172
155 assert(chansess->exited); 173 assert(chansess->exit.exitpid != -1);
156 assert(chansess->exitsignal > 0); 174 assert(chansess->exit.exitsignal > 0);
157 175
158 CHECKCLEARTOWRITE(); 176 CHECKCLEARTOWRITE();
159 177
160 /* we check that we can match a signal name, otherwise 178 /* we check that we can match a signal name, otherwise
161 * don't send anything */ 179 * don't send anything */
162 for (i = 0; signames[i].name != NULL; i++) { 180 for (i = 0; signames[i].name != NULL; i++) {
163 if (signames[i].signal == chansess->exitsignal) { 181 if (signames[i].signal == chansess->exit.exitsignal) {
164 signame = signames[i].name; 182 signame = signames[i].name;
165 break; 183 break;
166 } 184 }
167 } 185 }
168 186
173 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); 191 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
174 buf_putint(ses.writepayload, channel->remotechan); 192 buf_putint(ses.writepayload, channel->remotechan);
175 buf_putstring(ses.writepayload, "exit-signal", 11); 193 buf_putstring(ses.writepayload, "exit-signal", 11);
176 buf_putbyte(ses.writepayload, 0); /* boolean FALSE */ 194 buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
177 buf_putstring(ses.writepayload, signame, strlen(signame)); 195 buf_putstring(ses.writepayload, signame, strlen(signame));
178 buf_putbyte(ses.writepayload, chansess->exitcore); 196 buf_putbyte(ses.writepayload, chansess->exit.exitcore);
179 buf_putstring(ses.writepayload, "", 0); /* error msg */ 197 buf_putstring(ses.writepayload, "", 0); /* error msg */
180 buf_putstring(ses.writepayload, "", 0); /* lang */ 198 buf_putstring(ses.writepayload, "", 0); /* lang */
181 199
182 encrypt_packet(); 200 encrypt_packet();
183 } 201 }
197 chansess->master = -1; 215 chansess->master = -1;
198 chansess->slave = -1; 216 chansess->slave = -1;
199 chansess->tty = NULL; 217 chansess->tty = NULL;
200 chansess->term = NULL; 218 chansess->term = NULL;
201 219
202 chansess->exited = 0; 220 chansess->exit.exitpid = -1;
203 221
204 channel->typedata = chansess; 222 channel->typedata = chansess;
205 223
206 #ifndef DISABLE_X11FWD 224 #ifndef DISABLE_X11FWD
207 chansess->x11listener = NULL; 225 chansess->x11listener = NULL;
261 /* clear child pid entries */ 279 /* clear child pid entries */
262 for (i = 0; i < svr_ses.childpidsize; i++) { 280 for (i = 0; i < svr_ses.childpidsize; i++) {
263 if (svr_ses.childpids[i].chansess == chansess) { 281 if (svr_ses.childpids[i].chansess == chansess) {
264 assert(svr_ses.childpids[i].pid > 0); 282 assert(svr_ses.childpids[i].pid > 0);
265 TRACE(("closing pid %d", svr_ses.childpids[i].pid)); 283 TRACE(("closing pid %d", svr_ses.childpids[i].pid));
266 TRACE(("exited = %d", chansess->exited)); 284 TRACE(("exitpid = %d", chansess->exit.exitpid));
267 svr_ses.childpids[i].pid = -1; 285 svr_ses.childpids[i].pid = -1;
268 svr_ses.childpids[i].chansess = NULL; 286 svr_ses.childpids[i].chansess = NULL;
269 } 287 }
270 } 288 }
271 289
590 608
591 int infds[2]; 609 int infds[2];
592 int outfds[2]; 610 int outfds[2];
593 int errfds[2]; 611 int errfds[2];
594 pid_t pid; 612 pid_t pid;
613 unsigned int i;
595 614
596 TRACE(("enter noptycommand")); 615 TRACE(("enter noptycommand"));
597 616
598 /* redirect stdin/stdout/stderr */ 617 /* redirect stdin/stdout/stderr */
599 if (pipe(infds) != 0) 618 if (pipe(infds) != 0)
633 } else { 652 } else {
634 /* parent */ 653 /* parent */
635 TRACE(("continue noptycommand: parent")); 654 TRACE(("continue noptycommand: parent"));
636 chansess->pid = pid; 655 chansess->pid = pid;
637 656
638 /* add a child pid - Beware: there's a race between this, and the
639 * exec() called from the child. If the child finishes before we've
640 * done this (ie if it was a shell builtin and fast), we won't return a
641 * proper return code. For now, we ignore this case. */
642 addchildpid(chansess, pid); 657 addchildpid(chansess, pid);
658
659 if (svr_ses.lastexit.exitpid != -1) {
660 /* The child probably exited and the signal handler triggered
661 * possibly before we got around to adding the childpid. So we fill
662 * out it's data manually */
663 for (i = 0; i < svr_ses.childpidsize; i++) {
664 if (svr_ses.childpids[i].pid == pid) {
665 svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
666 svr_ses.lastexit.exitpid = -1;
667 }
668 }
669 }
670
643 671
644 close(infds[FDIN]); 672 close(infds[FDIN]);
645 close(outfds[FDOUT]); 673 close(outfds[FDOUT]);
646 close(errfds[FDOUT]); 674 close(errfds[FDOUT]);
647 channel->infd = infds[FDOUT]; 675 channel->infd = infds[FDOUT];