mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-03 01:46:02 -05:00
move config web dispatcher to configfile.c, add more flexible config parsing
This commit is contained in:
parent
093b24ca29
commit
e311b43354
248
src/configfile.c
248
src/configfile.c
@ -19,18 +19,52 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "configfile.h"
|
||||
#include "err.h"
|
||||
|
||||
|
||||
/*
|
||||
* Forwards
|
||||
*/
|
||||
void config_emit_string(void *value,WS_CONNINFO *pwsc);
|
||||
void config_emit_int(void *value,WS_CONNINFO *pwsc);
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
#define CONFIG_TYPE_INT 0
|
||||
#define CONFIG_TYPE_STRING 1
|
||||
|
||||
typedef struct tag_configelement {
|
||||
int config_element;
|
||||
int required;
|
||||
int changed;
|
||||
int type;
|
||||
char *name;
|
||||
void *var;
|
||||
void (*emit)(void *,WS_CONNINFO *);
|
||||
} CONFIGELEMENT;
|
||||
|
||||
CONFIGELEMENT config_elements[] = {
|
||||
{ 1,1,0,CONFIG_TYPE_STRING,"web_root",(void*)&config.web_root,config_emit_string },
|
||||
{ 1,1,0,CONFIG_TYPE_INT,"port",(void*)&config.port,config_emit_int },
|
||||
{ 1,1,0,CONFIG_TYPE_STRING,"admin_pw",(void*)&config.adminpassword,config_emit_string },
|
||||
{ 1,1,0,CONFIG_TYPE_STRING,"mp3_dir",(void*)&config.mp3dir,config_emit_string },
|
||||
{ -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL }
|
||||
};
|
||||
|
||||
|
||||
#define MAX_LINE 1024
|
||||
|
||||
@ -43,7 +77,7 @@
|
||||
*
|
||||
* This function returns 0 on success, errorcode on failure
|
||||
*/
|
||||
int config_read(char *file, CONFIG *pconfig) {
|
||||
int config_read(char *file) {
|
||||
FILE *fin;
|
||||
char *buffer;
|
||||
int err;
|
||||
@ -51,6 +85,8 @@ int config_read(char *file, CONFIG *pconfig) {
|
||||
char *comment;
|
||||
char path_buffer[PATH_MAX];
|
||||
err=0;
|
||||
CONFIGELEMENT *pce;
|
||||
int handled;
|
||||
|
||||
buffer=(char*)malloc(MAX_LINE);
|
||||
if(!buffer)
|
||||
@ -63,9 +99,9 @@ int config_read(char *file, CONFIG *pconfig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(pconfig,0,sizeof(CONFIG));
|
||||
memset((void*)&config,0,sizeof(CONFIG));
|
||||
|
||||
pconfig->configfile=strdup(file);
|
||||
config.configfile=strdup(file);
|
||||
|
||||
while(fgets(buffer,MAX_LINE,fin)) {
|
||||
if(*buffer != '#') {
|
||||
@ -81,21 +117,30 @@ int config_read(char *file, CONFIG *pconfig) {
|
||||
if(value[strlen(value)-1] == '\n')
|
||||
value[strlen(value)-1] = '\0';
|
||||
|
||||
if(!strcasecmp(buffer,"web_root")) {
|
||||
realpath(value,path_buffer);
|
||||
pconfig->web_root=strdup(path_buffer);
|
||||
DPRINTF(ERR_DEBUG,"Web root: %s\n",path_buffer);
|
||||
} else if(!strcasecmp(buffer,"port")) {
|
||||
pconfig->port=atoi(value);
|
||||
DPRINTF(ERR_DEBUG,"Port: %d\n",pconfig->port);
|
||||
} else if(!strcasecmp(buffer,"admin_password")) {
|
||||
pconfig->adminpassword=strdup(value);
|
||||
DPRINTF(ERR_DEBUG,"Admin pw: %s\n",value);
|
||||
} else if(!strcasecmp(buffer,"mp3_dir")) {
|
||||
pconfig->mp3dir=strdup(value);
|
||||
DPRINTF(ERR_DEBUG,"MP3 Dir: %s\n",value);
|
||||
} else {
|
||||
DPRINTF(ERR_INFO,"Bad config directive: %s\n",buffer);
|
||||
pce=config_elements;
|
||||
handled=0;
|
||||
while((!handled) && (pce->config_element != -1)) {
|
||||
if((strcasecmp(buffer,pce->name)==0) && (pce->config_element)) {
|
||||
/* valid config directive */
|
||||
handled=1;
|
||||
pce->changed=1;
|
||||
|
||||
switch(pce->type) {
|
||||
case CONFIG_TYPE_STRING:
|
||||
pce->var = (void*)strdup(value);
|
||||
break;
|
||||
case CONFIG_TYPE_INT:
|
||||
*((int*)(pce->var)) = atoi(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pce++;
|
||||
}
|
||||
|
||||
if(!handled) {
|
||||
fprintf(stderr,"Invalid config directive: %s\n",buffer);
|
||||
fclose(fin);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,29 +148,18 @@ int config_read(char *file, CONFIG *pconfig) {
|
||||
|
||||
fclose(fin);
|
||||
|
||||
if(!pconfig->web_root) {
|
||||
fprintf(stderr,"Config: missing web_root entry\n");
|
||||
errno=EINVAL;
|
||||
err=-1;
|
||||
}
|
||||
|
||||
if(!pconfig->adminpassword) {
|
||||
fprintf(stderr,"Config: missing admin_password entry\n");
|
||||
errno=EINVAL;
|
||||
err=-1;
|
||||
}
|
||||
|
||||
if(!pconfig->port) {
|
||||
fprintf(stderr,"Config: missing port entry\n");
|
||||
errno=EINVAL;
|
||||
err=-1;
|
||||
}
|
||||
|
||||
if(!pconfig->mp3dir) {
|
||||
fprintf(stderr,"Config: missing mp3_dir entry\n");
|
||||
errno=EINVAL;
|
||||
err=-1;
|
||||
/* check to see if all required elements are satisfied */
|
||||
pce=config_elements;
|
||||
err=0;
|
||||
while((pce->config_element != -1)) {
|
||||
if(pce->required && pce->config_element && !pce->changed) {
|
||||
fprintf(stderr,"Required config entry '%s' not specified\n",pce->name);
|
||||
err=-1;
|
||||
}
|
||||
pce->changed=0;
|
||||
pce++;
|
||||
}
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -139,3 +173,137 @@ int config_write(CONFIG *pconfig) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* config_handler
|
||||
*
|
||||
* Handle serving pages from the admin-root
|
||||
*/
|
||||
void config_handler(WS_CONNINFO *pwsc) {
|
||||
char path[PATH_MAX];
|
||||
char resolved_path[PATH_MAX];
|
||||
int file_fd;
|
||||
struct stat sb;
|
||||
char argbuffer[30];
|
||||
int in_arg;
|
||||
char *argptr;
|
||||
char next;
|
||||
|
||||
pwsc->close=1;
|
||||
ws_addresponseheader(pwsc,"Connection","close");
|
||||
|
||||
snprintf(path,PATH_MAX,"%s/%s",config.web_root,pwsc->uri);
|
||||
if(!realpath(path,resolved_path)) {
|
||||
pwsc->error=errno;
|
||||
DPRINTF(ERR_WARN,"Cannot resolve %s\n",path);
|
||||
ws_returnerror(pwsc,404,"Not found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* this should really return a 302:Found */
|
||||
stat(resolved_path,&sb);
|
||||
if(sb.st_mode & S_IFDIR)
|
||||
strcat(resolved_path,"/index.html");
|
||||
|
||||
DPRINTF(ERR_DEBUG,"Thread %d: Preparing to serve %s\n",
|
||||
pwsc->threadno, resolved_path);
|
||||
|
||||
if(strncmp(resolved_path,config.web_root,
|
||||
strlen(config.web_root))) {
|
||||
pwsc->error=EINVAL;
|
||||
DPRINTF(ERR_WARN,"Thread %d: Requested file %s out of root\n",
|
||||
pwsc->threadno,resolved_path);
|
||||
ws_returnerror(pwsc,403,"Forbidden");
|
||||
return;
|
||||
}
|
||||
|
||||
file_fd=r_open2(resolved_path,O_RDONLY);
|
||||
if(file_fd == -1) {
|
||||
pwsc->error=errno;
|
||||
DPRINTF(ERR_WARN,"Thread %d: Error opening %s: %s\n",
|
||||
pwsc->threadno,resolved_path,strerror(errno));
|
||||
ws_returnerror(pwsc,404,"Not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if(strcasecmp(pwsc->uri,"/config-update.html")==0) {
|
||||
/* we need to update stuff */
|
||||
argptr=ws_getvar(pwsc,"adminpw");
|
||||
if(argptr) {
|
||||
if(config.adminpassword)
|
||||
free(config.adminpassword);
|
||||
config.adminpassword=strdup(argptr);
|
||||
}
|
||||
}
|
||||
|
||||
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||
ws_emitheaders(pwsc);
|
||||
|
||||
/* now throw out the file, with replacements */
|
||||
in_arg=0;
|
||||
argptr=argbuffer;
|
||||
|
||||
while(1) {
|
||||
if(r_read(file_fd,&next,1) <= 0)
|
||||
break;
|
||||
|
||||
if(in_arg) {
|
||||
if(next == '@') {
|
||||
in_arg=0;
|
||||
if(strcasecmp(argbuffer,"WEB_ROOT") == 0) {
|
||||
ws_writefd(pwsc,"%s",config.web_root);
|
||||
} else if (strcasecmp(argbuffer,"PORT") == 0) {
|
||||
ws_writefd(pwsc,"%d",config.port);
|
||||
} else if (strcasecmp(argbuffer,"ADMINPW") == 0) {
|
||||
ws_writefd(pwsc,"%s",config.adminpassword);
|
||||
} else if (strcasecmp(argbuffer,"RELEASE") == 0) {
|
||||
ws_writefd(pwsc,"mt-daapd %s\n",VERSION);
|
||||
} else if (strcasecmp(argbuffer,"MP3DIR") == 0) {
|
||||
ws_writefd(pwsc,"%s",config.mp3dir);
|
||||
} else {
|
||||
ws_writefd(pwsc,"@ERR@");
|
||||
}
|
||||
} else {
|
||||
if((argptr - argbuffer) < (sizeof(argbuffer)-1))
|
||||
*argptr++ = next;
|
||||
}
|
||||
} else {
|
||||
if(next == '@') {
|
||||
argptr=argbuffer;
|
||||
memset(argbuffer,0,sizeof(argbuffer));
|
||||
in_arg=1;
|
||||
} else {
|
||||
if(r_write(pwsc->fd,&next,1) == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r_close(file_fd);
|
||||
DPRINTF(ERR_DEBUG,"Thread %d: Served successfully\n",pwsc->threadno);
|
||||
return;
|
||||
}
|
||||
|
||||
int config_auth(char *user, char *password) {
|
||||
return !strcmp(password,config.adminpassword);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config_emit_string
|
||||
*
|
||||
* write a simple string value to the connection
|
||||
*/
|
||||
void config_emit_string(void *value,WS_CONNINFO *pwsc) {
|
||||
ws_writefd(pwsc,"%s",value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config_emit_int
|
||||
*
|
||||
* write a simple int value to the connection
|
||||
*/
|
||||
void config_emit_int(void *value,WS_CONNINFO *pwsc) {
|
||||
ws_writefd(pwsc,"%d",value);
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,11 @@
|
||||
#define _CONFIGFILE_H_
|
||||
|
||||
#include "daapd.h"
|
||||
#include "webserver.h"
|
||||
|
||||
extern int config_read(char *file, CONFIG *pconfig);
|
||||
extern int config_read(char *file);
|
||||
extern int config_write(CONFIG *pconfig);
|
||||
extern int config_auth(char *user, char *password);
|
||||
extern void config_handler(WS_CONNINFO *pwsc);
|
||||
|
||||
#endif /* _CONFIGFILE_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user