source: roaraudio/roard/roard.c @ 5192:4237437ca526

Last change on this file since 5192:4237437ca526 was 5192:4237437ca526, checked in by phi, 13 years ago

declare some stuff 'extern', this saves like 5.3KB of diskspace in plugin files and make them more resistant against changes in roard

File size: 75.5 KB
RevLine 
[0]1//roard.c:
2
[668]3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
[668]5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[668]23 *
24 */
25
[4924]26/* ckport options:
27 * Stuff checked by configure:
28 * ckport: ignore-symbol: getuid of target win32
29 * ckport: ignore-symbol: setuid of target win32
30 * ckport: ignore-symbol: getgid of target win32
31 * ckport: ignore-symbol: setgid of target win32
32 * ckport: ignore-symbol: setsid of target win32
33 * ckport: ignore-symbol: kill of target win32
34 * ckport: ignore-symbol: chroot of target win32
35 * ckport: ignore-symbol: fork of target win32
36 * ckport: ignore-symbol: getservbyname of target win32
37 * ckport: ignore-symbol: nice of target win32
38 *
39 */
40
[0]41#include "roard.h"
42
[4722]43enum action {
44 START,
45 STOP,
46 RESTART,
47 RESTART_RETRY,
48 SHUTDOWN
49};
50
[4788]51enum af_mode {
52 AF_MODE_NONE,
53 AF_MODE_LOAD,
54 AF_MODE_GEN
55};
56
[5192]57// some stuff we only define extern globally.
58int alive;
59#ifdef ROAR_SUPPORT_LISTEN
60int g_no_listen;
61#endif
62
63uint32_t g_pos; // current possition in output stream
64
65int g_standby;
66int g_autostandby;
67
68struct roard_listen g_listen[ROAR_MAX_LISTEN_SOCKETS];
69
70int g_self_client;
71
72int g_terminate;
73
74struct roar_audio_info * g_sa, * g_max_sa;
75// end of extern block.
76
[1494]77#ifdef ROAR_SUPPORT_LISTEN
[4967]78static char * server[ROAR_MAX_LISTEN_SOCKETS];
[1494]79#endif
[60]80
[2104]81#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_FS_POSIX)
82#define SUPPORT_PIDFILE
[4967]83static char * pidfile = NULL;
[2104]84#endif
85
[2530]86#if defined(ROAR_HAVE_SETGID) || defined(ROAR_HAVE_SETUID)
[4967]87static int    setids    = 0;
[3374]88#endif
89
90#ifdef ROAR_HAVE_LIBX11
[4967]91static char * x11display = NULL;
[2530]92#endif
93
[4324]94void dbg_notify_cb(struct roar_notify_core * core, struct roar_event * event, void * userdata) {
95 char buf[1024] = "";
[4338]96 char estr[1024] = "/* ROAR_??? */";
97 char ttstr[1024] = "/* ROAR_OT_??? */";
98 const char * ttname;
99 uint32_t ev = ROAR_EVENT_GET_TYPE(event);
100 int i;
101
102 ttname = roar_ot2str(event->target_type);
103 if ( ttname != NULL ) {
104  snprintf(ttstr, sizeof(ttstr)-1, "/* ROAR_OT_%s */", ttname);
105  buf[sizeof(ttstr)-1] = 0;
106  for (i = 0; ttstr[i] != 0; i++)
107   if ( islower(ttstr[i]) )
108    ttstr[i] = toupper(ttstr[i]);
109 }
110
111 if ( ev == ROAR_NOTIFY_SPECIAL ) {
112  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_SPECIAL */");
113 } else if ( ROAR_NOTIFY_IS_CMD(ev) ) {
[4345]114  if ( command_get_name(ROAR_NOTIFY_EVENT2CMD(ev), &ttname) == -1 ) {
115   snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_CMD2EVENT(%i) */", ROAR_NOTIFY_EVENT2CMD(ev));
116  } else {
117   snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_CMD2EVENT(ROAR_CMD_%s) */", ttname);
118   for (i = 0; estr[i] != 0; i++)
119    if ( islower(estr[i]) )
120     estr[i] = toupper(estr[i]);
121  }
[4338]122 } else if ( ROAR_NOTIFY_IS_EGRP(ev) ) {
123  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_EGRP2EVENT(%i) */", ROAR_NOTIFY_EVENT2EGRP(ev));
124 } else if ( ROAR_NOTIFY_IS_OE(ev) ) {
125  switch (ev) {
[4418]126   // OE basics:
[4338]127   case ROAR_OE_BASICS_CHANGE_STATE:
128     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_CHANGE_STATE */");
129    break;
130   case ROAR_OE_BASICS_CHANGE_FLAGS:
131     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_CHANGE_FLAGS */");
132    break;
[4345]133   case ROAR_OE_BASICS_NEW:
134     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_NEW */");
135    break;
136   case ROAR_OE_BASICS_DELETE:
137     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_BASICS_DELETE */");
138    break;
[4418]139   // OE Streams:
140   case ROAR_OE_STREAM_CHANGE_VOLUME:
141     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_CHANGE_VOLUME */");
142    break;
143   case ROAR_OE_STREAM_XRUN:
144     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_XRUN */");
145    break;
[4842]146   case ROAR_OE_STREAM_META_UPDATE:
147     snprintf(estr, sizeof(estr)-1, "/* ROAR_OE_STREAM_META_UPDATE */");
148    break;
[4418]149   // OE Default:
[4338]150   default:
151     snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_OE2EVENT(%i) */", ROAR_NOTIFY_EVENT2OE(ev));
152    break;
153  }
154 } else if ( ROAR_NOTIFY_IS_USER(ev) ) {
155  snprintf(estr, sizeof(estr)-1, "/* ROAR_NOTIFY_USER2EVENT(%i) */", ROAR_NOTIFY_EVENT2USER(ev));
156 }
157
158 buf[sizeof(estr)-1] = 0;
[4324]159
160 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT ) {
[4338]161  snprintf(buf, sizeof(buf)-1, ".event_proxy=0x%.8x%s, ", (int)event->event_proxy, estr);
[4324]162  buf[sizeof(buf)-1] = 0;
163 }
164
[4418]165 ROAR_INFO("dbg_notify_cb(core=%p, event=%p{.flags=0x%.8x, event=0x%.8x%s, %s.emitter=%i, .target=%i, .target_type=%i%s, .arg0=%i, .arg1=%i, .arg2=%p}, userdata=%p) = (void)",
166           0 /* always print: minlevel = 0 */,
[4324]167           core, event,
168           (int)event->flags,
169           (int)event->event,
[4338]170           (event->flags & ROAR_EVENT_FLAG_PROXYEVENT ? "" : estr),
[4324]171           buf,
172           event->emitter,
173           event->target,
174           event->target_type,
[4338]175           ttstr,
[4324]176           event->arg0,
177           event->arg1,
178           event->arg2,
179           userdata);
180}
181
182void dbg_notify_cb_register (void) {
183 struct roar_event event;
184
185 memset(&event, 0, sizeof(event));
186
187 event.event = ROAR_EGRP_ANY_EVENT;
188
189 event.emitter = -1;
190 event.target = -1;
191 event.target_type = -1;
192
193 roar_notify_core_subscribe(NULL, &event, dbg_notify_cb, NULL);
194}
195
[1503]196#ifdef ROAR_HAVE_MAIN_ARGS
[0]197void usage (void) {
198 printf("Usage: roard [OPTIONS]...\n\n");
199
[68]200 printf("Misc Options:\n\n");
201 printf(
[5060]202#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
[775]203        " --daemon              - Bring the server into background after init\n"
[5060]204#endif
[2970]205        " --verbose             - Be more verbose, can be used multiple times\n"
[71]206        " --terminate           - Terminate after last client quited\n"
[2109]207        " --start               - No op parameter (starting roard is default operation)\n"
[274]208        " --restart             - Trys to stop an old instance and start a new with new settings\n"
[2109]209        " --stop                - Stops a running roard (provide --pidfile!)\n"
210        " --shutdown            - Terminates a running roard (provide --pidfile!)\n"
[276]211        " --realtime            - Trys to get realtime priority,\n"
212        "                         give multible times for being more realtime\n"
[4245]213        " --memlock LEVEL       - Set default memory locking level to LEVEL\n"
[4924]214#ifdef ROAR_HAVE_CHROOT
[444]215        " --chroot DIR          - chroots to the given dir\n"
[4924]216#endif
217#ifdef ROAR_HAVE_SETGID
[444]218        " --setgid              - GroupID to the audio group as specified via -G\n"
[4924]219#endif
220#ifdef ROAR_HAVE_SETUID
[444]221        " --setuid              - UserID to the audio user as specified via -U\n"
[4924]222#endif
[905]223        " --sysclocksync        - calculate exact sample rate using the system clock\n"
[2017]224        " --location  LOC       - Set lion readable location of server\n"
[4421]225        " --description  DESC   - Set lion readable description of server\n"
[2104]226#ifdef SUPPORT_PIDFILE
227        " --pidfile PIDFILE     - Write a pidfile at PIDFILE\n"
228#endif
[3688]229#ifdef ROAR_HAVE_SYSLOG
230        " --log-syslog          - Log Warnings, Errors, ... to syslog\n"
231#endif
[4851]232#ifdef ROAR_HAVE_SYSTEM
233        " --script-postdown S   - Run command lion S after complet shutdown.\n"
234#endif
[68]235       );
236
[4482]237 printf("\nAuth Options:\n\n");
238 printf(
[5146]239        " --guest-acclev ACCLEV - Sets the access level for guest access to ACCLEV,\n"
240        "                         Use \"none\" to disable guest access.\n"
[4482]241        " --trust-acclev ACCLEV - Sets the access level for trust-authed\n"
[5146]242        "                         connections to ACCLEV. Use \"none\" to disable trust auth.\n"
[4482]243        " --trust-root          - Trust root user\n"
244        " --no-trust-root       - Don't trust root user\n"
[4788]245        " --authfile-gen FILE   - Generate an new authfile\n"
[4792]246        " --authfile-load FILE  - Load an authfile\n"
[4788]247        " --authfile-type TYPE  - Type of authfile\n"
248        " --authfile-acclev ACCLEV\n"
249        "                       - Sets the access level for authfile\n"
[4789]250        " --new-authfile        - Parameters for new authfile follow\n"
[4482]251       );
252
[3356]253 printf("\nPlugin Options:\n\n");
254 printf(
255        " --plugin-load FILE    - Load plugin FILE\n"
256       );
257
[68]258 printf("\nAudio Options:\n\n");
[0]259 printf(
260        " -R  --rate   RATE     - Set server rate\n"
261        " -B  --bits   BITS     - Set server bits\n"
262        " -C  --chans  CHANNELS - Set server channels\n"
[3963]263        " --aiprofile  PROFILE  - Use the given audio profile\n"
[0]264       );
265
[2339]266 printf("\nStream Options:\n\n");
267 printf(
268        " --stream-flags D=F    - Set default flags for stream directions\n"
[4012]269        "                         D is the stream direction and F is a comma separated\n"
[2339]270        "                         list of flags in form +flag or -flag to set or unset\n"
271        "                         a flag as default or remove it from the default\n"
272       );
[4934]273 printf("\nStream Options:\n\n");
274 printf(
275        " --list-rolestack      - Show the current role stack\n"
276        " --rolestack-push R:A  - Add a rule for role R with action A on top\n"
277        "                         of the role stack.\n"
278       );
[2339]279
[932]280 printf("\nOutput Options:\n\n");
[974]281 printf(" -o  --odriver DRV     - Set the driver, use '--list-driver' to get a list\n");
[932]282 printf(" -O  --odevice DEV     - Set the device\n");
283 printf(" -oO OPTS              - Set output options\n");
284 printf(" -oN                   - Adds another output\n");
[961]285 printf(" -oP                   - Mark output as primary\n");
[4225]286#ifdef ROAR_DRIVER_DEFAULT
287 printf(" --list-driver         - List all drivers (default driver: %s)\n", ROAR_DRIVER_DEFAULT);
288#else
289 printf(" --list-driver         - List all drivers (default driver: (autodetect))\n");
290#endif
[932]291
[2485]292#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]293 printf("\nSource Options:\n\n");
294 printf(" -s  --source DRV      - Use DRV as input driver\n"
295        " -S           DEV      - Use DEV as input device\n"
296        " -sO          OPTS     - Use OPTS as input options\n"
[1512]297        " -sN                   - Adds another source\n"
[0]298        " -sP                   - Make souce as primary\n"
299       );
[2270]300 printf(" --list-sources        - List all sources\n");
[2485]301#endif
[0]302
[4358]303#ifndef ROAR_WITHOUT_DCOMP_MIXER
304 printf("\nHardware Mixer Options:\n\n");
305 printf(" -m  --mixer  DRV      - Use DRV as mixer driver\n"
306        " -M           DEV      - Use DEV as mixer device\n"
307        " -mO          OPTS     - Use OPTS as mixer options\n"
308        " -mN                   - Adds another mixer\n"
309        " -mP                   - Make mixer as primary\n"
310       );
311 printf(" --list-mixers         - List all mixers\n");
312#endif
313
[280]314 printf("\nCodec Filter Options:\n\n");
315 printf(" --list-cf             - List all codec filter\n"
316       );
[0]317
[2500]318#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1923]319 printf("\nMIDI Options:\n\n");
[1924]320 printf(" --midi-no-console     - Disable console based MIDI synth\n"
[2444]321        " --midi-console-enable - Enables the console based MIDI synth\n"
[1924]322        " --midi-console DEV    - Set device for MIDI console\n"
[2489]323#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]324        " --ssynth-enable       - Enable simple software synth\n"
325        " --ssynth-disable      - Disable simple software synth\n"
[2489]326#endif
[1924]327       );
[2500]328#endif
[1923]329
[2494]330#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]331 printf("\nLight Control Options:\n\n");
332 printf(" --light-channels NUM  - Sets the number of channels for Light control (default: %i)\n",
333                                  LIGHT_CHANNELS_DEFAULT
334       );
[2494]335#endif
[1923]336
[2725]337#ifndef ROAR_WITHOUT_DCOMP_RDTCS
[3339]338 printf("\nRadio Data and Transmitter Control System Options:\n\n");
[2725]339 printf(" --rds-pi   PI         - Sets the RDS Programme Identification (PI)\n"
340        " --rds-ps   PS         - Sets the RDS Programme Service Name (PS)\n"
341        " --rds-pty  PTY        - Sets the RDS Programme Type (PTY)\n"
342        " --rds-tp              - Sets the RDS Traffic Programme (TP) flag\n"
343        " --rds-ct              - Enables sending of RDS Clock Time (CT)\n"
344       );
345#endif
346
[3374]347#ifdef ROAR_HAVE_LIBX11
348 printf("\nX11 Options:\n\n");
349 printf(
350        " --x11-display DISPLAY - Set display for X11\n"
351        " --display DISPLAY     - Set display for X11\n"
352       );
353#endif
354
[0]355 printf("\nServer Options:\n\n");
356 printf(" -t  --tcp             - Use TCP listen socket\n"
[3992]357#ifdef ROAR_HAVE_UNIX
[0]358        " -u  --unix            - Use UNIX Domain listen socket (default)\n"
[3992]359#endif
[508]360#ifdef ROAR_HAVE_LIBDNET
361        " -n  --decnet          - use DECnet listen socket\n"
362#endif
[518]363        " -4                    - Use IPv4 connections (implies -t)\n"
[3837]364#ifdef AF_INET6
[518]365        " -6                    - Use IPv6 connections (implies -t)\n"
366#endif
367#ifdef IPV6_ADDRFORM
368        " -64                   - Try to downgrade sockets from IPv6 into IPv4,\n"
[4012]369        "                         this is normaly not useful.\n"
[518]370#endif
[0]371        " -p  --port            - TCP Port to bind to\n"
372        " -b  --bind            - IP/Hostname to bind to\n"
[1115]373        "     --sock            - Filename for UNIX Domain Socket\n"
[2530]374        "     --proto PROTO     - Use PROTO as protocol on Socket\n"
[3252]375        "     --proto-dir DIR   - Set direction parameter for protocol\n"
376        "     --proto-rate RATE - Set sample rate parameter for protocol\n"
377        "     --proto-bits BITS - Set bits per sample parameter for protocol\n"
378        "     --proto-codec E   - Set codec parameter for protocol\n"
[4012]379        "     --proto-chans C   - Set number of channels parameter for protocol\n"
[3954]380        "     --proto-aiprofile PROFILE\n"
381        "                       - Sets the audio profile for socket\n"
[3956]382        "     --proto-profile P - Set profile for listen socket\n"
[3127]383        "     --list-proto      - List supported protocols\n"
[3956]384        "     --list-profiles   - List supported profiles for --proto-profile\n"
[4882]385        "     --list-aiprofiles - List supported profiles for --proto-aiprofile\n"
[4789]386        "     --new-sock        - Parameters for new socket follow\n"
[1993]387#ifdef ROAR_HAVE_LIBSLP
388        "     --slp             - Enable OpenSLP support\n"
389#endif
[3373]390#ifdef ROAR_HAVE_LIBX11
391        "     --x11             - Enable X11 support\n"
392#endif
[3039]393        " --jumbo-mtu MTU       - Sets the MTU for Jumbo Packets\n"
[450]394        " -G  GROUP             - Sets the group for the UNIX Domain Socket, (default: %s)\n"
[2737]395        "                         You need the permissions to change the GID\n"
[444]396        " -U  USER              - Sets the user for the UNIX Domain Socket, (default: do not set)\n"
[2737]397        "                         You need the permissions to change the UID (normaly only root has)\n"
[548]398        " --no-listen           - Do not listen for new clients\n"
[4012]399        "                         (only useful for relaing, impleys --terminate)\n"
[274]400        " --client-fh           - Comunicate with a client over this handle\n"
[4012]401        "                         (only useful for relaing)\n"
[920]402        " --close-fh            - Closes the given fh\n"
403        " --standby             - Start in standby state\n"
404        " --auto-standby        - Automatical goes into standby if there are no streams\n",
[2755]405#ifdef ROAR_DEFAULT_SOCKGRP
[450]406        ROAR_DEFAULT_SOCKGRP
[2755]407#else
408        "(none)"
409#endif
[0]410       );
411// printf("\n Options:\n\n");
412 printf("\n");
413}
[3127]414
415static void list_proto (void) {
416 printf("  Protocol Flag Subsys - Description\n");
417 printf("------------------------------------------------------\n");
418 printf("  roar          WM LRX - RoarAudio native protocol\n");
419#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
420 printf("  esd           W      - EsounD emulation\n");
421#endif
[3603]422#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
[3257]423 printf("  simple        WM LRX - PulseAudio simple protocol\n");
[3597]424#endif
[3684]425#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
426 printf("  rsound        W      - RSound emulation\n");
427#endif
[3981]428#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
429 printf("  rplay         W      - RPlay emulation\n");
430#endif
[4703]431#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
432 printf("  gopher               - The Internet Gopher Protocol\n");
433#endif
[3127]434}
435
[1503]436#endif
[0]437
[4101]438#define _pmsg(format, args...) roar_debug_msg(type, __LINE__, __FILE__, ROAR_DBG_PREFIX, format, ## args)
439#define _pmsgc(group, counter, name) _pmsg("  Counter %-10s: %llu", (name), (long long unsigned int)counters_get(group, counter))
440void counters_print(int type, int force) {
441 if ( type != ROAR_DEBUG_TYPE_INFO || force || (ROAR_DBG_INFOVAR) >= ROAR_DBG_INFO_INFO ) {
442  _pmsg("--- Counter Listing ---");
443  _pmsg(" Current:");
444  _pmsgc(cur, clients, "Clients");
445  _pmsgc(cur, streams, "Streams");
446  _pmsg(" Total:");
447  _pmsgc(sum, clients, "Clients");
448  _pmsgc(sum, streams, "Streams");
449  _pmsg("--- End of Counter Listing ---");
450 }
451}
452#undef _pmsgc
453#undef _pmsg
454
[2109]455int restart_server (char * server, int terminate) {
[579]456 struct roar_connection con;
[2111]457#ifdef ROAR_HAVE_KILL
458 char buf[80];
459 ssize_t l;
460 struct roar_vio_calls fh;
461 pid_t pid;
462 int ok;
463
[4055]464 ROAR_INFO("restart_server(server='%s', terminate=%i): trying to restart server", ROAR_DBG_INFO_INFO, server, terminate);
465
[2111]466 if ( pidfile != NULL ) {
467  if ( roar_vio_open_file(&fh, pidfile, O_RDONLY, 0644) == -1 ) {
468   ROAR_WARN("restart_server(*): Can not read pidfile: %s", pidfile);
469  } else {
470   l = roar_vio_read(&fh, buf, 80);
471   roar_vio_close(&fh);
472   if ( l > 0 ) {
473    buf[l-1] = 0;
474    buf[79]  = 0;
475    pid = atoi(buf);
476    if ( terminate ) {
[2113]477     ok = kill(pid, SIGUSR1);
[2111]478    } else {
479     ok = kill(pid, SIGINT);
480    }
481    if ( ok == 0 ) {
482     return 0;
483    } else {
484     ROAR_WARN("restart_server(*): Can not kill roard by pidfile");
485    }
486   } else {
487    ROAR_WARN("restart_server(*): Can not find a PID in the pidfile");
488   }
489  }
490 }
491#endif
[2109]492
[4722]493 if ( roar_simple_connect(&con, server, "roard") == -1 ) {
[579]494  return -1;
495 }
496
[2109]497 if ( roar_terminate(&con, terminate) == -1 ) {
[579]498  return -1;
499 }
500
501 return roar_disconnect(&con);
502}
503
[444]504#define R_SETUID 1
505#define R_SETGID 2
506
[1609]507int init_config (void) {
508 int i;
509
510 memset(g_config, 0, sizeof(struct roard_config));
511
512 for (i = 0; i < ROAR_DIR_DIRIDS; i++) {
513  g_config->streams[i].mixer_channels = 1;
514  g_config->streams[i].mixer.rpg_mul  = 1;
515  g_config->streams[i].mixer.rpg_div  = 1;
516  g_config->streams[i].mixer.scale    = 65535;
517  g_config->streams[i].mixer.mixer[0] = g_config->streams[i].mixer.scale;
518 }
519
[2291]520 g_config->streams[ROAR_DIR_PLAY    ].flags = ROAR_FLAG_META;
[2413]521 g_config->streams[ROAR_DIR_OUTPUT  ].flags = ROAR_FLAG_PASSMIXER;
[2264]522 g_config->streams[ROAR_DIR_FILTER  ].flags = ROAR_FLAG_SYNC;
[1899]523 g_config->streams[ROAR_DIR_MIDI_OUT].flags = ROAR_FLAG_SYNC;
[2160]524 g_config->streams[ROAR_DIR_BIDIR   ].flags = ROAR_FLAG_ANTIECHO;
[1899]525
[4442]526 g_config->location    = CONF_DEF_STRING;
527 g_config->description = CONF_DEF_STRING;
[2017]528
[4245]529 g_config->memlock_level = -1;
530
[4851]531#ifdef ROAR_HAVE_SYSTEM
532 g_config->scripts.post_shutdown = NULL;
533#endif
534
[1609]535 return 0;
536}
537
[2530]538#ifdef ROAR_SUPPORT_LISTEN
539int init_listening (void) {
540 int i;
541
[3128]542 memset(g_listen, 0, sizeof(g_listen));
543
[2530]544 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3128]545  g_listen[i].proto  = ROAR_PROTO_ROARAUDIO;
[2530]546  server[i]          = NULL;
547 }
548
549 return 0;
550}
551
[3731]552int get_listen(struct roard_listen ** sock, char *** sockname) {
[3730]553 int i;
554
555 if ( sock == NULL )
556  return -1;
557
558 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]559  if ( ! g_listen[i].used ) {
[3730]560   server[i] = NULL;
[3731]561   *sock = &(g_listen[i]);
[3730]562
[3733]563   if ( sockname != NULL )
[3730]564    *sockname = &(server[i]);
[3733]565
566   return 0;
[3730]567  }
568 }
569
570 return -1;
571}
572
[3956]573#ifdef ROAR_SUPPORT_LISTEN
574static struct _listen_profile {
575 const char * name;
576 int          type;
577 int          port;
578 const char * sockaddr;
579 int          proto;
580 int          dir;
581 const char * aiprofile;
582 const char * desc;
583} _g_listen_profiles[] = {
584 // RoarAudio:
[3992]585#ifdef ROAR_HAVE_UNIX
[4058]586 {"roar-usock",     ROAR_SOCKET_TYPE_UNIX,   0,                 "~/" ROAR_DEFAULT_SOCK_USER,
587                    ROAR_PROTO_ROARAUDIO, -1, NULL,
588                    "RoarAudio default user profile"},
589 {"roar-gsock",     ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_SOCK_GLOBAL,
590                    ROAR_PROTO_ROARAUDIO, -1, NULL,
591                    "RoarAudio default global profile"},
[3992]592#endif
593#ifdef ROAR_HAVE_IPV4
[4058]594 {"roar-tcp",       ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, ROAR_DEFAULT_INET4_HOST,
595                    ROAR_PROTO_ROARAUDIO, -1, NULL,
596                    "RoarAudio local TCP profile"},
597 {"roar-tcp-pub",   ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, ROAR_NET_INET4_ANYHOST,
598                    ROAR_PROTO_ROARAUDIO, -1, NULL,
599                    "RoarAudio network TCP profile"},
[3992]600#endif
[4760]601#ifdef ROAR_HAVE_IPV6
[5096]602 {"roar-tcp6",      ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PORT, ROAR_DEFAULT_INET6_HOST,
[4760]603                    ROAR_PROTO_ROARAUDIO, -1, NULL,
604                    "RoarAudio local TCP profile"},
[5096]605 {"roar-tcp-pub6",  ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PORT, ROAR_NET_INET6_ANYHOST,
[4760]606                    ROAR_PROTO_ROARAUDIO, -1, NULL,
607                    "RoarAudio network TCP profile"},
608#endif
[3992]609#ifdef ROAR_HAVE_LIBDNET
[4058]610 {"roar-dnet",      ROAR_SOCKET_TYPE_DECNET, 0,                 ROAR_DEFAULT_LISTEN_OBJECT,
611                    ROAR_PROTO_ROARAUDIO, -1, NULL,
612                    "RoarAudio default DECnet"},
[3992]613#endif
614#ifdef ROAR_HAVE_UNIX
[4810]615 {"roar-abstract",  ROAR_SOCKET_TYPE_UNKNOWN,   0,              "+abstract",        ROAR_PROTO_ROARAUDIO, -1, NULL,
[4058]616                    "RoarAudio abstract namespace profile"},
[3992]617#endif
[3956]618
619 // EsounD:
[3992]620#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
621#ifdef ROAR_HAVE_UNIX
[4058]622 {"esd-unix",       ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_ESD_GSOCK,
623                    ROAR_PROTO_ESOUND,    -1, NULL,
624                    "EsounD default local profile"},
[3992]625#endif
626#ifdef ROAR_HAVE_IPV4
[4058]627 {"esd-tcp",        ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET4_LOCALHOST,
628                    ROAR_PROTO_ESOUND,    -1, NULL,
629                    "EsounD local TCP profile"},
630 {"esd-tcp-pub",    ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET4_ANYHOST,
631                    ROAR_PROTO_ESOUND,    -1, NULL,
632                    "EsounD network TCP profile"},
[3992]633#endif
[4760]634#ifdef ROAR_HAVE_IPV6
[4761]635 {"esd-tcp6",       ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET6_LOCALHOST,
[4760]636                    ROAR_PROTO_ESOUND,    -1, NULL,
637                    "EsounD local TCP profile"},
[4761]638 {"esd-tcp-pub6",   ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_ESD_PORT, ROAR_NET_INET6_ANYHOST,
[4760]639                    ROAR_PROTO_ESOUND,    -1, NULL,
640                    "EsounD network TCP profile"},
641#endif
[3992]642#endif
[3956]643
644 // RSound:
[3992]645#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
646#ifdef ROAR_HAVE_UNIX
[4058]647 {"rsound-unix",    ROAR_SOCKET_TYPE_UNIX,   0,                 ROAR_DEFAULT_RSOUND_GSOCK,
648                    ROAR_PROTO_RSOUND,    -1, NULL,
649                    "RSound default local profile"},
[3992]650#endif
651#ifdef ROAR_HAVE_IPV4
[4058]652 {"rsound-tcp",     ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET4_LOCALHOST,
653                    ROAR_PROTO_RSOUND,    -1, NULL,
654                    "RSound local TCP profile"},
655 {"rsound-tcp-pub", ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET4_ANYHOST,
656                    ROAR_PROTO_RSOUND,    -1, NULL,
657                    "RSound network TCP profile"},
[3992]658#endif
[4760]659#ifdef ROAR_HAVE_IPV6
[4761]660 {"rsound-tcp6",    ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET6_LOCALHOST,
[4760]661                    ROAR_PROTO_RSOUND,    -1, NULL,
662                    "RSound local TCP profile"},
[4761]663 {"rsound-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,  ROAR_DEFAULT_RSOUND_PORT, ROAR_NET_INET6_ANYHOST,
[4760]664                    ROAR_PROTO_RSOUND,    -1, NULL,
665                    "RSound network TCP profile"},
666#endif
[3992]667#ifdef ROAR_HAVE_LIBDNET
[4058]668 {"rsound-dnet",    ROAR_SOCKET_TYPE_DECNET, 0,                 ROAR_DEFAULT_RSOUND_OBJECT,
669                    ROAR_PROTO_RSOUND,    -1, NULL,
670                    "RSound DECnet profile"},
[3992]671#endif
672#endif
[3957]673
674 // PulseAudio Simple:
[3992]675#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
676#ifdef ROAR_HAVE_IPV4
[4058]677 {"pas-play-tcp",   ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PA_PORT, ROAR_NET_INET4_ANYHOST,
678                    ROAR_PROTO_SIMPLE, ROAR_DIR_PLAY, "default",
679                    "PulseAudio Simple TCP play profile"},
680 {"pas-mon-tcp",    ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PA_PORT, ROAR_NET_INET4_ANYHOST,
681                    ROAR_PROTO_SIMPLE, ROAR_DIR_MONITOR, "default",
682                    "PulseAudio Simple TCP monitor profile"},
[3992]683#endif
[4760]684#ifdef ROAR_HAVE_IPV6
[4761]685 {"pas-play-tcp6",  ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PA_PORT, ROAR_NET_INET6_ANYHOST,
[4760]686                    ROAR_PROTO_SIMPLE, ROAR_DIR_PLAY, "default",
687                    "PulseAudio Simple TCP play profile"},
[4761]688 {"pas-mon-tcp6",   ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_PA_PORT, ROAR_NET_INET6_ANYHOST,
[4760]689                    ROAR_PROTO_SIMPLE, ROAR_DIR_MONITOR, "default",
690                    "PulseAudio Simple TCP monitor profile"},
691#endif
[3992]692#endif
[3987]693
694 // RPlay:
[3992]695#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
696#ifdef ROAR_HAVE_IPV4
[4058]697 {"rplay-tcp",      ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET4_LOCALHOST,
698                    ROAR_PROTO_RPLAY,     -1, NULL,
699                    "RPlay local TCP profile"},
700 {"rplay-tcp-pub",  ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET4_ANYHOST,
701                    ROAR_PROTO_RPLAY,     -1, NULL,
702                    "RPlay network TCP profile"},
[3992]703#endif
[4760]704#ifdef ROAR_HAVE_IPV6
[4761]705 {"rplay-tcp6",     ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET6_LOCALHOST,
[4760]706                    ROAR_PROTO_RPLAY,     -1, NULL,
707                    "RPlay local TCP profile"},
[4761]708 {"rplay-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_RPLAY_PORT, ROAR_NET_INET6_ANYHOST,
[4760]709                    ROAR_PROTO_RPLAY,     -1, NULL,
710                    "RPlay network TCP profile"},
711#endif
[3992]712#endif
[3987]713
[4710]714// Gopher:
715#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
[4760]716#ifdef ROAR_HAVE_IPV4
[4710]717 {"gopher-tcp",     ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET4_LOCALHOST,
718                    ROAR_PROTO_GOPHER,    -1, NULL,
719                    "Gopher local TCP profile"},
720 {"gopher-tcp-pub", ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET4_ANYHOST,
721                    ROAR_PROTO_GOPHER,    -1, NULL,
722                    "Gopher network TCP profile"},
723#endif
[4760]724#ifdef ROAR_HAVE_IPV6
[4761]725 {"gopher-tcp6",    ROAR_SOCKET_TYPE_TCP6,   ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET6_LOCALHOST,
[4760]726                    ROAR_PROTO_GOPHER,    -1, NULL,
727                    "Gopher local TCP profile"},
[4761]728 {"gopher-tcp-pub6", ROAR_SOCKET_TYPE_TCP6,  ROAR_DEFAULT_GOPHER_PORT, ROAR_NET_INET6_ANYHOST,
[4760]729                    ROAR_PROTO_GOPHER,    -1, NULL,
730                    "Gopher network TCP profile"},
731#endif
732#endif
[4710]733
[3987]734 // End of List:
[3956]735 {NULL, -1, -1, NULL, -1, -1, NULL, NULL}
736};
737
738void listen_listen_profiles (void) {
739 struct _listen_profile * p;
740 char * type;
741 int i;
[3987]742 char port[8];
[3956]743
[4760]744 printf("Name            Type    Address          Port    Protocol  Dir        Audio Profile - Description\n");
745 printf("-------------------------------------------------------------------------------------------------\n");
[3956]746      //roar-tcp-pub 0.0.0.0       16002   RoarAudio unknown    (null) - (null)
747
748 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
749  switch (p->type) {
750   case ROAR_SOCKET_TYPE_UNIX:   type = "UNIX";   break;
751   case ROAR_SOCKET_TYPE_TCP:    type = "TCP";    break;
752   case ROAR_SOCKET_TYPE_DECNET: type = "DECnet"; break;
[4760]753   case ROAR_SOCKET_TYPE_TCP6:   type = "TCP6";   break;
[3956]754   default:
755     type = "unknown";
756    break;
757  }
[3987]758
759  if ( p->port ) {
[4049]760   snprintf(port, sizeof(port)-1, "%i", p->port);
761   port[sizeof(port)-1] = 0;
[3987]762  } else {
763   strcpy(port, "(none)");
764  }
765
[4760]766  printf("%-15s %-7s %-16s %-7s %-9s %-10s %-13s - %s\n",
[3956]767           p->name,
768           type,
[3987]769           p->sockaddr, port,
[3956]770           roar_proto2str(p->proto),
[3957]771           p->dir == -1 ? "(none)" : roar_dir2str(p->dir), p->aiprofile == NULL ? "(none)" : p->aiprofile,
[3956]772           p->desc == NULL ? "" : p->desc);
773 }
774}
775
776int get_listen_profile (const char * name,
777                        int * port, char ** sockaddr, int * type,
778                        int * proto,
779                        int * dir, struct roar_audio_info * info) {
780 static char buf[1024];
781 struct _listen_profile * p;
782 int i;
783
784 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
785  if ( !strcasecmp(p->name, name) ) {
786   *port     = p->port;
787
[3959]788   if ( p->type == ROAR_SOCKET_TYPE_UNIX && p->sockaddr[0] != '+' ) {
789    roar_env_render_path_r(buf, sizeof(buf), p->sockaddr);
790   } else {
791    strncpy(buf, p->sockaddr, sizeof(buf));
792   }
[3956]793   *sockaddr = buf;
[4642]794   *type     = p->type;
[3956]795
796   *proto    = p->proto;
797   *dir      = p->dir;
798
799   if ( p->aiprofile != NULL ) {
800    if ( roar_profile2info(info, p->aiprofile) == -1 ) {
801     ROAR_ERR("Unknown audio profile: %s", p->aiprofile);
802     return -1;
803    }
804   }
805   return 0;
806  }
807 }
808
809 return -1;
810}
811#endif
812
[3252]813int add_listen (char * addr, int port, int sock_type, char * user, char * group, int proto, int dir, struct roar_audio_info * info) {
[2530]814#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
815 struct group   * grp  = NULL;
816#endif
817#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
818 struct passwd  * pwd  = NULL;
819#endif
820#ifdef ROAR_HAVE_UNIX
821 char * env_roar_proxy_backup;
822#endif
823 int    sockid = -1;
[3907]824#ifdef ROAR_HAVE_UNIX
[2530]825 int    sock;
[3907]826#endif
[2530]827 int    i;
828
[4055]829 ROAR_INFO("add_listen(addr='%s', port=%i, sock_type=%i, user='%s', group='%s', proto=%s(%i), dir=%s(%i), info={.rate=%u, .bits=%u, .channels=%u, .codec=%s(%u)}): trying to add listen socket",
830            ROAR_DBG_INFO_INFO,
831            addr, port, sock_type, user, group, roar_proto2str(proto), proto, roar_dir2str(dir), dir,
832            info->rate, info->bits, info->channels, roar_codec2str(info->codec), info->codec);
833
[2530]834 if ( *addr != 0 ) {
835  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]836   if ( ! g_listen[i].used ) {
[2530]837    sockid = i;
838    break;
839   }
840  }
841
842  if ( sockid == -1 )
843   return -1;
844
[3128]845  g_listen[sockid].proto = proto;
[2530]846
847  ROAR_DBG("add_listen(*): proto=0x%.4x", proto);
848
[3802]849  if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
[2530]850#ifdef ROAR_HAVE_UNIX
851   if ( *addr == '/' ) {
852    if ( (env_roar_proxy_backup = getenv("ROAR_PROXY")) != NULL ) {
[4975]853     env_roar_proxy_backup = roar_mm_strdup(env_roar_proxy_backup);
[2530]854     unsetenv("ROAR_PROXY");
855    }
856    if ( (sock = roar_socket_connect(addr, port)) != -1 ) {
857     close(sock);
[3040]858     ROAR_ERR("Can not open listen socket: Socket allready in use");
[4641]859     return -1;
[2530]860    } else {
861     unlink(addr);
[3802]862     if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
[3040]863      ROAR_ERR("Can not open listen socket: %s", strerror(errno));
[4641]864      return -1;
[2530]865     }
866    }
867    if ( env_roar_proxy_backup != NULL ) {
868     setenv("ROAR_PROXY", env_roar_proxy_backup, 0);
[4975]869     roar_mm_free(env_roar_proxy_backup);
[2530]870    }
871#else
872   if (0) { // noop
873#endif
874   } else {
[3041]875    ROAR_ERR("Can not open listen socket: %s", strerror(errno));
[4641]876    return -1;
[2530]877   }
878  }
879
[4641]880  ROAR_DBG("add_listen(*) = ?");
881
[2530]882#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[2753]883  if ( group != NULL ) {
884   if ( (grp = getgrnam(group)) == NULL ) {
885    ROAR_ERR("Can not get GID for group %s: %s", group, strerror(errno));
886   }
[2530]887  }
888#endif
[4641]889
890  ROAR_DBG("add_listen(*) = ?");
891
[2530]892#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[5047]893  if ( user != NULL ) {
[2530]894   if ( (pwd = getpwnam(user)) == NULL ) {
895    ROAR_ERR("Can not get UID for user %s: %s", user, strerror(errno));
896   }
897  }
898#endif
899
[4641]900  ROAR_DBG("add_listen(*) = ?");
901
[2530]902#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_UNIX)
903  if ( *addr == '/' ) {
[5046]904   if ( grp != NULL || pwd != NULL ) {
905     if ( chown(addr, pwd != NULL ? pwd->pw_uid : -1, grp != NULL ? grp->gr_gid : -1) == -1 )
[4641]906      return -1;
[2753]907   }
[2530]908#ifdef ROAR_HAVE_GETUID
[5046]909   if ( grp != NULL ) {
[2530]910    if ( getuid() == 0 )
911     if ( chmod(addr, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1 )
[4641]912      return -1;
[2753]913   }
[2530]914#endif
915  }
916#endif
917 }
918
[4641]919 ROAR_DBG("add_listen(*) = ?");
920
[2736]921 // in case we opened the listening socket correctly.
[3256]922 if ( dir == -1 )
923  dir = ROAR_DIR_PLAY;
924
[3252]925 g_listen[sockid].inst.stpl.dir = dir;
926 memcpy(&(g_listen[sockid].inst.stpl.info), info, sizeof(struct roar_audio_info));
[3256]927
928 switch (dir) {
929  case ROAR_DIR_PLAY:
930  case ROAR_DIR_RECORD:
931  case ROAR_DIR_MONITOR:
932  case ROAR_DIR_FILTER:
933  case ROAR_DIR_BIDIR:
934    if ( !g_listen[sockid].inst.stpl.info.rate )
935     g_listen[sockid].inst.stpl.info.rate = g_sa->rate;
936
937    if ( !g_listen[sockid].inst.stpl.info.bits )
938     g_listen[sockid].inst.stpl.info.bits = g_sa->bits;
939
940    if ( !g_listen[sockid].inst.stpl.info.channels )
941     g_listen[sockid].inst.stpl.info.channels = g_sa->channels;
942
943    if ( !g_listen[sockid].inst.stpl.info.codec )
944     g_listen[sockid].inst.stpl.info.codec = g_sa->codec;
945   break;
946 }
947
[3802]948 g_listen[sockid].used = 1;
949 server[sockid]        = addr;
950
[2530]951 return 0;
952}
953#endif
954
[4882]955static void list_aiprofiles (void) {
956 struct roar_audio_info info;
957 const char * list[1024];
958 const char * mime;
959 ssize_t ret;
960 ssize_t i;
961
962 ret = roar_profiles_list(list, 1024, 0);
963
964 if ( ret == -1 )
965  return;
966
967 printf("  Name       Rate  Bits  Channels  Codec\n");
968 printf("---------------------------------------------\n");
969 for (i = 0; i < ret; i++) {
[5161]970  if ( roar_profile2info(&info, list[i]) == -1 ) {
971   printf("  %-10s --- unknown parameters ---\n", list[i]);
972   continue;
973  }
[4882]974
975  mime = roar_codec2mime(info.codec);
976
977  printf("  %-10s %5u %4u  %8u  %3u (%s%s%s%s)\n", list[i],
978            info.rate, info.bits, info.channels,
979            info.codec, roar_codec2str(info.codec),
980            info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
981            mime == NULL ? "" : " mimetype:",
982            mime == NULL ? "" : mime
983        );
984 }
985}
986
[2339]987int update_stream_flags (char * str) {
988 int    dir;
989 char * flags;
990 char * k;
991 int    op;
992 int    flag;
993
994 if ( (flags = strstr(str, "=")) == NULL )
995  return -1;
996
997 *flags = 0;
998  flags++;
999
1000 if ( (dir = roar_str2dir(str)) == -1 )
1001  return -1;
1002
1003 while (flags != NULL) {
1004  k = flags;
1005  flags = strstr(flags, ",");
1006
1007  if ( flags != NULL )
1008   *(flags++) = 0;
1009
1010  switch (*k) {
[2340]1011   case '+': k++; op = ROAR_SET_FLAG;   break;
1012   case '-': k++; op = ROAR_RESET_FLAG; break;
[2339]1013   default:
[2340]1014     op = ROAR_SET_FLAG;
[2339]1015  }
1016
1017  flag = 0;
1018
1019  if ( !strcmp(k, "sync") ) {
1020   flag = ROAR_FLAG_SYNC;
1021  } else if ( !strcmp(k, "meta") ) {
1022   flag = ROAR_FLAG_META;
1023  } else if ( !strcmp(k, "cleanmeta") ) {
1024   flag = ROAR_FLAG_CLEANMETA;
1025  } else if ( !strcmp(k, "pause") ) {
1026   flag = ROAR_FLAG_PAUSE;
1027  } else if ( !strcmp(k, "mute") ) {
1028   flag = ROAR_FLAG_MUTE;
1029  } else if ( !strcmp(k, "antiecho") ) {
1030   flag = ROAR_FLAG_ANTIECHO;
[2413]1031  } else if ( !strcmp(k, "passmixer") ) {
1032   flag = ROAR_FLAG_PASSMIXER;
[4815]1033  } else if ( !strcmp(k, "recsource") ) {
1034   flag = ROAR_FLAG_RECSOURCE;
[2339]1035  } else {
1036   return -1;
1037  }
1038
1039  g_config->streams[dir].flags |= flag;
1040
[2340]1041  if ( op == ROAR_RESET_FLAG )
[2339]1042   g_config->streams[dir].flags -= flag;
1043 }
1044
1045 return 0;
1046}
1047
[4788]1048int add_authfile (const char * file, const char * type, enum af_mode mode, enum roard_client_acclev acclev) {
1049 struct roar_authfile * authfile = NULL;
1050 struct roar_authfile_key *  key = NULL;
1051 int af_type = ROAR_AUTHFILE_TYPE_AUTO;
[4790]1052 void * keydata;
[4792]1053 int i;
[4788]1054
1055 if ( type == NULL ) {
1056  // noop.
1057 } else if ( !strcasecmp(type, "roar") ) {
1058  af_type = ROAR_AUTHFILE_TYPE_ROAR;
1059 } else if ( !strcasecmp(type, "roar") ) {
1060  af_type = ROAR_AUTHFILE_TYPE_ROAR;
1061 } else if ( !strcasecmp(type, "esd") ) {
1062  af_type = ROAR_AUTHFILE_TYPE_ESD;
1063 } else if ( !strcasecmp(type, "pulse") ) {
1064  af_type = ROAR_AUTHFILE_TYPE_PULSE;
1065 } else if ( !strcasecmp(type, "htpasswd") ) {
1066  af_type = ROAR_AUTHFILE_TYPE_HTPASSWD;
1067 } else if ( !strcasecmp(type, "xauth") ) {
1068  af_type = ROAR_AUTHFILE_TYPE_XAUTH;
1069 } else {
1070  ROAR_ERR("add_authfile(*): unknown authfile type '%s'.", type);
1071  return -1;
1072 }
1073
1074 if ( mode == AF_MODE_GEN && af_type == ROAR_AUTHFILE_TYPE_AUTO )
1075  af_type = ROAR_AUTHFILE_TYPE_ESD;
1076
1077 switch (mode) {
1078  case AF_MODE_NONE:
1079    return 0;
1080   break;
1081  case AF_MODE_GEN:
1082    switch (af_type) {
1083     case ROAR_AUTHFILE_TYPE_ESD:
1084       key = roar_authfile_key_new_random(ROAR_AUTH_T_COOKIE, 16, NULL);
1085      break;
1086     case ROAR_AUTHFILE_TYPE_PULSE:
1087       key = roar_authfile_key_new_random(ROAR_AUTH_T_COOKIE, 256, NULL);
1088      break;
1089     default:
1090       return -1;
1091      break;
1092    }
1093
1094    if ( key == NULL ) {
1095     ROAR_ERR("add_authfile(*): Can not generate key.");
1096     return -1;
1097    }
1098
1099    if ( (authfile = roar_authfile_open(af_type, file, 1, ROAR_AUTHFILE_VERSION_AUTO)) == NULL ) {
1100     roar_authfile_key_unref(key);
1101     return -1;
1102    }
1103
1104    if ( roar_authfile_add_key(authfile, key) == -1 ) {
1105     ROAR_WARN("add_authfile(*): Can not add key to authfile.");
1106    }
1107
[4790]1108    keydata = roar_mm_memdup(key->data, key->len);
1109
1110    if ( keydata == NULL ) {
1111     ROAR_WARN("add_authfile(*): Can not allocate memory for key.");
1112    } else if ( auth_addkey_cookie(acclev, keydata, key->len) == -1 ) {
[4788]1113     ROAR_WARN("add_authfile(*): Can not add key to internal key storage.");
1114    }
1115
1116    roar_authfile_key_unref(key);
1117    if ( roar_authfile_close(authfile) != 0 )
1118     return -1;
1119    return 0;
1120   break;
[4792]1121  case AF_MODE_LOAD:
1122    if ( (authfile = roar_authfile_open(af_type, file, 0, ROAR_AUTHFILE_VERSION_AUTO)) == NULL ) {
1123     return -1;
1124    }
1125
1126    for (i = 0; ; i++) {
1127     key = roar_authfile_lookup_key(authfile, ROAR_AUTH_T_AUTO, i, NULL);
1128     if ( key == NULL )
1129      break;
1130
1131     if ( key->type == ROAR_AUTH_T_COOKIE ) {
1132      keydata = roar_mm_memdup(key->data, key->len);
1133
1134      if ( keydata == NULL ) {
1135       ROAR_WARN("add_authfile(*): Can not allocate memory for key.");
1136      } else if ( auth_addkey_cookie(acclev, keydata, key->len) == -1 ) {
1137       ROAR_WARN("add_authfile(*): Can not add key to internal key storage.");
1138      }
1139     } else {
1140      ROAR_WARN("add_authfile(*): Unknown key type: %i", key->type);
1141     }
1142
1143     roar_authfile_key_unref(key);
1144    }
1145
1146    if ( roar_authfile_close(authfile) != 0 )
1147     return -1;
1148    return 0;
1149   break;
[4788]1150 }
1151
1152 return -1;
1153}
1154
[3373]1155// X11:
1156#ifdef ROAR_HAVE_LIBX11
1157int register_x11 (int unreg, char * sockname) {
1158 struct roar_x11_connection * x11con = NULL;
1159 int ret = 0;
1160
[4103]1161 if ( (x11con = roar_x11_connect(x11display)) == NULL ) {
[4155]1162  ROAR_ERR("Can not connect to X11 server for %sregistering", unreg ? "un" : "");
[3373]1163  return -1;
[4103]1164 }
[3373]1165
1166 if ( unreg ) {
[4103]1167  if ( roar_x11_delete_prop(x11con, "ROAR_SERVER") == -1 ) {
[3373]1168   ret = -1;
[4103]1169   ROAR_ERR("Error while unregistereing from X11", ROAR_DBG_INFO_INFO);
1170  } else {
1171   ROAR_INFO("Successfully unregistered from X11", ROAR_DBG_INFO_INFO);
1172  }
[3373]1173 } else {
[4103]1174  if ( roar_x11_set_prop(x11con, "ROAR_SERVER", sockname) == -1 ) {
[3373]1175   ret = -1;
[4103]1176   ROAR_ERR("Error while registereing to X11", ROAR_DBG_INFO_INFO);
1177  } else {
1178   ROAR_INFO("Successfully registered to X11", ROAR_DBG_INFO_INFO);
1179  }
[3373]1180 }
1181
1182 roar_x11_disconnect(x11con);
1183
1184 return ret;
1185}
1186#endif
[1993]1187
1188// SLP:
1189void register_slp_callback(SLPHandle hslp, SLPError errcode, void * cookie) {
1190 /* return the error code in the cookie */
1191 *(SLPError*)cookie = errcode;
1192}
1193
1194int register_slp (int unreg, char * sockname) {
1195#ifdef ROAR_HAVE_LIBSLP
1196 static int regged = 0;
1197 static char * sn = NULL;
1198 SLPError err;
1199 SLPError callbackerr;
1200 SLPHandle hslp;
1201 char addr[1024];
1202 char attr[1024] = "";
[2017]1203 char * location;
[4421]1204 char * description;
[4577]1205 char * standards;
[1993]1206
1207 if ( sockname != NULL )
1208  sn = sockname;
1209
[3076]1210 snprintf(addr, sizeof(addr), ROAR_SLP_URL_TYPE_ROAR "://%s", sn);
[1993]1211
1212 err = SLPOpen("en", SLP_FALSE, &hslp);
1213
1214 if (err != SLP_OK) {
1215  ROAR_ERR("Error opening slp handle: Error #%i", err);
1216  return -1;
1217 }
1218
1219 if (!unreg) {
[2017]1220
1221  if ( SLPEscape(g_config->location, &location, SLP_FALSE) != SLP_OK ) {
1222   ROAR_ERR("Error using SLPEscape() on server location, really bad!");
1223   SLPClose(hslp);
1224   return -1;
1225  }
1226
[4421]1227  if ( SLPEscape(g_config->description, &description, SLP_FALSE) != SLP_OK ) {
1228   ROAR_ERR("Error using SLPEscape() on server location, really bad!");
1229   SLPClose(hslp);
1230   return -1;
1231  }
1232
[4577]1233  standards = stds_string();
1234
1235  if ( standards == NULL ) {
1236   if ( (standards = roar_mm_malloc(1)) == NULL ) {
1237    SLPClose(hslp);
1238    return -1;
1239   }
1240   standards[0] = 0;
1241  }
1242
[1995]1243  snprintf(attr, sizeof(attr), "(wave-rate=%i),(wave-channels=%i),(wave-bits=%i),"
[2494]1244#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1245                               "(light-channels=%i),"
1246#endif
[4577]1247                               "(standards=%s),"
[4421]1248                               "(location=%s),(description=%s)",
[1995]1249           g_sa->rate, g_sa->channels, g_sa->bits,
[2494]1250#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[2017]1251           g_light_state.channels,
[2494]1252#endif
[4577]1253           standards,
[4421]1254           location, description
[1995]1255          );
1256
[4577]1257  roar_mm_free(standards);
1258
[1993]1259  /* Register a service with SLP */
1260  err = SLPReg(hslp,
1261               addr,
1262               SLP_LIFETIME_MAXIMUM,
1263               0,
1264               attr,
1265               SLP_TRUE,
1266               register_slp_callback,
1267               &callbackerr);
[1994]1268  regged = 1;
1269 } else if ( unreg && regged ) {
1270  err = SLPDereg(hslp, addr, register_slp_callback, &callbackerr);
1271  regged = 0;
1272 } else {
1273  SLPClose(hslp);
1274  return -1;
1275 }
[1993]1276
[1994]1277 /* err may contain an error code that occurred as the slp library    */
1278 /* _prepared_ to make the call.                                     */
1279 if ( err != SLP_OK ) {
1280  ROAR_ERR("Error (de)registering service with slp: Error #%i", err);
1281  return -1;
1282 }
1283
1284 /* callbackerr may contain an error code (that was assigned through */
1285 /* the callback cookie) that occurred as slp packets were sent on    */
1286 /* the wire */
1287 if (callbackerr != SLP_OK) {
1288  ROAR_ERR("Error (de)registering service with slp: Error #%i", callbackerr);
1289  return -1;
[1993]1290 }
1291
1292 SLPClose(hslp);
1293 return 0;
1294#else
1295 return -1;
1296#endif
1297}
1298
[4481]1299static int auth_setup (enum roard_client_acclev none_acclev,
1300                       enum roard_client_acclev trust_acclev, int trust_root, uid_t trust_uid, gid_t trust_gid) {
1301 union auth_typeunion * key;
1302 size_t i;
1303
[4482]1304 // Info:
1305 // if a authlevel is <= ACCLEV_IDENTED we do not need to add this to the keyring
1306 // as ACCLEV_IDENTED is already gained if IDENTIFY call was done correctly.
[4481]1307
[4482]1308 if ( !(none_acclev <= ACCLEV_IDENTED) ) {
1309  if ( auth_addkey_anonymous(none_acclev) == -1 )
1310   return -1;
1311 }
[4481]1312
[4482]1313 if ( !(trust_acclev <= ACCLEV_IDENTED) ) {
1314  if ( (key = auth_regkey_simple(ROAR_AUTH_T_TRUST, trust_acclev)) == NULL )
1315   return -1;
[4481]1316
[4482]1317  // zerosize all counters.
1318  memset(key, 0, sizeof(union auth_typeunion));
[4481]1319
[4482]1320  i = 0;
1321
1322  if ( trust_uid != -1 )
1323   key->trust.uids[i++] = trust_uid;
[4481]1324
1325#ifdef ROAR_ROOT_UID
[4482]1326  if ( trust_root )
1327   key->trust.uids[i++] = ROAR_ROOT_UID;
[4481]1328#endif
1329
[4482]1330  key->trust.uids_len = i;
[4481]1331
[4482]1332  i = 0;
[4481]1333
[4482]1334  if ( trust_gid != -1 )
1335   key->trust.gids[i++] = trust_gid;
[4481]1336
[4482]1337  key->trust.gids_len = i;
1338 }
[4481]1339
1340 return 0;
1341}
1342
[1993]1343
1344// MAIN:
1345
[4053]1346#define _CKHAVEARGS(x) if ( (i + (x)) >= argc ) { \
1347                        ROAR_ERR("Option %s requires more arguments. See --help for more details.", k); \
1348                        return 70; \
1349                       }
[4052]1350
[1503]1351#ifdef ROAR_HAVE_MAIN_ARGS
[0]1352int main (int argc, char * argv[]) {
[1503]1353#else
1354int main (void) {
1355#endif
1356#ifdef ROAR_HAVE_MAIN_ARGS
[4722]1357 enum action action = START;
[0]1358 int i;
1359 char * k;
[4955]1360 enum output_format print_format = FORMAT_NATIVE;
[1503]1361#endif
[2787]1362#if defined(ROAR_SUPPORT_LISTEN) && defined(ROAR_HAVE_GETUID)
[905]1363 char user_sock[80]  = {0};
[1494]1364#endif
[1609]1365 struct roar_audio_info sa, max_sa;
1366 struct roard_config config;
[4934]1367 const struct rolestack * rolestack;
[5060]1368#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
[905]1369 int    daemon       = 0;
[1486]1370#endif
[905]1371 int    realtime     = 0;
1372 int    sysclocksync = 0;
[60]1373// char * server = ROAR_DEFAULT_SOCK_GLOBAL;
[1494]1374#ifdef ROAR_SUPPORT_LISTEN
[2530]1375 int    port       = ROAR_DEFAULT_PORT;
1376 char * sock_addr  = NULL;
1377 int    sock_proto = ROAR_PROTO_ROARAUDIO;
[3252]1378 int    sock_dir   = -1;
1379 struct roar_audio_info sock_info = {0, 0, 0, 0};
[1494]1380#endif
[2486]1381#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[5103]1382 char * s_drv     = NULL;
[1110]1383 char * s_dev     = NULL;
[444]1384 char * s_con     = NULL;
1385 char * s_opt     = NULL;
1386 int    s_prim    = 0;
[2486]1387#endif
[1207]1388 char * o_drv     = getenv("ROAR_DRIVER");
1389 char * o_dev     = getenv("ROAR_DEVICE");
[932]1390 char * o_opts    = NULL;
[961]1391 int    o_prim    = 0;
[1145]1392 int    o_count   = 0;
[4358]1393#ifndef ROAR_WITHOUT_DCOMP_MIXER
1394 char * m_drv     = NULL;
1395 char * m_dev     = NULL;
1396 char * m_opts    = NULL;
1397 int    m_prim    = 0;
1398 int    m_count   = 0;
1399#endif
[4481]1400 enum roard_client_acclev none_acclev  = ACCLEV_ALL;
1401 enum roard_client_acclev trust_acclev = ACCLEV_ALL;
1402 int                      trust_root   = 1;
[4788]1403 char * af_file                        = NULL;
1404 char * af_type                        = NULL;
1405 enum af_mode af_mode                  = AF_MODE_NONE;
1406 enum roard_client_acclev af_acclev    = ACCLEV_ALL;
[2494]1407#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]1408 int    light_channels = LIGHT_CHANNELS_DEFAULT;
[2494]1409#endif
[2751]1410#ifdef ROAR_DEFAULT_SOCKGRP
[450]1411 char * sock_grp  = ROAR_DEFAULT_SOCKGRP;
[2751]1412#else
1413 char * sock_grp  = NULL;
1414#endif
[444]1415 char * sock_user = NULL;
[1494]1416#ifdef ROAR_SUPPORT_LISTEN
[517]1417 int    sock_type = ROAR_SOCKET_TYPE_UNKNOWN;
[1494]1418#endif
[1993]1419#ifdef ROAR_HAVE_LIBSLP
1420 int    reg_slp   = 0;
1421#endif
[3373]1422#ifdef ROAR_HAVE_LIBX11
1423 int    reg_x11   = 0;
1424#endif
[1486]1425#ifdef ROAR_HAVE_CHROOT
[444]1426 char * chrootdir = NULL;
[1486]1427#endif
1428#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[446]1429 struct group   * grp  = NULL;
[1486]1430#endif
1431#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[446]1432 struct passwd  * pwd  = NULL;
[1486]1433#endif
1434#ifdef ROAR_HAVE_GETSERVBYNAME
[446]1435 struct servent * serv = NULL;
[1486]1436#endif
[39]1437 struct roar_client * self = NULL;
[508]1438#ifdef ROAR_HAVE_LIBDNET
1439 char decnethost[80];
1440#endif
[2104]1441#ifdef SUPPORT_PIDFILE
1442 struct roar_vio_calls pidfile_vio;
1443#endif
[0]1444
[2784]1445 ROAR_DBG("main(*): starting roard...");
1446
[0]1447 g_standby       =  0;
[920]1448 g_autostandby   =  0;
[982]1449 alive           =  1;
[1494]1450#ifdef ROAR_SUPPORT_LISTEN
[1155]1451 g_no_listen     =  0;
[1494]1452#else
1453 g_terminate     =  1;
1454#endif
[0]1455
[2970]1456 g_verbose       = ROAR_DBG_INFO_NONE;
1457
[5180]1458 _LIBROAR_IGNORE_RET(roar_profile2info(&sa, "default-server"));
[0]1459
[1609]1460 g_sa        = &sa;
1461 g_max_sa    = &max_sa;
1462
1463 memcpy(g_max_sa, g_sa, sizeof(max_sa));
1464
[4101]1465 counters_init();
1466
[1609]1467 g_config = &config;
1468
1469 if ( init_config() == -1 ) {
1470  ROAR_ERR("Can not init default config!");
1471  return 1;
1472 }
[0]1473
[2968]1474 // load config
[5161]1475 _LIBROAR_IGNORE_RET(roar_libroar_get_config());
[2968]1476
[4323]1477 // init notify core:
1478 // TODO: reconsider number of lists.
1479 if ( roar_notify_core_new_global(-1) == -1 ) {
1480  ROAR_ERR("Can not init notify core!");
1481  return 1;
1482 }
1483
[4324]1484 if ( roar_notify_core_register_proxy(NULL, roar_notify_proxy_std, NULL) == -1 ) {
1485  ROAR_ERR("Can not init notify core!");
1486  return 1;
1487 }
1488
1489#ifdef DEBUG
[4418]1490 // enable early in case we have DEBUG set.
[4324]1491 dbg_notify_cb_register();
1492#endif
1493
[4934]1494 rolestack_init();
1495
[4469]1496 if ( auth_init() == -1 ) {
1497  ROAR_ERR("Can not init auth subsystem!");
1498  return 1;
1499 }
1500
[2530]1501#ifdef ROAR_SUPPORT_LISTEN
1502 if ( init_listening() == -1 ) {
1503  ROAR_ERR("Can not init listening sockets!");
1504  return 1;
1505 }
1506#endif
1507
[2500]1508#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1924]1509 if ( midi_init_config() == -1 ) {
1510  ROAR_ERR("Can not init MIDI config!");
1511  return 1;
1512 }
[2500]1513#endif
[60]1514
[2489]1515#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]1516 if ( ssynth_init_config() == -1 ) {
1517  ROAR_ERR("Can not init ssynth config!");
1518  return 1;
1519 }
[2489]1520#endif
[2451]1521
[2718]1522#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1523 if ( rdtcs_init_config() == -1 ) {
1524  ROAR_ERR("Can not init RDTCS config!");
1525  return 1;
1526 }
1527#endif
1528
[3354]1529 if ( plugins_preinit() == -1 ) {
1530  ROAR_ERR("Can not pre-init plugins!");
1531  return 1;
1532 }
1533
[1494]1534#ifdef ROAR_SUPPORT_LISTEN
[2767]1535#ifndef ROAR_TARGET_WIN32
[2530]1536 sock_addr = ROAR_DEFAULT_SOCK_GLOBAL;
[2767]1537#else
1538 sock_addr = ROAR_DEFAULT_HOST;
1539#endif
1540
[1753]1541#ifdef ROAR_HAVE_GETUID
[1486]1542 if ( getuid() != 0 && getenv("HOME") != NULL ) {
[3959]1543/*
[1486]1544  snprintf(user_sock, 79, "%s/%s", (char*)getenv("HOME"), ROAR_DEFAULT_SOCK_USER);
[3959]1545*/
1546  roar_env_render_path_r(user_sock, sizeof(user_sock), "~/" ROAR_DEFAULT_SOCK_USER);
[2530]1547  sock_addr = user_sock;
[3959]1548  ROAR_DBG("main(*): setting sock_addr='%s'", sock_addr);
[60]1549 }
[1753]1550#endif
[60]1551
[279]1552 if ( getenv("ROAR_SERVER") != NULL )
[2530]1553  sock_addr = getenv("ROAR_SERVER");
[1494]1554#endif
[279]1555
[63]1556 if ( clients_init() == -1 ) {
1557  ROAR_ERR("Can not init clients!");
1558  return 1;
1559 }
1560
1561 if ( streams_init() == -1 ) {
1562  ROAR_ERR("Can not init streams!");
1563  return 1;
1564 }
1565
[64]1566 if ( (g_self_client = clients_new()) == -1 ) {
1567  ROAR_ERR("Can not create self client!");
1568  return 1;
1569 }
1570
[2485]1571#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1572 if ( sources_init() == -1 ) {
1573  ROAR_ERR("Can not init sources!");
1574  return 1;
1575 }
1576
[64]1577 if ( (sources_set_client(g_self_client)) == -1 ) {
1578  ROAR_ERR("Can not init set source client!");
1579  return 1;
1580 }
[2485]1581#endif
[64]1582
[1503]1583#ifdef ROAR_HAVE_MAIN_ARGS
[0]1584 for (i = 1; i < argc; i++) {
1585  k = argv[i];
1586
1587  if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) {
1588   usage();
1589   return 0;
1590
[2109]1591  } else if ( strcmp(k, "--start") == 0 ) {
1592   // this is a no op
[4722]1593   action = START;
[579]1594  } else if ( strcmp(k, "--restart") == 0 ) {
[4722]1595   action = RESTART;
[1494]1596#ifdef ROAR_SUPPORT_LISTEN
[2530]1597   if ( restart_server(sock_addr, 1) == -1 ) {
[4722]1598    ROAR_WARN("Can not terminate old server (not running at %s?), will retry later.", sock_addr);
1599    action = RESTART_RETRY;
[579]1600   }
[1494]1601#else
1602   ROAR_ERR("--restart not supported");
1603#endif
[2109]1604  } else if ( strcmp(k, "--shutdown") == 0 ) {
[4722]1605   action = SHUTDOWN;
[2109]1606  } else if ( strcmp(k, "--stop") == 0 ) {
[4722]1607   action = STOP;
[2109]1608
[579]1609
[775]1610  } else if ( strcmp(k, "--demon") == 0 || strcmp(k, "--daemon") == 0 ) {
[5060]1611#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
[775]1612   daemon = 1;
[1486]1613#else
1614   ROAR_ERR("--daemon not supported");
1615#endif
[4986]1616  } else if ( strcmp(k, "--verbose") == 0 ) {
1617   g_verbose++;
1618
[4955]1619  } else if ( strcmp(k, "--print-format") == 0 ) {
1620   k = argv[++i];
1621   if ( !strcasecmp(k, "native") ) {
1622    print_format = FORMAT_NATIVE;
1623   } else if ( !strcasecmp(k, "wiki") ) {
1624    print_format = FORMAT_WIKI;
1625   } else if ( !strcasecmp(k, "csv") ) {
1626    print_format = FORMAT_CSV;
1627   } else {
1628    ROAR_WARN("Unknown print format: %s", k);
1629   }
1630
1631  } else if ( strcmp(k, "--print-format") == 0 ) {
1632   _CKHAVEARGS(1);
1633
[71]1634  } else if ( strcmp(k, "--terminate") == 0 ) {
1635   g_terminate = 1;
[905]1636  } else if ( strcmp(k, "--sysclocksync") == 0 ) {
1637   sysclocksync = 1000;
[275]1638  } else if ( strcmp(k, "--realtime") == 0 ) {
[276]1639   realtime++;
[4245]1640  } else if ( strcmp(k, "--memlock") == 0 ) {
1641   _CKHAVEARGS(1);
1642   g_config->memlock_level = memlock_str2level(argv[++i]);
[444]1643  } else if ( strcmp(k, "--chroot") == 0 ) {
[4052]1644   _CKHAVEARGS(1);
[1486]1645#ifdef ROAR_HAVE_CHROOT
[444]1646   chrootdir = argv[++i];
[1486]1647#else
1648   ROAR_ERR("--chroot not supported");
1649   i++;
1650#endif
[444]1651  } else if ( strcmp(k, "--setgid") == 0 ) {
[1486]1652#ifdef ROAR_HAVE_SETGID
[444]1653   setids |= R_SETGID;
[1486]1654#else
1655   ROAR_ERR("--setgid not supported");
1656#endif
[444]1657  } else if ( strcmp(k, "--setuid") == 0 ) {
[1486]1658#ifdef ROAR_HAVE_SETUID
[444]1659   setids |= R_SETUID;
[1486]1660#else
1661   ROAR_ERR("--setuid not supported");
1662#endif
[2017]1663  } else if ( strcmp(k, "--location") == 0 ) {
[4052]1664   _CKHAVEARGS(1);
[2017]1665   g_config->location = argv[++i];
[4421]1666  } else if ( strcmp(k, "--description") == 0 ) {
1667   _CKHAVEARGS(1);
1668   g_config->description = argv[++i];
[2104]1669  } else if ( strcmp(k, "--pidfile") == 0 ) {
[4052]1670   _CKHAVEARGS(1);
[2104]1671#ifdef SUPPORT_PIDFILE
1672   pidfile = argv[++i];
1673#else
1674   ROAR_ERR("--pidfile not supported");
1675   i++;
1676#endif
[3688]1677  } else if ( strcmp(k, "--log-syslog") == 0 ) {
1678#ifdef ROAR_HAVE_SYSLOG
1679   roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
1680#else
1681   ROAR_ERR("--log-syslog not supported");
1682#endif
[4851]1683  } else if ( strcmp(k, "--script-postdown") == 0 ) {
1684   _CKHAVEARGS(1);
1685#ifdef ROAR_HAVE_SYSTEM
1686   g_config->scripts.post_shutdown = argv[++i];
1687#else
1688   ROAR_ERR("--script-postdown not supported");
1689   i++;
1690#endif
[3688]1691
[68]1692
[3356]1693  } else if ( strcmp(k, "--plugin-load") == 0 ) {
[4052]1694   _CKHAVEARGS(1);
[3356]1695   if ( plugins_load(argv[++i]) == -1 ) {
1696    ROAR_ERR("Can not load plugin");
1697   }
1698
[4482]1699  } else if ( strcmp(k, "--guest-acclev") == 0 ) {
1700   _CKHAVEARGS(1);
1701   none_acclev = clients_str2acclev(argv[++i]);
[5146]1702   if ( none_acclev == -1 ) {
1703    ROAR_ERR("Invalid access level: %s", argv[i]);
1704    return 1;
1705   }
[4482]1706  } else if ( strcmp(k, "--trust-acclev") == 0 ) {
1707   _CKHAVEARGS(1);
1708   trust_acclev = clients_str2acclev(argv[++i]);
[5146]1709   if ( trust_acclev == -1 ) {
1710    ROAR_ERR("Invalid access level: %s", argv[i]);
1711    return 1;
1712   }
[4482]1713  } else if ( strcmp(k, "--trust-root") == 0 ) {
1714   trust_root = 1;
1715  } else if ( strcmp(k, "--no-trust-root") == 0 ) {
1716   trust_root = 0;
1717
[4788]1718  } else if ( strcmp(k, "--authfile-gen") == 0 ) {
1719   _CKHAVEARGS(1);
1720   af_file = argv[++i];
1721   af_mode = AF_MODE_GEN;
1722  } else if ( strcmp(k, "--authfile-load") == 0 ) {
1723   _CKHAVEARGS(1);
1724   af_file = argv[++i];
1725   af_mode = AF_MODE_LOAD;
1726  } else if ( strcmp(k, "--authfile-type") == 0 ) {
1727   _CKHAVEARGS(1);
1728   af_type = argv[++i];
1729  } else if ( strcmp(k, "--authfile-acclev") == 0 ) {
1730   _CKHAVEARGS(1);
1731   af_acclev = clients_str2acclev(argv[++i]);
[4789]1732  } else if ( strcmp(k, "--new-authfile") == 0 ) {
1733   if ( af_mode != AF_MODE_NONE ) {
1734    if ( add_authfile(af_file, af_type, af_mode, af_acclev) == -1 ) {
1735     ROAR_ERR("main(*): adding authfile '%s' failed!", af_file);
1736    }
1737   }
1738   af_file   = NULL;
1739   af_type   = NULL;
1740   af_mode   = AF_MODE_NONE;
1741   af_acclev = ACCLEV_ALL;
[4788]1742
[280]1743  } else if ( strcmp(k, "--list-cf") == 0 ) {
1744   print_codecfilterlist();
1745   return 0;
1746
[0]1747  } else if ( strcmp(k, "-R") == 0 || strcmp(k, "--rate") == 0 ) {
[4052]1748   _CKHAVEARGS(1);
[0]1749   sa.rate = atoi(argv[++i]);
1750  } else if ( strcmp(k, "-B") == 0 || strcmp(k, "--bits") == 0 ) {
[4052]1751   _CKHAVEARGS(1);
[0]1752   sa.bits = atoi(argv[++i]);
1753  } else if ( strcmp(k, "-C") == 0 || strcmp(k, "--chans") == 0 ) {
[4052]1754   _CKHAVEARGS(1);
[0]1755   sa.channels = atoi(argv[++i]);
1756
[3962]1757  } else if ( strcmp(k, "--aiprofile") == 0 ) {
[4052]1758   _CKHAVEARGS(1);
[3962]1759   if ( roar_profile2info(&sa, argv[++i]) == -1 ) {
1760    ROAR_ERR("Unknown audio profile: %s", argv[i]);
1761    return 1;
1762   }
1763   sa.codec    = ROAR_CODEC_DEFAULT;
1764
[2339]1765  } else if ( strcmp(k, "--stream-flags") == 0 ) {
[4052]1766   _CKHAVEARGS(1);
[2339]1767   if ( update_stream_flags(argv[++i]) == -1 ) {
1768    ROAR_ERR("Can not set stream flags");
1769    return 1;
1770   }
1771
[4934]1772  } else if ( strcmp(k, "--list-rolestack") == 0 ) {
1773   print_rolestack();
1774   return 0;
1775  } else if ( strcmp(k, "--rolestack-push") == 0 ) {
1776   _CKHAVEARGS(1);
1777  if ( (rolestack = rolestack_parse(argv[++i])) == NULL ) {
1778   ROAR_ERR("Can not parse rolestack request: %s", roar_error2str(roar_error));
1779  } else {
1780   if ( rolestack_push(rolestack) == -1 ) {
1781    ROAR_ERR("Can not push request to rolestack: %s", roar_error2str(roar_error));
1782   }
1783  }
1784
[4882]1785  } else if ( strcmp(k, "--list-aiprofiles") == 0 ) {
1786   list_aiprofiles();
1787   return 0;
1788
[973]1789  } else if ( strcmp(k, "--list-driver") == 0 ) {
[4955]1790   print_driverlist(print_format);
[973]1791   return 0;
[0]1792
[932]1793  } else if ( strcmp(k, "-o") == 0 || strcmp(k, "--odriver") == 0 ) {
[4052]1794   _CKHAVEARGS(1);
[932]1795   o_drv  = argv[++i];
1796  } else if ( strcmp(k, "-O") == 0 || strcmp(k, "--odevice") == 0 ) {
[4052]1797   _CKHAVEARGS(1);
[932]1798   o_dev  = argv[++i];
1799  } else if ( strcmp(k, "-oO") == 0 ) {
[4052]1800   _CKHAVEARGS(1);
[932]1801   o_opts = argv[++i];
[961]1802  } else if ( strcmp(k, "-oP") == 0 ) {
1803   o_prim = 1;
[932]1804  } else if ( strcmp(k, "-oN") == 0 ) {
[4722]1805   if ( action == START || action == RESTART ) {
[4852]1806    if ( output_add(o_drv, o_dev, o_opts, o_prim, o_count) != -1 )
[4722]1807     o_count++;
[1145]1808
[4722]1809    o_drv  = o_dev = o_opts = NULL;
1810    o_prim = 0;
1811   }
[932]1812
[0]1813  } else if ( strcmp(k, "-s") == 0 || strcmp(k, "--source") == 0 ) {
[4052]1814   _CKHAVEARGS(1);
[2485]1815#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[550]1816   s_drv = argv[++i];
[2485]1817#else
1818   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1819   i++;
[2485]1820#endif
[550]1821  } else if ( strcmp(k, "-S") == 0 ) {
[4052]1822   _CKHAVEARGS(1);
[2485]1823#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[1110]1824   s_dev = argv[++i];
[2485]1825#else
1826   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1827   i++;
[2485]1828#endif
[0]1829  } else if ( strcmp(k, "-sO") == 0 ) {
[4052]1830   _CKHAVEARGS(1);
[2485]1831#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1832   s_opt = argv[++i];
[2485]1833#else
1834   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1835   i++;
[2485]1836#endif
[0]1837  } else if ( strcmp(k, "-sC") == 0 ) {
[4052]1838   _CKHAVEARGS(1);
[2485]1839#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1840   s_con = argv[++i];
[2485]1841#else
1842   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1843   i++;
[2485]1844#endif
[0]1845  } else if ( strcmp(k, "-sP") == 0 ) {
[2485]1846#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1847   s_prim = 1;
[2485]1848#else
1849   ROAR_ERR("main(*): No support for sources compiled in");
1850#endif
[1110]1851  } else if ( strcmp(k, "-sN") == 0 ) {
[2485]1852#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[1110]1853   if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
1854    ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
1855   }
1856   s_opt = s_dev = s_con = NULL;
[5103]1857   s_drv = NULL;
[1110]1858   s_prim = 0;
[2485]1859#else
1860   ROAR_ERR("main(*): No support for sources compiled in");
1861#endif
[2270]1862  } else if ( strcmp(k, "--list-sources") == 0 ) {
[2485]1863#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[2270]1864   print_sourcelist();
1865   return 0;
[2485]1866#else
1867   ROAR_ERR("main(*): No support for sources compiled in");
[2504]1868   return 1;
[2485]1869#endif
[0]1870
[4358]1871  } else if ( strcmp(k, "-m") == 0 || strcmp(k, "--mixer") == 0 ) {
1872   _CKHAVEARGS(1);
1873#ifndef ROAR_WITHOUT_DCOMP_MIXER
1874   m_drv  = argv[++i];
1875#else
1876   ROAR_ERR("main(*): No support for mixer compiled in");
1877   return 1;
1878#endif
1879  } else if ( strcmp(k, "-M") == 0 ) {
1880   _CKHAVEARGS(1);
1881#ifndef ROAR_WITHOUT_DCOMP_MIXER
1882   m_dev  = argv[++i];
1883#else
1884   ROAR_ERR("main(*): No support for mixer compiled in");
1885   return 1;
1886#endif
1887  } else if ( strcmp(k, "-mO") == 0 ) {
1888   _CKHAVEARGS(1);
1889#ifndef ROAR_WITHOUT_DCOMP_MIXER
1890   m_opts = argv[++i];
1891#else
1892   ROAR_ERR("main(*): No support for mixer compiled in");
1893   return 1;
1894#endif
1895  } else if ( strcmp(k, "-mP") == 0 ) {
1896#ifndef ROAR_WITHOUT_DCOMP_MIXER
1897   m_prim = 1;
1898#else
1899   ROAR_ERR("main(*): No support for mixer compiled in");
1900   return 1;
1901#endif
1902  } else if ( strcmp(k, "-mN") == 0 ) {
1903#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4852]1904   if ( hwmixer_add(m_drv, m_dev, m_opts, m_prim, m_count) != -1 )
[4358]1905    m_count++;
1906
1907   m_drv  = o_dev = o_opts = NULL;
1908   m_prim = 0;
1909#else
1910   ROAR_ERR("main(*): No support for mixer compiled in");
1911   return 1;
1912#endif
[4360]1913  } else if ( strcmp(k, "--list-mixers") == 0 ) {
1914#ifndef ROAR_WITHOUT_DCOMP_MIXER
1915   print_hwmixerlist();
1916   return 0;
1917#else
1918   ROAR_ERR("main(*): No support for mixer compiled in");
1919   return 1;
1920#endif
[4358]1921
[1923]1922  } else if ( strcmp(k, "--light-channels") == 0 ) {
[4052]1923   _CKHAVEARGS(1);
[2494]1924#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]1925   light_channels = atoi(argv[++i]);
[2494]1926#else
1927   ROAR_WARN("main(*): no light subsystem compiled in");
[4052]1928   i++;
[2494]1929#endif
[1923]1930
[2725]1931  } else if ( strcmp(k, "--rds-pi") == 0 ) {
[4052]1932   _CKHAVEARGS(1);
[2725]1933#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1934   g_rdtcs.rds.pi = atoi(argv[++i]);
1935#else
1936   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1937   i++;
[2725]1938#endif
[2728]1939  } else if ( strcmp(k, "--rds-ps") == 0 ) {
[4052]1940   _CKHAVEARGS(1);
[2728]1941#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1942   if ( rdtcs_rds_set_ps(argv[++i]) == -1 ) {
[2729]1943    ROAR_ERR("Can not set RDS PS to '%s' (longer than 8 chars?)", argv[i]);
[2728]1944    return 1;
1945   }
1946#else
1947   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1948   i++;
[2728]1949#endif
1950  } else if ( strcmp(k, "--rds-pty") == 0 ) {
[4052]1951   _CKHAVEARGS(1);
[2728]1952#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1953   if ( rdtcs_rds_set_pty(argv[++i]) == -1 ) {
[2729]1954    ROAR_ERR("Can not set RDS PTY to '%s'", argv[i]);
[2728]1955    return 1;
1956   }
1957#else
1958   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1959   i++;
[2728]1960#endif
1961  } else if ( strcmp(k, "--rds-tp") == 0 ) {
1962#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1963   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_TP, 0) == -1 ) {
1964    ROAR_ERR("Can not set RDS TP flag");
1965    return 1;
1966   }
1967#else
1968   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1969#endif
1970  } else if ( strcmp(k, "--rds-ct") == 0 ) {
1971#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1972   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_CT, 0) == -1 ) {
1973    ROAR_ERR("Can not set RDS CT flag");
1974    return 1;
1975   }
1976#else
1977   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1978#endif
1979
[2725]1980
[1924]1981  } else if ( strcmp(k, "--midi-no-console") == 0 ) {
[2487]1982#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]1983   midi_config.init_cb = 0;
[2487]1984#else
1985   // no warning here as this is the disable option
1986#endif
[2444]1987  } else if ( strcmp(k, "--midi-console-enable") == 0 ) {
[2487]1988#ifndef ROAR_WITHOUT_DCOMP_CB
[2444]1989   midi_config.init_cb = 1;
[2487]1990#else
1991   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
1992#endif
[1924]1993  } else if ( strcmp(k, "--midi-console") == 0 ) {
[4052]1994   _CKHAVEARGS(1);
[2487]1995#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]1996   midi_config.console_dev = argv[++i];
[2444]1997   midi_config.init_cb = 1;
[2487]1998#else
1999   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
[4052]2000   i++;
[2487]2001#endif
[1924]2002
[2451]2003  } else if ( strcmp(k, "--ssynth-enable") == 0 ) {
[2489]2004#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]2005   ssynth_conf.enable = 1;
[2489]2006#else
2007   ROAR_ERR("main(*): No support for ssynth compiled in");
2008#endif
[2451]2009  } else if ( strcmp(k, "--ssynth-disable") == 0 ) {
[2489]2010#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]2011   ssynth_conf.enable = 0;
[2489]2012#else
2013   // we can safely ignore the disable
2014#endif
[2451]2015
[3374]2016  } else if ( strcmp(k, "--x11-display") == 0 || strcmp(k, "--display") == 0 ) {
[4052]2017   _CKHAVEARGS(1);
[3374]2018#ifdef ROAR_HAVE_LIBX11
2019   x11display = argv[++i];
2020#else
2021   ROAR_ERR("No X11 support compiled in!");
2022   return 1;
2023#endif
2024
2025
[0]2026  } else if ( strcmp(k, "-p") == 0 || strcmp(k, "--port") == 0 ) {
[4052]2027   _CKHAVEARGS(1);
[4012]2028   // This is only useful in INET not UNIX mode.
[1494]2029#ifdef ROAR_SUPPORT_LISTEN
[2530]2030   if ( *sock_addr == '/' )
2031    sock_addr = ROAR_DEFAULT_HOST;
[447]2032
[446]2033   errno = 0;
2034   if ( (port = atoi(argv[++i])) < 1 ) {
[1486]2035#ifdef ROAR_HAVE_GETSERVBYNAME
[446]2036    if ( (serv = getservbyname(argv[i], "tcp")) == NULL ) {
2037     ROAR_ERR("Unknown service: %s: %s", argv[i], strerror(errno));
2038     return 1;
2039    }
2040    // NOTE: we need to use ROAR_NET2HOST16() here even if s_port is of type int!
2041    ROAR_DBG("main(*): serv = {s_name='%s', s_aliases={...}, s_port=%i, s_proto='%s'}",
2042            serv->s_name, ROAR_NET2HOST16(serv->s_port), serv->s_proto);
2043    port = ROAR_NET2HOST16(serv->s_port);
[1486]2044#else
2045    ROAR_ERR("invalite port number: %s", argv[i]);
2046    return 1;
2047#endif
[446]2048   }
[1494]2049#endif
[1115]2050  } else if ( strcmp(k, "-b") == 0 || strcmp(k, "--bind") == 0 || strcmp(k, "--sock") == 0 ) {
[4052]2051   _CKHAVEARGS(1);
[1494]2052#ifdef ROAR_SUPPORT_LISTEN
[2530]2053   sock_addr = argv[++i];
[4052]2054#else
2055   i++;
[2530]2056#endif
2057
2058  } else if ( strcmp(k, "--proto") == 0 ) {
2059#ifdef ROAR_SUPPORT_LISTEN
[2549]2060   if ( (sock_proto = roar_str2proto(argv[++i])) == -1 ) {
[2530]2061    ROAR_ERR("Unknown protocol: %s", argv[i]);
2062    return 1;
2063   }
[1494]2064#endif
[3252]2065  } else if ( strcmp(k, "--proto-dir") == 0 ) {
[4052]2066   _CKHAVEARGS(1);
[3252]2067#ifdef ROAR_SUPPORT_LISTEN
2068   if ( (sock_dir = roar_str2dir(argv[++i])) == -1 ) {
2069    ROAR_ERR("Unknown stream direction: %s", argv[i]);
2070    return 1;
2071   }
[4052]2072#else
2073   i++;
[3252]2074#endif
2075  } else if ( strcmp(k, "--proto-rate") == 0 ) {
[4052]2076   _CKHAVEARGS(1);
[3252]2077#ifdef ROAR_SUPPORT_LISTEN
2078   sock_info.rate = atoi(argv[++i]);
[4052]2079#else
2080   i++;
[3252]2081#endif
2082  } else if ( strcmp(k, "--proto-bits") == 0 ) {
[4052]2083   _CKHAVEARGS(1);
[3252]2084#ifdef ROAR_SUPPORT_LISTEN
2085   sock_info.bits = atoi(argv[++i]);
[4052]2086#else
2087   i++;
[3252]2088#endif
2089  } else if ( strcmp(k, "--proto-chans") == 0 ) {
[4052]2090   _CKHAVEARGS(1);
[3252]2091#ifdef ROAR_SUPPORT_LISTEN
2092   sock_info.channels = atoi(argv[++i]);
[4052]2093#else
2094   i++;
[3252]2095#endif
2096  } else if ( strcmp(k, "--proto-codec") == 0 ) {
[4052]2097   _CKHAVEARGS(1);
[3252]2098#ifdef ROAR_SUPPORT_LISTEN
2099   if ( (sock_info.codec = roar_str2codec(argv[++i])) == -1 ) {
2100    ROAR_ERR("Unknown codec: %s", argv[i]);
2101    return 1;
2102   }
[4052]2103#else
2104   i++;
[3252]2105#endif
[3954]2106  } else if ( strcmp(k, "--proto-aiprofile") == 0 ) {
[4052]2107   _CKHAVEARGS(1);
[3954]2108#ifdef ROAR_SUPPORT_LISTEN
2109   if ( roar_profile2info(&sock_info, argv[++i]) == -1 ) {
2110    ROAR_ERR("Unknown audio profile: %s", argv[i]);
2111    return 1;
2112   }
[4052]2113#else
2114   i++;
[3954]2115#endif
[3956]2116  } else if ( strcmp(k, "--list-profiles") == 0 ) {
2117#ifdef ROAR_SUPPORT_LISTEN
2118   listen_listen_profiles();
2119   return 0;
2120#endif
2121  } else if ( strcmp(k, "--proto-profile") == 0 ) {
[4052]2122   _CKHAVEARGS(1);
[3956]2123#ifdef ROAR_SUPPORT_LISTEN
2124   if ( get_listen_profile(argv[++i], &port, &sock_addr, &sock_type, &sock_proto, &sock_dir, &sock_info) == -1 ) {
2125    ROAR_ERR("Unknown listen profile: %s", argv[i]);
2126    return 1;
2127   }
[4052]2128#else
2129   i++;
[3956]2130#endif
[3252]2131
2132
[3127]2133  } else if ( strcmp(k, "--list-proto") == 0 ) {
2134   list_proto();
2135   return 0;
[518]2136
[573]2137  } else if ( strcmp(k, "-t") == 0 || strcmp(k, "--tcp") == 0 ) {
[1494]2138#ifdef ROAR_SUPPORT_LISTEN
[518]2139   if ( sock_type != ROAR_SOCKET_TYPE_TCP && sock_type != ROAR_SOCKET_TYPE_TCP6 )
2140    sock_type = ROAR_SOCKET_TYPE_TCP;
2141
[2530]2142   if ( *sock_addr == '/' )
2143    sock_addr = ROAR_DEFAULT_HOST;
[1494]2144#endif
[518]2145
2146  } else if ( strcmp(k, "-4") == 0 ) {
[1494]2147#ifdef ROAR_SUPPORT_LISTEN
[517]2148   sock_type = ROAR_SOCKET_TYPE_TCP;
[2530]2149   if ( *sock_addr == '/' )
2150    sock_addr = ROAR_DEFAULT_HOST;
[1494]2151#endif
[518]2152  } else if ( strcmp(k, "-6") == 0 ) {
[1494]2153#ifdef ROAR_SUPPORT_LISTEN
[3837]2154#ifdef AF_INET6
[518]2155   sock_type = ROAR_SOCKET_TYPE_TCP6;
[2530]2156   if ( *sock_addr == '/' )
2157    sock_addr = ROAR_DEFAULT_HOST;
[519]2158#else
2159    ROAR_ERR("No IPv6 support compiled in!");
2160    return 1;
2161#endif
[1494]2162#endif
[518]2163
[573]2164  } else if ( strcmp(k, "-u") == 0 || strcmp(k, "--unix") == 0 ) {
[1494]2165#ifdef ROAR_SUPPORT_LISTEN
[62]2166   // ignore this case as it is the default behavor.
[517]2167   sock_type = ROAR_SOCKET_TYPE_UNIX;
[1494]2168#endif
[518]2169
[573]2170  } else if ( strcmp(k, "-n") == 0 || strcmp(k, "--decnet") == 0 ) {
[1494]2171#ifdef ROAR_SUPPORT_LISTEN
[508]2172#ifdef ROAR_HAVE_LIBDNET
2173    port   = ROAR_DEFAULT_NUM;
2174    strcpy(decnethost, ROAR_DEFAULT_LISTEN_OBJECT);
[2530]2175    sock_addr = decnethost;
[517]2176    sock_type = ROAR_SOCKET_TYPE_DECNET;
[508]2177#else
2178    ROAR_ERR("No DECnet support compiled in!");
2179    return 1;
2180#endif
[1494]2181#endif
[2530]2182  } else if ( strcmp(k, "--new-sock") == 0 ) {
2183#ifdef ROAR_SUPPORT_LISTEN
[4722]2184   if ( action == START || action == RESTART ) {
2185    if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
2186     ROAR_ERR("Can not open listen socket!");
2187     return 1;
2188    }
[2530]2189   }
2190#endif
[518]2191
[1993]2192  } else if ( strcmp(k, "--slp") == 0 ) {
2193#ifdef ROAR_HAVE_LIBSLP
2194   reg_slp = 1;
2195#else
[3373]2196   ROAR_ERR("No OpenSLP support compiled in!");
2197   return 1;
[1993]2198#endif
2199
[3373]2200  } else if ( strcmp(k, "--x11") == 0 ) {
2201#ifdef ROAR_HAVE_LIBX11
2202   reg_x11 = 1;
2203#else
2204   ROAR_ERR("No X11 support compiled in!");
2205   return 1;
2206#endif
2207
2208
[3039]2209  } else if ( strcmp(k, "--jumbo-mtu") == 0 ) {
[4052]2210   _CKHAVEARGS(1);
[3039]2211   g_config->jumbo_mtu = atoi(argv[++i]);
2212
[60]2213  } else if ( strcmp(k, "-G") == 0 ) {
[4052]2214   _CKHAVEARGS(1);
[444]2215   sock_grp  = argv[++i];
2216  } else if ( strcmp(k, "-U") == 0 ) {
[4052]2217   _CKHAVEARGS(1);
[444]2218   sock_user = argv[++i];
[0]2219
[68]2220  } else if ( strcmp(k, "--no-listen") == 0 ) {
[1494]2221#ifdef ROAR_SUPPORT_LISTEN
[2530]2222   sock_addr   = "";
[548]2223   g_terminate = 1;
[1155]2224   g_no_listen = 1;
[1494]2225#endif
[68]2226  } else if ( strcmp(k, "--client-fh") == 0 ) {
[4052]2227   _CKHAVEARGS(1);
[3737]2228   if ( clients_new_from_fh(atoi(argv[++i]), ROAR_PROTO_ROARAUDIO, ROAR_BYTEORDER_NETWORK, 1) == -1 ) {
[68]2229    ROAR_ERR("main(*): Can not set client's fh");
2230    return 1;
2231   }
[501]2232  } else if ( strcmp(k, "--close-fh") == 0 ) {
[4052]2233   _CKHAVEARGS(1);
[1486]2234#ifdef ROAR_HAVE_IO_POSIX
[501]2235   close(atoi(argv[++i]));
[1486]2236#else
2237   i++;
2238   ROAR_WARN("can not close file handle %s (closing not supported)", argv[i]);
2239#endif
[68]2240
[920]2241  } else if ( strcmp(k, "--standby") == 0 ) {
2242   g_standby = 1;
2243  } else if ( strcmp(k, "--auto-standby") == 0 ) {
2244   g_autostandby = 1;
[0]2245  } else {
2246   usage();
2247   return 1;
2248  }
2249
2250 }
[1503]2251#endif
[0]2252
[4722]2253#ifdef ROAR_HAVE_MAIN_ARGS
2254 switch (action) {
2255  case START:
2256    // NO-OP.
2257   break;
2258  case RESTART:
2259    // NO-OP, done before.
2260   break;
2261  case STOP:
2262#ifdef ROAR_SUPPORT_LISTEN
2263    if ( restart_server(sock_addr, 0) == -1 ) {
2264     ROAR_WARN("Can not stop old server (not running at %s?)", sock_addr);
2265     return 1;
2266    }
2267    return 0;
2268#else
2269    ROAR_ERR("--stop not supported");
2270    return 1;
2271#endif
2272   break;
2273  case SHUTDOWN:
2274#ifdef ROAR_SUPPORT_LISTEN
2275    if ( restart_server(sock_addr, 1) == -1 ) {
2276     ROAR_WARN("Can not terminate old server (not running at %s?)", sock_addr);
2277     return 1;
2278    }
2279    return 0;
2280#else
2281    ROAR_ERR("--shutdown not supported");
2282    return 1;
2283#endif
2284   break;
2285  case RESTART_RETRY:
2286#ifdef ROAR_SUPPORT_LISTEN
2287    if ( restart_server(sock_addr, 1) == -1 ) {
2288     ROAR_WARN("Can not terminate old server (again) (not running at %s?), tring to continue anyway", sock_addr);
2289     action = RESTART;
2290    }
2291#endif
2292   break;
2293 }
2294#endif
2295
[4418]2296#ifndef DEBUG
2297 // notify dbg if requested, if in DEBUG mode
2298 // do not able because it got enabled early.
2299 if ( g_verbose >= 4 )
2300  dbg_notify_cb_register();
2301#endif
2302
[4788]2303 if ( af_mode != AF_MODE_NONE ) {
2304  if ( add_authfile(af_file, af_type, af_mode, af_acclev) == -1 ) {
2305   ROAR_ERR("main(*): adding authfile '%s' failed!", af_file);
2306  }
2307 }
2308
[4358]2309#ifndef ROAR_WITHOUT_DCOMP_MIXER
2310 if ( m_drv != NULL ) {
[4852]2311  if ( hwmixer_add(m_drv, m_dev, m_opts, m_prim, m_count) == -1 ) {
[4358]2312   ROAR_ERR("main(*): adding mixer '%s' via '%s' failed!", m_dev, m_drv);
2313  }
2314 }
2315#endif
2316
[2485]2317#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[5103]2318 if ( s_drv != NULL || s_dev != NULL ) {
[1110]2319  if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
2320   ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
2321  }
2322 }
[2485]2323#endif
[1110]2324
[4852]2325 if ( output_add_default(o_drv, o_dev, o_opts, o_prim, o_count) == -1 ) {
[4848]2326  ROAR_ERR("Can not initialize default driver");
2327  return 1;
2328 }
[932]2329
[4055]2330 ROAR_INFO("Server config: rate=%i, bits=%i, chans=%i", ROAR_DBG_INFO_NOTICE, sa.rate, sa.bits, sa.channels);
[0]2331
[2945]2332 if ( waveform_init() == -1 ) {
2333  ROAR_ERR("Can not initialize Waveform subsystem");
2334  return 1;
2335 }
2336
[2500]2337#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1819]2338 if ( midi_init() == -1 ) {
[281]2339  ROAR_ERR("Can not initialize MIDI subsystem");
[1819]2340 }
[2500]2341#endif
[1819]2342
[2489]2343#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]2344 if ( ssynth_init() == -1 ) {
2345  ROAR_ERR("Can not initialize ssynth subsystem");
2346 }
[2489]2347#endif
[2451]2348
[2494]2349#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1819]2350 if ( light_init(light_channels) == -1 ) {
2351  ROAR_ERR("Can not initialize light control subsystem");
2352 }
[2494]2353#endif
[281]2354
[2718]2355#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2356 if ( rdtcs_init() == -1 ) {
2357  ROAR_ERR("Can not initialize RDTCS subsystem");
2358 }
2359#endif
2360
[3354]2361 if ( plugins_init() == -1 ) {
2362  ROAR_ERR("Can not initialize plugins");
2363 }
2364
[1494]2365#ifdef ROAR_SUPPORT_LISTEN
[3760]2366 if ( !g_no_listen ) {
2367  if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
2368   ROAR_ERR("Can not open listen socket!");
2369   return 1;
2370  }
[60]2371 }
[1494]2372#endif
[60]2373
[0]2374 if ( output_buffer_init(&sa) == -1 ) {
2375  ROAR_ERR("Can not init output buffer!");
2376  return 1;
2377 }
2378
[44]2379 if ( samples_init() == -1 ) {
2380  ROAR_ERR("Can not init samples!");
2381  return 1;
2382 }
2383
2384
[1486]2385 // we should handle this on microcontrollers, too.
[1753]2386#if !defined(ROAR_TARGET_MICROCONTROLLER) && !defined(ROAR_TARGET_WIN32)
[0]2387 signal(SIGINT,  on_sig_int);
[2732]2388 signal(SIGTERM, on_sig_term);
[285]2389 signal(SIGCHLD, on_sig_chld);
[2112]2390 signal(SIGUSR1, on_sig_usr1);
[0]2391 signal(SIGPIPE, SIG_IGN);  // ignore broken pipes
[1486]2392#endif
[0]2393
[4245]2394 if ( g_config->memlock_level == -1 ) {
2395  g_config->memlock_level = MEMLOCK_DEFAULT;
2396 }
2397
2398 if ( memlock_set_level(g_config->memlock_level) == -1 ) {
2399  ROAR_WARN("Can not set memory locking level to target level.");
2400 }
2401
[275]2402 if ( realtime ) {
[278]2403#ifdef DEBUG
[4246]2404  ROAR_WARN("compiled with -DDEBUG but realtime is enabled: for real realtime support compile without -DDEBUG");
[278]2405#endif
2406
[1486]2407#ifdef ROAR_HAVE_NICE
[4739]2408  // this stupid error check is because type of returned data of nice() changed
2409  // too often. On some systems it may return 0/-1, on some new nice value or
2410  // mixed forms of both.
[275]2411  errno = 0;
[4739]2412  (void)nice(-5*realtime); // -5 for each --realtime
[1486]2413  if ( errno ) {
2414   ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
2415  }
2416#else
2417  ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
2418#endif
[277]2419/*
[276]2420#ifdef __linux__
[277]2421  if ( ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0)) == -1 )
2422   ROAR_WARN("Can not set io priority: %s", strerror(errno));
[276]2423#endif
[277]2424*/
[275]2425 }
2426
[2756]2427#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[444]2428 if ( setids & R_SETGID ) {
[2754]2429  if ( sock_grp == NULL ) {
2430   ROAR_ERR("Can not set GID if no groupname is supplied");
2431   return 1;
2432  }
[2584]2433  if ( (grp = getgrnam(sock_grp)) == NULL ) {
2434   ROAR_ERR("Can not get GID for group %s: %s", sock_grp, strerror(errno));
2435   return 1;
2436  }
[444]2437  if ( setgroups(0, (const gid_t *) NULL) == -1 ) {
2438   ROAR_ERR("Can not clear supplementary group IDs: %s", strerror(errno));
2439  }
[5160]2440  if ( grp == NULL || setgid(grp->gr_gid) == -1 ) {
[444]2441   ROAR_ERR("Can not set GroupID: %s", strerror(errno));
2442  }
2443 }
[1486]2444#endif
[444]2445
[0]2446
[39]2447 clients_set_pid(g_self_client, getpid());
[1753]2448#ifdef ROAR_HAVE_GETUID
[440]2449 clients_set_uid(g_self_client, getuid());
[1753]2450#endif
2451#ifdef ROAR_HAVE_GETGID
[440]2452 clients_set_gid(g_self_client, getgid());
[1753]2453#endif
[39]2454 clients_get(g_self_client, &self);
[37]2455
[39]2456 if ( self == NULL ) {
2457  ROAR_ERR("Can not get self client!");
2458  return 1;
2459 }
2460
[775]2461 strcpy(self->name, "RoarAudio daemon internal");
[68]2462
[2815]2463 if ( roar_nnode_free(&(self->nnode)) == -1 )
2464  return 1;
2465
2466 // not fully correct but ok as workaorund
2467 // so tools assume that roard runs on the same machine as
2468 // they in case they use AF_UNIX:
2469 if ( roar_nnode_new(&(self->nnode), ROAR_SOCKET_TYPE_UNIX) == -1 )
2470  return 1;
2471
[5060]2472#if defined(ROAR_HAVE_FORK) || defined(ROAR_TARGET_WIN32)
[775]2473 if ( daemon ) {
[3613]2474#ifdef ROAR_HAVE_SYSLOG
2475  roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
2476#else
[3609]2477  roar_debug_set_stderr_fh(-1);
[3613]2478#endif
[3609]2479
[5060]2480#ifdef ROAR_TARGET_WIN32
2481  FreeConsole();
2482#else
2483
[68]2484  close(ROAR_STDIN );
2485  close(ROAR_STDOUT);
2486  close(ROAR_STDERR);
[1753]2487
[68]2488  if ( fork() )
[1486]2489   ROAR_U_EXIT(0);
[1753]2490
2491#ifdef ROAR_HAVE_SETSID
2492  setsid();
2493#endif
[1046]2494  clients_set_pid(g_self_client, getpid()); // reset pid as it changed
[5060]2495#endif
[68]2496 }
[1486]2497#endif
[68]2498
[2757]2499#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
2500 // early test for UID as we need this for the pidfile and the setuid()
2501 if ( sock_user != NULL ) {
2502  if ( (pwd = getpwnam(sock_user)) == NULL ) {
2503   ROAR_ERR("Can not get UID for user %s: %s", sock_user, strerror(errno));
2504   return 1;
2505  }
2506 }
2507#endif
2508
[4423]2509 ROAR_INFO("Process ID: %i", ROAR_DBG_INFO_INFO, (int)getpid());
2510
[2104]2511#ifdef SUPPORT_PIDFILE
[2106]2512 if ( pidfile != NULL ) {
2513  if ( roar_vio_open_file(&pidfile_vio, pidfile, O_WRONLY|O_CREAT, 0644) == -1 ) {
2514   ROAR_ERR("Can not write pidfile: %s", pidfile);
2515  } else {
2516   roar_vio_printf(&pidfile_vio, "%i\n", getpid());
2517   roar_vio_close(&pidfile_vio);
2518  }
[2765]2519#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[5160]2520  if ( pwd != NULL || grp != NULL ) {
2521   if ( chown(pidfile, pwd != NULL ? pwd->pw_uid : -1, grp != NULL ? grp->gr_gid : -1) == -1 ) {
[2759]2522    ROAR_WARN("Can not change ownership of pidfile: %s: %s", pidfile, strerror(errno));
2523   }
2524  }
2525  if ( chmod(pidfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1 ) {
2526   ROAR_WARN("Can not change permissions of pidfile: %s: %s", pidfile, strerror(errno));
2527  }
[2765]2528#endif
[2104]2529 }
2530#endif
2531
[1486]2532#ifdef ROAR_HAVE_CHROOT
[444]2533 if (chrootdir) {
2534  if ( chroot(chrootdir) == -1 ) {
2535   ROAR_ERR("Can not chroot to %s: %s", chrootdir, strerror(errno));
2536   return 2;
2537  }
2538  if ( chdir("/") == -1 ) {
2539   ROAR_ERR("Can not chdir to /: %s", strerror(errno));
2540   return 2;
2541  }
2542 }
[1486]2543#endif
[444]2544
[2756]2545#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[444]2546 if ( setids & R_SETUID ) {
[2752]2547  if ( sock_user == NULL ) {
2548   ROAR_ERR("Can not set UID if no username is supplied");
2549   return 1;
2550  }
[5160]2551  if ( pwd == NULL || setuid(pwd->pw_uid) == -1 ) {
[444]2552   ROAR_ERR("Can not set UserID: %s", strerror(errno));
2553   return 3;
2554  }
[1753]2555#ifdef ROAR_HAVE_GETUID
[444]2556  clients_set_uid(g_self_client, getuid());
[1753]2557#endif
[444]2558 }
[1486]2559#endif
[444]2560
[4481]2561 // setup auth:
[4690]2562#if defined(ROAR_HAVE_GETUID) && defined(ROAR_HAVE_GETGID)
[4481]2563 if ( auth_setup(none_acclev, trust_acclev, trust_root, getuid(), getgid()) == -1 ) {
[4690]2564#else
2565 if ( auth_setup(none_acclev, trust_acclev, trust_root, -1, -1) == -1 ) {
2566#endif
[4481]2567  ROAR_ERR("Can not set up auth. Bad.");
2568  alive = 0;
2569 }
2570
[1993]2571 // Register with OpenSLP:
[2028]2572#ifdef ROAR_HAVE_LIBSLP
[1993]2573 if ( reg_slp ) {
[2530]2574  register_slp(0, sock_addr);
[1993]2575 }
[2028]2576#endif
[1993]2577
[3373]2578#ifdef ROAR_HAVE_LIBX11
2579 if ( reg_x11 ) {
2580  register_x11(0, sock_addr);
2581 }
2582#endif
2583
[4846]2584 // update sync counter.
2585 streams_change_sync_num(-1, 0);
2586
[4103]2587 ROAR_INFO("Startup complet", ROAR_DBG_INFO_INFO);
2588
[0]2589 // start main loop...
[4055]2590 ROAR_INFO("Entering main loop", ROAR_DBG_INFO_INFO);
[4811]2591 main_loop(&sa, sysclocksync);
[4055]2592 ROAR_INFO("Left main loop", ROAR_DBG_INFO_INFO);
[0]2593
2594 // clean up.
2595 clean_quit_prep();
2596 output_buffer_free();
2597
[4323]2598 roar_notify_core_free(NULL);
2599
[4851]2600 ROAR_INFO("Shuting down complete", ROAR_DBG_INFO_INFO);
2601
2602 if ( g_config->scripts.post_shutdown != NULL )
2603  system(g_config->scripts.post_shutdown);
2604
[4055]2605 ROAR_INFO("Exiting, no error", ROAR_DBG_INFO_INFO);
[0]2606 return 0;
2607}
2608
[574]2609void cleanup_listen_socket (int terminate) {
[2530]2610 int i;
2611
[4055]2612 ROAR_DBG("cleanup_listen_socket(terminate=%i) = (void)?", terminate);
2613
2614 ROAR_INFO("Cleaning up listen sockets", ROAR_DBG_INFO_INFO);
2615
[1993]2616 // Deregister from SLP:
[2028]2617#ifdef ROAR_HAVE_LIBSLP
[1993]2618 register_slp(1, NULL);
[2028]2619#endif
[580]2620
[3373]2621#ifdef ROAR_HAVE_LIBX11
2622 register_x11(1, NULL);
2623#endif
2624
[1494]2625#ifdef ROAR_SUPPORT_LISTEN
[2530]2626 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]2627  if ( g_listen[i].used  ) {
2628   roar_vio_close(&(g_listen[i].sock));
[60]2629
[3802]2630   g_listen[i].used = 0;
[576]2631
[1486]2632#ifdef ROAR_HAVE_UNIX
[2530]2633   if ( server[i] != NULL )
2634    if ( *(server[i]) == '/' )
2635     unlink(server[i]);
[1486]2636#endif
[2530]2637  }
[580]2638 }
[60]2639
[1494]2640#endif
2641
[574]2642 if ( terminate )
2643  g_terminate = 1;
2644}
2645
2646void clean_quit_prep (void) {
2647 cleanup_listen_socket(0);
[60]2648
[3354]2649 plugins_free();
2650
[2485]2651#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]2652 sources_free();
[2485]2653#endif
[0]2654 streams_free();
2655 clients_free();
[2489]2656#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]2657 ssynth_free();
[2489]2658#endif
[2487]2659#ifndef ROAR_WITHOUT_DCOMP_CB
[282]2660 midi_cb_stop(); // stop console beep
[2487]2661#endif
[2500]2662#ifndef ROAR_WITHOUT_DCOMP_MIDI
[281]2663 midi_free();
[2500]2664#endif
[2494]2665#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1819]2666 light_free();
[2494]2667#endif
[2718]2668#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2669 rdtcs_free();
2670#endif
[2104]2671
[2945]2672 waveform_free();
2673
[2104]2674#ifdef SUPPORT_PIDFILE
2675 if ( pidfile != NULL )
2676  unlink(pidfile);
2677#endif
[4469]2678
2679 auth_free();
[0]2680}
2681
2682void clean_quit (void) {
[4055]2683 ROAR_INFO("Shuting down", ROAR_DBG_INFO_INFO);
2684
[4101]2685 counters_print(ROAR_DEBUG_TYPE_INFO, 0);
2686
[0]2687 clean_quit_prep();
2688// output_buffer_free();
[4055]2689
[4323]2690 roar_notify_core_free(NULL);
2691
[4851]2692 ROAR_INFO("Shuting down complete", ROAR_DBG_INFO_INFO);
2693
2694 if ( g_config->scripts.post_shutdown != NULL )
2695  system(g_config->scripts.post_shutdown);
2696
[4055]2697 ROAR_INFO("Exiting, no error", ROAR_DBG_INFO_INFO);
[0]2698 exit(0);
2699}
2700
2701//ll
Note: See TracBrowser for help on using the repository browser.