mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-03 18:06:04 -05:00
Remove OS abstraction layer
Migrate daemon startup code in main.c, migrate functions with a single callsite to that file. Remove setpgrp() usage in favor of setsid(), remove configure check for setpgrp().
This commit is contained in:
parent
9d026442b2
commit
e8c9a04376
@ -23,8 +23,6 @@ AC_CHECK_FUNCS(timegm)
|
||||
AC_CHECK_FUNCS(va_copy)
|
||||
AC_CHECK_FUNCS(__va_copy)
|
||||
|
||||
AC_FUNC_SETPGRP
|
||||
|
||||
if test "x$prefix" != xNONE -a "x$prefix" != "x/usr"; then
|
||||
CONFFILE="$prefix/etc/mt-daapd.conf"
|
||||
else
|
||||
|
@ -23,8 +23,8 @@ mt_daapd_SOURCES = main.c daapd.h webserver.c \
|
||||
rxml.c rxml.h redblack.c redblack.h \
|
||||
scan-xml.c scan-wma.c scan-url.c \
|
||||
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
||||
os.h ll.c ll.h conf.c conf.h util.c util.h \
|
||||
os-unix.h os-unix.c os.h plugin.c plugin.h db-sql-updates.c \
|
||||
ll.c ll.h conf.c conf.h util.c util.h \
|
||||
plugin.c plugin.h db-sql-updates.c \
|
||||
io.h io.c io-errors.h io-plugin.h \
|
||||
db-sql.c db-sql.h db-sql-sqlite3.c db-sql-sqlite3.h\
|
||||
$(FLACSRC) $(MUSEPACKSRC)
|
||||
|
40
src/conf.c
40
src/conf.c
@ -46,12 +46,13 @@
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "conf.h"
|
||||
#include "err.h"
|
||||
#include "ll.h"
|
||||
#include "os.h"
|
||||
#include "util.h"
|
||||
#include "webserver.h"
|
||||
#include "xml-rpc.h"
|
||||
@ -191,6 +192,36 @@ void _conf_remap_entry(char *old_section, char *old_key, char **new_section, cha
|
||||
*new_key = old_key;
|
||||
}
|
||||
|
||||
static int _conf_chown(char *path, char *user) {
|
||||
struct passwd *pw=NULL;
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Chowning %s to %s\n",path,user);
|
||||
|
||||
/* drop privs */
|
||||
if(getuid() == (uid_t)0) {
|
||||
if(atoi(user)) {
|
||||
pw=getpwuid((uid_t)atoi(user)); /* doh! */
|
||||
} else {
|
||||
pw=getpwnam(user);
|
||||
}
|
||||
|
||||
if(pw) {
|
||||
if(initgroups(user,pw->pw_gid) != 0 ||
|
||||
chown(path, pw->pw_uid, pw->pw_gid) != 0) {
|
||||
DPRINTF(E_LOG,L_MISC,"Couldn't chown %s, gid=%d, uid=%d\n",
|
||||
user,pw->pw_gid, pw->pw_uid);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_MISC,"Couldn't lookup user %s for chown\n",user);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Success!\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and create a directory, including parents (probably
|
||||
* in response to a config file entry that does not exist).
|
||||
@ -233,7 +264,7 @@ int _conf_makedir(char *path,char *user) {
|
||||
path_buffer,strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
os_chown(path_buffer,user);
|
||||
_conf_chown(path_buffer,user);
|
||||
}
|
||||
retval = TRUE;
|
||||
}
|
||||
@ -254,9 +285,8 @@ int _conf_existdir(char *path) {
|
||||
|
||||
DPRINTF(E_DBG,L_CONF,"Checking existence of %s\n",path);
|
||||
|
||||
if(os_stat(path,&sb)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (stat(path, &sb))
|
||||
return FALSE;
|
||||
|
||||
if(sb.st_mode & S_IFDIR)
|
||||
return TRUE;
|
||||
|
@ -54,7 +54,6 @@
|
||||
#include "configfile.h"
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "os.h"
|
||||
#include "xml-rpc.h"
|
||||
|
||||
|
||||
@ -175,7 +174,8 @@ int config_password_required(WS_CONNINFO *pwsc, char *role) {
|
||||
/* don't need a password from localhost
|
||||
when the password isn't set */
|
||||
|
||||
if((ws_hostname(pwsc)) && (os_islocaladdr(ws_hostname(pwsc)))) {
|
||||
if((ws_hostname(pwsc))
|
||||
&& (strncmp(ws_hostname(pwsc), "127.", 4) == 0)) {
|
||||
if(pw) free(pw);
|
||||
return FALSE;
|
||||
}
|
||||
@ -394,7 +394,7 @@ void config_handler(WS_CONNINFO *pwsc) {
|
||||
}
|
||||
|
||||
/* FIXME: should feed this file directly, so as to bypass perms */
|
||||
if(!os_islocaladdr(ws_hostname(pwsc))) {
|
||||
if(strncmp(ws_hostname(pwsc), "127.", 4) != 0) {
|
||||
pw=conf_alloc_string("general","admin_pw",NULL);
|
||||
if((!pw) || (strlen(pw) == 0)) {
|
||||
if(pw) free(pw);
|
||||
@ -446,7 +446,7 @@ void config_handler(WS_CONNINFO *pwsc) {
|
||||
}
|
||||
|
||||
/* this is quite broken, but will work */
|
||||
os_stat(resolved_path,&sb);
|
||||
stat(resolved_path,&sb);
|
||||
if(S_ISDIR(sb.st_mode)) {
|
||||
ws_addresponseheader(pwsc,"Location","index.html");
|
||||
ws_returnerror(pwsc,302,"Moved");
|
||||
@ -942,7 +942,7 @@ void config_emit_include(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
}
|
||||
|
||||
/* this should really return a 302:Found */
|
||||
os_stat(resolved_path,&sb);
|
||||
stat(resolved_path,&sb);
|
||||
if(sb.st_mode & S_IFDIR) {
|
||||
ws_writefd(pwsc,"<hr><i>error: cannot include dir %s</i><hr>",arg);
|
||||
return;
|
||||
|
@ -38,6 +38,9 @@
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define PATHSEP '/'
|
||||
#define PATHSEP_STR "/"
|
||||
|
||||
#ifdef DEBUG
|
||||
# ifndef ASSERT
|
||||
# define ASSERT(f) \
|
||||
|
26
src/err.c
26
src/err.c
@ -46,12 +46,13 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "err.h"
|
||||
#include "io.h"
|
||||
|
||||
#ifndef ERR_LEAN
|
||||
# include "os.h"
|
||||
# include "plugin.h"
|
||||
#endif
|
||||
|
||||
@ -82,6 +83,14 @@ static char *err_categorylist[] = {
|
||||
|
||||
static ERR_THREADLIST err_threadlist = { 0, NULL };
|
||||
|
||||
static int lvl2syslog[10] =
|
||||
{
|
||||
LOG_ALERT, LOG_ALERT,
|
||||
LOG_NOTICE, LOG_NOTICE, LOG_NOTICE,
|
||||
LOG_INFO, LOG_INFO, LOG_INFO, LOG_INFO,
|
||||
LOG_DEBUG
|
||||
};
|
||||
|
||||
/*
|
||||
* Forwards
|
||||
*/
|
||||
@ -245,9 +254,10 @@ void err_log(int level, unsigned int cat, char *fmt, ...)
|
||||
/* always log fatals and level 1 to syslog */
|
||||
if(level <= 1) {
|
||||
if(!err_syslog_open)
|
||||
os_opensyslog();
|
||||
openlog(PACKAGE, LOG_PID, LOG_DAEMON);
|
||||
|
||||
err_syslog_open=1;
|
||||
os_syslog(level,errbuf);
|
||||
syslog((level > E_DBG) ? LOG_DEBUG : lvl2syslog[level], "%s", errbuf);
|
||||
|
||||
if(syslog_only && !level) {
|
||||
fprintf(stderr,"Aborting\n");
|
||||
@ -361,8 +371,9 @@ int err_setlogfile(char *file) {
|
||||
if(!err_file) {
|
||||
err_logdest &= ~LOGDEST_LOGFILE;
|
||||
if(!err_syslog_open)
|
||||
os_opensyslog();
|
||||
os_syslog(1,"Error initializing logfile");
|
||||
openlog(PACKAGE, LOG_PID, LOG_DAEMON);
|
||||
|
||||
syslog(lvl2syslog[1], "Error initializing logfile");
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,8 +396,9 @@ int err_setlogfile(char *file) {
|
||||
err_logdest &= ~LOGDEST_LOGFILE;
|
||||
|
||||
if(!err_syslog_open)
|
||||
os_opensyslog();
|
||||
os_syslog(1,"Error opening logfile");
|
||||
openlog(PACKAGE, LOG_PID, LOG_DAEMON);
|
||||
|
||||
syslog(lvl2syslog[1], "Error opening logfile");
|
||||
|
||||
result=FALSE;
|
||||
}
|
||||
|
211
src/main.c
211
src/main.c
@ -77,6 +77,9 @@
|
||||
#endif
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "daapd.h"
|
||||
|
||||
#include "conf.h"
|
||||
@ -85,7 +88,6 @@
|
||||
#include "mp3-scanner.h"
|
||||
#include "webserver.h"
|
||||
#include "db-generic.h"
|
||||
#include "os.h"
|
||||
#include "plugin.h"
|
||||
#include "util.h"
|
||||
#include "io.h"
|
||||
@ -108,6 +110,10 @@
|
||||
# define atoll(a) atol(a)
|
||||
#endif
|
||||
|
||||
#ifndef PIDFILE
|
||||
#define PIDFILE "/var/run/mt-daapd.pid"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
@ -156,7 +162,6 @@ int main_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||
void usage(char *program) {
|
||||
printf("Usage: %s [options]\n\n",program);
|
||||
printf("Options:\n");
|
||||
printf(" -a Set cwd to app dir before starting\n");
|
||||
printf(" -d <number> Debug level (0-9)\n");
|
||||
printf(" -D <mod,mod..> Debug modules\n");
|
||||
printf(" -c <file> Use configfile specified\n");
|
||||
@ -217,6 +222,160 @@ int load_plugin_dir(char *plugindir) {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
static int
|
||||
sigterm_server(char *pidfile)
|
||||
{
|
||||
FILE *fp;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
|
||||
fp = fopen(pidfile, "r");
|
||||
if (!fp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Failed to open pidfile %s: %s\n", pidfile, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fscanf(fp, "%d\n", &pid);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (ret < 1)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Failed to get pid from pidfile %s\n", pidfile);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = kill(pid, SIGTERM);
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Failed to kill pid %d: %s\n", pid, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
daemonize(int foreground, char *runas, char *pidfile)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
pid_t childpid;
|
||||
pid_t ret;
|
||||
int iret;
|
||||
struct passwd *pw;
|
||||
|
||||
if (geteuid() == (uid_t) 0)
|
||||
{
|
||||
pw = getpwnam(runas);
|
||||
|
||||
if (!pw)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "Could not lookup user %s: %s\n", runas, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
pw = NULL;
|
||||
|
||||
if (!foreground)
|
||||
{
|
||||
fp = fopen(pidfile, "w");
|
||||
if (!fp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Error opening pidfile (%s): %s\n", pidfile, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open("/dev/null", O_RDWR, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Error opening /dev/null: %s\n", strerror(errno));
|
||||
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
childpid = fork();
|
||||
|
||||
if (childpid > 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
else if (childpid < 0)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "Fork failed: %s\n", strerror(errno));
|
||||
|
||||
close(fd);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = setsid();
|
||||
if (ret == (pid_t) -1)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "setsid() failed: %s\n", strerror(errno));
|
||||
|
||||
close(fd);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
|
||||
chdir("/");
|
||||
umask(0);
|
||||
|
||||
fprintf(fp, "%d\n", getpid());
|
||||
fclose(fp);
|
||||
|
||||
DPRINTF(E_DBG, L_MAIN, "PID: %d\n", getpid());
|
||||
}
|
||||
|
||||
if (pw)
|
||||
{
|
||||
iret = initgroups(runas, pw->pw_gid);
|
||||
if (iret != 0)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "initgroups() failed: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
iret = setgid(pw->pw_gid);
|
||||
if (iret != 0)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "setgid() failed: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
iret = setuid(pw->pw_uid);
|
||||
if (iret != 0)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_MAIN, "setuid() failed: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set up an errorhandler for io errors
|
||||
*
|
||||
@ -381,11 +540,11 @@ int main(int argc, char *argv[]) {
|
||||
char **mp3_dir_array;
|
||||
char *servername;
|
||||
char *ffid = NULL;
|
||||
int appdir = 0;
|
||||
char *perr=NULL;
|
||||
char *txtrecord[10];
|
||||
void *phandle;
|
||||
char *plugindir;
|
||||
char *pidfile = PIDFILE;
|
||||
struct event *main_timer;
|
||||
struct timeval tv;
|
||||
sigset_t sigs;
|
||||
@ -395,19 +554,14 @@ int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
int err;
|
||||
char *apppath;
|
||||
|
||||
int debuglevel=0;
|
||||
|
||||
err_setlevel(2);
|
||||
|
||||
config.foreground=0;
|
||||
while((option=getopt(argc,argv,"D:d:c:P:mfrysiuvab:Vk")) != -1) {
|
||||
while((option=getopt(argc,argv,"D:d:c:P:frysiuvb:Vk")) != -1) {
|
||||
switch(option) {
|
||||
case 'a':
|
||||
appdir = 1;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
ffid=optarg;
|
||||
break;
|
||||
@ -434,7 +588,7 @@ int main(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
os_set_pidfile(optarg);
|
||||
pidfile = optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
@ -477,10 +631,14 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
|
||||
if(kill_server) {
|
||||
os_signal_server(S_STOP);
|
||||
exit(0);
|
||||
}
|
||||
if (kill_server)
|
||||
{
|
||||
ret = sigterm_server(pidfile);
|
||||
if (ret == 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
else
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
io_init();
|
||||
io_set_errhandler(main_io_errhandler);
|
||||
@ -491,15 +649,6 @@ int main(int argc, char *argv[]) {
|
||||
config.stats.start_time=start_time=(int)time(NULL);
|
||||
config.stop=0;
|
||||
|
||||
/* set appdir first, that way config resolves relative to appdir */
|
||||
if(appdir) {
|
||||
apppath = os_apppath(argv[0]);
|
||||
DPRINTF(E_INF,L_MAIN,"Changing cwd to %s\n",apppath);
|
||||
chdir(apppath);
|
||||
free(apppath);
|
||||
configfile="mt-daapd.conf";
|
||||
}
|
||||
|
||||
if(CONF_E_SUCCESS != conf_read(configfile)) {
|
||||
fprintf(stderr,"Error reading config file (%s)\n",configfile);
|
||||
exit(EXIT_FAILURE);
|
||||
@ -556,13 +705,18 @@ int main(int argc, char *argv[]) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
runas = conf_alloc_string("general","runas","nobody");
|
||||
/* Daemonize and drop privileges */
|
||||
runas = conf_alloc_string("general", "runas", "nobody");
|
||||
|
||||
if(!os_init(config.foreground,runas)) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Could not initialize server\n");
|
||||
ret = daemonize(config.foreground, runas, pidfile);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MAIN, "Could not initialize server\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(runas);
|
||||
|
||||
/* Initialize libevent (after forking) */
|
||||
evbase_main = event_init();
|
||||
@ -573,7 +727,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
free(runas);
|
||||
|
||||
DPRINTF(E_LOG, L_MAIN, "mDNS init\n");
|
||||
ret = mdns_init();
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "err.h"
|
||||
#include "io.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "os.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
@ -295,7 +294,7 @@ int scan_path(char *path) {
|
||||
|
||||
snprintf(relative_path,PATH_MAX,"%s/%s",path,pde->d_name);
|
||||
|
||||
if(!os_lstat(relative_path,&sb)) {
|
||||
if(!lstat(relative_path, &sb)) {
|
||||
if(S_ISLNK(sb.st_mode) && !follow_symlinks)
|
||||
continue;
|
||||
}
|
||||
@ -303,7 +302,7 @@ int scan_path(char *path) {
|
||||
mp3_path[0] = '\x0';
|
||||
realpath(relative_path,mp3_path);
|
||||
DPRINTF(E_DBG,L_SCAN,"Found %s\n",relative_path);
|
||||
if(os_stat(mp3_path,&sb)) {
|
||||
if (stat(mp3_path, &sb)) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error statting %s: %s\n",mp3_path,strerror(errno));
|
||||
} else {
|
||||
if(S_ISDIR(sb.st_mode)) { /* follow dir */
|
||||
@ -353,7 +352,7 @@ int scan_static_playlist(char *path) {
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_WARN,L_SCAN|L_PL,"Processing static playlist: %s\n",path);
|
||||
if(os_stat(path,&sb)) {
|
||||
if (stat(path, &sb)) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error statting %s: %s\n",path,strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
@ -535,7 +534,7 @@ void scan_filename(char *path, int compdir, char *extensions) {
|
||||
}
|
||||
|
||||
|
||||
if(os_stat(mp3_path,&sb)) {
|
||||
if(stat(mp3_path, &sb)) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error statting: %s\n",strerror(errno));
|
||||
} else {
|
||||
/* we assume this is regular file */
|
||||
|
410
src/os-unix.c
410
src/os-unix.c
@ -1,410 +0,0 @@
|
||||
/*
|
||||
* Abstracts os interface
|
||||
*
|
||||
* Copyright (c) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "conf.h"
|
||||
#include "err.h"
|
||||
#include "os.h"
|
||||
|
||||
/** You say po-tay-to, I say po-tat-o */
|
||||
#ifndef SIGCLD
|
||||
# define SIGCLD SIGCHLD
|
||||
#endif
|
||||
|
||||
/** Where to dump the pidfile */
|
||||
#ifndef PIDFILE
|
||||
#define PIDFILE "/var/run/mt-daapd.pid"
|
||||
#endif
|
||||
|
||||
/* Forwards */
|
||||
static int _os_daemon_start(void);
|
||||
|
||||
/* Globals */
|
||||
char *_os_pidfile = PIDFILE;
|
||||
|
||||
/**
|
||||
* this initializes the platform... sets up signal handlers, forks to the
|
||||
* background, etc
|
||||
*
|
||||
* @param foreground whether to run in fg or fork to bg
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_init(int foreground, char *runas) {
|
||||
int pid_fd;
|
||||
FILE *pid_fp=NULL;
|
||||
|
||||
/* open the pidfile, so it can be written once we detach */
|
||||
if(!foreground) {
|
||||
if(-1 == (pid_fd = open(_os_pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644))) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Error opening pidfile (%s): %s\n",
|
||||
_os_pidfile,strerror(errno));
|
||||
} else {
|
||||
if(0 == (pid_fp = fdopen(pid_fd, "w")))
|
||||
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
}
|
||||
_os_daemon_start();
|
||||
fprintf(pid_fp,"%d\n",getpid());
|
||||
fclose(pid_fp);
|
||||
DPRINTF(E_DBG,L_MAIN,"Pid: %d\n",getpid());
|
||||
}
|
||||
|
||||
// Drop privs here
|
||||
if(os_drop_privs(runas)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error in drop_privs: %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* start syslogging
|
||||
*
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_opensyslog(void) {
|
||||
openlog(PACKAGE,LOG_PID,LOG_DAEMON);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* stop syslogging
|
||||
*
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_closesyslog(void) {
|
||||
closelog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* log a syslog message
|
||||
*
|
||||
* @param level log level (1-9: 1=fatal, 9=debug)
|
||||
* @param msg message to log to the syslog
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_syslog(int level, char *msg) {
|
||||
int priority;
|
||||
|
||||
switch(level) {
|
||||
case 0:
|
||||
case 1:
|
||||
priority = LOG_ALERT;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
priority = LOG_NOTICE;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
default:
|
||||
priority = LOG_DEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
syslog(priority,"%s",msg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* os-specific chown
|
||||
*
|
||||
*
|
||||
*/
|
||||
extern int os_chown(char *path, char *user) {
|
||||
struct passwd *pw=NULL;
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Chowning %s to %s\n",path,user);
|
||||
|
||||
/* drop privs */
|
||||
if(getuid() == (uid_t)0) {
|
||||
if(atoi(user)) {
|
||||
pw=getpwuid((uid_t)atoi(user)); /* doh! */
|
||||
} else {
|
||||
pw=getpwnam(user);
|
||||
}
|
||||
|
||||
if(pw) {
|
||||
if(initgroups(user,pw->pw_gid) != 0 ||
|
||||
chown(path, pw->pw_uid, pw->pw_gid) != 0) {
|
||||
DPRINTF(E_LOG,L_MISC,"Couldn't chown %s, gid=%d, uid=%d\n",
|
||||
user,pw->pw_gid, pw->pw_uid);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_MISC,"Couldn't lookup user %s for chown\n",user);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Success!\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the old service pid and send it a SIGTERM
|
||||
*/
|
||||
int os_signal_server(int what) {
|
||||
FILE *pid_fp;
|
||||
int pid;
|
||||
int result = TRUE;
|
||||
int signal = 0;
|
||||
|
||||
if(NULL == (pid_fp = fopen(_os_pidfile, "r"))) {
|
||||
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(fscanf(pid_fp,"%d\n",&pid)) {
|
||||
kill(pid,SIGTERM);
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_MAIN,"os_service_kill: can't get pid from pidfile\n");
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
fclose(pid_fp);
|
||||
|
||||
switch(what) {
|
||||
case S_SCAN:
|
||||
signal=SIGUSR1;
|
||||
break;
|
||||
case S_FULL:
|
||||
signal=SIGUSR2;
|
||||
break;
|
||||
case S_STOP:
|
||||
signal=SIGTERM;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(kill(pid,signal)) {
|
||||
perror("kill");
|
||||
result = FALSE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fork and exit. Stolen pretty much straight from Stevens.
|
||||
*
|
||||
* @returns 0 on success, -1 with errno set on error
|
||||
*/
|
||||
int _os_daemon_start(void) {
|
||||
int childpid, fd;
|
||||
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
// Fork and exit
|
||||
if ((childpid = fork()) < 0) {
|
||||
fprintf(stderr, "Can't fork!\n");
|
||||
return -1;
|
||||
} else if (childpid > 0)
|
||||
exit(0);
|
||||
|
||||
#ifdef SETPGRP_VOID
|
||||
setpgrp();
|
||||
#else
|
||||
setpgrp(0,0);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
|
||||
ioctl(fd, TIOCNOTTY, (char *) NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
for (fd = 0; fd < FOPEN_MAX; fd++)
|
||||
close(fd);
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
|
||||
chdir("/");
|
||||
umask(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drop privs. This allows mt-daapd to run as a non-privileged user.
|
||||
* Hopefully this will limit the damage it could do if exploited
|
||||
* remotely. Note that only the user need be specified. GID
|
||||
* is set to the primary group of the user.
|
||||
*
|
||||
* \param user user to run as (or UID)
|
||||
*/
|
||||
int os_drop_privs(char *user) {
|
||||
int err;
|
||||
struct passwd *pw=NULL;
|
||||
|
||||
/* drop privs */
|
||||
if(getuid() == (uid_t)0) {
|
||||
if(atoi(user)) {
|
||||
pw=getpwuid((uid_t)atoi(user)); /* doh! */
|
||||
} else {
|
||||
pw=getpwnam(user);
|
||||
}
|
||||
|
||||
if(pw) {
|
||||
if(initgroups(user,pw->pw_gid) != 0 ||
|
||||
setgid(pw->pw_gid) != 0 ||
|
||||
setuid(pw->pw_uid) != 0) {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
|
||||
user,pw->pw_gid, pw->pw_uid);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't lookup user %s\n",user);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set the pidfile to a non-default value
|
||||
*
|
||||
* @param file file to use as pidfile
|
||||
*/
|
||||
void os_set_pidfile(char *file) {
|
||||
_os_pidfile = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* load a shared library
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
void *os_loadlib(char **pe, char *path) {
|
||||
void *retval;
|
||||
|
||||
if(!(retval = dlopen(path,RTLD_NOW)))
|
||||
*pe = strdup(dlerror());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void *os_libfunc(char **pe, void *handle, char *function) {
|
||||
void *retval;
|
||||
|
||||
if((!(retval = dlsym(handle,function))) && (pe))
|
||||
*pe = strdup(dlerror());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int os_unload(void *handle) {
|
||||
return dlclose(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an address is local or not
|
||||
*
|
||||
* @param hostaddr the address to test for locality
|
||||
*/
|
||||
int os_islocaladdr(char *hostaddr) {
|
||||
/* how can we check interfaces without something like libnet? */
|
||||
|
||||
if(strncmp(hostaddr,"127.",4) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char *os_apppath(char *parm) {
|
||||
char path[PATH_MAX];
|
||||
|
||||
realpath(parm,path);
|
||||
if(strrchr(path,'/')) {
|
||||
*strrchr(path,'/') = '\0';
|
||||
}
|
||||
|
||||
return strdup(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* stat wrapper
|
||||
*/
|
||||
int os_stat(const char *path, struct stat *sb) {
|
||||
return stat(path, sb);
|
||||
}
|
||||
|
||||
int os_lstat(const char *path, struct stat *sb) {
|
||||
return lstat(path, sb);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OS_UNIX_H_
|
||||
#define _OS_UNIX_H_
|
||||
|
||||
#define PATHSEP '/'
|
||||
#define PATHSEP_STR "/"
|
||||
#define OS_SOCKETTYPE unsigned int
|
||||
|
||||
/* unix-specific functions */
|
||||
extern int os_drop_privs(char *user);
|
||||
void os_set_pidfile(char *file);
|
||||
#endif
|
||||
|
51
src/os.h
51
src/os.h
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Abstract os interface for non-unix platforms
|
||||
*
|
||||
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _OS_H_
|
||||
#define _OS_H_
|
||||
|
||||
#define S_STOP 0
|
||||
#define S_SCAN 1
|
||||
#define S_FULL 2
|
||||
|
||||
/* backgrounding, signal handling, etc */
|
||||
extern int os_init(int foreground, char *runas);
|
||||
|
||||
/* system native logging functions */
|
||||
extern int os_opensyslog(void);
|
||||
extern int os_closesyslog(void);
|
||||
extern int os_syslog(int level, char *msg);
|
||||
extern int os_chown(char *path, char *user);
|
||||
|
||||
/* library loading functions */
|
||||
extern void *os_loadlib(char **pe, char *path);
|
||||
extern void *os_libfunc(char **pe, void *handle, char *function);
|
||||
extern int os_unload(void *handle);
|
||||
|
||||
/* misc */
|
||||
extern int os_stat(const char *path, struct stat *sb);
|
||||
extern int os_lstat(const char *path, struct stat *sb);
|
||||
extern int os_islocaladdr(char *hostaddr);
|
||||
extern char *os_apppath(char *parm);
|
||||
extern int os_signal_server(int what); /* signal a running server */
|
||||
|
||||
#include "os-unix.h"
|
||||
|
||||
#endif
|
18
src/plugin.c
18
src/plugin.c
@ -49,13 +49,15 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "conf.h"
|
||||
#include "configfile.h"
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "io.h"
|
||||
#include "os.h"
|
||||
#include "plugin.h"
|
||||
#include "smart-parser.h"
|
||||
#include "xml-rpc.h"
|
||||
@ -230,8 +232,9 @@ int plugin_load(char **pe, char *path) {
|
||||
|
||||
DPRINTF(E_DBG,L_PLUG,"Attempting to load plugin %s\n",path);
|
||||
|
||||
phandle = os_loadlib(pe, path);
|
||||
if(!phandle) {
|
||||
phandle = dlopen(path, RTLD_NOW);
|
||||
if (!phandle) {
|
||||
*pe = strdup(dlerror());
|
||||
DPRINTF(E_INF,L_PLUG,"Couldn't get lib handle for %s\n",path);
|
||||
return PLUGIN_E_NOLOAD;
|
||||
}
|
||||
@ -241,10 +244,11 @@ int plugin_load(char **pe, char *path) {
|
||||
|
||||
ppi->phandle = phandle;
|
||||
|
||||
info_func = (PLUGIN_INFO*(*)(void)) os_libfunc(pe, phandle,"plugin_info");
|
||||
info_func = (PLUGIN_INFO*(*)(void)) dlsym(phandle, "plugin_info");
|
||||
if(info_func == NULL) {
|
||||
*pe = strdup(dlerror());
|
||||
DPRINTF(E_INF,L_PLUG,"Couldn't get info_func for %s\n",path);
|
||||
os_unload(phandle);
|
||||
dlclose(phandle);
|
||||
free(ppi);
|
||||
return PLUGIN_E_BADFUNCS;
|
||||
}
|
||||
@ -254,7 +258,7 @@ int plugin_load(char **pe, char *path) {
|
||||
|
||||
if(!pinfo) {
|
||||
if(pe) *pe = strdup("plugin declined to load");
|
||||
os_unload(phandle);
|
||||
dlclose(phandle);
|
||||
free(ppi);
|
||||
return PLUGIN_E_NOLOAD;
|
||||
}
|
||||
@ -262,7 +266,7 @@ int plugin_load(char **pe, char *path) {
|
||||
if(pinfo->version != PLUGIN_VERSION) {
|
||||
DPRINTF(E_INF,L_PLUG,"Plugin is too old: version %d, expecting %d\n",
|
||||
pinfo->version, PLUGIN_VERSION);
|
||||
os_unload(phandle);
|
||||
dlclose(phandle);
|
||||
free(ppi);
|
||||
return PLUGIN_E_NOLOAD;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "os.h"
|
||||
#include "rxml.h"
|
||||
#include "redblack.h"
|
||||
#include "util.h"
|
||||
@ -165,7 +164,7 @@ int scan_xml_rb_compare(const void *pa, const void *pb, const void *cfg) {
|
||||
int scan_xml_is_file(char *path) {
|
||||
struct stat sb;
|
||||
|
||||
if(os_stat(path,&sb))
|
||||
if(stat(path, &sb))
|
||||
return 0;
|
||||
|
||||
if(sb.st_mode & S_IFREG)
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "os.h"
|
||||
#include "plugin.h"
|
||||
#include "webserver.h"
|
||||
#include "xml-rpc.h"
|
||||
@ -458,7 +457,7 @@ void xml_browse_path(WS_CONNINFO *pwsc) {
|
||||
snprintf(full_path,PATH_MAX,"%s%c%s",base_path,PATHSEP,pde->d_name);
|
||||
realpath(full_path,resolved_path);
|
||||
|
||||
if(os_stat(resolved_path,&sb)) {
|
||||
if(stat(resolved_path, &sb)) {
|
||||
DPRINTF(E_INF,L_XML,"Error statting %s: %s\n",
|
||||
resolved_path,strerror(errno));
|
||||
continue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user