| 166 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); |
170 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); |
| 167 perror(errmsg); |
171 perror(errmsg); |
| 168 } |
172 } |
| 169 } |
173 } |
| 170 |
174 |
| 171 char *segfault_message; |
175 static void sighandler(int sig) |
| 172 |
176 { |
| 173 /* |
177 ssize_t written; |
| 174 * This signal handler shouldn't be touching this much stuff. |
178 |
| 175 * It should just set a flag and return, and something else in |
179 /* |
| 176 * Pidgin should monitor the flag to see if something needs to |
180 * We won't do any of the heavy lifting for the signal handling here |
| 177 * be done. Because the signal handler interrupts the program, |
181 * because we have no idea what was interrupted. Previously this signal |
| 178 * it could be called in the middle of adding a new connection |
182 * handler could result in some calls to malloc/free, which can cause |
| 179 * to the list of connections, and then if we try to disconnect |
183 * deadlock in libc when the signal handler was interrupting a previous |
| 180 * all connections it could lead to a crash because the linked |
184 * malloc or free. So instead we'll do an ugly hack where we write the |
| 181 * list of connections could be in a weird state. But, well, |
185 * signal number to one end of a socket pair. The other half of the |
| 182 * this signal handler probably isn't called very often, so it's |
186 * socket pair is watched by our main loop. When the main loop sees new |
| 183 * not a big deal. |
187 * data on the socket it reads in the signal and performs the appropriate |
| 184 */ |
188 * action without fear of interrupting stuff. |
| 185 static void |
189 */ |
| 186 sighandler(int sig) |
190 if (sig == SIGSEGV) { |
| 187 { |
191 fprintf(stderr, "%s", segfault_message); |
| |
192 abort(); |
| |
193 return; |
| |
194 } |
| |
195 |
| |
196 written = write(signal_sockets[0], &sig, sizeof(int)); |
| |
197 if (written < 0 || written != sizeof(int)) { |
| |
198 /* This should never happen */ |
| |
199 purple_debug_error("sighandler", "Received signal %d but only " |
| |
200 "wrote %" G_GSSIZE_FORMAT " bytes out of %" |
| |
201 G_GSIZE_FORMAT ": %s\n", |
| |
202 sig, written, sizeof(int), g_strerror(errno)); |
| |
203 exit(1); |
| |
204 } |
| |
205 } |
| |
206 |
| |
207 static gboolean |
| |
208 mainloop_sighandler(GIOChannel *source, GIOCondition cond, gpointer data) |
| |
209 { |
| |
210 GIOStatus stat; |
| |
211 int sig; |
| |
212 gsize bytes_read; |
| |
213 GError *error = NULL; |
| |
214 |
| |
215 /* read the signal number off of the io channel */ |
| |
216 stat = g_io_channel_read_chars(source, (gchar *)&sig, sizeof(int), |
| |
217 &bytes_read, &error); |
| |
218 if (stat != G_IO_STATUS_NORMAL) { |
| |
219 purple_debug_error("sighandler", "Signal callback failed to read " |
| |
220 "from signal socket: %s", error->message); |
| |
221 purple_core_quit(); |
| |
222 return FALSE; |
| |
223 } |
| |
224 |
| 188 switch (sig) { |
225 switch (sig) { |
| 189 case SIGHUP: |
226 case SIGHUP: |
| 190 purple_debug_warning("sighandler", "Caught signal %d\n", sig); |
227 purple_debug_warning("sighandler", "Caught signal %d\n", sig); |
| 191 break; |
|
| 192 case SIGSEGV: |
|
| 193 fprintf(stderr, "%s", segfault_message); |
|
| 194 abort(); |
|
| 195 break; |
228 break; |
| 196 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING) |
229 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING) |
| 197 /* By default, gstreamer forks when you initialize it, and waitpids for the |
230 /* By default, gstreamer forks when you initialize it, and waitpids for the |
| 198 * child. But if libpurple reaps the child rather than leaving it to |
231 * child. But if libpurple reaps the child rather than leaving it to |
| 199 * gstreamer, gstreamer's initialization fails. So, we wait a second before |
232 * gstreamer, gstreamer's initialization fails. So, we wait a second before |
| 590 "haven't been cheating on you!! How many times do you want me to tell you?! And\n" |
627 "haven't been cheating on you!! How many times do you want me to tell you?! And\n" |
| 591 "for the last time, it's just a rash!\n" |
628 "for the last time, it's just a rash!\n" |
| 592 ); |
629 ); |
| 593 #endif |
630 #endif |
| 594 |
631 |
| |
632 /* |
| |
633 * Create a socket pair for receiving unix signals from a signal |
| |
634 * handler. |
| |
635 */ |
| |
636 if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sockets) < 0) { |
| |
637 perror("Failed to create sockets for GLib signal handling"); |
| |
638 exit(1); |
| |
639 } |
| |
640 signal_channel = g_io_channel_unix_new(signal_sockets[1]); |
| |
641 |
| |
642 /* |
| |
643 * Set the channel encoding to raw binary instead of the default of |
| |
644 * UTF-8, because we'll be sending integers across instead of strings. |
| |
645 */ |
| |
646 error = NULL; |
| |
647 signal_status = g_io_channel_set_encoding(signal_channel, NULL, &error); |
| |
648 if (signal_status != G_IO_STATUS_NORMAL) { |
| |
649 fprintf(stderr, "Failed to set the signal channel to raw " |
| |
650 "binary: %s", error->message); |
| |
651 exit(1); |
| |
652 } |
| |
653 g_io_add_watch(signal_channel, G_IO_IN, mainloop_sighandler, NULL); |
| |
654 |
| 595 /* Let's not violate any PLA's!!!! */ |
655 /* Let's not violate any PLA's!!!! */ |
| 596 /* jseymour: whatever the fsck that means */ |
656 /* jseymour: whatever the fsck that means */ |
| 597 /* Robot101: for some reason things like gdm like to block * |
657 /* Robot101: for some reason things like gdm like to block * |
| 598 * useful signals like SIGCHLD, so we unblock all the ones we * |
658 * useful signals like SIGCHLD, so we unblock all the ones we * |
| 599 * declare a handler for. thanks JSeymour and Vann. */ |
659 * declare a handler for. thanks JSeymour and Vann. */ |