chiark / gitweb /
log: more general error message formatting
[disorder] / lib / configuration.c
index 0b173d4113e22098ff0c52d017725dd958bfe245..c2c9a9f69b4d7ed8a83ae5e2df6b2a04b22a4388 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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"
@@ -44,7 +52,9 @@
 #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"
@@ -200,8 +210,13 @@ static int set_collections(const struct config_state *cs,
   /* 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));
@@ -240,6 +255,7 @@ static int set_string(const struct config_state *cs,
                   cs->path, cs->line, whoami->name);
     return -1;
   }
+  xfree(VALUE(cs->config, char *));
   VALUE(cs->config, char *) = xstrdup(vec[0]);
   return 0;
 }
@@ -322,33 +338,6 @@ static int set_string_accum(const struct config_state *cs,
   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) {
@@ -421,6 +410,7 @@ static int set_sample_format(const struct config_state *cs,
                             nvec, vec);
 }
 
+#if HAVE_PCRE_H
 static int set_namepart(const struct config_state *cs,
                        const struct conf *whoami,
                        int nvec, char **vec) {
@@ -506,6 +496,7 @@ static int set_transform(const struct config_state *cs,
   ++tl->n;
   return 0;
 }
+#endif
 
 static int set_rights(const struct config_state *cs,
                      const struct conf *whoami,
@@ -520,8 +511,7 @@ static int set_rights(const struct config_state *cs,
                   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,
@@ -588,6 +578,7 @@ static void free_collectionlist(struct config *c,
   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);
@@ -620,6 +611,7 @@ static void free_transformlist(struct config *c,
   }
   xfree(tl->t);
 }
+#endif
 
 static void free_netaddress(struct config *c,
                            const struct conf *whoami) {
@@ -640,11 +632,10 @@ static const struct conftype
   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 },
   type_namepart = { set_namepart, free_namepartlist },
   type_transform = { set_transform, free_transformlist },
   type_netaddress = { set_netaddress, free_netaddress },
-  type_rights = { set_rights, free_none };
+  type_rights = { set_rights, free_string };
 
 /* specific validation routine */
 
@@ -725,7 +716,7 @@ static int validate_isreg(const struct config_state *cs,
 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;
@@ -742,7 +733,7 @@ static int validate_player(const struct config_state *cs,
 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;
@@ -750,24 +741,6 @@ static int validate_tracklength(const struct config_state *cs,
   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
@@ -835,9 +808,7 @@ static int validate_positive(const struct config_state *cs,
 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;
   }
@@ -1047,6 +1018,7 @@ static int validate_destaddr(const struct config_state attribute((unused)) *cs,
     disorder_error(0, "%s:%d: destination address required", cs->path, cs->line);
     return -1;
   }
+  xfree(na->address);
   return 0;
 }
 
@@ -1058,7 +1030,6 @@ static int validate_destaddr(const struct config_state attribute((unused)) *cs,
 /** @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 },
@@ -1073,17 +1044,17 @@ static const struct conf conf[] = {
   { 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 },
@@ -1098,15 +1069,15 @@ static const struct conf conf[] = {
   { 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 },
@@ -1119,8 +1090,9 @@ static const struct conf conf[] = {
   { 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 },
@@ -1176,7 +1148,9 @@ static int config_set_args(const struct config_state *cs,
     vector_append(v, s);
   va_end(ap);
   vector_terminate(v);
-  return config_set(cs, v->nvec, v->vec);
+  int rc = config_set(cs, v->nvec, v->vec);
+  xfree(v->vec);
+  return rc;
 }
 
 /** @brief Error callback used by config_include()
@@ -1331,7 +1305,6 @@ static struct config *config_default(void) {
   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())))
@@ -1340,10 +1313,8 @@ static struct config *config_default(void) {
   c->username = xstrdup(logname);
   c->refresh = 15;
   c->refresh_min = 1;
-  c->prefsync = 0;
   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;
@@ -1391,6 +1362,7 @@ static struct config *config_default(void) {
   c->broadcast_from.af = -1;
   c->listen.af = -1;
   c->connect.af = -1;
+  c->rtp_mode = xstrdup("auto");
   return c;
 }
 
@@ -1419,7 +1391,7 @@ static void set_configfile(void) {
  *
  * @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) {
@@ -1442,9 +1414,12 @@ static void config_free(struct config *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" },
@@ -1462,10 +1437,12 @@ static void config_postdefaults(struct config *c,
     { "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)
@@ -1476,13 +1453,15 @@ static void config_postdefaults(struct config *c,
     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>");
   }
@@ -1512,18 +1491,7 @@ static void config_postdefaults(struct config *c,
                                     |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);
   }
 }
@@ -1594,10 +1562,12 @@ int config_read(int server,
       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;
@@ -1610,18 +1580,6 @@ int config_read(int server,
   /* 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;
 }
@@ -1687,6 +1645,7 @@ static int stringlist_compare(const struct stringlist *a,
     return 0;
 }
 
+#if HAVE_PCRE_H
 /** @brief Order two namepart definitions
  * @param a First namepart definition
  * @param b Second namepart definition
@@ -1732,6 +1691,7 @@ static int namepartlist_compare(const struct namepartlist *a,
   else
     return 0;
 }
+#endif
 
 /** @brief Verify configuration table.
  * @return The number of problems found