Mercurial > dropbear
comparison svr-chansession.c @ 1495:0c16b4ccbd54
make signal flags volatile, simplify handling
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 14 Feb 2018 23:06:01 +0800 |
parents | 58a74cb829b8 |
children | da3bed08607b |
comparison
equal
deleted
inserted
replaced
1494:da095983a60b | 1495:0c16b4ccbd54 |
---|---|
78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; | 78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; |
79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) | 79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) |
80 return chansess->exit.exitpid != -1; | 80 return chansess->exit.exitpid != -1; |
81 } | 81 } |
82 | 82 |
83 void svr_chansess_checksignal(void) { | |
84 int status; | |
85 pid_t pid; | |
86 | |
87 if (!ses.channel_signal_pending) { | |
88 return; | |
89 } | |
90 | |
91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | |
92 unsigned int i; | |
93 struct exitinfo *ex = NULL; | |
94 TRACE(("sigchld handler: pid %d", pid)) | |
95 | |
96 ex = NULL; | |
97 /* find the corresponding chansess */ | |
98 for (i = 0; i < svr_ses.childpidsize; i++) { | |
99 if (svr_ses.childpids[i].pid == pid) { | |
100 TRACE(("found match session")); | |
101 ex = &svr_ses.childpids[i].chansess->exit; | |
102 break; | |
103 } | |
104 } | |
105 | |
106 /* If the pid wasn't matched, then we might have hit the race mentioned | |
107 * above. So we just store the info for the parent to deal with */ | |
108 if (ex == NULL) { | |
109 TRACE(("using lastexit")); | |
110 ex = &svr_ses.lastexit; | |
111 } | |
112 | |
113 ex->exitpid = pid; | |
114 if (WIFEXITED(status)) { | |
115 ex->exitstatus = WEXITSTATUS(status); | |
116 } | |
117 if (WIFSIGNALED(status)) { | |
118 ex->exitsignal = WTERMSIG(status); | |
119 #if !defined(AIX) && defined(WCOREDUMP) | |
120 ex->exitcore = WCOREDUMP(status); | |
121 #else | |
122 ex->exitcore = 0; | |
123 #endif | |
124 } else { | |
125 /* we use this to determine how pid exited */ | |
126 ex->exitsignal = -1; | |
127 } | |
128 | |
129 } | |
130 } | |
131 | |
83 /* Handler for childs exiting, store the state for return to the client */ | 132 /* Handler for childs exiting, store the state for return to the client */ |
84 | 133 |
85 /* There's a particular race we have to watch out for: if the forked child | 134 /* There's a particular race we have to watch out for: if the forked child |
86 * executes, exits, and this signal-handler is called, all before the parent | 135 * executes, exits, and this signal-handler is called, all before the parent |
87 * gets to run, then the childpids[] array won't have the pid in it. Hence we | 136 * gets to run, then the childpids[] array won't have the pid in it. Hence we |
88 * use the svr_ses.lastexit struct to hold the exit, which is then compared by | 137 * use the svr_ses.lastexit struct to hold the exit, which is then compared by |
89 * the parent when it runs. This work correctly at least in the case of a | 138 * the parent when it runs. This work correctly at least in the case of a |
90 * single shell spawned (ie the usual case) */ | 139 * single shell spawned (ie the usual case) */ |
91 static void sesssigchild_handler(int UNUSED(dummy)) { | 140 static void sesssigchild_handler(int UNUSED(dummy)) { |
92 | |
93 int status; | |
94 pid_t pid; | |
95 unsigned int i; | 141 unsigned int i; |
96 struct sigaction sa_chld; | 142 struct sigaction sa_chld; |
97 struct exitinfo *exit = NULL; | |
98 | 143 |
99 const int saved_errno = errno; | 144 const int saved_errno = errno; |
100 | 145 |
101 /* Make channel handling code look for closed channels */ | |
102 ses.channel_signal_pending = 1; | |
103 | |
104 TRACE(("enter sigchld handler")) | 146 TRACE(("enter sigchld handler")) |
105 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | 147 |
106 TRACE(("sigchld handler: pid %d", pid)) | 148 /* Make sure that the main select() loop wakes up */ |
107 | 149 while (1) { |
108 exit = NULL; | 150 /* isserver is just a random byte to write. We can't do anything |
109 /* find the corresponding chansess */ | 151 about an error so should just ignore it */ |
110 for (i = 0; i < svr_ses.childpidsize; i++) { | 152 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 |
111 if (svr_ses.childpids[i].pid == pid) { | 153 || errno != EINTR) { |
112 TRACE(("found match session")); | 154 break; |
113 exit = &svr_ses.childpids[i].chansess->exit; | |
114 break; | |
115 } | |
116 } | |
117 | |
118 /* If the pid wasn't matched, then we might have hit the race mentioned | |
119 * above. So we just store the info for the parent to deal with */ | |
120 if (exit == NULL) { | |
121 TRACE(("using lastexit")); | |
122 exit = &svr_ses.lastexit; | |
123 } | |
124 | |
125 exit->exitpid = pid; | |
126 if (WIFEXITED(status)) { | |
127 exit->exitstatus = WEXITSTATUS(status); | |
128 } | |
129 if (WIFSIGNALED(status)) { | |
130 exit->exitsignal = WTERMSIG(status); | |
131 #if !defined(AIX) && defined(WCOREDUMP) | |
132 exit->exitcore = WCOREDUMP(status); | |
133 #else | |
134 exit->exitcore = 0; | |
135 #endif | |
136 } else { | |
137 /* we use this to determine how pid exited */ | |
138 exit->exitsignal = -1; | |
139 } | |
140 | |
141 /* Make sure that the main select() loop wakes up */ | |
142 while (1) { | |
143 /* isserver is just a random byte to write. We can't do anything | |
144 about an error so should just ignore it */ | |
145 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 | |
146 || errno != EINTR) { | |
147 break; | |
148 } | |
149 } | 155 } |
150 } | 156 } |
151 | 157 |
152 sa_chld.sa_handler = sesssigchild_handler; | 158 sa_chld.sa_handler = sesssigchild_handler; |
153 sa_chld.sa_flags = SA_NOCLDSTOP; | 159 sa_chld.sa_flags = SA_NOCLDSTOP; |