]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/bsd_helper.cc
Cygwin: set NTDDI_VERSION to enable more recent windows definitions
[newlib-cygwin.git] / winsup / cygserver / bsd_helper.cc
CommitLineData
282113ba
CV
1/* bsd_helper.cc
2
282113ba
CV
3This file is part of Cygwin.
4
5This software is a copyrighted work licensed under the terms of the
6Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7details. */
8#ifdef __OUTSIDE_CYGWIN__
9#include "woutsup.h"
1dcd520b 10#include <errno.h>
282113ba
CV
11#define _KERNEL 1
12#define __BSD_VISIBLE 1
13#include <sys/smallprint.h>
14#include <sys/cygwin.h>
15#include <sys/ipc.h>
16#include <sys/param.h>
17#include <sys/msg.h>
18#include <sys/queue.h>
19#include <malloc.h>
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24
282113ba
CV
25#include "cygserver.h"
26#include "process.h"
27#include "cygserver_ipc.h"
28#include "cygserver_msg.h"
29#include "cygserver_sem.h"
30#include "cygserver_shm.h"
31
32/*
33 * Copy a piece of memory from the client process into the server process.
34 * Returns an error code.
35 */
36int
37win_copyin (struct thread *td, const void *client_src,
38 void *server_tgt, size_t len)
39{
40 if (!ReadProcessMemory (td->client->handle (), client_src, server_tgt,
41 len, NULL))
42 return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
43 GetLastError (), EINVAL);
44 return 0;
45}
46
47/*
48 * Copy a piece of memory from the server process into the client process.
49 * Returns an error code.
50 */
51int
52win_copyout (struct thread *td, const void *server_src,
53 void *client_tgt, size_t len)
54{
55 if (!WriteProcessMemory (td->client->handle (), client_tgt, server_src,
56 len, NULL))
57 return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
58 GetLastError (), EINVAL);
59 return 0;
60}
61
62#define enter_critical_section(c) _enter_critical_section((c),__FILE__,__LINE__)
63static void
64_enter_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
65{
663b4ab8 66 _debug (file, line, "Try enter critical section(%p)", pcs);
282113ba 67 EnterCriticalSection (pcs);
663b4ab8 68 _debug (file, line, "Entered critical section(%p)", pcs);
282113ba
CV
69}
70
71#define leave_critical_section(c) _leave_critical_section((c),__FILE__,__LINE__)
72static void
73_leave_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
74{
75 LeaveCriticalSection (pcs);
663b4ab8 76 _debug (file, line, "Left critical section(%p)", pcs);
282113ba
CV
77}
78
79CRITICAL_SECTION ipcht_cs;
80
81struct ipc_hookthread_storage {
82 HANDLE process_hdl;
83 proc ipcblk;
84};
85
86struct ipc_hookthread {
96e949de 87 SLIST_ENTRY (ipc_hookthread) sht_next;
282113ba
CV
88 HANDLE thread;
89 DWORD winpid;
90 struct vmspace vmspace;
91};
96e949de 92static SLIST_HEAD (, ipc_hookthread) ipcht_list; /* list of hook threads */
282113ba
CV
93
94static HANDLE ipcexit_event;
95
96struct vmspace *
97ipc_p_vmspace (struct proc *proc)
98{
99 struct vmspace *ret = NULL;
100 ipc_hookthread *ipcht_entry;
101 enter_critical_section (&ipcht_cs);
102 SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
103 {
104 if (ipcht_entry->winpid == proc->winpid)
105 {
106 ret = proc->p_vmspace = &ipcht_entry->vmspace;
107 break;
108 }
109 }
110 leave_critical_section (&ipcht_cs);
111 return ret;
112}
113
114static DWORD WINAPI
96e949de 115ipcexit_hookthread (const LPVOID param)
282113ba
CV
116{
117 ipc_hookthread_storage *shs = (ipc_hookthread_storage *) param;
118 HANDLE obj[2] = { ipcexit_event, shs->process_hdl };
119 switch (WaitForMultipleObjects (2, obj, FALSE, INFINITE))
120 {
121 case WAIT_OBJECT_0:
122 /* Cygserver shutdown. */
225d376b 123 fallthrough;
282113ba
CV
124 case WAIT_OBJECT_0 + 1:
125 /* Process exited. Call semexit_myhook to handle SEM_UNDOs for the
126 exiting process and shmexit_myhook to keep track of shared
127 memory. */
128 if (Giant.owner == shs->ipcblk.winpid)
dafef5e2 129 mtx_unlock (&Giant);
282113ba
CV
130 if (support_semaphores == TUN_TRUE)
131 semexit_myhook (NULL, &shs->ipcblk);
132 if (support_sharedmem == TUN_TRUE)
133 {
134 _mtx_lock (&Giant, shs->ipcblk.winpid, __FILE__, __LINE__);
135 ipc_p_vmspace (&shs->ipcblk);
136 shmexit_myhook (shs->ipcblk.p_vmspace);
137 mtx_unlock (&Giant);
138 }
139 break;
140 default:
141 /* FIXME: Panic? */
142 break;
143 }
144 CloseHandle (shs->process_hdl);
145 ipc_hookthread *ipcht_entry, *sav_entry;
146 enter_critical_section (&ipcht_cs);
147 SLIST_FOREACH_SAFE (ipcht_entry, &ipcht_list, sht_next, sav_entry)
148 {
149 if (ipcht_entry->winpid == shs->ipcblk.winpid)
150 {
151 SLIST_REMOVE (&ipcht_list, ipcht_entry, ipc_hookthread, sht_next);
dafef5e2 152 CloseHandle (ipcht_entry->thread);
282113ba
CV
153 delete ipcht_entry;
154 }
155 }
156 leave_critical_section (&ipcht_cs);
157 delete shs;
158 return 0;
159}
160
161/* Deletes all pending hook threads. Called by ipcunload() which in turn
162 is called by the cygserver main routine. */
163static void
96e949de 164ipcexit_dispose_hookthreads (void)
282113ba
CV
165{
166 SetEvent (ipcexit_event);
167 ipc_hookthread *ipcht_entry;
168 enter_critical_section (&ipcht_cs);
169 SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
170 {
171 WaitForSingleObject (ipcht_entry->thread, 1000);
172 /* Don't bother removing the linked list on cygserver shutdown. */
173 /* FIXME: Error handling? */
174 }
175 leave_critical_section (&ipcht_cs);
176}
177
178/* Creates the per process wait thread. Called by semget() under locked
179 Giant mutex condition. */
180int
96e949de 181ipcexit_creat_hookthread (struct thread *td)
282113ba
CV
182{
183 ipc_hookthread *ipcht_entry;
184 int ret = -1;
185 enter_critical_section (&ipcht_cs);
186 SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
187 {
188 if (ipcht_entry->winpid == td->ipcblk->winpid)
189 ret = 0;
190 }
191 leave_critical_section (&ipcht_cs);
192 if (!ret)
193 return 0;
194
195 DWORD tid;
196 ipc_hookthread_storage *shs = new ipc_hookthread_storage;
197 if (!DuplicateHandle (GetCurrentProcess (), td->client->handle (),
198 GetCurrentProcess (), &shs->process_hdl,
199 0, FALSE, DUPLICATE_SAME_ACCESS))
200 {
cf06a0b1 201 delete shs;
681bb2f7 202 log (LOG_CRIT, "failed to duplicate process handle, error = %u",
282113ba
CV
203 GetLastError ());
204 return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
205 GetLastError (), ENOMEM);
206 }
207 shs->ipcblk = *td->ipcblk;
208 HANDLE thread = CreateThread (NULL, 0, ipcexit_hookthread, shs, 0, &tid);
209 if (!thread)
210 {
ca6183c3 211 delete shs;
681bb2f7 212 log (LOG_CRIT, "failed to create thread, error = %u", GetLastError ());
282113ba
CV
213 return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
214 GetLastError (), ENOMEM);
215 }
216 ipcht_entry = new ipc_hookthread;
217 ipcht_entry->thread = thread;
218 ipcht_entry->winpid = td->ipcblk->winpid;
219 ipcht_entry->vmspace.vm_map = NULL;
220 ipcht_entry->vmspace.vm_shm = NULL;
221 enter_critical_section (&ipcht_cs);
222 SLIST_INSERT_HEAD (&ipcht_list, ipcht_entry, sht_next);
223 leave_critical_section (&ipcht_cs);
224 return 0;
225}
226
227/*
228 * Need the admins group SID to compare with groups in client token.
229 */
230PSID admininstrator_group_sid;
231
232static void
233init_admin_sid (void)
234{
7131554a
CV
235 SID_IDENTIFIER_AUTHORITY nt_auth = {SECURITY_NT_AUTHORITY};
236 if (! AllocateAndInitializeSid (&nt_auth, 2, 32, 544, 0, 0, 0, 0, 0, 0,
237 &admininstrator_group_sid))
681bb2f7 238 panic ("failed to create well known sids, error = %u",
7131554a 239 GetLastError ());
282113ba
CV
240}
241
242SECURITY_DESCRIPTOR sec_all_nih_sd;
243SECURITY_ATTRIBUTES sec_all_nih = { sizeof (SECURITY_ATTRIBUTES),
244 &sec_all_nih_sd,
245 FALSE };
246
2d015bd6
CV
247void
248securityinit ()
249{
250 InitializeSecurityDescriptor (&sec_all_nih_sd, SECURITY_DESCRIPTOR_REVISION);
251 SetSecurityDescriptorDacl (&sec_all_nih_sd, TRUE, 0, FALSE);
252 init_admin_sid ();
253}
254
282113ba
CV
255/* Global vars, determining whether the IPC stuff should be started or not. */
256tun_bool_t support_sharedmem = TUN_UNDEF;
257tun_bool_t support_msgqueues = TUN_UNDEF;
258tun_bool_t support_semaphores = TUN_UNDEF;
259
260void
261ipcinit ()
262{
96e949de 263 mtx_init (&Giant, "Giant", NULL, MTX_DEF);
282113ba
CV
264 msleep_init ();
265 ipcexit_event = CreateEvent (NULL, TRUE, FALSE, NULL);
266 if (!ipcexit_event)
267 panic ("Failed to create ipcexit event object");
268 InitializeCriticalSection (&ipcht_cs);
269 if (support_msgqueues == TUN_TRUE)
270 msginit ();
271 if (support_semaphores == TUN_TRUE)
272 seminit ();
273 if (support_sharedmem == TUN_TRUE)
274 shminit ();
275}
276
277int
278ipcunload ()
279{
96e949de 280 ipcexit_dispose_hookthreads ();
282113ba
CV
281 CloseHandle (ipcexit_event);
282 wakeup_all ();
283 if (support_semaphores == TUN_TRUE)
284 semunload ();
285 if (support_sharedmem == TUN_TRUE)
286 shmunload ();
287 if (support_msgqueues == TUN_TRUE)
96e949de
CV
288 msgunload ();
289 mtx_destroy (&Giant);
282113ba
CV
290 return 0;
291}
292
293/*
294 * Helper function to find a gid in a list of gids.
295 */
296static bool
297is_grp_member (gid_t grp, gid_t *grplist, int listsize)
298{
299 if (grplist)
300 for (; listsize > 0; --listsize)
301 if (grp == grplist[listsize - 1])
302 return true;
303 return false;
304}
305
306/*
307 * Helper function to get a specific token information from a token.
308 * This function mallocs the necessary buffer spcae by itself. It
309 * must be free'd by the calling function.
310 */
d4db08d7 311void *
282113ba
CV
312get_token_info (HANDLE tok, TOKEN_INFORMATION_CLASS tic)
313{
314 void *buf;
315 DWORD size;
316
317 if (!GetTokenInformation (tok, tic, NULL, 0, &size)
318 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
319 return NULL;
320 if (!(buf = malloc (size)))
321 return NULL;
322 if (!GetTokenInformation (tok, tic, buf, size, &size))
323 {
324 free (buf);
325 return NULL;
326 }
327 return buf;
328}
329
330/*
331 * Check if client user helds "mode" permission when accessing object
332 * associated with "perm" permission record.
333 * Returns an error code.
334 */
335int
336ipcperm (struct thread *td, ipc_perm *perm, unsigned int mode)
337{
338 proc *p = td->ipcblk;
339
340 if (!suser (td))
341 return 0;
342 if (mode & IPC_M)
343 {
344 return (p->uid != perm->cuid && p->uid != perm->uid)
345 ? EACCES : 0;
346 }
347 if (p->uid != perm->cuid && p->uid != perm->uid)
348 {
349 /* If the user is a member of the creator or owner group, test
350 against group bits, otherwise against other bits. */
351 mode >>= p->gid != perm->gid && p->gid != perm->cgid
352 && !is_grp_member (perm->gid, p->gidlist, p->gidcnt)
353 && !is_grp_member (perm->cgid, p->gidlist, p->gidcnt)
354 ? 6 : 3;
355 }
356 return (mode & perm->mode) != mode ? EACCES : 0;
357}
358
359/*
360 * Check for client user being superuser.
361 * Returns an error code.
362 */
363int
364suser (struct thread *td)
365{
282113ba
CV
366 /* This value has been set at ImpersonateNamedPipeClient() time
367 using the token information. See adjust_identity_info() below. */
368 return td->ipcblk->is_admin ? 0 : EACCES;
369}
370
371/*
372 * Retrieves user and group info from impersonated token and creates the
373 * correct uid, gid, gidlist and is_admin entries in p from that.
374 */
375bool
376adjust_identity_info (struct proc *p)
377{
378 HANDLE tok;
379
282113ba
CV
380 if (!OpenThreadToken (GetCurrentThread (), TOKEN_READ, TRUE, &tok))
381 {
382 debug ("Failed to open worker thread access token for pid %d, winpid %d",
383 p->cygpid, p->winpid);
384 return false;
385 }
386
387 /* Get uid from user SID in token. */
388 PTOKEN_USER user;
389 if (!(user = (PTOKEN_USER)get_token_info (tok, TokenUser)))
390 goto faulty;
391 p->uid = cygwin_internal (CW_GET_UID_FROM_SID, user->User.Sid);
392 free (user);
393 if (p->uid == (uid_t)-1)
394 log (LOG_WARNING, "WARNING: User not found in /etc/passwd! Using uid -1!");
395
396 /* Get gid from primary group SID in token. */
397 PTOKEN_PRIMARY_GROUP pgrp;
398 if (!(pgrp = (PTOKEN_PRIMARY_GROUP)get_token_info (tok, TokenPrimaryGroup)))
399 goto faulty;
400 p->gid = cygwin_internal (CW_GET_GID_FROM_SID, pgrp->PrimaryGroup);
401 free (pgrp);
402 if (p->gid == (gid_t)-1)
0f93784f 403 log (LOG_WARNING,"WARNING: Group not found in /etc/group! Using gid -1!");
282113ba
CV
404
405 /* Generate gid list from token group's SID list. Also look if the token
406 has an enabled admin group SID. That means, the process has admin
407 privileges. That knowledge is used in suser(). */
408 PTOKEN_GROUPS gsids;
409 if (!(gsids = (PTOKEN_GROUPS)get_token_info (tok, TokenGroups)))
410 goto faulty;
411 if (gsids->GroupCount)
412 {
413 p->gidlist = (gid_t *) calloc (gsids->GroupCount, sizeof (gid_t));
414 if (p->gidlist)
415 p->gidcnt = gsids->GroupCount;
416 }
417 for (DWORD i = 0; i < gsids->GroupCount; ++i)
418 {
419 if (p->gidlist)
420 p->gidlist[i] = cygwin_internal (CW_GET_GID_FROM_SID,
421 gsids->Groups[i].Sid);
422 if (EqualSid (gsids->Groups[i].Sid, admininstrator_group_sid)
423 && (gsids->Groups[i].Attributes & SE_GROUP_ENABLED))
424 p->is_admin = true;
425 }
426 free (gsids);
427
428 CloseHandle (tok);
429 return true;
430
431faulty:
432 CloseHandle (tok);
433 log (LOG_CRIT, "Failed to get token information for pid %d, winpid %d",
434 p->cygpid, p->winpid);
435 return false;
436}
437
438/*
439 * Windows wrapper implementation of the VM functions called by sysv_shm.cc.
440 */
441
442vm_object_t
443_vm_pager_allocate (int size, int shmflg)
444{
445 /* Create the file mapping object with full access for everyone. This is
446 necessary to allow later calls to shmctl(..., IPC_SET,...) to
447 change the access rights and ownership of a shared memory region.
448 The access rights are tested at the beginning of every shm... function.
449 Note that this does not influence the actual read or write access
450 defined in a call to shmat. */
451 vm_object_t object = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_all_nih,
452 PAGE_READWRITE, 0, size, NULL);
453 if (!object)
681bb2f7 454 panic ("CreateFileMapping in _vm_pager_allocate failed, %u", GetLastError ());
282113ba
CV
455 return object;
456}
457
458vm_object_t
459vm_object_duplicate (struct thread *td, vm_object_t object)
460{
461 vm_object_t dup_object;
96e949de
CV
462 if (!DuplicateHandle (GetCurrentProcess (), object,
463 td->client->handle (), &dup_object,
464 0, TRUE, DUPLICATE_SAME_ACCESS))
681bb2f7 465 panic ("!DuplicateHandle in vm_object_duplicate failed, %u", GetLastError ());
282113ba
CV
466 return dup_object;
467}
468
469void
470vm_object_deallocate (vm_object_t object)
471{
472 if (object)
473 CloseHandle (object);
474}
475
476/*
477 * Tunable parameters are read from a system wide cygserver.conf file.
478 * On the first call to tunable_int_fetch, the file is read and the
479 * parameters are set accordingly. Each parameter has default, max and
480 * min settings.
481 */
482
483enum tun_params_type {
484 TUN_NULL,
485 TUN_INT,
486 TUN_BOOL
487};
488
489union tun_value {
490 long ival;
491 tun_bool_t bval;
492};
493
494struct tun_struct {
495 const char *name;
496 tun_params_type type;
497 union tun_value value;
498 union tun_value min;
499 union tun_value max;
500 void (*check_func)(tun_struct *, char *, const char *);
501};
502
503static void
504default_tun_check (tun_struct *that, char *value, const char *fname)
505{
506 char *c = NULL;
507 tun_value val;
508 switch (that->type)
509 {
510 case TUN_INT:
511 val.ival = strtoul (value, &c, 10);
512 if (!val.ival || (c && *c))
513 panic ("Error in config file %s: Value of parameter %s malformed",
514 fname, that->name);
515 if (val.ival < that->min.ival || val.ival > that->max.ival)
516 panic ("Error in config file %s: Value of parameter %s must be "
517 "between %lu and %lu",
518 fname, that->name, that->min.ival, that->max.ival);
519 if (that->value.ival)
520 panic ("Error in config file %s: Parameter %s set twice.\n",
521 fname, that->name);
522 that->value.ival = val.ival;
523 break;
524 case TUN_BOOL:
525 if (!strcasecmp (value, "no") || !strcasecmp (value, "n")
526 || !strcasecmp (value, "false") || !strcasecmp (value, "f")
527 || !strcasecmp (value, "0"))
528 val.bval = TUN_FALSE;
529 else if (!strcasecmp (value, "yes") || !strcasecmp (value, "y")
530 || !strcasecmp (value, "true") || !strcasecmp (value, "t")
531 || !strcasecmp (value, "1"))
532 val.bval = TUN_TRUE;
533 else
534 panic ("Error in config file %s: Value of parameter %s malformed\n"
535 "Allowed values: \"yes\", \"no\", \"y\", \"n\", \"true\", \"false\", \"t\", \"f\", \"1\" and \"0\"", fname, that->name);
536 that->value.bval = val.bval;
537 break;
538 default:
539 /* Shouldn't happen. */
540 panic ("Internal error: Wrong type of tunable parameter");
541 break;
542 }
543}
544
545static tun_struct tunable_params[] =
546{
547 /* SRV */
2d015bd6
CV
548 { "kern.srv.cleanup_threads", TUN_INT, {0}, {1}, {32}, default_tun_check},
549 { "kern.srv.request_threads", TUN_INT, {0}, {1}, {310}, default_tun_check},
550 { "kern.srv.process_cache_size", TUN_INT, {0}, {1}, {310}, default_tun_check},
282113ba
CV
551 { "kern.srv.sharedmem", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
552 { "kern.srv.msgqueues", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
553 { "kern.srv.semaphores", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
554
555 /* LOG */
556 { "kern.log.syslog", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
557 { "kern.log.stderr", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
558 { "kern.log.debug", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
559 { "kern.log.level", TUN_INT, {0}, {1}, {7}, default_tun_check},
560
561 /* MSG */
11377ba6 562 { "kern.ipc.msgseg", TUN_INT, {0}, {256}, {65535}, default_tun_check},
282113ba 563 { "kern.ipc.msgssz", TUN_INT, {0}, {8}, {1024}, default_tun_check},
11377ba6 564 { "kern.ipc.msgmnb", TUN_INT, {0}, {1}, {65535}, default_tun_check},
282113ba 565 { "kern.ipc.msgmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
11377ba6 566 { "kern.ipc.msgtql", TUN_INT, {0}, {1}, {1024}, default_tun_check},
282113ba
CV
567
568 /* SEM */
569 //{ "kern.ipc.semmap", TUN_INT, {0}, {1}, {1024}, default_tun_check},
570 { "kern.ipc.semmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
571 { "kern.ipc.semmns", TUN_INT, {0}, {1}, {1024}, default_tun_check},
572 { "kern.ipc.semmnu", TUN_INT, {0}, {1}, {1024}, default_tun_check},
573 { "kern.ipc.semmsl", TUN_INT, {0}, {1}, {1024}, default_tun_check},
574 { "kern.ipc.semopm", TUN_INT, {0}, {1}, {1024}, default_tun_check},
575 { "kern.ipc.semume", TUN_INT, {0}, {1}, {1024}, default_tun_check},
576 //{ "kern.ipc.semusz", TUN_INT, {0}, {1}, {1024}, default_tun_check},
577 { "kern.ipc.semvmx", TUN_INT, {0}, {1}, {32767}, default_tun_check},
578 { "kern.ipc.semaem", TUN_INT, {0}, {1}, {32767}, default_tun_check},
579
580 /* SHM */
581 { "kern.ipc.shmmaxpgs", TUN_INT, {0}, {1}, {32767}, default_tun_check},
582 //{ "kern.ipc.shmmin", TUN_INT, {0}, {1}, {32767}, default_tun_check},
583 { "kern.ipc.shmmni", TUN_INT, {0}, {1}, {32767}, default_tun_check},
584 { "kern.ipc.shmseg", TUN_INT, {0}, {1}, {32767}, default_tun_check},
8f14a113 585 { "kern.ipc.shm_allow_removed", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
282113ba
CV
586 //{ "kern.ipc.shm_use_phys", TUN_INT, {0}, {1}, {32767}, default_tun_check},
587 { NULL, TUN_NULL, {0}, {0}, {0}, NULL}
588};
589
590#define skip_whitespace(c) while (*(c) && isspace (*(c))) ++(c)
591#define skip_nonwhitespace(c) while (*(c) && !isspace (*(c)) && *(c) != '#') ++(c)
592#define end_of_content(c) (!*(c) || *(c) == '#')
593
594void
595tunable_param_init (const char *config_file, bool force)
596{
597 FILE *fp = fopen (config_file, "rt");
598 if (!fp)
599 {
600 if (force)
601 panic ("can't open config file %s\n", config_file);
602 return;
603 }
604 char line[1024];
605 while (fgets (line, 1024, fp))
606 {
607 char *c = strrchr (line, '\n');
608 if (!c)
609 panic ("Line too long in confg file %s\n", config_file);
610 /* Overwrite trailing NL. */
611 *c = '\0';
612 c = line;
613 skip_whitespace (c);
614 if (end_of_content (c))
615 continue;
616 /* So we are on the first character of a parameter name. */
617 char *name = c;
618 /* Find end of name. */
619 skip_nonwhitespace (c);
620 if (end_of_content (c))
621 {
622 *c++ = '\0';
623 panic ("Error in config file %s: Parameter %s has no value.\n",
624 config_file, name);
625 }
626 /* Mark end of name. */
627 *c++ = '\0';
628 skip_whitespace (c);
629 if (end_of_content (c))
630 panic ("Error in config file %s: Parameter %s has no value.\n",
631 config_file, name);
632 /* Now we are on the first character of a parameter's value. */
633 char *value = c;
634 /* This only works for simple parameters. If complex string parameters
635 are added at one point, the scanning routine must be changed here. */
636 /* Find end of value. */
637 skip_nonwhitespace (c);
638 /* Mark end of value. */
639 *c++ = '\0';
640 /* Now look if name is one from our list. */
641 tun_struct *s;
642 for (s = &tunable_params[0]; s->name; ++s)
643 if (!strcmp (name, s->name))
644 {
645 /* Now read value and check for validity. check_func doesn't
646 return on error. */
647 s->check_func (s, value, config_file);
648 break;
649 }
650 if (!s->name)
651 panic ("Error in config file %s: Unknown parameter %s.\n",
652 config_file, name);
653 }
654 fclose (fp);
655}
656
657void
61522196 658tunable_int_fetch (const char *name, int32_t *tunable_target)
282113ba
CV
659{
660 tun_struct *s;
661 for (s = &tunable_params[0]; s->name; ++s)
662 if (!strcmp (name, s->name))
663 break;
664 if (!s) /* Not found */
665 return;
666 if (s->type != TUN_INT) /* Wrong type */
667 return;
668 if (!s->value.ival) /* Not set in config file */
669 return;
670 *tunable_target = s->value.ival;
681bb2f7 671 debug ("\nSet %s to %u\n", name, *tunable_target);
282113ba
CV
672}
673
674void
675tunable_bool_fetch (const char *name, tun_bool_t *tunable_target)
676{
677 tun_struct *s;
678 const char *tun_bool_val_string[] = { "undefined", "no", "yes" };
679 for (s = &tunable_params[0]; s->name; ++s)
680 if (!strcmp (name, s->name))
681 break;
682 if (!s) /* Not found */
683 return;
684 if (s->type != TUN_BOOL) /* Wrong type */
685 return;
686 if (!s->value.ival) /* Not set in config file */
687 return;
688 *tunable_target = s->value.bval;
689 debug ("\nSet %s to %s\n", name, tun_bool_val_string[*tunable_target]);
690}
691#endif /* __OUTSIDE_CYGWIN__ */
This page took 0.287255 seconds and 5 git commands to generate.