]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/cygserver.cc
newlib: Add more FreeBSD files for non LDBL_EQ_DBL support
[newlib-cygwin.git] / winsup / cygserver / cygserver.cc
CommitLineData
f449bfef
RC
1/* cygserver.cc
2
f449bfef
RC
3 Written by Egor Duda <deo@logos-m.ru>
4
1c001dd2 5This file is part of Cygwin.
f449bfef 6
1c001dd2
CS
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
10
282113ba 11#ifdef __OUTSIDE_CYGWIN__
1c001dd2 12#include "woutsup.h"
f449bfef 13
f449bfef 14#include <sys/types.h>
1c001dd2
CS
15
16#include <assert.h>
1dcd520b 17#include <errno.h>
1c001dd2 18#include <ctype.h>
1c001dd2 19#include <getopt.h>
f449bfef 20#include <signal.h>
1c001dd2 21#include <stdio.h>
59a2339f 22#include <stdlib.h>
1c001dd2
CS
23#include <string.h>
24#include <unistd.h>
f449bfef 25
1c001dd2 26#include "cygwin_version.h"
f449bfef 27
56797078 28#include "cygserver.h"
282113ba
CV
29#include "process.h"
30#include "transport.h"
f449bfef 31
282113ba
CV
32#include "cygserver_ipc.h"
33#include "cygserver_msg.h"
34#include "cygserver_sem.h"
1c001dd2 35
282113ba 36#define DEF_CONFIG_FILE "" SYSCONFDIR "/cygserver.conf"
1c001dd2 37
2d015bd6 38#define SERVER_VERSION "1.20"
1c001dd2
CS
39
40GENERIC_MAPPING access_mapping;
41
282113ba 42static bool
f449bfef
RC
43setup_privileges ()
44{
45 BOOL rc, ret_val;
46 HANDLE hToken = NULL;
47 TOKEN_PRIVILEGES sPrivileges;
48
1c001dd2 49 rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
73ea29f4 50 if (!rc)
f449bfef 51 {
61522196 52 debug ("error opening process token (err %u)", GetLastError ());
282113ba 53 return false;
f449bfef 54 }
73ea29f4
CF
55 rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
56 if (!rc)
f449bfef 57 {
61522196 58 debug ("error getting privilege luid (err %u)", GetLastError ());
282113ba 59 ret_val = false;
f449bfef
RC
60 goto out;
61 }
62 sPrivileges.PrivilegeCount = 1 ;
63 sPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
73ea29f4
CF
64 rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
65 if (!rc)
f449bfef 66 {
61522196 67 debug ("error adjusting privilege level. (err %u)", GetLastError ());
282113ba 68 ret_val = false;
f449bfef
RC
69 goto out;
70 }
71
72 access_mapping.GenericRead = FILE_READ_DATA;
73 access_mapping.GenericWrite = FILE_WRITE_DATA;
74 access_mapping.GenericExecute = 0;
75 access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA;
76
282113ba 77 ret_val = true;
f449bfef
RC
78
79out:
73ea29f4 80 CloseHandle (hToken);
f449bfef
RC
81 return ret_val;
82}
83
84int
85check_and_dup_handle (HANDLE from_process, HANDLE to_process,
86 HANDLE from_process_token,
73ea29f4
CF
87 DWORD access,
88 HANDLE from_handle,
1c001dd2 89 HANDLE *to_handle_ptr, BOOL bInheritHandle = FALSE)
f449bfef
RC
90{
91 HANDLE local_handle = NULL;
92 int ret_val = EACCES;
7131554a
CV
93 char sd_buf [1024];
94 PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf;
95 DWORD bytes_needed;
96 PRIVILEGE_SET ps;
97 DWORD ps_len = sizeof (ps);
98 BOOL status;
f449bfef
RC
99
100 if (from_process != GetCurrentProcess ())
73ea29f4 101 {
1c001dd2
CS
102 if (!DuplicateHandle (from_process, from_handle,
103 GetCurrentProcess (), &local_handle,
104 0, bInheritHandle,
105 DUPLICATE_SAME_ACCESS))
106 {
61522196
CV
107 log (LOG_ERR, "error getting handle(%p) to server (err %u)",
108 from_handle, GetLastError ());
1c001dd2
CS
109 goto out;
110 }
111 } else
112 local_handle = from_handle;
f449bfef 113
7131554a
CV
114 if (!GetKernelObjectSecurity (local_handle,
115 (OWNER_SECURITY_INFORMATION
116 | GROUP_SECURITY_INFORMATION
117 | DACL_SECURITY_INFORMATION),
118 sd, sizeof (sd_buf), &bytes_needed))
f449bfef 119 {
61522196 120 log (LOG_ERR, "error getting handle SD (err %u)", GetLastError ());
7131554a
CV
121 goto out;
122 }
f449bfef 123
7131554a 124 MapGenericMask (&access, &access_mapping);
f449bfef 125
7131554a
CV
126 if (!AccessCheck (sd, from_process_token, access, &access_mapping,
127 &ps, &ps_len, &access, &status))
128 {
61522196 129 log (LOG_ERR, "error checking access rights (err %u)", GetLastError ());
7131554a
CV
130 goto out;
131 }
f449bfef 132
7131554a
CV
133 if (!status)
134 {
135 log (LOG_ERR, "access to object denied");
136 goto out;
f449bfef
RC
137 }
138
139 if (!DuplicateHandle (from_process, from_handle,
73ea29f4
CF
140 to_process, to_handle_ptr,
141 access, bInheritHandle, 0))
f449bfef 142 {
61522196 143 log (LOG_ERR, "error getting handle to client (err %u)", GetLastError ());
f449bfef
RC
144 goto out;
145 }
1c001dd2 146
282113ba 147 debug ("Duplicated %p to %p", from_handle, *to_handle_ptr);
f449bfef
RC
148
149 ret_val = 0;
73ea29f4 150
1c001dd2 151 out:
f449bfef
RC
152 if (local_handle && from_process != GetCurrentProcess ())
153 CloseHandle (local_handle);
154
155 return (ret_val);
156}
157
1c001dd2
CS
158/*
159 * client_request_attach_tty::serve ()
160 */
f449bfef
RC
161
162void
1c001dd2
CS
163client_request_attach_tty::serve (transport_layer_base *const conn,
164 process_cache *)
f449bfef 165{
1c001dd2
CS
166 assert (conn);
167
168 assert (!error_code ());
f449bfef 169
1c001dd2 170 if (msglen () != sizeof (req))
f449bfef 171 {
282113ba 172 log (LOG_ERR, "bad request body length: expecting %lu bytes, got %lu",
1c001dd2
CS
173 sizeof (req), msglen ());
174 error_code (EINVAL);
175 msglen (0);
176 return;
f449bfef
RC
177 }
178
1c001dd2 179 msglen (0); // Until we fill in some fields.
73ea29f4 180
681bb2f7 181 debug ("pid %d:(%p,%p) -> pid %d", req.master_pid, req.from_master,
282113ba 182 req.to_master, req.pid);
f449bfef 183
681bb2f7 184 debug ("opening process %d", req.master_pid);
f449bfef 185
1c001dd2
CS
186 const HANDLE from_process_handle =
187 OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
188
189 if (!from_process_handle)
f449bfef 190 {
61522196 191 log (LOG_ERR, "error opening `from' process (err %u)", GetLastError ());
1c001dd2
CS
192 error_code (EACCES);
193 return;
f449bfef
RC
194 }
195
681bb2f7 196 debug ("opening process %d", req.pid);
1c001dd2
CS
197
198 const HANDLE to_process_handle =
199 OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
200
201 if (!to_process_handle)
f449bfef 202 {
61522196 203 log (LOG_ERR, "error opening `to' process (err %u)", GetLastError ());
1c001dd2
CS
204 CloseHandle (from_process_handle);
205 error_code (EACCES);
206 return;
f449bfef
RC
207 }
208
282113ba
CV
209 debug ("Impersonating client");
210 if (!conn->impersonate_client ())
211 {
212 CloseHandle (from_process_handle);
213 CloseHandle (to_process_handle);
214 error_code (EACCES);
215 return;
216 }
1c001dd2
CS
217
218 HANDLE token_handle = NULL;
219
282113ba 220 debug ("about to open thread token");
1c001dd2
CS
221 const DWORD rc = OpenThreadToken (GetCurrentThread (),
222 TOKEN_QUERY,
223 TRUE,
224 &token_handle);
225
61522196 226 debug ("opened thread token, rc=%u", rc);
282113ba
CV
227 if (!conn->revert_to_self ())
228 {
229 CloseHandle (from_process_handle);
230 CloseHandle (to_process_handle);
231 error_code (EACCES);
232 return;
233 }
1c001dd2
CS
234
235 if (!rc)
f449bfef 236 {
61522196 237 log (LOG_ERR, "error opening thread token (err %u)", GetLastError ());
1c001dd2
CS
238 CloseHandle (from_process_handle);
239 CloseHandle (to_process_handle);
240 error_code (EACCES);
241 return;
f449bfef
RC
242 }
243
1c001dd2 244 // From this point on, a reply body is returned to the client.
f449bfef 245
1c001dd2
CS
246 const HANDLE from_master = req.from_master;
247 const HANDLE to_master = req.to_master;
f449bfef 248
1c001dd2
CS
249 req.from_master = NULL;
250 req.to_master = NULL;
251
252 msglen (sizeof (req));
253
254 if (from_master)
255 if (check_and_dup_handle (from_process_handle, to_process_handle,
256 token_handle,
257 GENERIC_READ,
258 from_master,
259 &req.from_master, TRUE) != 0)
260 {
61522196 261 log (LOG_ERR, "error duplicating from_master handle (err %u)",
1c001dd2
CS
262 GetLastError ());
263 error_code (EACCES);
264 }
265
266 if (to_master)
267 if (check_and_dup_handle (from_process_handle, to_process_handle,
268 token_handle,
269 GENERIC_WRITE,
270 to_master,
271 &req.to_master, TRUE) != 0)
272 {
61522196 273 log (LOG_ERR, "error duplicating to_master handle (err %u)",
1c001dd2
CS
274 GetLastError ());
275 error_code (EACCES);
276 }
277
278 CloseHandle (from_process_handle);
279 CloseHandle (to_process_handle);
280 CloseHandle (token_handle);
281
61522196
CV
282 debug ("%u(%p, %p) -> %u(%p,%p)", req.master_pid, from_master, to_master,
283 req.pid, req.from_master, req.to_master);
1c001dd2
CS
284
285 return;
f449bfef
RC
286}
287
288void
1c001dd2 289client_request_get_version::serve (transport_layer_base *, process_cache *)
f449bfef 290{
1c001dd2
CS
291 assert (!error_code ());
292
293 if (msglen ())
282113ba 294 log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
1c001dd2
CS
295
296 msglen (sizeof (version));
297
f449bfef
RC
298 version.major = CYGWIN_SERVER_VERSION_MAJOR;
299 version.api = CYGWIN_SERVER_VERSION_API;
300 version.minor = CYGWIN_SERVER_VERSION_MINOR;
301 version.patch = CYGWIN_SERVER_VERSION_PATCH;
302}
303
304class server_request : public queue_request
305{
1c001dd2
CS
306public:
307 server_request (transport_layer_base *const conn, process_cache *const cache)
308 : _conn (conn), _cache (cache)
309 {}
f449bfef 310
1c001dd2
CS
311 virtual ~server_request ()
312 {
282113ba 313 delete _conn;
1c001dd2 314 }
f449bfef 315
1c001dd2
CS
316 virtual void process ()
317 {
318 client_request::handle_request (_conn, _cache);
319 }
320
321private:
322 transport_layer_base *const _conn;
323 process_cache *const _cache;
f449bfef 324};
f449bfef 325
1c001dd2 326class server_submission_loop : public queue_submission_loop
f449bfef 327{
1c001dd2
CS
328public:
329 server_submission_loop (threaded_queue *const queue,
330 transport_layer_base *const transport,
331 process_cache *const cache)
332 : queue_submission_loop (queue, false),
333 _transport (transport),
334 _cache (cache)
f449bfef 335 {
1c001dd2
CS
336 assert (_transport);
337 assert (_cache);
f449bfef 338 }
f449bfef 339
1c001dd2
CS
340private:
341 transport_layer_base *const _transport;
342 process_cache *const _cache;
343
344 virtual void request_loop ();
345};
346
347/* FIXME: this is a little ugly. What we really want is to wait on
348 * two objects: one for the pipe/socket, and one for being told to
349 * shutdown. Otherwise this will stay a problem (we won't actually
350 * shutdown until the request _AFTER_ the shutdown request. And
351 * sending ourselves a request is ugly
352 */
f449bfef 353void
1c001dd2 354server_submission_loop::request_loop ()
f449bfef 355{
1c001dd2
CS
356 /* I'd like the accepting thread's priority to be above any "normal"
357 * thread in the system to avoid overflowing the listen queue (for
358 * sockets; similar issues exist for named pipes); but, for example,
359 * a normal priority thread in a foregrounded process is boosted to
360 * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current
361 * thread's priority to a level one above that. This fails on
362 * win9x/ME so assume any failure in that call is due to that and
363 * simply call again at one priority level lower.
7131554a
CV
364 * FIXME: This looks weird and is an issue on NT, too. Per MSDN,
365 * THREAD_PRIORITY_HIGHEST + 1 is only a valid priority level if
366 * the priority class is set to REALTIME_PRIORITY_CLASS.
1c001dd2
CS
367 */
368 if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
369 if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
61522196 370 debug ("failed to raise accept thread priority (err %u)",
282113ba 371 GetLastError ());
1c001dd2
CS
372
373 while (_running)
374 {
375 bool recoverable = false;
376 transport_layer_base *const conn = _transport->accept (&recoverable);
377 if (!conn && !recoverable)
378 {
282113ba 379 log (LOG_ERR, "fatal error on IPC transport: closing down");
1c001dd2
CS
380 return;
381 }
382 // EINTR probably implies a shutdown request; so back off for a
383 // moment to let the main thread take control, otherwise the
384 // server spins here receiving EINTR repeatedly since the signal
385 // handler in the main thread doesn't get a chance to be called.
386 if (!conn && errno == EINTR)
387 {
388 if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
61522196 389 debug ("failed to reset thread priority (err %u)",
282113ba 390 GetLastError ());
1c001dd2
CS
391
392 Sleep (0);
393 if (!SetThreadPriority (GetCurrentThread (),
394 THREAD_PRIORITY_HIGHEST + 1))
395 if (!SetThreadPriority (GetCurrentThread (),
396 THREAD_PRIORITY_HIGHEST))
61522196 397 debug ("failed to raise thread priority (err %u)",
282113ba 398 GetLastError ());
1c001dd2
CS
399 }
400 if (conn)
282113ba 401 _queue->add (new server_request (conn, _cache));
1c001dd2
CS
402 }
403}
404
405client_request_shutdown::client_request_shutdown ()
406 : client_request (CYGSERVER_REQUEST_SHUTDOWN)
407{
f449bfef
RC
408}
409
410void
1c001dd2 411client_request_shutdown::serve (transport_layer_base *, process_cache *)
f449bfef 412{
1c001dd2
CS
413 assert (!error_code ());
414
415 if (msglen ())
282113ba 416 log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
1c001dd2 417
f449bfef
RC
418 /* FIXME: link upwards, and then this becomes a trivial method call to
419 * only shutdown _this queue_
420 */
1c001dd2
CS
421
422 kill (getpid (), SIGINT);
423
424 msglen (0);
f449bfef
RC
425}
426
1c001dd2
CS
427static sig_atomic_t shutdown_server = false;
428
429static void
430handle_signal (const int signum)
f449bfef 431{
1c001dd2
CS
432 /* any signal makes us die :} */
433
434 shutdown_server = true;
f449bfef
RC
435}
436
1c001dd2
CS
437/*
438 * print_usage ()
439 */
440
441static void
442print_usage (const char *const pgm)
f449bfef 443{
282113ba 444 log (LOG_NOTICE, "Usage: %s [OPTIONS]\n"
9e9bc3a4
CV
445"\n"
446"Cygwin background service daemon\n"
447"\n"
282113ba 448"Configuration option:\n"
9e9bc3a4 449"\n"
282113ba 450" -f, --config-file <file> Use <file> as config file. Default is\n"
e74c79a8 451" " DEF_CONFIG_FILE "\n"
282113ba
CV
452"\n"
453"Performance options:\n"
9e9bc3a4 454"\n"
282113ba 455" -c, --cleanup-threads <num> Number of cleanup threads to use.\n"
2d015bd6 456" -p, --process-cache <num> Size of process cache.\n"
282113ba
CV
457" -r, --request-threads <num> Number of request threads to use.\n"
458"\n"
459"Logging options:\n"
9e9bc3a4 460"\n"
282113ba
CV
461" -d, --debug Log debug messages to stderr.\n"
462" -e, --stderr Log to stderr (default if stderr is a tty).\n"
463" -E, --no-stderr Don't log to stderr (see -y, -Y options).\n"
282113ba
CV
464" -l, --log-level <level> Verbosity of logging (1..7). Default: 6\n"
465" -y, --syslog Log to syslog (default if stderr is no tty).\n"
466" -Y, --no-syslog Don't log to syslog (See -e, -E options).\n"
467"\n"
468"Support options:\n"
9e9bc3a4 469"\n"
282113ba
CV
470" -m, --no-sharedmem Don't start XSI Shared Memory support.\n"
471" -q, --no-msgqueues Don't start XSI Message Queue support.\n"
472" -s, --no-semaphores Don't start XSI Semaphore support.\n"
473"\n"
474"Miscellaneous:\n"
9e9bc3a4 475"\n"
282113ba
CV
476" -S, --shutdown Shutdown the daemon.\n"
477" -h, --help Output usage information and exit.\n"
9e9bc3a4 478" -V, --version Output version information and exit.\n"
282113ba 479, pgm);
1c001dd2 480}
f449bfef 481
1c001dd2
CS
482/*
483 * print_version ()
484 */
f449bfef 485
1c001dd2 486static void
282113ba 487print_version ()
1c001dd2 488{
9e9bc3a4
CV
489 log (LOG_INFO,
490 "cygserver (cygwin) %d.%d.%d\n"
491 "Cygwin background service daemon\n"
6e623e93 492 "Copyright (C) 2001 - %s Cygwin Authors\n"
9e9bc3a4
CV
493 "This is free software; see the source for copying conditions. There is NO\n"
494 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
495 CYGWIN_VERSION_DLL_MAJOR / 1000,
496 CYGWIN_VERSION_DLL_MAJOR % 1000,
497 CYGWIN_VERSION_DLL_MINOR,
498 strrchr (__DATE__, ' ') + 1);
f449bfef
RC
499}
500
1c001dd2
CS
501/*
502 * main ()
503 */
f449bfef 504
1c001dd2
CS
505int
506main (const int argc, char *argv[])
f449bfef 507{
1c001dd2
CS
508 const struct option longopts[] = {
509 {"cleanup-threads", required_argument, NULL, 'c'},
282113ba
CV
510 {"debug", no_argument, NULL, 'd'},
511 {"stderr", no_argument, NULL, 'e'},
512 {"no-stderr", no_argument, NULL, 'E'},
513 {"config-file", required_argument, NULL, 'f'},
1c001dd2 514 {"help", no_argument, NULL, 'h'},
282113ba
CV
515 {"log-level", required_argument, NULL, 'l'},
516 {"no-sharedmem", no_argument, NULL, 'm'},
2d015bd6 517 {"process-cache", required_argument, NULL, 'p'},
282113ba 518 {"no-msgqueues", no_argument, NULL, 'q'},
1c001dd2 519 {"request-threads", required_argument, NULL, 'r'},
282113ba
CV
520 {"no-semaphores", no_argument, NULL, 's'},
521 {"shutdown", no_argument, NULL, 'S'},
9e9bc3a4 522 {"version", no_argument, NULL, 'V'},
282113ba
CV
523 {"syslog", no_argument, NULL, 'y'},
524 {"no-syslog", no_argument, NULL, 'Y'},
1c001dd2
CS
525 {0, no_argument, NULL, 0}
526 };
f449bfef 527
9e9bc3a4 528 const char opts[] = "c:deEf:hl:mp:qr:sSVyY";
f449bfef 529
61522196
CV
530 int32_t cleanup_threads = 0;
531 int32_t request_threads = 0;
532 int32_t process_cache_size = 0;
1c001dd2 533 bool shutdown = false;
282113ba
CV
534 const char *config_file = DEF_CONFIG_FILE;
535 bool force_config_file = false;
536 tun_bool_t option_log_stderr = TUN_UNDEF;
537 tun_bool_t option_log_syslog = TUN_UNDEF;
538
539 char *c = NULL;
540
541 /* Check if we have a terminal. If so, default to stderr logging,
542 otherwise default to syslog logging. This must be done early
543 to allow default logging already in option processing state. */
544 openlog ("cygserver", LOG_PID, LOG_KERN);
545 if (isatty (2))
546 log_stderr = TUN_TRUE;
1c001dd2 547 else
282113ba 548 log_syslog = TUN_TRUE;
1c001dd2
CS
549
550 int opt;
551
2d015bd6 552 securityinit ();
c9508cb4 553
282113ba 554 opterr = 0;
1c001dd2
CS
555 while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
556 switch (opt)
f449bfef 557 {
1c001dd2 558 case 'c':
282113ba
CV
559 c = NULL;
560 cleanup_threads = strtol (optarg, &c, 10);
2d015bd6
CV
561 if (cleanup_threads <= 0 || cleanup_threads > 32 || (c && *c))
562 panic ("Number of cleanup threads must be between 1 and 32");
282113ba
CV
563 break;
564
565 case 'd':
566 log_debug = TUN_TRUE;
567 break;
568
569 case 'e':
570 option_log_stderr = TUN_TRUE;
571 break;
572
573 case 'E':
574 option_log_stderr = TUN_FALSE;
1c001dd2
CS
575 break;
576
282113ba
CV
577 case 'f':
578 config_file = optarg;
579 force_config_file = true;
580 break;
581
1c001dd2 582 case 'h':
282113ba 583 print_usage (getprogname ());
1c001dd2
CS
584 return 0;
585
282113ba
CV
586 case 'l':
587 c = NULL;
588 log_level = strtoul (optarg, &c, 10);
589 if (!log_level || log_level > 7 || (c && *c))
590 panic ("Log level must be between 1 and 7");
591 break;
592
593 case 'm':
594 support_sharedmem = TUN_FALSE;
595 break;
596
2d015bd6
CV
597 case 'p':
598 c = NULL;
599 process_cache_size = strtol (optarg, &c, 10);
600 if (process_cache_size <= 0 || process_cache_size > 310 || (c && *c))
601 panic ("Size of process cache must be between 1 and 310");
602 break;
603
282113ba
CV
604 case 'q':
605 support_msgqueues = TUN_FALSE;
606 break;
607
1c001dd2 608 case 'r':
282113ba
CV
609 c = NULL;
610 request_threads = strtol (optarg, &c, 10);
2d015bd6
CV
611 if (request_threads <= 0 || request_threads > 310 || (c && *c))
612 panic ("Number of request threads must be between 1 and 310");
73ea29f4 613 break;
1c001dd2
CS
614
615 case 's':
282113ba
CV
616 support_semaphores = TUN_FALSE;
617 break;
618
619 case 'S':
1c001dd2 620 shutdown = true;
73ea29f4 621 break;
1c001dd2 622
9e9bc3a4 623 case 'V':
282113ba 624 print_version ();
1c001dd2
CS
625 return 0;
626
282113ba
CV
627 case 'y':
628 option_log_syslog = TUN_TRUE;
629 break;
630
631 case 'Y':
632 option_log_syslog = TUN_FALSE;
633 break;
634
1c001dd2 635 case '?':
282113ba
CV
636 panic ("unknown option -- %c\n"
637 "Try `%s --help' for more information.", optopt, getprogname ());
f449bfef
RC
638 }
639
1c001dd2 640 if (optind != argc)
282113ba 641 panic ("Too many arguments");
f449bfef
RC
642
643 if (shutdown)
644 {
1c001dd2
CS
645 /* Setting `cygserver_running' stops the request code making a
646 * version request, which is not much to the point.
647 */
648 cygserver_running = CYGSERVER_OK;
649
650 client_request_shutdown req;
651
652 if (req.make_request () == -1 || req.error_code ())
282113ba 653 panic("Shutdown request failed: %s", strerror (req.error_code ()));
1c001dd2
CS
654
655 // FIXME: It would be nice to wait here for the daemon to exit.
656
657 return 0;
f449bfef
RC
658 }
659
1c001dd2
CS
660 SIGHANDLE (SIGHUP);
661 SIGHANDLE (SIGINT);
662 SIGHANDLE (SIGTERM);
663
282113ba
CV
664 tunable_param_init (config_file, force_config_file);
665
666 loginit (option_log_stderr, option_log_syslog);
667
668 log (LOG_INFO, "daemon starting up");
669
670 if (!cleanup_threads)
671 TUNABLE_INT_FETCH ("kern.srv.cleanup_threads", &cleanup_threads);
672 if (!cleanup_threads)
673 cleanup_threads = 2;
1c001dd2 674
282113ba
CV
675 if (!request_threads)
676 TUNABLE_INT_FETCH ("kern.srv.request_threads", &request_threads);
677 if (!request_threads)
678 request_threads = 10;
679
2d015bd6
CV
680 if (!process_cache_size)
681 TUNABLE_INT_FETCH ("kern.srv.process_cache_size", &process_cache_size);
682 if (!process_cache_size)
683 process_cache_size = 62;
684
282113ba
CV
685 if (support_sharedmem == TUN_UNDEF)
686 TUNABLE_BOOL_FETCH ("kern.srv.sharedmem", &support_sharedmem);
687 if (support_sharedmem == TUN_UNDEF)
688 support_sharedmem = TUN_TRUE;
689
690 if (support_msgqueues == TUN_UNDEF)
691 TUNABLE_BOOL_FETCH ("kern.srv.msgqueues", &support_msgqueues);
692 if (support_msgqueues == TUN_UNDEF)
693 support_msgqueues = TUN_TRUE;
694
695 if (support_semaphores == TUN_UNDEF)
696 TUNABLE_BOOL_FETCH ("kern.srv.semaphores", &support_semaphores);
697 if (support_semaphores == TUN_UNDEF)
698 support_semaphores = TUN_TRUE;
699
7131554a 700 if (!setup_privileges ())
282113ba
CV
701 panic ("Setting process privileges failed.");
702
1d88f8ce
CV
703 ipcinit ();
704
282113ba 705 /*XXXXX*/
1c001dd2 706 threaded_queue request_queue (request_threads);
1c001dd2
CS
707
708 transport_layer_base *const transport = create_server_transport ();
709 assert (transport);
1c001dd2 710
5ed0628c
CV
711 if (transport->listen () == -1)
712 return 1;
713
2d015bd6 714 process_cache cache (process_cache_size, cleanup_threads);
1c001dd2
CS
715
716 server_submission_loop submission_loop (&request_queue, transport, &cache);
1c001dd2
CS
717
718 request_queue.add_submission_loop (&submission_loop);
1c001dd2 719
1c001dd2 720 cache.start ();
1c001dd2
CS
721
722 request_queue.start ();
1c001dd2 723
282113ba 724 log (LOG_NOTICE, "Initialization complete. Waiting for requests.");
1c001dd2
CS
725
726 /* TODO: wait on multiple objects - the thread handle for each
727 * request loop + all the process handles. This should be done by
728 * querying the request_queue and the process cache for all their
729 * handles, and then waiting for (say) 30 seconds. after that we
730 * recreate the list of handles to wait on, and wait again. the
731 * point of all this abstraction is that we can trivially server
732 * both sockets and pipes simply by making a new transport, and then
733 * calling request_queue.process_requests (transport2);
f449bfef
RC
734 */
735 /* WaitForMultipleObjects abort && request_queue && process_queue && signal
736 -- if signal event then retrigger it
1c001dd2
CS
737 */
738 while (!shutdown_server && request_queue.running () && cache.running ())
282113ba
CV
739 {
740 pause ();
741 if (ipcunload ())
742 {
743 shutdown_server = false;
744 log (LOG_WARNING, "Shutdown request received but ignored. "
745 "Dependent processes still running.");
746 }
747 }
1c001dd2 748
282113ba 749 log (LOG_INFO, "Shutdown request received - new requests will be denied");
1c001dd2 750 request_queue.stop ();
282113ba
CV
751 log (LOG_INFO, "All pending requests processed");
752 delete transport;
753 log (LOG_INFO, "No longer accepting requests - cygwin will operate in daemonless mode");
1c001dd2 754 cache.stop ();
282113ba
CV
755 log (LOG_INFO, "All outstanding process-cache activities completed");
756 log (LOG_NOTICE, "Shutdown finished.");
1c001dd2
CS
757
758 return 0;
f449bfef 759}
282113ba 760#endif /* __OUTSIDE_CYGWIN__ */
This page took 0.363949 seconds and 6 git commands to generate.