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