/*
* This file is part of DisOrder.
- * Copyright (C) 2004-2010 Richard Kettlewell
+ * Copyright (C) 2004-2011, 2013 Richard Kettlewell
* Portions copyright (C) 2007 Mark Wooding
*
* This program is free software: you can redistribute it and/or modify
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include <ctype.h>
#include <stddef.h>
-#include <pwd.h>
-#include <langinfo.h>
-#include <pcre.h>
+#if HAVE_PWD_H
+# include <pwd.h>
+#endif
+#if HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+#if HAVE_PCRE_H
+# include <pcre.h>
+#endif
#include <signal.h>
#include "rights.h"
#include "charset.h"
#include "defs.h"
#include "printf.h"
-#include "regsub.h"
+#if HAVE_PCRE_H
+# include "regsub.h"
+#endif
#include "signame.h"
#include "authhash.h"
#include "vector.h"
/** @brief Path to config file
*
- * set_configfile() sets the deafult if it is null.
+ * set_configfile() sets the default if it is null.
*/
char *configfile;
/* Defaults */
if(!module)
module = "fs";
+#if HAVE_LANGINFO_H
if(!encoding)
encoding = nl_langinfo(CODESET);
+#else
+ if(!encoding)
+ encoding = "ascii";
+#endif
cl = ADDRESS(cs->config, struct collectionlist);
++cl->n;
cl->s = xrealloc(cl->s, cl->n * sizeof (struct collection));
cs->path, cs->line, whoami->name);
return -1;
}
+ xfree(VALUE(cs->config, char *));
VALUE(cs->config, char *) = xstrdup(vec[0]);
return 0;
}
return 0;
}
-static int set_restrict(const struct config_state *cs,
- const struct conf *whoami,
- int nvec, char **vec) {
- unsigned r = 0;
- int n, i;
-
- static const struct restriction {
- const char *name;
- unsigned bit;
- } restrictions[] = {
- { "remove", RESTRICT_REMOVE },
- { "scratch", RESTRICT_SCRATCH },
- { "move", RESTRICT_MOVE },
- };
-
- for(n = 0; n < nvec; ++n) {
- if((i = TABLE_FIND(restrictions, name, vec[n])) < 0) {
- disorder_error(0, "%s:%d: invalid restriction '%s'",
- cs->path, cs->line, vec[n]);
- return -1;
- }
- r |= restrictions[i].bit;
- }
- VALUE(cs->config, unsigned) = r;
- return 0;
-}
-
static int parse_sample_format(const struct config_state *cs,
struct stream_header *format,
int nvec, char **vec) {
nvec, vec);
}
+#if HAVE_PCRE_H
static int set_namepart(const struct config_state *cs,
const struct conf *whoami,
int nvec, char **vec) {
++tl->n;
return 0;
}
+#endif
static int set_rights(const struct config_state *cs,
const struct conf *whoami,
cs->path, cs->line, vec[0]);
return -1;
}
- *ADDRESS(cs->config, char *) = vec[0];
- return 0;
+ return set_string(cs, whoami, nvec, vec);
}
static int set_netaddress(const struct config_state *cs,
xfree(cll->s);
}
+#if HAVE_PCRE_H
static void free_namepartlist(struct config *c,
const struct conf *whoami) {
struct namepartlist *npl = ADDRESS(c, struct namepartlist);
}
xfree(tl->t);
}
+#endif
static void free_netaddress(struct config *c,
const struct conf *whoami) {
type_stringlist_accum = { set_stringlist_accum, free_stringlistlist },
type_string_accum = { set_string_accum, free_stringlist },
type_sample_format = { set_sample_format, free_none },
- type_restrict = { set_restrict, free_none },
+#if HAVE_PCRE_H
type_namepart = { set_namepart, free_namepartlist },
type_transform = { set_transform, free_transformlist },
+#endif
type_netaddress = { set_netaddress, free_netaddress },
- type_rights = { set_rights, free_none };
+ type_rights = { set_rights, free_string };
/* specific validation routine */
for(n = 0; n < nvec; ++n)
if(vec[n][0] != '/') {
- disorder_error(errno, "%s:%d: %s: not an absolute path",
+ disorder_error(0, "%s:%d: %s: not an absolute path",
cs->path, cs->line, vec[n]);
return -1;
}
static int validate_player(const struct config_state *cs,
int nvec,
char attribute((unused)) **vec) {
- if(nvec < 2) {
+ if(nvec && nvec < 2) {
disorder_error(0, "%s:%d: should be at least 'player PATTERN MODULE'",
cs->path, cs->line);
return -1;
static int validate_tracklength(const struct config_state *cs,
int nvec,
char attribute((unused)) **vec) {
- if(nvec < 2) {
+ if(nvec && nvec < 2) {
disorder_error(0, "%s:%d: should be at least 'tracklength PATTERN MODULE'",
cs->path, cs->line);
return -1;
return 0;
}
-/** @brief Validate an allow directive
- * @param cs Configuration state
- * @param nvec Length of (proposed) new value
- * @param vec Elements of new value
- * @return 0 on success, non-0 on error
- *
- * Obsolete - only used for parsing legacy configuration.
- */
-static int validate_allow(const struct config_state *cs,
- int nvec,
- char attribute((unused)) **vec) {
- if(nvec != 2) {
- disorder_error(0, "%s:%d: must be 'allow NAME PASS'", cs->path, cs->line);
- return -1;
- }
- return 0;
-}
-
/** @brief Validate a non-negative (@c long) integer
* @param cs Configuration state
* @param nvec Length of (proposed) new value
static int validate_non_negative(const struct config_state *cs,
int nvec, char **vec) {
long n;
+ char errbuf[1024];
if(nvec < 1) {
disorder_error(0, "%s:%d: missing argument", cs->path, cs->line);
return -1;
}
if(xstrtol(&n, vec[0], 0, 0)) {
- disorder_error(0, "%s:%d: %s", cs->path, cs->line, strerror(errno));
+ disorder_error(0, "%s:%d: %s", cs->path, cs->line,
+ format_error(ec_errno, errno, errbuf, sizeof errbuf));
return -1;
}
if(n < 0) {
static int validate_positive(const struct config_state *cs,
int nvec, char **vec) {
long n;
+ char errbuf[1024];
if(nvec < 1) {
disorder_error(0, "%s:%d: missing argument", cs->path, cs->line);
return -1;
}
if(xstrtol(&n, vec[0], 0, 0)) {
- disorder_error(0, "%s:%d: %s", cs->path, cs->line, strerror(errno));
+ disorder_error(0, "%s:%d: %s", cs->path, cs->line,
+ format_error(ec_errno, errno, errbuf, sizeof errbuf));
return -1;
}
if(n <= 0) {
static int validate_isauser(const struct config_state *cs,
int attribute((unused)) nvec,
char **vec) {
- struct passwd *pw;
-
- if(!(pw = getpwnam(vec[0]))) {
+ if(!getpwnam(vec[0])) {
disorder_error(0, "%s:%d: no such user as '%s'", cs->path, cs->line, vec[0]);
return -1;
}
disorder_error(0, "%s:%d: destination address required", cs->path, cs->line);
return -1;
}
+ xfree(na->address);
return 0;
}
/** @brief All configuration items */
static const struct conf conf[] = {
{ C(alias), &type_string, validate_alias },
- { C(allow), &type_stringlist_accum, validate_allow },
{ C(api), &type_string, validate_backend },
{ C(authorization_algorithm), &type_string, validate_algo },
{ C(broadcast), &type_netaddress, validate_destaddr },
{ C(dbversion), &type_integer, validate_positive },
{ C(default_rights), &type_rights, validate_any },
{ C(device), &type_string, validate_any },
- { C(gap), &type_integer, validate_non_negative },
{ C(history), &type_integer, validate_positive },
{ C(home), &type_string, validate_isabspath },
{ C(listen), &type_netaddress, validate_any },
- { C(lock), &type_boolean, validate_any },
{ C(mail_sender), &type_string, validate_any },
{ C(mixer), &type_string, validate_any },
+ { C(mount_rescan), &type_boolean, validate_any },
{ C(multicast_loop), &type_boolean, validate_any },
{ C(multicast_ttl), &type_integer, validate_non_negative },
+#if HAVE_PCRE_H
{ C(namepart), &type_namepart, validate_any },
+#endif
{ C(new_bias), &type_integer, validate_positive },
{ C(new_bias_age), &type_integer, validate_positive },
{ C(new_max), &type_integer, validate_positive },
{ C(playlist_lock_timeout), &type_integer, validate_positive },
{ C(playlist_max) , &type_integer, validate_positive },
{ C(plugins), &type_string_accum, validate_isdir },
- { C(prefsync), &type_integer, validate_positive },
{ C(queue_pad), &type_integer, validate_positive },
{ C(refresh), &type_integer, validate_positive },
+ { C(refresh_min), &type_integer, validate_non_negative },
{ C(reminder_interval), &type_integer, validate_positive },
{ C(remote_userman), &type_boolean, validate_any },
{ C(replay_min), &type_integer, validate_non_negative },
- { C2(restrict, restrictions), &type_restrict, validate_any },
{ C(rtp_delay_threshold), &type_integer, validate_positive },
+ { C(rtp_mode), &type_string, validate_any },
+ { C(rtp_verbose), &type_boolean, validate_any },
{ C(sample_format), &type_sample_format, validate_sample_format },
{ C(scratch), &type_string_accum, validate_isreg },
{ C(sendmail), &type_string, validate_isabspath },
{ C(stopword), &type_string_accum, validate_any },
{ C(templates), &type_string_accum, validate_isdir },
{ C(tracklength), &type_stringlist_accum, validate_tracklength },
+#if HAVE_PCRE_H
{ C(transform), &type_transform, validate_any },
- { C(trust), &type_string_accum, validate_any },
+#endif
{ C(url), &type_string, validate_url },
{ C(user), &type_string, validate_isauser },
{ C(username), &type_string, validate_any },
va_list ap;
struct vector v[1];
char *s;
+ int rc;
vector_init(v);
vector_append(v, (char *)which);
vector_append(v, s);
va_end(ap);
vector_terminate(v);
- return config_set(cs, v->nvec, v->vec);
+ rc = config_set(cs, v->nvec, v->vec);
+ xfree(v->vec);
+ return rc;
}
/** @brief Error callback used by config_include()
cs.line = 0;
cs.config = c;
/* Strings had better be xstrdup'd as they will get freed at some point. */
- c->gap = 0;
c->history = 60;
c->home = xstrdup(pkgstatedir);
if(!(pw = getpwuid(getuid())))
logname = pw->pw_name;
c->username = xstrdup(logname);
c->refresh = 15;
- c->prefsync = 0;
+ c->refresh_min = 1;
c->signal = SIGKILL;
c->alias = xstrdup("{/artist}{/album}{/title}{ext}");
- c->lock = 1;
c->device = xstrdup("default");
c->nice_rescan = 10;
c->speaker_command = 0;
c->sox_generation = DEFAULT_SOX_GENERATION;
c->playlist_max = INT_MAX; /* effectively no limit */
c->playlist_lock_timeout = 10; /* 10s */
+ c->mount_rescan = 1;
/* Default stopwords */
if(config_set(&cs, (int)NDEFAULT_STOPWORDS, (char **)default_stopwords))
exit(1);
c->broadcast_from.af = -1;
c->listen.af = -1;
c->connect.af = -1;
+ c->rtp_mode = xstrdup("auto");
return c;
}
*
* @p c is indeterminate after this function is called.
*/
-static void config_free(struct config *c) {
+void config_free(struct config *c) {
int n;
if(c) {
static void config_postdefaults(struct config *c,
int server) {
struct config_state cs;
+#if HAVE_PCRE_H
const struct conf *whoami;
int n;
+#endif
+#if HAVE_PCRE_H
static const char *namepart[][4] = {
{ "title", "/([0-9]+ *[-:]? *)?([^/]+)\\.[a-zA-Z0-9]+$", "$2", "display" },
{ "title", "/([^/]+)\\.[a-zA-Z0-9]+$", "$1", "sort" },
{ "dir", "[[:punct:]]", "", "sort", "g", }
};
#define NTRANSFORM (int)(sizeof transform / sizeof *transform)
+#endif
cs.path = "<internal>";
cs.line = 0;
cs.config = c;
+#if HAVE_PCRE_H
if(!c->namepart.n) {
whoami = find("namepart");
for(n = 0; n < NNAMEPART; ++n)
for(n = 0; n < NTRANSFORM; ++n)
set_transform(&cs, whoami, 5, (char **)transform[n]);
}
+#endif
if(!c->api) {
if(c->speaker_command)
c->api = xstrdup("command");
else if(c->broadcast.af != -1)
c->api = xstrdup("rtp");
else if(config_uaudio_apis)
- c->api = xstrdup(config_uaudio_apis[0]->name);
+ c->api = xstrdup(uaudio_default(config_uaudio_apis,
+ UAUDIO_API_SERVER)->name);
else
c->api = xstrdup("<none>");
}
|RIGHT_MOVE__MASK
|RIGHT_SCRATCH__MASK
|RIGHT_REMOVE__MASK);
- /* The idea is to approximate the meaning of the old 'restrict' directive
- * in the default rights if they are not overridden. */
- if(c->restrictions & RESTRICT_SCRATCH)
- r |= RIGHT_SCRATCH_MINE|RIGHT_SCRATCH_RANDOM;
- else
- r |= RIGHT_SCRATCH_ANY;
- if(!(c->restrictions & RESTRICT_MOVE))
- r |= RIGHT_MOVE_ANY;
- if(c->restrictions & RESTRICT_REMOVE)
- r |= RIGHT_REMOVE_MINE;
- else
- r |= RIGHT_REMOVE_ANY;
+ r |= RIGHT_SCRATCH_ANY|RIGHT_MOVE_ANY|RIGHT_REMOVE_ANY;
c->default_rights = rights_string(r);
}
}
disorder_error(0, "'nice_server' cannot be changed without a restart");
/* ...but we accept the new config anyway */
}
+#if HAVE_PCRE_H
if(namepartlist_compare(&c->namepart, &oldconfig->namepart)) {
disorder_error(0, "'namepart' settings cannot be changed without a restart");
failed = 1;
}
+#endif
if(stringlist_compare(&c->stopword, &oldconfig->stopword)) {
disorder_error(0, "'stopword' settings cannot be changed without a restart");
failed = 1;
/* everything is good so we shall use the new config */
config_free(config);
/* warn about obsolete directives */
- if(c->restrictions)
- disorder_error(0, "'restrict' will be removed in a future version");
- if(c->allow.n)
- disorder_error(0, "'allow' will be removed in a future version");
- if(c->trust.n)
- disorder_error(0, "'trust' will be removed in a future version");
- if(!c->lock)
- disorder_error(0, "'lock' will be removed in a future version");
- if(c->gap)
- disorder_error(0, "'gap' will be removed in a future version");
- if(c->prefsync)
- disorder_error(0, "'prefsync' will be removed in a future version");
config = c;
return 0;
}
return 0;
}
+#if HAVE_PCRE_H
/** @brief Order two namepart definitions
* @param a First namepart definition
* @param b Second namepart definition
else
return 0;
}
+#endif
/** @brief Verify configuration table.
* @return The number of problems found
*/
int config_verify(void) {
int fails = 0;
- for(size_t n = 1; n < sizeof conf / sizeof *conf; ++n)
+ size_t n;
+ for(n = 1; n < sizeof conf / sizeof *conf; ++n)
if(strcmp(conf[n-1].name, conf[n].name) >= 0) {
fprintf(stderr, "%s >= %s\n", conf[n-1].name, conf[n].name);
++fails;