Mercurial > dropbear
comparison svr-chansession.c @ 423:b2b67cfcd66e channel-fix
- Fix bug in child-exit handling where the wrong pid was being matched.
- Also wait for errfd to close before closing the channel
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 12 Feb 2007 10:39:22 +0000 |
parents | a01c0c8e543a |
children | 5df05d0a5366 |
comparison
equal
deleted
inserted
replaced
422:a9e0ddac5ba7 | 423:b2b67cfcd66e |
---|---|
65 /* required to clear environment */ | 65 /* required to clear environment */ |
66 extern char** environ; | 66 extern char** environ; |
67 | 67 |
68 static int sesscheckclose(struct Channel *channel) { | 68 static int sesscheckclose(struct Channel *channel) { |
69 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; | 69 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; |
70 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) | |
70 return chansess->exit.exitpid != -1; | 71 return chansess->exit.exitpid != -1; |
71 } | 72 } |
72 | 73 |
73 /* 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 */ |
74 | 75 |
86 struct sigaction sa_chld; | 87 struct sigaction sa_chld; |
87 struct exitinfo *exit = NULL; | 88 struct exitinfo *exit = NULL; |
88 | 89 |
89 TRACE(("enter sigchld handler")) | 90 TRACE(("enter sigchld handler")) |
90 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | 91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { |
92 TRACE(("sigchld handler: pid %d", pid)) | |
91 | 93 |
92 exit = NULL; | 94 exit = NULL; |
93 /* find the corresponding chansess */ | 95 /* find the corresponding chansess */ |
94 for (i = 0; i < svr_ses.childpidsize; i++) { | 96 for (i = 0; i < svr_ses.childpidsize; i++) { |
95 if (svr_ses.childpids[i].pid == pid) { | 97 if (svr_ses.childpids[i].pid == pid) { |
96 | 98 TRACE(("found match session")); |
97 exit = &svr_ses.childpids[i].chansess->exit; | 99 exit = &svr_ses.childpids[i].chansess->exit; |
98 break; | 100 break; |
99 } | 101 } |
100 } | 102 } |
101 | 103 |
102 /* If the pid wasn't matched, then we might have hit the race mentioned | 104 /* If the pid wasn't matched, then we might have hit the race mentioned |
103 * above. So we just store the info for the parent to deal with */ | 105 * above. So we just store the info for the parent to deal with */ |
104 if (exit == NULL) { | 106 if (exit == NULL) { |
107 TRACE(("using lastexit")); | |
105 exit = &svr_ses.lastexit; | 108 exit = &svr_ses.lastexit; |
106 } | 109 } |
107 | 110 |
108 exit->exitpid = pid; | 111 exit->exitpid = pid; |
109 if (WIFEXITED(status)) { | 112 if (WIFEXITED(status)) { |
123 | 126 |
124 /* Make sure that the main select() loop wakes up */ | 127 /* Make sure that the main select() loop wakes up */ |
125 while (1) { | 128 while (1) { |
126 /* EAGAIN means the pipe's full, so don't need to write anything */ | 129 /* EAGAIN means the pipe's full, so don't need to write anything */ |
127 /* isserver is just a random byte to write */ | 130 /* isserver is just a random byte to write */ |
128 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 || errno == EAGAIN) { | 131 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 |
132 || errno == EAGAIN) { | |
129 break; | 133 break; |
130 } | 134 } |
131 if (errno == EINTR) { | 135 if (errno == EINTR) { |
132 continue; | 136 continue; |
133 } | 137 } |
140 sigaction(SIGCHLD, &sa_chld, NULL); | 144 sigaction(SIGCHLD, &sa_chld, NULL); |
141 TRACE(("leave sigchld handler")) | 145 TRACE(("leave sigchld handler")) |
142 } | 146 } |
143 | 147 |
144 /* send the exit status or the signal causing termination for a session */ | 148 /* send the exit status or the signal causing termination for a session */ |
145 /* XXX server */ | |
146 static void send_exitsignalstatus(struct Channel *channel) { | 149 static void send_exitsignalstatus(struct Channel *channel) { |
147 | 150 |
148 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; | 151 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; |
149 | 152 |
150 if (chansess->exit.exitpid >= 0) { | 153 if (chansess->exit.exitpid >= 0) { |
179 static void send_msg_chansess_exitsignal(struct Channel * channel, | 182 static void send_msg_chansess_exitsignal(struct Channel * channel, |
180 struct ChanSess * chansess) { | 183 struct ChanSess * chansess) { |
181 | 184 |
182 int i; | 185 int i; |
183 char* signame = NULL; | 186 char* signame = NULL; |
184 | |
185 dropbear_assert(chansess->exit.exitpid != -1); | 187 dropbear_assert(chansess->exit.exitpid != -1); |
186 dropbear_assert(chansess->exit.exitsignal > 0); | 188 dropbear_assert(chansess->exit.exitsignal > 0); |
189 | |
190 TRACE(("send_msg_chansess_exitsignal %d", chansess->exit.exitsignal)) | |
187 | 191 |
188 CHECKCLEARTOWRITE(); | 192 CHECKCLEARTOWRITE(); |
189 | 193 |
190 /* we check that we can match a signal name, otherwise | 194 /* we check that we can match a signal name, otherwise |
191 * don't send anything */ | 195 * don't send anything */ |
292 /* clear child pid entries */ | 296 /* clear child pid entries */ |
293 for (i = 0; i < svr_ses.childpidsize; i++) { | 297 for (i = 0; i < svr_ses.childpidsize; i++) { |
294 if (svr_ses.childpids[i].chansess == chansess) { | 298 if (svr_ses.childpids[i].chansess == chansess) { |
295 dropbear_assert(svr_ses.childpids[i].pid > 0); | 299 dropbear_assert(svr_ses.childpids[i].pid > 0); |
296 TRACE(("closing pid %d", svr_ses.childpids[i].pid)) | 300 TRACE(("closing pid %d", svr_ses.childpids[i].pid)) |
297 TRACE(("exitpid = %d", chansess->exit.exitpid)) | 301 TRACE(("exitpid is %d", chansess->exit.exitpid)) |
298 svr_ses.childpids[i].pid = -1; | 302 svr_ses.childpids[i].pid = -1; |
299 svr_ses.childpids[i].chansess = NULL; | 303 svr_ses.childpids[i].chansess = NULL; |
300 } | 304 } |
301 } | 305 } |
302 | 306 |
680 | 684 |
681 } else { | 685 } else { |
682 /* parent */ | 686 /* parent */ |
683 TRACE(("continue noptycommand: parent")) | 687 TRACE(("continue noptycommand: parent")) |
684 chansess->pid = pid; | 688 chansess->pid = pid; |
689 TRACE(("child pid is %d", pid)) | |
685 | 690 |
686 addchildpid(chansess, pid); | 691 addchildpid(chansess, pid); |
687 | 692 |
688 if (svr_ses.lastexit.exitpid != -1) { | 693 if (svr_ses.lastexit.exitpid != -1) { |
694 TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid)) | |
689 /* The child probably exited and the signal handler triggered | 695 /* The child probably exited and the signal handler triggered |
690 * possibly before we got around to adding the childpid. So we fill | 696 * possibly before we got around to adding the childpid. So we fill |
691 * out it's data manually */ | 697 * out its data manually */ |
692 for (i = 0; i < svr_ses.childpidsize; i++) { | 698 for (i = 0; i < svr_ses.childpidsize; i++) { |
693 if (svr_ses.childpids[i].pid == pid) { | 699 if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) { |
700 TRACE(("found match for lastexitpid")) | |
694 svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; | 701 svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; |
695 svr_ses.lastexit.exitpid = -1; | 702 svr_ses.lastexit.exitpid = -1; |
696 } | 703 } |
697 } | 704 } |
698 } | 705 } |
699 | |
700 | 706 |
701 close(infds[FDIN]); | 707 close(infds[FDIN]); |
702 close(outfds[FDOUT]); | 708 close(outfds[FDOUT]); |
703 close(errfds[FDOUT]); | 709 close(errfds[FDOUT]); |
704 channel->writefd = infds[FDOUT]; | 710 channel->writefd = infds[FDOUT]; |