SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
system.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include "server.h"
18 
19 #ifndef _MSWINDOWS_
20 
21 #include <signal.h>
22 #include <sys/wait.h>
23 #include <syslog.h>
24 #include <fcntl.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <limits.h>
30 #include <errno.h>
31 
32 #endif
33 
34 namespace sipwitch {
35 
36 static shell::flagopt helpflag('h',"--help", _TEXT("display this list"));
37 static shell::flagopt althelp('?', NULL, NULL);
38 static shell::stringopt iface('A', "--address", _TEXT("sip interface address"), "address", NULL);
39 static shell::numericopt port('P', "--port", _TEXT("sip port to bind"), "port", 5060);
40 static shell::flagopt backflag('b', "--background", _TEXT("run in background"));
41 static shell::flagopt altback('d', NULL, NULL);
42 static shell::flagopt dump('D', "--dump-config", _TEXT("show configuration"));
43 static shell::numericopt concurrency('c', "--concurrency", _TEXT("process concurrency"), "level");
44 static shell::flagopt desktop(0, "--desktop", _TEXT("enable desktop access"));
45 static shell::flagopt foreflag('f', "--foreground", _TEXT("run in foreground"));
46 #ifdef HAVE_PWD_H
47 static shell::stringopt group('g', "--group", _TEXT("use specified group permissions"), "groupid", NULL);
48 #endif
49 static shell::numericopt histbuf('h', "--history", _TEXT("set history buffer"), "count", 0);
50 static shell::stringopt loglevel('L', "--logging", _TEXT("set log level"), "level", "err");
51 static shell::stringopt loading('l', "--plugins", _TEXT("specify modules to load"), "names", "none");
52 static shell::flagopt nolocalusers('n', "--no-localusers", _TEXT("disable local user accounts"));
53 static shell::counteropt priority('p', "--priority", _TEXT("set priority level"), "level");
54 static shell::flagopt hotspot(0, "--public", _TEXT("public access mode"));
55 static shell::flagopt restart('r', "--restartable", _TEXT("set to restartable process"));
56 static shell::flagopt sservice('S', "--service", _TEXT("system service mode"));
57 static shell::flagopt trace('t', "--trace", _TEXT("trace sip messages"));
58 #ifdef HAVE_PWD_H
59 static shell::stringopt user('u', "--user", _TEXT("user to run as"), "userid", NULL);
60 #endif
61 static shell::flagopt verbose('v', NULL, _TEXT("set verbosity, can be used multiple times"), false);
62 static shell::flagopt version(0, "--version", _TEXT("show version information"));
63 static shell::numericopt debuglevel('x', "--debug", _TEXT("set debug level directly"), "level", 0);
64 
65 static shell::groupopt groupconfig(_TEXT("User Options"));
66 static shell::stringopt configpath(0, "--configpath", _TEXT("config file"), "path", NULL);
67 static shell::stringopt cachepath(0, "--cachepath", _TEXT("cache files"), "dir", NULL);
68 static shell::stringopt prefixpath(0, "--prefixpath", _TEXT("provisioning files"), "dir", NULL);
69 
70 #if defined(HAVE_SETRLIMIT) && defined(DEBUG)
71 #include <sys/time.h>
72 #include <sys/resource.h>
73 
74 static void corefiles(void)
75 {
76  struct rlimit core;
77 
78  assert(getrlimit(RLIMIT_CORE, &core) == 0);
79 #ifdef MAX_CORE_SOFT
80  core.rlim_cur = MAX_CORE_SOFT;
81 #else
82  core.rlim_cur = RLIM_INFINITY;
83 #endif
84 #ifdef MAX_CORE_HARD
85  core.rlim_max = MAX_CORE_HARD;
86 #else
87  core.rlim_max = RLIM_INFINITY;
88 #endif
89  assert(setrlimit(RLIMIT_CORE, &core) == 0);
90 }
91 #else
92 static void corefiles(void)
93 {
94 }
95 #endif
96 
97 #ifdef HAVE_PWD_H
98 static const char *userpath(const char *path)
99 {
100  if(!path)
101  return NULL;
102 
103 #ifndef _MSWINDOWS_
104  if(eq(path, "~/", 2) && getuid()) {
105  const char *home = getenv("HOME");
106  if(home)
107  return strdup(str(home) + ++path);
108  }
109 #endif
110  return path;
111 }
112 #endif
113 
114 static void usage(void)
115 {
116 #if defined(DEBUG)
117  printf("%s\n", _TEXT("Usage: sipw [debug] [options]"));
118 #else
119  printf("%s\n", _TEXT("Usage: sipw [options]"));
120 #endif
121  printf("%s\n\n", _TEXT("Start sipwitch service"));
122  printf("%s\n", _TEXT("Options:"));
123  shell::help();
124  #if defined(DEBUG)
125  printf("%s", _TEXT(
126  "\nDebug Options:\n"
127  " --dbg execute command in debugger\n"
128  " --memcheck execute with valgrind memory check\n"
129  " --memleak execute with valgrind leak detection\n"
130  "\n"
131  ));
132 #endif
133 
134  printf("\n%s\n", _TEXT("Report bugs to sipwitch-devel@gnu.org"));
135  exit(0);
136 }
137 
138 static void versioninfo(void)
139 {
140  printf("SIP Witch " VERSION "\n%s", _TEXT(
141  "Copyright (C) 2007,2008,2009 David Sugar, Tycho Softworks\n"
142  "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
143  "This is free software: you are free to change and redistribute it.\n"
144  "There is NO WARRANTY, to the extent permitted by law.\n"));
145  exit(0);
146 }
147 
148 static void dumpconfig(void)
149 {
150  const char *dirpath = control::env("users"); // /etc/sipwitch.d
151  if(!dirpath)
152  dirpath = control::env("prefix");
153 
154  printf("config: %s\n", control::env("config"));
155  printf("control: %s\n", control::env("control"));
156  printf("runtime: %s\n", control::env("controls"));
157  printf("cache: %s\n", control::env("cache"));
158  printf("provision: %s\n", dirpath);
159  exit(0);
160 }
161 
162 static bool errlog(shell::loglevel_t level, const char *text)
163 {
164  switch(level) {
165  case shell::WARN:
166  events::warning(text);
167  break;
168  case shell::FAIL:
169  events::terminate(text);
170  break;
171  case shell::ERR:
172  events::failure(text);
173  default:
174  break;
175  }
176  modules::errlog(level, text);
177  history::add(level, text);
178  return false;
179 }
180 
181 static void up(const char *pidfile)
182 {
183  if(pidfile) {
184  ::remove(pidfile);
185  FILE *fp = fopen(pidfile, "w");
186  if(fp) {
187  fprintf(fp, " %ld\n", (long)getpid());
188  fclose(fp);
189  fp = NULL;
190  }
191  }
192 
193  cache::init();
194  server::reload();
195  server::startup();
196 
197  if(is(trace))
199 
200  psignals::start();
201  events::start();
202  notify::start();
203  server::run();
204 
205  events::terminate("server shutdown");
206  notify::stop();
207  psignals::stop();
210 
211  if(pidfile)
212  ::remove(pidfile);
213 }
214 
215 
216 static void init(int argc, char **argv, bool detached, shell::mainproc_t svc = NULL)
217 {
218  secure::init();
219 
220  bool daemon = true;
221  const char *cp;
222  const char *prefix;
223  const char *rundir;
224  const char *plugins = DEFAULT_LIBPATH "/sipwitch";
225  shell args;
226 
227  shell::bind("sipwitch");
228  corefiles();
229  args.getargv0(argv);
230 
231  const char *security = args.getenv("SECURITY");
232  if(!security)
233  security = "default";
234 
235 #if defined(DEBUG)
236  if(eq(argv[1], "-gdb") || eq(argv[1], "--gdb") || eq(argv[1], "-dbg") || eq(argv[1], "--dbg")) {
237  char *dbg[] = {(char *)"gdb", (char *)"--args", NULL};
238  const char *cp = args.getenv("DEBUGGER");
239  if(cp && *cp)
240  dbg[0] = (char *)cp;
241  args.restart(argv[0], &argv[2], dbg);
242  }
243 
244  if(eq(argv[1], "-memcheck") || eq(argv[1], "--memcheck")) {
245  char *mem[] = {(char *)"valgrind", (char *)"--tool=memcheck", NULL};
246  args.restart(argv[0], &argv[2], mem);
247  }
248 
249  if(eq(argv[1], "-memleak") || eq(argv[1], "--memleak")) {
250  char *mem[] = {(char *)"valgrind",
251  (char *)"--tool=memcheck", (char *)"--leak-check=yes", NULL};
252  args.restart(argv[0], &argv[2], mem);
253  }
254 #endif
255 
256  // parse and check for help
257  args.parse(argc, argv);
258  if(is(helpflag) || is(althelp) || args.argc() > 0)
259  usage();
260 
261  if(is(version))
262  versioninfo();
263 
264  // cheat out shell parser...
265  // argv[0] = (char *)"sipwitch";
266 
267  args.setsym("statmap", STAT_MAP);
268  args.setsym("callmap", CALL_MAP);
269  args.setsym("regmap", REGISTRY_MAP);
270 
271 #ifdef _MSWINDOWS_
272  rundir = strdup(str(args.getenv("APPDATA")) + "/sipwitch");
273  prefix = args.execdir();
274  plugins = args.execdir();
275  args.setsym("config", _STR(str(prefix) + "/sipwitch.ini"));
276  args.setsym("controls", rundir);
277  args.setsym("control", "\\\\.\\mailslot\\sipwitch_ctrl");
278  args.setsym("cache", _STR(str(prefix) + "/cache"));
279  args.setsym("logfiles", _STR(str(prefix) + "/logs"));
280  args.setsym("siplogs", _STR(str(prefix) + "/logs/siptrace.log"));
281  args.setsym("logfile", _STR(str(prefix) + "/logs/sipwitch.log"));
282  args.setsym("calls", _STR(str(prefix) + "/logs/sipwitch.calls"));
283  args.setsym("stats", _STR(str(prefix) + "/logs/sipwitch.stats"));
284  args.setsym("prefix", rundir);
285  args.setsym("shell", "cmd.exe");
286  prefix = rundir;
287 #else
288  // if local build directory image being executed directly...
289  const char *dp = strrchr(args.execdir(), '/');
290  if(dp && (eq(dp, "/.") || eq(dp, "/server") || eq(dp, "/.libs")))
291  plugins = args.execdir();
292 
293  prefix = DEFAULT_VARPATH "/lib/sipwitch";
294  rundir = DEFAULT_VARPATH "/run/sipwitch";
295  args.setsym("reply", "/tmp/.sipwitch.");
296 
297  args.setsym("config", DEFAULT_CFGPATH "/sipwitch.conf");
298  args.setsym("cache", DEFAULT_VARPATH "/cache/sipwitch");
299  args.setsym("controls", DEFAULT_VARPATH "/run/sipwitch");
300  args.setsym("control", DEFAULT_VARPATH "/run/sipwitch/control");
301  args.setsym("pidfile", DEFAULT_VARPATH "/run/sipwitch/pidfile");
302  args.setsym("events", DEFAULT_VARPATH "/run/sipwitch/events");
303  args.setsym("config", DEFAULT_CFGPATH "/sipwitch.conf");
304  args.setsym("logfiles", DEFAULT_VARPATH "/log");
305  args.setsym("siplogs", DEFAULT_VARPATH "/log/siptrace.log");
306  args.setsym("logfile", DEFAULT_VARPATH "/log/sipwitch.log");
307  args.setsym("calls", DEFAULT_VARPATH "/log/sipwitch.calls");
308  args.setsym("stats", DEFAULT_VARPATH "/log/sipwitch.stats");
309  args.setsym("prefix", prefix);
310  args.setsym("shell", "/bin/sh");
311 #endif
312 
313 #ifdef HAVE_PWD_H
314  struct passwd *pwd = getpwuid(getuid());
315  umask(007);
316 
317  if(getuid() && pwd && pwd->pw_dir && *pwd->pw_dir == '/') {
318  args.setsym("prefix", pwd->pw_dir);
319  if(!eq(pwd->pw_shell, "/bin/false") && !eq(pwd->pw_dir, "/var/", 5) && !eq(pwd->pw_dir, "/srv/", 5)) {
320  umask(077);
321  daemon = false;
322  };
323  }
324 
325  if(!daemon && pwd) {
326  rundir = strdup(str("/tmp/sipwitch-") + str(pwd->pw_name));
327  prefix = strdup(str(pwd->pw_dir) + "/.sipwitch");
328 
329  args.setsym("statmap", _STR(str(STAT_MAP "-") + str(pwd->pw_name)));
330  args.setsym("callmap", _STR(str(CALL_MAP "-") + str(pwd->pw_name)));
331  args.setsym("regmap", _STR(str(REGISTRY_MAP "-") + str(pwd->pw_name)));
332 
333  cp = userpath(*configpath);
334  if(is(configpath) && fsys::is_file(cp))
335  args.setsym("config", cp);
336  else
337  args.setsym("config", _STR(str(pwd->pw_dir) + "/.sipwitchrc"));
338 
339  cp = userpath(*cachepath);
340  if(is(cachepath) && fsys::is_dir(cp))
341  args.setsym("cache", cp);
342  else
343  args.setsym("cache", _STR(str(rundir) + "/cache"));
344 
345  args.setsym("controls", rundir);
346  args.setsym("control", _STR(str(rundir) + "/control"));
347  args.setsym("events", _STR(str(rundir) + "/events"));
348  args.setsym("pidfile", _STR(str(rundir) + "/pidfile"));
349  args.setsym("logfiles", rundir);
350  args.setsym("siplogs", _STR(str(rundir) + "/siplogs"));
351  args.setsym("logfile", _STR(str(rundir) + "/logfile"));
352  args.setsym("calls", _STR(str(rundir) + "/calls"));
353  args.setsym("stats", _STR(str(rundir) + "/stats"));
354 
355 
356  cp = userpath(*prefixpath);
357  if(is(prefixpath) && fsys::is_dir(cp))
358  args.setsym("prefix", cp);
359  else
360  args.setsym("prefix", prefix);
361 
362  args.setsym("shell", pwd->pw_shell);
363  }
364 
365 #else
366  if(argv[1])
367  daemon = false;
368 #endif
369 
370 #ifdef HAVE_PWD_H
371  cp = args.getenv("GROUP");
372  if(cp && *cp && !is(group))
373  group.set(cp);
374 
375  cp = args.getenv("USER");
376  if(cp && *cp && !is(user))
377  user.set(cp);
378 
379  // root gets these from default to act as user daemon...
380 
381  if(!getuid()) {
382  cp = getenv("FIRSTUID");
383  if(!cp)
384  cp = getenv("UID");
385 
386  if(cp && *cp)
387  server::uid = atoi(cp);
388 
389  cp = getenv("SIPUSERS");
390  if(cp && *cp)
391  server::sipusers = strdup(cp);
392 
393  cp = getenv("SIPADMIN");
394  if(cp && *cp)
395  server::sipadmin = strdup(cp);
396  }
397 
398  if(is(nolocalusers)) {
399  server::sipusers = NULL;
400  server::sipadmin = NULL;
401  }
402 
403 #endif
404 
405  cp = args.getenv("CONCURRENCY");
406  if(cp && *cp)
407  concurrency.set(atol(cp));
408 
409  cp = args.getenv("PRIORITY");
410  if(cp && *cp)
411  priority.set(atol(cp));
412 
413  cp = args.getenv("VERBOSE");
414  if(cp && *cp)
415  loglevel.set(strdup(cp));
416 
417  cp = args.getenv("LOGGING");
418  if(cp && *cp)
419  loglevel.set(strdup(cp));
420 
421  cp = args.getenv("LOGGING");
422  if(cp && *cp)
423  histbuf.set(atoi(cp));
424 
425  cp = args.getenv("PLUGINS");
426  if(cp && *cp)
427  loading.set(strdup(cp));
428 
429  if(is(dump)) {
430  control::config(&args);
431  dumpconfig();
432  }
433 
434  // check validity of some options...
435 
436  if(*concurrency < 0)
437  shell::errexit(1, "sipw: concurrency: %ld: %s\n",
438  *concurrency, _TEXT("negative levels invalid"));
439 
440  if(*histbuf < 0)
441  shell::errexit(1, "sipw: history: %ld: %s\n",
442  *histbuf, _TEXT("negative buffer limit invalid"));
443 
444  // bind sip interface and port from command line options...
445  // use xx:..:xx for ipv6 address, or a.b.c.d for ipv4
446 
447  if(is(iface))
448  service::callback::bind(*iface);
449 
450  if(is(port))
451  service::callback::bind((unsigned short)*port);
452 
453  // set threading properties...
454 
455  if(*concurrency > 0)
456  Thread::concurrency(*concurrency);
457 
458  shell::priority(*priority);
459 
460 #ifdef SCHED_RR
461  if(*priority > 0)
462  Thread::policy(SCHED_RR);
463 #endif
464 
465  // fore and background...
466 
467  if(is(backflag) || is(altback))
468  daemon = true;
469 
470  if(is(foreflag))
471  daemon = false;
472 
473  // lets play with verbose level and logging options
474 
475  if(is(verbose))
476  verbose.set(*verbose + (unsigned)shell::INFO);
477  else {
478  if(atoi(*loglevel) > 0)
479  verbose.set(atoi(*loglevel));
480  else if(eq(*loglevel, "0") || eq(*loglevel, "no", 2) || eq(*loglevel, "fail", 4))
481  verbose.set((unsigned)shell::FAIL);
482  else if(eq(*loglevel, "err", 3))
483  verbose.set((unsigned)shell::ERR);
484  else if(eq(*loglevel, "warn", 4))
485  verbose.set((unsigned)shell::WARN);
486  else if(eq(*loglevel, "noti", 4))
487  verbose.set((unsigned)shell::NOTIFY);
488  else if(eq(*loglevel, "info"))
489  verbose.set((unsigned)shell::INFO);
490  else if(eq(*loglevel, "debug", 5))
491  verbose.set((unsigned)shell::DEBUG0 + atoi(*loglevel + 5));
492  }
493 
494  if(is(debuglevel))
495  verbose.set((unsigned)shell::DEBUG0 + *debuglevel);
496 
497  if(is(hotspot) || eq(security, "public"))
499 
500 #ifdef HAVE_PWD_H
501  pwd = NULL;
502  struct group *grp = NULL;
503 
504  // if root user, then see if we change permissions...
505 
506  if(!getuid()) {
507  if(*user) {
508  if(atoi(*user))
509  pwd = getpwuid(atoi(*user));
510  else
511  pwd = getpwnam(*user);
512  if(!pwd)
513  shell::errexit(2, "*** sipw: %s: %s\n", *user,
514  _TEXT("unknown or invalid user id"));
515  }
516  }
517 
518  if(*group) {
519  if(atoi(*group))
520  grp = getgrgid(atoi(*group));
521  else
522  grp = getgrnam(*group);
523  if(!grp)
524  shell::errexit(2, "*** sipw: %s: %s\n", *group,
525  _TEXT("unknown or invalid group id"));
526  }
527 
528  if(grp) {
529 #ifdef HAVE_SETGROUPS
530  setgroups(0, NULL);
531 #endif
532  umask(007);
533  if(setgid(grp->gr_gid))
534  shell::errlog("*** sipw: %u: %s\n", grp->gr_gid,
535  _TEXT("cannot set group"));
536  }
537 
538  int uid = 0;
539 
540  if(pwd) {
541 #ifdef HAVE_SETGROUPS
542  setgroups(0, NULL);
543 #endif
544  umask(007);
545  if(!grp) {
546  if(setgid(pwd->pw_gid))
547  shell::errlog("*** sip: %u: %s\n", pwd->pw_gid,
548  _TEXT("cannot set group"));
549  }
550  uid = pwd->pw_uid;
551  }
552 
553  endgrent();
554  endpwent();
555 
556  if(is(desktop) || eq(security, "desktop")) {
557  umask(002);
559  }
560 
561 #endif
562 
563  dir::create(rundir, fsys::GROUP_PUBLIC);
564  dir::create(prefix, fsys::GROUP_PRIVATE);
565  dir::create(args.getsym("cache"), fsys::GROUP_PRIVATE);
566 
567  if(fsys::prefix(prefix))
568  shell::errexit(3, "*** sip: %s: %s\n",
569  prefix, _TEXT("data directory unavailable"));
570 
571  shell::loglevel_t level = (shell::loglevel_t)*verbose;
572  history::set(*histbuf);
573 
574 #ifdef HAVE_SYSTEMD
575  if(is(sservice)) // systemd services no need for fork...
576  detached = true;
577 #endif
578 
579  // daemonify process....
580  if(daemon) {
581  if(!detached)
582  args.detach(svc);
583  server::logmode = shell::CONSOLE_LOG;
584  }
585  else
586  shell::log("sipwitch", level, server::logmode, &errlog);
587 
588  server::plugins(plugins, *loading);
589  psignals::setup();
590 
591  const char *home = getenv("HOME");
592 
593 #ifdef _MSWINDOWS_
594  if(!home)
595  home = getenv("USERPROFILE");
596 #endif
597 
598  if(!home)
599  home = args.getenv("prefix");
600 
601  args.setsym("HOME", home);
602 
603  if(!control::attach(&args))
604  shell::errexit(1, "*** sipw: %s\n",
605  _TEXT("no control file; exiting"));
606 
607  // drop root privilege
608 #ifdef HAVE_PWD_H
609  if(uid) {
610  if(setuid(uid))
611  shell::errlog("*** sipw: %u: %s\n", uid,
612  _TEXT("cannot set user"));
613  }
614 #endif
615 
616  if(is(restart))
617  args.restart();
618 
619  up(args.getsym("pidfile"));
620 #ifdef HAVE_SYSTEMD
621  if(is(sservice)) {
622  sd_notify(0, "READY=1");
623  }
624 #endif
625 }
626 
627 } // end namespace
628 
629 using namespace sipwitch;
630 
631 // stub code for windows service daemon...
632 
633 static SERVICE_MAIN(main, argc, argv)
634 {
635  psignals::service("sipwitch");
636  init(argc, argv, true);
637 }
638 
639 // program main
640 
641 PROGRAM_MAIN(argc, argv)
642 {
643  init(argc, argv, false, &service_main);
644  PROGRAM_EXIT(server::exit_code);
645 }
static const char * sipusers
Definition: server.h:496
static void failure(const char *reason)
Send error to user.
Definition: events.cpp:354
static void reload(void)
Definition: server.cpp:912
static void startup(void)
Definition: service.cpp:700
static size_t attach(shell_t *env)
Creates the control fifo using server configuration.
Definition: control.cpp:61
int main()
Definition: libs.cpp:40
static void init(void)
Definition: cache.cpp:68
static void bind(unsigned short port)
Definition: service.h:238
static void add(shell::loglevel_t lid, const char *msg)
Definition: history.cpp:47
static void release(void)
Used by the server to destroy the control fifo.
Definition: control.cpp:81
#define REGISTRY_MAP
Definition: mapped.h:77
static void config(shell *envp)
Definition: control.h:144
static void enableDumping(void)
Definition: stack.cpp:325
static void terminate(const char *reason)
Notify server termination.
Definition: events.cpp:390
static void run(void)
Definition: server.cpp:1100
static void shutdown(void)
Definition: service.cpp:719
static void stop(void)
Definition: psignals.cpp:343
static void errlog(shell::loglevel_t level, const char *text)
Module access to error logging system.
Definition: modules.cpp:81
static bool start(void)
Start server event system by binding event session listener.
Definition: events.cpp:203
static void stop(void)
Definition: psignals.cpp:210
static int exit_code
Definition: server.h:498
static void start(void)
Definition: psignals.cpp:339
static void warning(const char *reason)
Send warning to user.
Definition: events.cpp:345
static void setPublic(void)
Definition: service.h:241
static unsigned uid
Definition: server.h:495
static const char * sipadmin
Definition: server.h:497
static shell::logmode_t logmode
Definition: server.h:494
PROGRAM_MAIN(argc, argv)
Definition: system.cpp:641
short argc
Definition: cgiserver.cpp:93
void set(shell::loglevel_t lid, const char *msg)
Definition: history.cpp:33
static void service(const char *name)
Definition: psignals.cpp:198
static void start(void)
Definition: psignals.cpp:206
static void setup(void)
Definition: psignals.cpp:202
#define STAT_MAP
Definition: stats.h:45
static void plugins(const char *argv0, const char *names)
Definition: server.cpp:1053
static const char * env(const char *id)
Return the value of a server environment variable.
Definition: control.h:131
#define CALL_MAP
Definition: mapped.h:76