Newer
Older
#include <stdio.h>
#include <fcntl.h>

Andrew Price
committed
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <time.h>

Andrew Price
committed
#include <socket.h>
#define MWUSER "mw"
#define MWSERVCONF "mwserv.conf"
static void usage(char *name)

Andrew Price
committed
{
printf("Usage:\n %s "
"[--config|-c <file>]"
"[--help|-h]"
"[--foreground|-f]"
"[--port|-p <port>]"
"[--print-config|-P]"
"\n", name);

Andrew Price
committed
}
/**
* Config options must be set here so that the config system will recognise
* them. It also uses them to validate the types of the overrides specified in
* config files. Any options found in config files that are not listed here
* will be ignored (non-fatally).
**/
static const struct cfg_default_opt defcfgs[] = {
CFG_OPT(BOOL, "foreground", 0),
CFG_OPT(INT, "port", 9999),
CFG_END
};
static int config_init(void)
{
const char *homedir;
int ret;
ret = cfg_init_defaults(defcfgs);
if (ret)
return ret;
homedir = getenv("HOME");
if (homedir) {
ret = asprintf(&homeconf, "%s/."MWSERVCONF, homedir);
if (ret > 0) {
ret = cfg_load(homeconf);
if (ret <= 0)
return ret;
}
}
ret = cfg_load("/etc/"MWSERVCONF);
if (ret <= 0)
return ret;
return 0;
}
static int getconfig(int argc, char **argv)

Andrew Price
committed
{
int c;

Andrew Price
committed
int optidx = 0;

Andrew Price
committed
static struct option loptspec[] = {
{"config", required_argument, 0, 'c'},
{"foreground", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"print-config", no_argument, 0, 'P'},
{"port", required_argument, 0, 'p'},

Andrew Price
committed
{0, 0, 0, 0}
};

Andrew Price
committed
while (1) {
c = getopt_long(argc, argv, "c:fhPp:", loptspec, &optidx);

Andrew Price
committed
if (c == -1)
break;
switch (c) {
case 'c':
ret = cfg_load(optarg);
if (ret != 0)
return ret;
break;
case 'P':
/* Do this once all the config sources have been merged */
printcfg = 1;
break;

Andrew Price
committed
case 'p':
errno = 0;
num = strtol(optarg, NULL, 0);
if (errno != 0 || num < 1 || num > UINT16_MAX) {
fprintf(stderr, "Bad port number\n");
return 1;
}

Andrew Price
committed
break;

Andrew Price
committed
case 'h':

Andrew Price
committed
case '?':
default:

Andrew Price
committed
return 1;
}
}
if (optind < argc) {
fprintf(stderr, "Unrecognised arguments: ");
while (optind < argc)
fprintf(stderr, "%s ", argv[optind++]);
fprintf(stderr, "\n");
return 1;
}
if (printcfg) {
cfg_dump(stdout);
exit(0);
}

Andrew Price
committed
return 0;
}
int main(int argc, char **argv)
{
int mainsock = -1;

Andrew Price
committed
err = getconfig(argc, argv);
if (err)

Andrew Price
committed
mainsock = open_mainsock(cfg_get_int("port"));
if (mainsock < 0) {
fprintf(stderr, "Failed.\n");
return 1;
}
if (geteuid() == 0) {
const char *user = cfg_get_string("user");
struct passwd *pwbuff = getpwnam(user);
fprintf(stderr, "Username %s does not exist.\n", user);
return 1;
}
if (setgid(pwbuff->pw_gid)) {
fprintf(stderr, "Failed to setgid. %s\n", strerror(errno));
return 1;
}
if (setuid(pwbuff->pw_uid)) {
fprintf(stderr, "Failed to setuid. %s\n", strerror(errno));
return 1;
}
}
migrate_old_folders();
if (cfg_get_bool("foreground"))
setlinebuf(stdout);
else
daemon(0, 0);

Thomas Lake
committed
watch_mainsock(mainsock);
printf("Done.\n");
}