--- a/src/upmpd.cxx
+++ b/src/upmpd.cxx
@@ -16,22 +16,6 @@
*/
#include "upmpd.hxx"
-
-#include <errno.h> // for errno
-#include <fcntl.h> // for open, O_CREAT, O_RDWR
-#include <pwd.h> // for getpwnam, passwd
-#include <signal.h> // for sigaction, SIG_IGN, etc
-#include <stdio.h> // for fprintf, perror, stderr
-#include <stdlib.h> // for atoi, getenv, exit
-#include <sys/param.h> // for MIN
-#include <unistd.h> // for geteuid, chown, sleep, etc
-#include <string.h> // for memset
-#include <grp.h>
-
-#include <iostream> // for basic_ostream, operator<<, etc
-#include <string> // for string, operator<<, etc
-#include <unordered_map> // for unordered_map, etc
-#include <vector> // for vector, vector<>::iterator
#include "libupnpp/device/device.hxx" // for UpnpDevice, UpnpService
#include "libupnpp/log.hxx" // for LOGFAT, LOGERR, Logger, etc
@@ -58,7 +42,7 @@
using namespace UPnPP;
bool OHService::getEventData(bool all, vector<string>& names,
- vector<std::string>& values)
+ vector<std::string>& values)
{
//LOGDEB("OHService::getEventData" << std::endl);
@@ -89,8 +73,8 @@
: UpnpDevice(deviceid, files), m_mpdcli(mpdcli), m_mpds(0),
m_options(opts.options),
m_mcachefn(opts.cachefn),
- m_rdctl(0), m_avt(0), m_ohpr(0), m_ohpl(0), m_ohrd(0), m_ohrcv(0), m_sndrcv(0),
- m_friendlyname(friendlyname)
+ m_rdctl(0), m_avt(0), m_ohpr(0), m_ohpl(0), m_ohrd(0), m_ohrcv(0),
+ m_sndrcv(0), m_friendlyname(friendlyname)
{
bool avtnoev = (m_options & upmpdNoAV) != 0;
// Note: the order is significant here as it will be used when
@@ -158,482 +142,3 @@
m_mpds = &m_mpdcli->getStatus();
return *m_mpds;
}
-
-/////////////////////////////////////////////////////////////////////
-// Main program
-
-#include "conftree.hxx"
-
-static char *thisprog;
-
-static int op_flags;
-#define OPT_MOINS 0x1
-#define OPT_h 0x2
-#define OPT_p 0x4
-#define OPT_d 0x8
-#define OPT_D 0x10
-#define OPT_c 0x20
-#define OPT_l 0x40
-#define OPT_f 0x80
-#define OPT_q 0x100
-#define OPT_i 0x200
-#define OPT_P 0x400
-#define OPT_O 0x800
-#define OPT_v 0x1000
-
-static const char usage[] =
- "-c configfile \t configuration file to use\n"
- "-h host \t specify host MPD is running on\n"
- "-p port \t specify MPD port\n"
- "-d logfilename\t debug messages to\n"
- "-l loglevel\t log level (0-6)\n"
- "-D \t run as a daemon\n"
- "-f friendlyname\t define device displayed name\n"
- "-q 0|1\t if set, we own the mpd queue, else avoid clearing it whenever we feel like it\n"
- "-i iface \t specify network interface name to be used for UPnP\n"
- "-P upport \t specify port number to be used for UPnP\n"
- "-O 0|1\t decide if we run and export the OpenHome services\n"
- "-v \tprint version info\n"
- "\n"
- ;
-
-static void
-versionInfo(FILE *fp)
-{
- fprintf(fp, "Upmpdcli %s %s\n",
- UPMPDCLI_PACKAGE_VERSION, LibUPnP::versionString().c_str());
-}
-
-static void
-Usage(FILE *fp = stderr)
-{
- fprintf(fp, "%s: usage:\n%s", thisprog, usage);
- versionInfo(fp);
- exit(1);
-}
-
-
-static const string dfltFriendlyName("UpMpd");
-
-// This is global
-string g_protocolInfo;
-
-// Static for cleanup in sig handler.
-static UpnpDevice *dev;
-
-string g_datadir(DATADIR "/");
-
-// Global
-string g_configfilename(CONFIGDIR "/upmpdcli.conf");
-ConfSimple *g_config;
-
-static void onsig(int)
-{
- LOGDEB("Got sig" << endl);
- dev->shouldExit();
-}
-
-static const int catchedSigs[] = {SIGINT, SIGQUIT, SIGTERM};
-static void setupsigs()
-{
- struct sigaction action;
- action.sa_handler = onsig;
- action.sa_flags = 0;
- sigemptyset(&action.sa_mask);
- for (unsigned int i = 0; i < sizeof(catchedSigs) / sizeof(int); i++)
- if (signal(catchedSigs[i], SIG_IGN) != SIG_IGN) {
- if (sigaction(catchedSigs[i], &action, 0) < 0) {
- perror("Sigaction failed");
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- // Path for the sc2mpd command, or empty
- string sc2mpdpath;
-
- // Sender mode: path for the command creating the mpd and mpd2sc
- // processes, and port for the auxiliary mpd.
- string senderpath;
- int sendermpdport = 6700;
-
- // Main MPD parameters
- string mpdhost("localhost");
- int mpdport = 6600;
- string mpdpassword;
-
- string logfilename;
- int loglevel(Logger::LLINF);
- string friendlyname(dfltFriendlyName);
- bool ownqueue = true;
- bool enableAV = true;
- bool enableOH = true;
- bool ohmetapersist = true;
- string upmpdcliuser("upmpdcli");
- string pidfilename("/var/run/upmpdcli.pid");
- string iconpath(DATADIR "/icon.png");
- string presentationhtml(DATADIR "/presentation.html");
- string iface;
- unsigned short upport = 0;
- string upnpip;
-
- const char *cp;
- if ((cp = getenv("UPMPD_HOST")))
- mpdhost = cp;
- if ((cp = getenv("UPMPD_PORT")))
- mpdport = atoi(cp);
- if ((cp = getenv("UPMPD_FRIENDLYNAME")))
- friendlyname = atoi(cp);
- if ((cp = getenv("UPMPD_CONFIG")))
- g_configfilename = cp;
- if ((cp = getenv("UPMPD_UPNPIFACE")))
- iface = cp;
- if ((cp = getenv("UPMPD_UPNPPORT")))
- upport = atoi(cp);
-
- thisprog = argv[0];
- argc--; argv++;
- while (argc > 0 && **argv == '-') {
- (*argv)++;
- if (!(**argv))
- Usage();
- while (**argv)
- switch (*(*argv)++) {
- case 'c': op_flags |= OPT_c; if (argc < 2) Usage();
- g_configfilename = *(++argv); argc--; goto b1;
- case 'D': op_flags |= OPT_D; break;
- case 'd': op_flags |= OPT_d; if (argc < 2) Usage();
- logfilename = *(++argv); argc--; goto b1;
- case 'f': op_flags |= OPT_f; if (argc < 2) Usage();
- friendlyname = *(++argv); argc--; goto b1;
- case 'h': op_flags |= OPT_h; if (argc < 2) Usage();
- mpdhost = *(++argv); argc--; goto b1;
- case 'i': op_flags |= OPT_i; if (argc < 2) Usage();
- iface = *(++argv); argc--; goto b1;
- case 'l': op_flags |= OPT_l; if (argc < 2) Usage();
- loglevel = atoi(*(++argv)); argc--; goto b1;
- case 'O': {
- op_flags |= OPT_O;
- if (argc < 2) Usage();
- const char *cp = *(++argv);
- if (*cp == '1' || *cp == 't' || *cp == 'T' || *cp == 'y' ||
- *cp == 'Y')
- enableOH = true;
- argc--; goto b1;
- }
- case 'P': op_flags |= OPT_P; if (argc < 2) Usage();
- upport = atoi(*(++argv)); argc--; goto b1;
- case 'p': op_flags |= OPT_p; if (argc < 2) Usage();
- mpdport = atoi(*(++argv)); argc--; goto b1;
- case 'q': op_flags |= OPT_q; if (argc < 2) Usage();
- ownqueue = atoi(*(++argv)) != 0; argc--; goto b1;
- case 'v': versionInfo(stdout); exit(0); break;
- default: Usage(); break;
- }
- b1: argc--; argv++;
- }
-
- if (argc != 0)
- Usage();
-
- UpMpd::Options opts;
-
- string cachedir;
- string onstart;
- string onstop;
- string onvolumechange;
- if (!g_configfilename.empty()) {
- g_config = new ConfSimple(g_configfilename.c_str(), 1, true);
- if (!g_config || !g_config->ok()) {
- cerr << "Could not open config: " << g_configfilename << endl;
- return 1;
- }
-
- string value;
- if (!(op_flags & OPT_d))
- g_config->get("logfilename", logfilename);
- if (!(op_flags & OPT_f))
- g_config->get("friendlyname", friendlyname);
- if (!(op_flags & OPT_l) && g_config->get("loglevel", value))
- loglevel = atoi(value.c_str());
- if (!(op_flags & OPT_h))
- g_config->get("mpdhost", mpdhost);
- if (!(op_flags & OPT_p) && g_config->get("mpdport", value)) {
- mpdport = atoi(value.c_str());
- }
- g_config->get("mpdpassword", mpdpassword);
- if (!(op_flags & OPT_q) && g_config->get("ownqueue", value)) {
- ownqueue = atoi(value.c_str()) != 0;
- }
- if (g_config->get("openhome", value)) {
- enableOH = atoi(value.c_str()) != 0;
- }
- if (g_config->get("upnpav", value)) {
- enableAV = atoi(value.c_str()) != 0;
- }
- if (g_config->get("ohmetapersist", value)) {
- ohmetapersist = atoi(value.c_str()) != 0;
- }
- g_config->get("iconpath", iconpath);
- g_config->get("presentationhtml", presentationhtml);
- g_config->get("cachedir", cachedir);
- g_config->get("onstart", onstart);
- g_config->get("onstop", onstop);
- g_config->get("onvolumechange", onvolumechange);
- if (!(op_flags & OPT_i)) {
- g_config->get("upnpiface", iface);
- if (iface.empty()) {
- g_config->get("upnpip", upnpip);
- }
- }
- if (!(op_flags & OPT_P) && g_config->get("upnpport", value)) {
- upport = atoi(value.c_str());
- }
- if (g_config->get("schttpport", value))
- opts.schttpport = atoi(value.c_str());
- g_config->get("scplaymethod", opts.scplaymethod);
- g_config->get("sc2mpd", sc2mpdpath);
- if (g_config->get("ohmetasleep", value))
- opts.ohmetasleep = atoi(value.c_str());
-
- g_config->get("scsenderpath", senderpath);
- if (g_config->get("scsendermpdport", value))
- sendermpdport = atoi(value.c_str());
- }
- if (Logger::getTheLog(logfilename) == 0) {
- cerr << "Can't initialize log" << endl;
- return 1;
- }
- Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
-
- Pidfile pidfile(pidfilename);
-
- // If started by root, do the pidfile + change uid thing
- uid_t runas(0);
- gid_t runasg(0);
- if (geteuid() == 0) {
- struct passwd *pass = getpwnam(upmpdcliuser.c_str());
- if (pass == 0) {
- LOGFAT("upmpdcli won't run as root and user " << upmpdcliuser <<
- " does not exist " << endl);
- return 1;
- }
- runas = pass->pw_uid;
- runasg = pass->pw_gid;
-
- pid_t pid;
- if ((pid = pidfile.open()) != 0) {
- LOGFAT("Can't open pidfile: " << pidfile.getreason() <<
- ". Return (other pid?): " << pid << endl);
- return 1;
- }
- if (pidfile.write_pid() != 0) {
- LOGFAT("Can't write pidfile: " << pidfile.getreason() << endl);
- return 1;
- }
- if (cachedir.empty())
- cachedir = "/var/cache/upmpdcli";
- } else {
- if (cachedir.empty())
- cachedir = path_cat(path_tildexpand("~") , "/.cache/upmpdcli");
- }
-
- string& mcfn = opts.cachefn;
- if (ohmetapersist) {
- opts.cachefn = path_cat(cachedir, "/metacache");
- if (!path_makepath(cachedir, 0755)) {
- LOGERR("makepath("<< cachedir << ") : errno : " << errno << endl);
- } else {
- int fd;
- if ((fd = open(mcfn.c_str(), O_CREAT|O_RDWR, 0644)) < 0) {
- LOGERR("creat("<< mcfn << ") : errno : " << errno << endl);
- } else {
- close(fd);
- if (geteuid() == 0 && chown(mcfn.c_str(), runas, -1) != 0) {
- LOGERR("chown("<< mcfn << ") : errno : " << errno << endl);
- }
- if (geteuid() == 0 && chown(cachedir.c_str(), runas, -1) != 0) {
- LOGERR("chown("<< cachedir << ") : errno : " << errno << endl);
- }
- }
- }
- }
-
- if ((op_flags & OPT_D)) {
- if (daemon(1, 0)) {
- LOGFAT("Daemon failed: errno " << errno << endl);
- return 1;
- }
- }
-
- if (geteuid() == 0) {
- // Need to rewrite pid, it may have changed with the daemon call
- pidfile.write_pid();
- if (!logfilename.empty() && logfilename.compare("stderr")) {
- if (chown(logfilename.c_str(), runas, -1) < 0) {
- LOGERR("chown("<<logfilename<<") : errno : " << errno << endl);
- }
- }
- if (initgroups(upmpdcliuser.c_str(), runasg) < 0) {
- LOGERR("initgroup failed. Errno: " << errno << endl);
- }
- if (setuid(runas) < 0) {
- LOGFAT("Can't set my uid to " << runas << " current: " << geteuid()
- << endl);
- return 1;
- }
-#if 0
- gid_t list[100];
- int ng = getgroups(100, list);
- cerr << "GROUPS: ";
- for (int i = 0; i < ng; i++) {
- cerr << int(list[i]) << " ";
- }
- cerr << endl;
-#endif
- }
-
-//// Dropped root
-
- if (sc2mpdpath.empty()) {
- // Do we have an sc2mpd command installed (for songcast)?
- if (!ExecCmd::which("sc2mpd", sc2mpdpath))
- sc2mpdpath.clear();
- }
- if (senderpath.empty()) {
- // Do we have an scmakempdsender command installed (for
- // starting the songcast sender and its auxiliary mpd)?
- if (!ExecCmd::which("scmakempdsender", senderpath))
- senderpath.clear();
- }
-
- if (!sc2mpdpath.empty()) {
- // Check if sc2mpd is actually there
- if (access(sc2mpdpath.c_str(), X_OK|R_OK) != 0) {
- LOGERR("Specified path for sc2mpd: " << sc2mpdpath <<
- " is not executable" << endl);
- sc2mpdpath.clear();
- }
- }
-
- if (!senderpath.empty()) {
- // Check that both the starter script and the mpd2sc sender
- // command are executable. We'll assume that mpd is ok
- if (access(senderpath.c_str(), X_OK|R_OK) != 0) {
- LOGERR("The specified path for the sender starter script: ["
- << senderpath <<
- "] is not executable, disabling the sender mode.\n");
- senderpath.clear();
- } else {
- string path;
- if (!ExecCmd::which("mpd2sc", path)) {
- LOGERR("Sender starter was specified and found but the mpd2sc "
- "command is not found (or executable). Disabling "
- "the sender mode.\n");
- senderpath.clear();
- }
- }
- }
-
-
- // Initialize MPD client object. Retry until it works or power fail.
- MPDCli *mpdclip = 0;
- int mpdretrysecs = 2;
- for (;;) {
- mpdclip = new MPDCli(mpdhost, mpdport, mpdpassword, onstart, onstop,
- onvolumechange);
- if (mpdclip == 0) {
- LOGFAT("Can't allocate MPD client object" << endl);
- return 1;
- }
- if (!mpdclip->ok()) {
- LOGERR("MPD connection failed" << endl);
- delete mpdclip;
- mpdclip = 0;
- sleep(mpdretrysecs);
- mpdretrysecs = MIN(2*mpdretrysecs, 120);
- } else {
- break;
- }
- }
-
- // Initialize libupnpp, and check health
- LibUPnP *mylib = 0;
- string hwaddr;
- int libretrysecs = 10;
- for (;;) {
- // Libupnp init fails if we're started at boot and the network
- // is not ready yet. So retry this forever
- mylib = LibUPnP::getLibUPnP(true, &hwaddr, iface, upnpip, upport);
- if (mylib) {
- break;
- }
- sleep(libretrysecs);
- libretrysecs = MIN(2*libretrysecs, 120);
- }
-
- if (!mylib->ok()) {
- LOGFAT("Lib init failed: " <<
- mylib->errAsString("main", mylib->getInitError()) << endl);
- return 1;
- }
-
- if ((cp = getenv("UPMPDCLI_UPNPLOGFILENAME"))) {
- char *cp1 = getenv("UPMPDCLI_UPNPLOGLEVEL");
- int loglevel = LibUPnP::LogLevelNone;
- if (cp1) {
- loglevel = atoi(cp1);
- }
- loglevel = loglevel < 0 ? 0: loglevel;
- loglevel = loglevel > int(LibUPnP::LogLevelDebug) ?
- int(LibUPnP::LogLevelDebug) : loglevel;
-
- if (loglevel != LibUPnP::LogLevelNone) {
- mylib->setLogFileName(cp, LibUPnP::LogLevel(loglevel));
- }
- }
-
- // Create unique ID
- string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
-
- // Initialize the data we serve through HTTP (device and service
- // descriptions, icons, presentation page, etc.)
- unordered_map<string, VDirContent> files;
- if (!initHttpFs(files, g_datadir, UUID, friendlyname, enableAV, enableOH,
- !senderpath.empty(),
- iconpath, presentationhtml)) {
- exit(1);
- }
-
- if (ownqueue)
- opts.options |= UpMpd::upmpdOwnQueue;
- if (enableOH)
- opts.options |= UpMpd::upmpdDoOH;
- if (ohmetapersist)
- opts.options |= UpMpd::upmpdOhMetaPersist;
- if (!sc2mpdpath.empty()) {
- opts.sc2mpdpath = sc2mpdpath;
- opts.options |= UpMpd::upmpdOhReceiver;
- }
- if (!senderpath.empty()) {
- opts.options |= UpMpd::upmpdOhSenderReceiver;
- opts.senderpath = senderpath;
- opts.sendermpdport = sendermpdport;
- }
-
- if (!enableAV)
- opts.options |= UpMpd::upmpdNoAV;
- // Initialize the UPnP device object.
- UpMpd device(string("uuid:") + UUID, friendlyname,
- files, mpdclip, opts);
- dev = &device;
-
- // And forever generate state change events.
- LOGDEB("Entering event loop" << endl);
- setupsigs();
- device.eventloop();
- LOGDEB("Event loop returned" << endl);
-
- return 0;
-}