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