28 #include <sys/resource.h>
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"));
47 static shell::stringopt group(
'g',
"--group", _TEXT(
"use specified group permissions"),
"groupid", NULL);
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"));
59 static shell::stringopt user(
'u',
"--user", _TEXT(
"user to run as"),
"userid", NULL);
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);
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);
70 #if defined(HAVE_SETRLIMIT) && defined(DEBUG)
72 #include <sys/resource.h>
74 static void corefiles(
void)
78 assert(getrlimit(RLIMIT_CORE, &core) == 0);
80 core.rlim_cur = MAX_CORE_SOFT;
82 core.rlim_cur = RLIM_INFINITY;
85 core.rlim_max = MAX_CORE_HARD;
87 core.rlim_max = RLIM_INFINITY;
89 assert(setrlimit(RLIMIT_CORE, &core) == 0);
92 static void corefiles(
void)
98 static const char *userpath(
const char *path)
104 if(eq(path,
"~/", 2) && getuid()) {
105 const char *home = getenv(
"HOME");
107 return strdup(str(home) + ++path);
114 static void usage(
void)
117 printf(
"%s\n", _TEXT(
"Usage: sipw [debug] [options]"));
119 printf(
"%s\n", _TEXT(
"Usage: sipw [options]"));
121 printf(
"%s\n\n", _TEXT(
"Start sipwitch service"));
122 printf(
"%s\n", _TEXT(
"Options:"));
127 " --dbg execute command in debugger\n"
128 " --memcheck execute with valgrind memory check\n"
129 " --memleak execute with valgrind leak detection\n"
134 printf(
"\n%s\n", _TEXT(
"Report bugs to sipwitch-devel@gnu.org"));
138 static void versioninfo(
void)
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"));
148 static void dumpconfig(
void)
158 printf(
"provision: %s\n", dirpath);
162 static bool errlog(shell::loglevel_t level,
const char *text)
181 static void up(
const char *pidfile)
185 FILE *fp = fopen(pidfile,
"w");
187 fprintf(fp,
" %ld\n", (
long)getpid());
216 static void init(
int argc,
char **argv,
bool detached, shell::mainproc_t svc = NULL)
224 const char *plugins = DEFAULT_LIBPATH
"/sipwitch";
227 shell::bind(
"sipwitch");
231 const char *security = args.getenv(
"SECURITY");
233 security =
"default";
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");
241 args.restart(argv[0], &argv[2], dbg);
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);
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);
257 args.parse(argc, argv);
258 if(is(helpflag) || is(althelp) || args.argc() > 0)
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");
289 const char *dp = strrchr(args.execdir(),
'/');
290 if(dp && (eq(dp,
"/.") || eq(dp,
"/server") || eq(dp,
"/.libs")))
291 plugins = args.execdir();
293 prefix = DEFAULT_VARPATH
"/lib/sipwitch";
294 rundir = DEFAULT_VARPATH
"/run/sipwitch";
295 args.setsym(
"reply",
"/tmp/.sipwitch.");
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");
314 struct passwd *pwd = getpwuid(getuid());
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)) {
326 rundir = strdup(str(
"/tmp/sipwitch-") + str(pwd->pw_name));
327 prefix = strdup(str(pwd->pw_dir) +
"/.sipwitch");
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)));
333 cp = userpath(*configpath);
334 if(is(configpath) && fsys::is_file(cp))
335 args.setsym(
"config", cp);
337 args.setsym(
"config", _STR(str(pwd->pw_dir) +
"/.sipwitchrc"));
339 cp = userpath(*cachepath);
340 if(is(cachepath) && fsys::is_dir(cp))
341 args.setsym(
"cache", cp);
343 args.setsym(
"cache", _STR(str(rundir) +
"/cache"));
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"));
356 cp = userpath(*prefixpath);
357 if(is(prefixpath) && fsys::is_dir(cp))
358 args.setsym(
"prefix", cp);
360 args.setsym(
"prefix", prefix);
362 args.setsym(
"shell", pwd->pw_shell);
371 cp = args.getenv(
"GROUP");
372 if(cp && *cp && !is(group))
375 cp = args.getenv(
"USER");
376 if(cp && *cp && !is(user))
382 cp = getenv(
"FIRSTUID");
389 cp = getenv(
"SIPUSERS");
393 cp = getenv(
"SIPADMIN");
398 if(is(nolocalusers)) {
405 cp = args.getenv(
"CONCURRENCY");
407 concurrency.set(atol(cp));
409 cp = args.getenv(
"PRIORITY");
411 priority.set(atol(cp));
413 cp = args.getenv(
"VERBOSE");
415 loglevel.set(strdup(cp));
417 cp = args.getenv(
"LOGGING");
419 loglevel.set(strdup(cp));
421 cp = args.getenv(
"LOGGING");
423 histbuf.set(atoi(cp));
425 cp = args.getenv(
"PLUGINS");
427 loading.set(strdup(cp));
437 shell::errexit(1,
"sipw: concurrency: %ld: %s\n",
438 *concurrency, _TEXT(
"negative levels invalid"));
441 shell::errexit(1,
"sipw: history: %ld: %s\n",
442 *histbuf, _TEXT(
"negative buffer limit invalid"));
456 Thread::concurrency(*concurrency);
458 shell::priority(*priority);
462 Thread::policy(SCHED_RR);
467 if(is(backflag) || is(altback))
476 verbose.set(*verbose + (
unsigned)shell::INFO);
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));
495 verbose.set((
unsigned)shell::DEBUG0 + *debuglevel);
497 if(is(hotspot) || eq(security,
"public"))
502 struct group *grp = NULL;
509 pwd = getpwuid(atoi(*user));
511 pwd = getpwnam(*user);
513 shell::errexit(2,
"*** sipw: %s: %s\n", *user,
514 _TEXT(
"unknown or invalid user id"));
520 grp = getgrgid(atoi(*group));
522 grp = getgrnam(*group);
524 shell::errexit(2,
"*** sipw: %s: %s\n", *group,
525 _TEXT(
"unknown or invalid group id"));
529 #ifdef HAVE_SETGROUPS
533 if(setgid(grp->gr_gid))
534 shell::errlog(
"*** sipw: %u: %s\n", grp->gr_gid,
535 _TEXT(
"cannot set group"));
541 #ifdef HAVE_SETGROUPS
546 if(setgid(pwd->pw_gid))
547 shell::errlog(
"*** sip: %u: %s\n", pwd->pw_gid,
548 _TEXT(
"cannot set group"));
556 if(is(desktop) || eq(security,
"desktop")) {
563 dir::create(rundir, fsys::GROUP_PUBLIC);
564 dir::create(prefix, fsys::GROUP_PRIVATE);
565 dir::create(args.getsym(
"cache"), fsys::GROUP_PRIVATE);
567 if(fsys::prefix(prefix))
568 shell::errexit(3,
"*** sip: %s: %s\n",
569 prefix, _TEXT(
"data directory unavailable"));
571 shell::loglevel_t level = (shell::loglevel_t)*verbose;
591 const char *home = getenv(
"HOME");
595 home = getenv(
"USERPROFILE");
599 home = args.getenv(
"prefix");
601 args.setsym(
"HOME", home);
604 shell::errexit(1,
"*** sipw: %s\n",
605 _TEXT(
"no control file; exiting"));
611 shell::errlog(
"*** sipw: %u: %s\n", uid,
612 _TEXT(
"cannot set user"));
619 up(args.getsym(
"pidfile"));
622 sd_notify(0,
"READY=1");
629 using namespace sipwitch;
633 static SERVICE_MAIN(
main, argc, argv)
636 init(argc, argv,
true);
643 init(argc, argv,
false, &service_main);
static const char * sipusers
static void failure(const char *reason)
Send error to user.
static void startup(void)
static size_t attach(shell_t *env)
Creates the control fifo using server configuration.
static void bind(unsigned short port)
static void add(shell::loglevel_t lid, const char *msg)
static void release(void)
Used by the server to destroy the control fifo.
static void config(shell *envp)
static void enableDumping(void)
static void terminate(const char *reason)
Notify server termination.
static void shutdown(void)
static void errlog(shell::loglevel_t level, const char *text)
Module access to error logging system.
static bool start(void)
Start server event system by binding event session listener.
static void warning(const char *reason)
Send warning to user.
static void setPublic(void)
static const char * sipadmin
static shell::logmode_t logmode
void set(shell::loglevel_t lid, const char *msg)
static void service(const char *name)
static void plugins(const char *argv0, const char *names)
static const char * env(const char *id)
Return the value of a server environment variable.