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