X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/cca89d7ce589d10a226c6dfa212e36cbcad25fd2..73df7db645fa36e1e6d732ec34b7020bc316248e:/lib/configuration.c diff --git a/lib/configuration.c b/lib/configuration.c index c2c9a9f..c2f0791 100644 --- a/lib/configuration.c +++ b/lib/configuration.c @@ -39,6 +39,9 @@ #if HAVE_PCRE_H # include #endif +#if HAVE_SHLOBJ_H +# include +#endif #include #include "rights.h" @@ -58,7 +61,9 @@ #include "signame.h" #include "authhash.h" #include "vector.h" +#if !_WIN32 #include "uaudio.h" +#endif /** @brief Path to config file * @@ -72,11 +77,13 @@ char *configfile; */ int config_per_user = 1; +#if !_WIN32 /** @brief Table of audio APIs * * Only set in server processes. */ const struct uaudio *const *config_uaudio_apis; +#endif /** @brief Config file parser state */ struct config_state { @@ -260,22 +267,6 @@ static int set_string(const struct config_state *cs, return 0; } -static int set_stringlist(const struct config_state *cs, - const struct conf *whoami, - int nvec, char **vec) { - int n; - struct stringlist *sl; - - sl = ADDRESS(cs->config, struct stringlist); - sl->n = 0; - for(n = 0; n < nvec; ++n) { - sl->n++; - sl->s = xrealloc(sl->s, (sl->n * sizeof (char *))); - sl->s[sl->n - 1] = xstrdup(vec[n]); - } - return 0; -} - static int set_integer(const struct config_state *cs, const struct conf *whoami, int nvec, char **vec) { @@ -358,13 +349,13 @@ static int parse_sample_format(const struct config_state *cs, cs->path, cs->line, t); return -1; } - if(format) format->bits = t; + if(format) format->bits = (uint8_t)t; switch (*p) { case 'l': case 'L': t = ENDIAN_LITTLE; p++; break; case 'b': case 'B': t = ENDIAN_BIG; p++; break; default: t = ENDIAN_NATIVE; break; } - if(format) format->endian = t; + if(format) format->endian = (uint8_t)t; if(*p != '/') { disorder_error(errno, "%s:%d: expected `/' after bits-per-sample", cs->path, cs->line); @@ -395,7 +386,7 @@ static int parse_sample_format(const struct config_state *cs, cs->path, cs->line, t); return -1; } - if(format) format->channels = t; + if(format) format->channels = (uint8_t)t; if(*p) { disorder_error(0, "%s:%d: junk after channels", cs->path, cs->line); return -1; @@ -627,13 +618,14 @@ static const struct conftype type_collections = { set_collections, free_collectionlist }, type_boolean = { set_boolean, free_none }, type_string = { set_string, free_string }, - type_stringlist = { set_stringlist, free_stringlist }, type_integer = { set_integer, free_none }, type_stringlist_accum = { set_stringlist_accum, free_stringlistlist }, type_string_accum = { set_string_accum, free_stringlist }, type_sample_format = { set_sample_format, 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_string }; @@ -676,7 +668,7 @@ static int validate_isabspath(const struct config_state *cs, 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; } @@ -750,6 +742,7 @@ static int validate_tracklength(const struct config_state *cs, 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); @@ -760,7 +753,8 @@ static int validate_non_negative(const struct config_state *cs, 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) { @@ -779,6 +773,7 @@ static int validate_non_negative(const struct config_state *cs, 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); @@ -789,7 +784,8 @@ static int validate_positive(const struct config_state *cs, 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) { @@ -799,6 +795,7 @@ static int validate_positive(const struct config_state *cs, return 0; } +#if !_WIN32 /** @brief Validate a system username * @param cs Configuration state * @param nvec Length of (proposed) new value @@ -814,6 +811,7 @@ static int validate_isauser(const struct config_state *cs, } return 0; } +#endif /** @brief Validate a sample format string * @param cs Configuration state @@ -952,6 +950,7 @@ static int validate_algo(const struct config_state attribute((unused)) *cs, return 0; } +#if !_WIN32 /** @brief Validate a playback backend name * @param cs Configuration state * @param nvec Length of (proposed) new value @@ -980,6 +979,7 @@ static int validate_backend(const struct config_state attribute((unused)) *cs, /* In non-server processes we have no idea what's valid */ return 0; } +#endif /** @brief Validate a pause mode string * @param cs Configuration state @@ -1030,7 +1030,9 @@ 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 }, +#if !_WIN32 { C(api), &type_string, validate_backend }, +#endif { C(authorization_algorithm), &type_string, validate_algo }, { C(broadcast), &type_netaddress, validate_destaddr }, { C(broadcast_from), &type_netaddress, validate_any }, @@ -1045,7 +1047,9 @@ static const struct conf conf[] = { { C(default_rights), &type_rights, validate_any }, { C(device), &type_string, validate_any }, { C(history), &type_integer, validate_positive }, +#if !_WIN32 { C(home), &type_string, validate_isabspath }, +#endif { C(listen), &type_netaddress, validate_any }, { C(mail_sender), &type_string, validate_any }, { C(mixer), &type_string, validate_any }, @@ -1080,12 +1084,16 @@ static const struct conf conf[] = { { C(rtp_verbose), &type_boolean, validate_any }, { C(sample_format), &type_sample_format, validate_sample_format }, { C(scratch), &type_string_accum, validate_isreg }, +#if !_WIN32 { C(sendmail), &type_string, validate_isabspath }, +#endif { C(short_display), &type_integer, validate_positive }, { C(signal), &type_signal, validate_any }, { C(smtp_server), &type_string, validate_any }, { C(sox_generation), &type_integer, validate_non_negative }, +#if !_WIN32 { C2(speaker_backend, api), &type_string, validate_backend }, +#endif { C(speaker_command), &type_string, validate_any }, { C(stopword), &type_string_accum, validate_any }, { C(templates), &type_string_accum, validate_isdir }, @@ -1094,7 +1102,9 @@ static const struct conf conf[] = { { C(transform), &type_transform, validate_any }, #endif { C(url), &type_string, validate_url }, +#if !_WIN32 { C(user), &type_string, validate_isauser }, +#endif { C(username), &type_string, validate_any }, }; @@ -1140,6 +1150,7 @@ static int config_set_args(const struct config_state *cs, va_list ap; struct vector v[1]; char *s; + int rc; vector_init(v); vector_append(v, (char *)which); @@ -1148,7 +1159,7 @@ static int config_set_args(const struct config_state *cs, vector_append(v, s); va_end(ap); vector_terminate(v); - int rc = config_set(cs, v->nvec, v->vec); + rc = config_set(cs, v->nvec, v->vec); xfree(v->vec); return rc; } @@ -1296,8 +1307,10 @@ static const char *const default_players[] = { */ static struct config *config_default(void) { struct config *c = xmalloc(sizeof *c); +#if !_WIN32 const char *logname; struct passwd *pw; +#endif struct config_state cs; size_t n; @@ -1306,14 +1319,30 @@ static struct config *config_default(void) { cs.config = c; /* Strings had better be xstrdup'd as they will get freed at some point. */ c->history = 60; +#if !_WIN32 c->home = xstrdup(pkgstatedir); +#endif +#if _WIN32 + { + char buffer[128]; + DWORD bufsize = sizeof buffer; + if(!GetUserNameA(buffer, &bufsize)) + disorder_fatal(0, "cannot determine our username"); + c->username = xstrdup(buffer); + } +#else if(!(pw = getpwuid(getuid()))) disorder_fatal(0, "cannot determine our username"); logname = pw->pw_name; c->username = xstrdup(logname); +#endif c->refresh = 15; c->refresh_min = 1; +#ifdef SIGKILL c->signal = SIGKILL; +#else + c->signal = SIGTERM; +#endif c->alias = xstrdup("{/artist}{/album}{/title}{ext}"); c->device = xstrdup("default"); c->nice_rescan = 10; @@ -1335,8 +1364,10 @@ static struct config *config_default(void) { c->dbversion = 2; c->cookie_login_lifetime = 86400; c->cookie_key_lifetime = 86400 * 7; +#if !_WIN32 if(sendmail_binary[0] && strcmp(sendmail_binary, "none")) c->sendmail = xstrdup(sendmail_binary); +#endif c->smtp_server = xstrdup("127.0.0.1"); c->new_max = 100; c->reminder_interval = 600; /* 10m */ @@ -1366,6 +1397,7 @@ static struct config *config_default(void) { return c; } +#if !_WIN32 /** @brief Construct a filename * @param c Configuration * @param name Base filename @@ -1379,11 +1411,14 @@ char *config_get_file2(struct config *c, const char *name) { byte_xasprintf(&s, "%s/%s", c->home, name); return s; } +#endif /** @brief Set the default configuration file */ static void set_configfile(void) { +#if !_WIN32 if(!configfile) byte_xasprintf(&configfile, "%s/config", pkgconfdir); +#endif } /** @brief Free a configuration object @@ -1459,9 +1494,11 @@ static void config_postdefaults(struct config *c, c->api = xstrdup("command"); else if(c->broadcast.af != -1) c->api = xstrdup("rtp"); +#if !_WIN32 else if(config_uaudio_apis) c->api = xstrdup(uaudio_default(config_uaudio_apis, UAUDIO_API_SERVER)->name); +#endif else c->api = xstrdup(""); } @@ -1508,14 +1545,15 @@ int config_read(int server, const struct config *oldconfig) { struct config *c; char *privconf; - struct passwd *pw; + struct passwd *pw = NULL; set_configfile(); c = config_default(); - /* standalone Disobedience installs might not have a global config file */ - if(access(configfile, F_OK) == 0) - if(config_include(c, configfile)) - return -1; + /* standalone client installs might not have a global config file */ + if(configfile) + if(access(configfile, F_OK) == 0) + if(config_include(c, configfile)) + return -1; /* if we can read the private config file, do */ if((privconf = config_private()) && access(privconf, R_OK) == 0 @@ -1524,6 +1562,7 @@ int config_read(int server, xfree(privconf); /* if there's a per-user system config file for this user, read it */ if(config_per_user) { +#if !_WIN32 if(!(pw = getpwuid(getuid()))) disorder_fatal(0, "cannot determine our username"); if((privconf = config_usersysconf(pw)) @@ -1531,6 +1570,7 @@ int config_read(int server, && config_include(c, privconf)) return -1; xfree(privconf); +#endif /* if we have a password file, read it */ if((privconf = config_userconf(0, pw)) && access(privconf, F_OK) == 0 @@ -1542,10 +1582,12 @@ int config_read(int server, config_postdefaults(c, server); if(oldconfig) { int failed = 0; +#if !_WIN32 if(strcmp(c->home, oldconfig->home)) { disorder_error(0, "'home' cannot be changed without a restart"); failed = 1; } +#endif if(strcmp(c->alias, oldconfig->alias)) { disorder_error(0, "'alias' cannot be changed without a restart"); failed = 1; @@ -1586,23 +1628,37 @@ int config_read(int server, /** @brief Return the path to the private configuration file */ char *config_private(void) { +#if _WIN32 + return NULL; +#else char *s; set_configfile(); byte_xasprintf(&s, "%s.private", configfile); return s; +#endif } /** @brief Return the path to user's personal configuration file */ char *config_userconf(const char *home, const struct passwd *pw) { char *s; - +#if _WIN32 + wchar_t *wpath = 0; + char *appdata; + if(SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &wpath) != S_OK) + disorder_fatal(0, "error calling SHGetKnownFolderPath"); + appdata = win_wtomb(wpath); + CoTaskMemFree(wpath); + byte_xasprintf(&s, "%s\\DisOrder\\passwd", appdata); +#else if(!home && !pw && !(pw = getpwuid(getuid()))) disorder_fatal(0, "cannot determine our username"); byte_xasprintf(&s, "%s/.disorder/passwd", home ? home : pw->pw_dir); +#endif return s; } +#if !_WIN32 /** @brief Return the path to user-specific system configuration */ char *config_usersysconf(const struct passwd *pw) { char *s; @@ -1622,6 +1678,7 @@ char *config_usersysconf(const struct passwd *pw) { char *config_get_file(const char *name) { return config_get_file2(config, name); } +#endif /** @brief Order two stringlists * @param a First stringlist @@ -1698,7 +1755,8 @@ static int namepartlist_compare(const struct namepartlist *a, */ 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;