Mercurial > dropbear
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]; |