Annotation of embedaddon/curl/tests/server/util.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22: #include "server_setup.h"
23:
24: #ifdef HAVE_SIGNAL_H
25: #include <signal.h>
26: #endif
27: #ifdef HAVE_NETINET_IN_H
28: #include <netinet/in.h>
29: #endif
30: #ifdef _XOPEN_SOURCE_EXTENDED
31: /* This define is "almost" required to build on HPUX 11 */
32: #include <arpa/inet.h>
33: #endif
34: #ifdef HAVE_NETDB_H
35: #include <netdb.h>
36: #endif
37: #ifdef HAVE_POLL_H
38: #include <poll.h>
39: #elif defined(HAVE_SYS_POLL_H)
40: #include <sys/poll.h>
41: #endif
42: #ifdef __MINGW32__
43: #include <w32api.h>
44: #endif
45:
46: #define ENABLE_CURLX_PRINTF
47: /* make the curlx header define all printf() functions to use the curlx_*
48: versions instead */
49: #include "curlx.h" /* from the private lib dir */
50: #include "getpart.h"
51: #include "util.h"
52: #include "timeval.h"
53:
54: #ifdef USE_WINSOCK
55: #undef EINTR
56: #define EINTR 4 /* errno.h value */
57: #undef EINVAL
58: #define EINVAL 22 /* errno.h value */
59: #endif
60:
61: /* MinGW with w32api version < 3.6 declared in6addr_any as extern,
62: but lacked the definition */
63: #if defined(ENABLE_IPV6) && defined(__MINGW32__)
64: #if (__W32API_MAJOR_VERSION < 3) || \
65: ((__W32API_MAJOR_VERSION == 3) && (__W32API_MINOR_VERSION < 6))
66: const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
67: #endif /* w32api < 3.6 */
68: #endif /* ENABLE_IPV6 && __MINGW32__*/
69:
70: static struct timeval tvnow(void);
71:
72: /* This function returns a pointer to STATIC memory. It converts the given
73: * binary lump to a hex formatted string usable for output in logs or
74: * whatever.
75: */
76: char *data_to_hex(char *data, size_t len)
77: {
78: static char buf[256*3];
79: size_t i;
80: char *optr = buf;
81: char *iptr = data;
82:
83: if(len > 255)
84: len = 255;
85:
86: for(i = 0; i < len; i++) {
87: if((data[i] >= 0x20) && (data[i] < 0x7f))
88: *optr++ = *iptr++;
89: else {
90: msnprintf(optr, 4, "%%%02x", *iptr++);
91: optr += 3;
92: }
93: }
94: *optr = 0; /* in case no sprintf was used */
95:
96: return buf;
97: }
98:
99: void logmsg(const char *msg, ...)
100: {
101: va_list ap;
102: char buffer[2048 + 1];
103: FILE *logfp;
104: struct timeval tv;
105: time_t sec;
106: struct tm *now;
107: char timebuf[20];
108: static time_t epoch_offset;
109: static int known_offset;
110:
111: if(!serverlogfile) {
112: fprintf(stderr, "Error: serverlogfile not set\n");
113: return;
114: }
115:
116: tv = tvnow();
117: if(!known_offset) {
118: epoch_offset = time(NULL) - tv.tv_sec;
119: known_offset = 1;
120: }
121: sec = epoch_offset + tv.tv_sec;
122: now = localtime(&sec); /* not thread safe but we don't care */
123:
124: msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
125: (int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec,
126: (long)tv.tv_usec);
127:
128: va_start(ap, msg);
129: mvsnprintf(buffer, sizeof(buffer), msg, ap);
130: va_end(ap);
131:
132: logfp = fopen(serverlogfile, "ab");
133: if(logfp) {
134: fprintf(logfp, "%s %s\n", timebuf, buffer);
135: fclose(logfp);
136: }
137: else {
138: int error = errno;
139: fprintf(stderr, "fopen() failed with error: %d %s\n",
140: error, strerror(error));
141: fprintf(stderr, "Error opening file: %s\n", serverlogfile);
142: fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer);
143: }
144: }
145:
146: #ifdef WIN32
147: /* use instead of perror() on generic windows */
148: void win32_perror(const char *msg)
149: {
150: char buf[512];
151: DWORD err = SOCKERRNO;
152:
153: if(!FormatMessageA((FORMAT_MESSAGE_FROM_SYSTEM |
154: FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
155: LANG_NEUTRAL, buf, sizeof(buf), NULL))
156: msnprintf(buf, sizeof(buf), "Unknown error %lu (%#lx)", err, err);
157: if(msg)
158: fprintf(stderr, "%s: ", msg);
159: fprintf(stderr, "%s\n", buf);
160: }
161: #endif /* WIN32 */
162:
163: #ifdef USE_WINSOCK
164: void win32_init(void)
165: {
166: WORD wVersionRequested;
167: WSADATA wsaData;
168: int err;
169: wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
170:
171: err = WSAStartup(wVersionRequested, &wsaData);
172:
173: if(err != 0) {
174: perror("Winsock init failed");
175: logmsg("Error initialising winsock -- aborting");
176: exit(1);
177: }
178:
179: if(LOBYTE(wsaData.wVersion) != USE_WINSOCK ||
180: HIBYTE(wsaData.wVersion) != USE_WINSOCK) {
181: WSACleanup();
182: perror("Winsock init failed");
183: logmsg("No suitable winsock.dll found -- aborting");
184: exit(1);
185: }
186: }
187:
188: void win32_cleanup(void)
189: {
190: WSACleanup();
191: }
192: #endif /* USE_WINSOCK */
193:
194: /* set by the main code to point to where the test dir is */
195: const char *path = ".";
196:
197: FILE *test2fopen(long testno)
198: {
199: FILE *stream;
200: char filename[256];
201: /* first try the alternative, preprocessed, file */
202: msnprintf(filename, sizeof(filename), ALTTEST_DATA_PATH, path, testno);
203: stream = fopen(filename, "rb");
204: if(stream)
205: return stream;
206:
207: /* then try the source version */
208: msnprintf(filename, sizeof(filename), TEST_DATA_PATH, path, testno);
209: stream = fopen(filename, "rb");
210:
211: return stream;
212: }
213:
214: /*
215: * Portable function used for waiting a specific amount of ms.
216: * Waiting indefinitely with this function is not allowed, a
217: * zero or negative timeout value will return immediately.
218: *
219: * Return values:
220: * -1 = system call error, or invalid timeout value
221: * 0 = specified timeout has elapsed
222: */
223: int wait_ms(int timeout_ms)
224: {
225: #if !defined(MSDOS) && !defined(USE_WINSOCK)
226: #ifndef HAVE_POLL_FINE
227: struct timeval pending_tv;
228: #endif
229: struct timeval initial_tv;
230: int pending_ms;
231: #endif
232: int r = 0;
233:
234: if(!timeout_ms)
235: return 0;
236: if(timeout_ms < 0) {
237: errno = EINVAL;
238: return -1;
239: }
240: #if defined(MSDOS)
241: delay(timeout_ms);
242: #elif defined(USE_WINSOCK)
243: Sleep(timeout_ms);
244: #else
245: pending_ms = timeout_ms;
246: initial_tv = tvnow();
247: do {
248: int error;
249: #if defined(HAVE_POLL_FINE)
250: r = poll(NULL, 0, pending_ms);
251: #else
252: pending_tv.tv_sec = pending_ms / 1000;
253: pending_tv.tv_usec = (pending_ms % 1000) * 1000;
254: r = select(0, NULL, NULL, NULL, &pending_tv);
255: #endif /* HAVE_POLL_FINE */
256: if(r != -1)
257: break;
258: error = errno;
259: if(error && (error != EINTR))
260: break;
261: pending_ms = timeout_ms - (int)timediff(tvnow(), initial_tv);
262: if(pending_ms <= 0)
263: break;
264: } while(r == -1);
265: #endif /* USE_WINSOCK */
266: if(r)
267: r = -1;
268: return r;
269: }
270:
271: int write_pidfile(const char *filename)
272: {
273: FILE *pidfile;
274: curl_off_t pid;
275:
276: pid = (curl_off_t)getpid();
277: pidfile = fopen(filename, "wb");
278: if(!pidfile) {
279: logmsg("Couldn't write pid file: %s %s", filename, strerror(errno));
280: return 0; /* fail */
281: }
282: #if defined(WIN32) || defined(_WIN32)
283: /* store pid + 65536 to avoid conflict with Cygwin/msys PIDs, see also:
284: * - https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; ↵
285: * h=b5e1003722cb14235c4f166be72c09acdffc62ea
286: * - https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; ↵
287: * h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe
288: */
289: pid += 65536;
290: #endif
291: fprintf(pidfile, "%" CURL_FORMAT_CURL_OFF_T "\n", pid);
292: fclose(pidfile);
293: logmsg("Wrote pid %ld to %s", pid, filename);
294: return 1; /* success */
295: }
296:
297: /* store the used port number in a file */
298: int write_portfile(const char *filename, int port)
299: {
300: FILE *portfile = fopen(filename, "wb");
301: if(!portfile) {
302: logmsg("Couldn't write port file: %s %s", filename, strerror(errno));
303: return 0; /* fail */
304: }
305: fprintf(portfile, "%d\n", port);
306: fclose(portfile);
307: logmsg("Wrote port %d to %s", port, filename);
308: return 1; /* success */
309: }
310:
311: void set_advisor_read_lock(const char *filename)
312: {
313: FILE *lockfile;
314: int error = 0;
315: int res;
316:
317: do {
318: lockfile = fopen(filename, "wb");
319: } while((lockfile == NULL) && ((error = errno) == EINTR));
320: if(lockfile == NULL) {
321: logmsg("Error creating lock file %s error: %d %s",
322: filename, error, strerror(error));
323: return;
324: }
325:
326: do {
327: res = fclose(lockfile);
328: } while(res && ((error = errno) == EINTR));
329: if(res)
330: logmsg("Error closing lock file %s error: %d %s",
331: filename, error, strerror(error));
332: }
333:
334: void clear_advisor_read_lock(const char *filename)
335: {
336: int error = 0;
337: int res;
338:
339: /*
340: ** Log all removal failures. Even those due to file not existing.
341: ** This allows to detect if unexpectedly the file has already been
342: ** removed by a process different than the one that should do this.
343: */
344:
345: do {
346: res = unlink(filename);
347: } while(res && ((error = errno) == EINTR));
348: if(res)
349: logmsg("Error removing lock file %s error: %d %s",
350: filename, error, strerror(error));
351: }
352:
353:
354: /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
355: its behavior is altered by the current locale. */
356: static char raw_toupper(char in)
357: {
358: #if !defined(CURL_DOES_CONVERSIONS)
359: if(in >= 'a' && in <= 'z')
360: return (char)('A' + in - 'a');
361: #else
362: switch(in) {
363: case 'a':
364: return 'A';
365: case 'b':
366: return 'B';
367: case 'c':
368: return 'C';
369: case 'd':
370: return 'D';
371: case 'e':
372: return 'E';
373: case 'f':
374: return 'F';
375: case 'g':
376: return 'G';
377: case 'h':
378: return 'H';
379: case 'i':
380: return 'I';
381: case 'j':
382: return 'J';
383: case 'k':
384: return 'K';
385: case 'l':
386: return 'L';
387: case 'm':
388: return 'M';
389: case 'n':
390: return 'N';
391: case 'o':
392: return 'O';
393: case 'p':
394: return 'P';
395: case 'q':
396: return 'Q';
397: case 'r':
398: return 'R';
399: case 's':
400: return 'S';
401: case 't':
402: return 'T';
403: case 'u':
404: return 'U';
405: case 'v':
406: return 'V';
407: case 'w':
408: return 'W';
409: case 'x':
410: return 'X';
411: case 'y':
412: return 'Y';
413: case 'z':
414: return 'Z';
415: }
416: #endif
417:
418: return in;
419: }
420:
421: int strncasecompare(const char *first, const char *second, size_t max)
422: {
423: while(*first && *second && max) {
424: if(raw_toupper(*first) != raw_toupper(*second)) {
425: break;
426: }
427: max--;
428: first++;
429: second++;
430: }
431: if(0 == max)
432: return 1; /* they are equal this far */
433:
434: return raw_toupper(*first) == raw_toupper(*second);
435: }
436:
437: #if defined(WIN32) && !defined(MSDOS)
438:
439: static struct timeval tvnow(void)
440: {
441: /*
442: ** GetTickCount() is available on _all_ Windows versions from W95 up
443: ** to nowadays. Returns milliseconds elapsed since last system boot,
444: ** increases monotonically and wraps once 49.7 days have elapsed.
445: **
446: ** GetTickCount64() is available on Windows version from Windows Vista
447: ** and Windows Server 2008 up to nowadays. The resolution of the
448: ** function is limited to the resolution of the system timer, which
449: ** is typically in the range of 10 milliseconds to 16 milliseconds.
450: */
451: struct timeval now;
452: #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && \
453: (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
454: ULONGLONG milliseconds = GetTickCount64();
455: #else
456: DWORD milliseconds = GetTickCount();
457: #endif
458: now.tv_sec = (long)(milliseconds / 1000);
459: now.tv_usec = (long)((milliseconds % 1000) * 1000);
460: return now;
461: }
462:
463: #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
464:
465: static struct timeval tvnow(void)
466: {
467: /*
468: ** clock_gettime() is granted to be increased monotonically when the
469: ** monotonic clock is queried. Time starting point is unspecified, it
470: ** could be the system start-up time, the Epoch, or something else,
471: ** in any case the time starting point does not change once that the
472: ** system has started up.
473: */
474: struct timeval now;
475: struct timespec tsnow;
476: if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
477: now.tv_sec = tsnow.tv_sec;
478: now.tv_usec = tsnow.tv_nsec / 1000;
479: }
480: /*
481: ** Even when the configure process has truly detected monotonic clock
482: ** availability, it might happen that it is not actually available at
483: ** run-time. When this occurs simply fallback to other time source.
484: */
485: #ifdef HAVE_GETTIMEOFDAY
486: else
487: (void)gettimeofday(&now, NULL);
488: #else
489: else {
490: now.tv_sec = (long)time(NULL);
491: now.tv_usec = 0;
492: }
493: #endif
494: return now;
495: }
496:
497: #elif defined(HAVE_GETTIMEOFDAY)
498:
499: static struct timeval tvnow(void)
500: {
501: /*
502: ** gettimeofday() is not granted to be increased monotonically, due to
503: ** clock drifting and external source time synchronization it can jump
504: ** forward or backward in time.
505: */
506: struct timeval now;
507: (void)gettimeofday(&now, NULL);
508: return now;
509: }
510:
511: #else
512:
513: static struct timeval tvnow(void)
514: {
515: /*
516: ** time() returns the value of time in seconds since the Epoch.
517: */
518: struct timeval now;
519: now.tv_sec = (long)time(NULL);
520: now.tv_usec = 0;
521: return now;
522: }
523:
524: #endif
525:
526: long timediff(struct timeval newer, struct timeval older)
527: {
528: timediff_t diff = newer.tv_sec-older.tv_sec;
529: if(diff >= (LONG_MAX/1000))
530: return LONG_MAX;
531: else if(diff <= (LONG_MIN/1000))
532: return LONG_MIN;
533: return (long)(newer.tv_sec-older.tv_sec)*1000+
534: (long)(newer.tv_usec-older.tv_usec)/1000;
535: }
536:
537: /* do-nothing macro replacement for systems which lack siginterrupt() */
538:
539: #ifndef HAVE_SIGINTERRUPT
540: #define siginterrupt(x,y) do {} while(0)
541: #endif
542:
543: /* vars used to keep around previous signal handlers */
544:
545: typedef RETSIGTYPE (*SIGHANDLER_T)(int);
546:
547: #ifdef SIGHUP
548: static SIGHANDLER_T old_sighup_handler = SIG_ERR;
549: #endif
550:
551: #ifdef SIGPIPE
552: static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
553: #endif
554:
555: #ifdef SIGALRM
556: static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
557: #endif
558:
559: #ifdef SIGINT
560: static SIGHANDLER_T old_sigint_handler = SIG_ERR;
561: #endif
562:
563: #ifdef SIGTERM
564: static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
565: #endif
566:
567: #if defined(SIGBREAK) && defined(WIN32)
568: static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
569: #endif
570:
571: #ifdef WIN32
572: static DWORD thread_main_id = 0;
573: static HANDLE thread_main_window = NULL;
574: static HWND hidden_main_window = NULL;
575: #endif
576:
577: /* var which if set indicates that the program should finish execution */
578: volatile int got_exit_signal = 0;
579:
580: /* if next is set indicates the first signal handled in exit_signal_handler */
581: volatile int exit_signal = 0;
582:
583: /* signal handler that will be triggered to indicate that the program
584: * should finish its execution in a controlled manner as soon as possible.
585: * The first time this is called it will set got_exit_signal to one and
586: * store in exit_signal the signal that triggered its execution.
587: */
588: static RETSIGTYPE exit_signal_handler(int signum)
589: {
590: int old_errno = errno;
591: logmsg("exit_signal_handler: %d", signum);
592: if(got_exit_signal == 0) {
593: got_exit_signal = 1;
594: exit_signal = signum;
595: }
596: (void)signal(signum, exit_signal_handler);
597: errno = old_errno;
598: }
599:
600: #ifdef WIN32
601: /* CTRL event handler for Windows Console applications to simulate
602: * SIGINT, SIGTERM and SIGBREAK on CTRL events and trigger signal handler.
603: *
604: * Background information from MSDN:
605: * SIGINT is not supported for any Win32 application. When a CTRL+C
606: * interrupt occurs, Win32 operating systems generate a new thread
607: * to specifically handle that interrupt. This can cause a single-thread
608: * application, such as one in UNIX, to become multithreaded and cause
609: * unexpected behavior.
610: * [...]
611: * The SIGILL and SIGTERM signals are not generated under Windows.
612: * They are included for ANSI compatibility. Therefore, you can set
613: * signal handlers for these signals by using signal, and you can also
614: * explicitly generate these signals by calling raise. Source:
615: * https://docs.microsoft.com/de-de/cpp/c-runtime-library/reference/signal
616: */
617: static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType)
618: {
619: int signum = 0;
620: logmsg("ctrl_event_handler: %d", dwCtrlType);
621: switch(dwCtrlType) {
622: #ifdef SIGINT
623: case CTRL_C_EVENT: signum = SIGINT; break;
624: #endif
625: #ifdef SIGTERM
626: case CTRL_CLOSE_EVENT: signum = SIGTERM; break;
627: #endif
628: #ifdef SIGBREAK
629: case CTRL_BREAK_EVENT: signum = SIGBREAK; break;
630: #endif
631: default: return FALSE;
632: }
633: if(signum) {
634: logmsg("ctrl_event_handler: %d -> %d", dwCtrlType, signum);
635: exit_signal_handler(signum);
636: }
637: return TRUE;
638: }
639: /* Window message handler for Windows applications to add support
640: * for graceful process termination via taskkill (without /f) which
641: * sends WM_CLOSE to all Windows of a process (even hidden ones).
642: *
643: * Therefore we create and run a hidden Window in a separate thread
644: * to receive and handle the WM_CLOSE message as SIGTERM signal.
645: */
646: static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg,
647: WPARAM wParam, LPARAM lParam)
648: {
649: int signum = 0;
650: if(hwnd == hidden_main_window) {
651: switch(uMsg) {
652: #ifdef SIGTERM
653: case WM_CLOSE: signum = SIGTERM; break;
654: #endif
655: case WM_DESTROY: PostQuitMessage(0); break;
656: }
657: if(signum) {
658: logmsg("main_window_proc: %d -> %d", uMsg, signum);
659: exit_signal_handler(signum);
660: }
661: }
662: return DefWindowProc(hwnd, uMsg, wParam, lParam);
663: }
664: /* Window message queue loop for hidden main window, details see above.
665: */
666: static DWORD WINAPI main_window_loop(LPVOID lpParameter)
667: {
668: WNDCLASS wc;
669: BOOL ret;
670: MSG msg;
671:
672: ZeroMemory(&wc, sizeof(wc));
673: wc.lpfnWndProc = (WNDPROC)main_window_proc;
674: wc.hInstance = (HINSTANCE)lpParameter;
675: wc.lpszClassName = "MainWClass";
676: if(!RegisterClass(&wc)) {
677: perror("RegisterClass failed");
678: return (DWORD)-1;
679: }
680:
681: hidden_main_window = CreateWindowEx(0, "MainWClass", "Recv WM_CLOSE msg",
682: WS_OVERLAPPEDWINDOW,
683: CW_USEDEFAULT, CW_USEDEFAULT,
684: CW_USEDEFAULT, CW_USEDEFAULT,
685: (HWND)NULL, (HMENU)NULL,
686: wc.hInstance, (LPVOID)NULL);
687: if(!hidden_main_window) {
688: perror("CreateWindowEx failed");
689: return (DWORD)-1;
690: }
691:
692: do {
693: ret = GetMessage(&msg, NULL, 0, 0);
694: if(ret == -1) {
695: perror("GetMessage failed");
696: return (DWORD)-1;
697: }
698: else if(ret) {
699: if(msg.message == WM_APP) {
700: DestroyWindow(hidden_main_window);
701: }
702: else if(msg.hwnd && !TranslateMessage(&msg)) {
703: DispatchMessage(&msg);
704: }
705: }
706: } while(ret);
707:
708: hidden_main_window = NULL;
709: return (DWORD)msg.wParam;
710: }
711: #endif
712:
713: void install_signal_handlers(bool keep_sigalrm)
714: {
715: #ifdef SIGHUP
716: /* ignore SIGHUP signal */
717: old_sighup_handler = signal(SIGHUP, SIG_IGN);
718: if(old_sighup_handler == SIG_ERR)
719: logmsg("cannot install SIGHUP handler: %s", strerror(errno));
720: #endif
721: #ifdef SIGPIPE
722: /* ignore SIGPIPE signal */
723: old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
724: if(old_sigpipe_handler == SIG_ERR)
725: logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
726: #endif
727: #ifdef SIGALRM
728: if(!keep_sigalrm) {
729: /* ignore SIGALRM signal */
730: old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
731: if(old_sigalrm_handler == SIG_ERR)
732: logmsg("cannot install SIGALRM handler: %s", strerror(errno));
733: }
734: #else
735: (void)keep_sigalrm;
736: #endif
737: #ifdef SIGINT
738: /* handle SIGINT signal with our exit_signal_handler */
739: old_sigint_handler = signal(SIGINT, exit_signal_handler);
740: if(old_sigint_handler == SIG_ERR)
741: logmsg("cannot install SIGINT handler: %s", strerror(errno));
742: else
743: siginterrupt(SIGINT, 1);
744: #endif
745: #ifdef SIGTERM
746: /* handle SIGTERM signal with our exit_signal_handler */
747: old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
748: if(old_sigterm_handler == SIG_ERR)
749: logmsg("cannot install SIGTERM handler: %s", strerror(errno));
750: else
751: siginterrupt(SIGTERM, 1);
752: #endif
753: #if defined(SIGBREAK) && defined(WIN32)
754: /* handle SIGBREAK signal with our exit_signal_handler */
755: old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
756: if(old_sigbreak_handler == SIG_ERR)
757: logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
758: else
759: siginterrupt(SIGBREAK, 1);
760: #endif
761: #ifdef WIN32
762: if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
763: logmsg("cannot install CTRL event handler");
764: thread_main_window = CreateThread(NULL, 0,
765: &main_window_loop,
766: (LPVOID)GetModuleHandle(NULL),
767: 0, &thread_main_id);
768: if(!thread_main_window || !thread_main_id)
769: logmsg("cannot start main window loop");
770: #endif
771: }
772:
773: void restore_signal_handlers(bool keep_sigalrm)
774: {
775: #ifdef SIGHUP
776: if(SIG_ERR != old_sighup_handler)
777: (void)signal(SIGHUP, old_sighup_handler);
778: #endif
779: #ifdef SIGPIPE
780: if(SIG_ERR != old_sigpipe_handler)
781: (void)signal(SIGPIPE, old_sigpipe_handler);
782: #endif
783: #ifdef SIGALRM
784: if(!keep_sigalrm) {
785: if(SIG_ERR != old_sigalrm_handler)
786: (void)signal(SIGALRM, old_sigalrm_handler);
787: }
788: #else
789: (void)keep_sigalrm;
790: #endif
791: #ifdef SIGINT
792: if(SIG_ERR != old_sigint_handler)
793: (void)signal(SIGINT, old_sigint_handler);
794: #endif
795: #ifdef SIGTERM
796: if(SIG_ERR != old_sigterm_handler)
797: (void)signal(SIGTERM, old_sigterm_handler);
798: #endif
799: #if defined(SIGBREAK) && defined(WIN32)
800: if(SIG_ERR != old_sigbreak_handler)
801: (void)signal(SIGBREAK, old_sigbreak_handler);
802: #endif
803: #ifdef WIN32
804: (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);
805: if(thread_main_window && thread_main_id) {
806: if(PostThreadMessage(thread_main_id, WM_APP, 0, 0))
807: (void)WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE);
808: }
809: #endif
810: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>