Example #1
0
File: common.c Project: zandeez/hgd
/* make state dir if not existing */
void
hgd_mk_state_dir()
{
	if (mkdir(state_path, S_IRWXU) != 0) {
		if (errno != EEXIST) {
			DPRINTF(HGD_D_ERROR, "%s: %s", state_path, SERROR);
			hgd_exit_nicely();
		}
	}

	/* make filestore if not existing */
	if (mkdir(filestore_path, S_IRWXU) != 0) {
		if (errno != EEXIST) {
			DPRINTF(HGD_D_ERROR, "%s:%s", filestore_path, SERROR);
			hgd_exit_nicely();
		}
	}

	/* correct any insecure perms (user may think he knows better) */
	if (chmod(filestore_path, S_IRWXU) != 0)
		DPRINTF(HGD_D_WARN, "Could not make filestore secure");

	if (chmod(state_path, S_IRWXU) != 0)
		DPRINTF(HGD_D_WARN, "Could not make state dir secure");
}
Example #2
0
int
hgd_cmd_encrypt(struct hgd_session *sess, char **unused)
{
	int			ssl_err = 0, ret = -1;

	unused = unused;

	if (sess->ssl != NULL) {
		DPRINTF(HGD_D_WARN, "User tried to enable encyption twice");
		return (HGD_FAIL);
	}

	if ((!ssl_capable) || (crypto_pref == HGD_CRYPTO_PREF_NEVER)) {
		DPRINTF(HGD_D_WARN, "User tried encrypt, when not possible");
		hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|nossl");
		return (HGD_FAIL);
	}

	DPRINTF(HGD_D_DEBUG, "New SSL for session");
	sess->ssl = SSL_new(ctx);
	if (sess->ssl == NULL) {
		PRINT_SSL_ERR(HGD_D_ERROR, "SSL_new");
		goto clean;
	}

	DPRINTF(HGD_D_DEBUG, "SSL_set_fd");
	ssl_err = SSL_set_fd(sess->ssl, sess->sock_fd);
	if (ssl_err == 0) {
		PRINT_SSL_ERR(HGD_D_ERROR, "SSL_set_fd");
		goto clean;
	}

	DPRINTF(HGD_D_DEBUG, "SSL_accept");
	ssl_err = SSL_accept(sess->ssl);
	if (ssl_err != 1) {
		PRINT_SSL_ERR(HGD_D_ERROR, "SSL_accept");
		goto clean;
	}

	/* This cannot fail so no error check */
	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);

	ret = HGD_OK; /* all is well */
clean:

	if (ret == HGD_FAIL) {
		DPRINTF(HGD_D_INFO, "SSL connection failed");
		hgd_exit_nicely(); /* be paranoid and kick client */
	} else {
		DPRINTF(HGD_D_INFO, "SSL connection established");
		hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok");
	}

	return (ret);
}
Example #3
0
File: common.c Project: zandeez/hgd
void *
xrealloc(void *old_p, size_t sz)
{
	void			*ptr;

	ptr = realloc(old_p, sz);
	if (!ptr) {
		DPRINTF(HGD_D_ERROR, "Could not reallocate");
		hgd_exit_nicely();
	}

	return (ptr);
}
Example #4
0
File: common.c Project: zandeez/hgd
void *
xcalloc(size_t sz, size_t size)
{
	void			*ptr;

	ptr = calloc(sz, size);
	if (!ptr) {
		DPRINTF(HGD_D_ERROR, "Could not allocate");
		hgd_exit_nicely();
	}

	return (ptr);
}
Example #5
0
File: common.c Project: zandeez/hgd
int
xasprintf(char **buf, char *fmt, ...)
{
	va_list			ap;
	int			ret;

	va_start(ap, fmt);
	ret = vasprintf(buf, fmt, ap);

	if (ret == -1) {
		DPRINTF(HGD_D_ERROR, "Can't allocate");
		hgd_exit_nicely();
	}

	return (ret);
}
Example #6
0
/* main loop that deals with network requests */
void
hgd_listen_loop(void)
{
	struct sockaddr_in	addr, cli_addr;
	int			cli_fd, child_pid = 0;
	socklen_t		cli_addr_len;
	int			sockopt = 1, data_ready;
	struct pollfd		pfd;

start:

	DPRINTF(HGD_D_DEBUG, "Setting up socket");

	if ((svr_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		DPRINTF(HGD_D_ERROR, "socket(): %s", SERROR);
		hgd_exit_nicely();
	}

	/* allow socket to be re-used right away after we exit */
	if (setsockopt(svr_fd, SOL_SOCKET, SO_REUSEADDR,
		     &sockopt, sizeof(sockopt)) < 0) {
		DPRINTF(HGD_D_WARN, "Can't set SO_REUSEADDR");
	}

	/* configure socket */
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(port);

	if (bind(svr_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
		DPRINTF(HGD_D_ERROR, "Bind to port %d: %s", port, SERROR);
		hgd_exit_nicely();
	}

	if (listen(svr_fd, sock_backlog) < 0) {
		DPRINTF(HGD_D_ERROR, "Listen: %s", SERROR);
		hgd_exit_nicely();
	}

	DPRINTF(HGD_D_INFO, "Socket ready and listening on port %d", port);

	/* setup signal handler */
	signal(SIGCHLD, hgd_sigchld);

	while (1) {
		DPRINTF(HGD_D_INFO, "waiting for client connection");

		/* spin until something is ready */
		pfd.fd = svr_fd;
		pfd.events = POLLIN;
		data_ready = 0;

		while (!dying && !restarting && !data_ready) {
			data_ready = poll(&pfd, 1, INFTIM);
			if (data_ready == -1) {
				if (errno != EINTR) {
					DPRINTF(HGD_D_ERROR, "Poll error");
					dying = 1;
				}
				data_ready = 0;
			}
		}

		if (dying || restarting) {
			if (restarting)
				exit_ok = 1;
			hgd_exit_nicely();
		}

		cli_addr_len = sizeof(cli_addr);
		cli_fd = accept(svr_fd, (struct sockaddr *) &cli_addr,
		    &cli_addr_len);

		if (cli_fd < 0) {
			DPRINTF(HGD_D_WARN, "Server failed to accept");
			close(svr_fd);
			/*
			 * accept will fail next time aswell :\
			 * it seems the fix is to re-initialise the socket
			 */
			goto start;
		}

		if (setsockopt(cli_fd, SOL_SOCKET, SO_REUSEADDR,
			    &sockopt, sizeof(sockopt)) < 0) {
			DPRINTF(HGD_D_WARN, "Can't set SO_REUSEADDR");
		}

		/* ok, let's deal with that request then */
		if (!single_client)
			child_pid = fork();

		if (!child_pid) {

			/* turn off HUP handler */
			//signal(SIGHUP, SIG_DFL);

			db = hgd_open_db(db_path, 0);
			if (db == NULL)
				hgd_exit_nicely();

			hgd_service_client(cli_fd, &cli_addr);
			DPRINTF(HGD_D_DEBUG, "client service complete");

			/* and we are done with this client */
			if (shutdown(cli_fd, SHUT_RDWR) == -1)
				DPRINTF(HGD_D_WARN, "Can't shutdown socket");
			close(cli_fd);

			close(svr_fd);
			svr_fd = -1; /* prevent shutdown of svr_fd */
			exit_ok = 1;
			hgd_exit_nicely();
		} /* child block ends */

		close (cli_fd);
		DPRINTF(HGD_D_DEBUG, "client servicer PID = '%d'", child_pid);
		/* otherwise, back round for the next client */
	}
	/* NOREACH */
}
Example #7
0
int
main(int argc, char **argv)
{
	char			*xdg_config_home;
	char			*config_path[4] = {NULL, NULL, NULL, NULL};
	int			 num_config = 2, ch;

	/* as early as possible */
	HGD_INIT_SYSLOG_DAEMON();

	config_path[0] = NULL;
	xasprintf(&config_path[1], "%s",  HGD_GLOBAL_CFG_DIR HGD_SERV_CFG );

	xdg_config_home =  getenv("XDG_CONFIG_HOME");
	if (xdg_config_home == NULL) {
		xasprintf(&config_path[2], "%s%s", getenv("HOME"),
		    HGD_USR_CFG_DIR HGD_SERV_CFG );
	} else {
		xasprintf(&config_path[2], "%s%s",
		    xdg_config_home , "/hgd" HGD_SERV_CFG);
	}

	/* if killed, die nicely */
	hgd_register_sig_handlers();

	state_path = xstrdup(HGD_DFL_DIR);
	ssl_key_path = xstrdup(HGD_DFL_KEY_FILE);
	ssl_cert_path = xstrdup(HGD_DFL_CERT_FILE);

	DPRINTF(HGD_D_DEBUG, "Parsing options:1");
	while ((ch = getopt(argc, argv, "Bc:Dd:EefF:hk:n:p:s:S:vx:y:")) != -1) {
		switch (ch) {
		case 'c':
			if (num_config < 3) {
				num_config++;
				DPRINTF(HGD_D_DEBUG, "added config %d %s",
				    num_config, optarg);
				config_path[num_config] = optarg;
			} else {
				DPRINTF(HGD_D_WARN,
				    "Too many config files specified");
				hgd_exit_nicely();
			}
			break;
		case 'x':
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			DPRINTF(HGD_D_DEBUG, "set debug to %d", hgd_debug);
			break;
		default:
			break; /* next getopt will catch errors */
		}
	}


	RESET_GETOPT();

	/* cache HUP info */
	if (hgd_cache_exec_context(argv) != HGD_OK)
		hgd_exit_nicely();

	hgd_read_config(config_path + num_config);

	DPRINTF(HGD_D_DEBUG, "Parsing options:2");
	while ((ch = getopt(argc, argv, "Bc:Dd:EefF:hk:n:p:s:S:vx:y:")) != -1) {
		switch (ch) {
		case 'B':
			background = 0;
			DPRINTF(HGD_D_DEBUG, "Not \"backgrounding\" daemon.");
			break;
		case 'c':
			break; /* already handled */
		case 'D':
			DPRINTF(HGD_D_DEBUG, "No client DNS lookups");
			lookup_client_dns = 0;
			break;
		case 'd':
			free(state_path);
			state_path = xstrdup(optarg);
			DPRINTF(HGD_D_DEBUG, "Set hgd dir to '%s'", state_path);
			break;
		case 'e':
			crypto_pref = HGD_CRYPTO_PREF_ALWAYS;
			DPRINTF(HGD_D_DEBUG, "Server will insist on crypto");
			break;
		case 'E':
			crypto_pref = HGD_CRYPTO_PREF_NEVER;
			DPRINTF(HGD_D_WARN, "Encryption disabled manually");
			break;
		case 'f':
			single_client = 1;
			DPRINTF(HGD_D_DEBUG, "Single client debug mode on");
			break;
		case 'F':
			flood_limit = atoi(optarg);
			DPRINTF(HGD_D_DEBUG, "Set flood limit to %d",
			    flood_limit);
			break;
		case 'k':
			free(ssl_key_path);
			ssl_key_path = optarg;
			DPRINTF(HGD_D_DEBUG,
			    "set ssl private key path to '%s'", ssl_key_path);
			break;
		case 'n':
			req_votes = atoi(optarg);
			DPRINTF(HGD_D_DEBUG,
			    "Set required-votes to %d", req_votes);
			break;
		case 'p':
			port = atoi(optarg);
			DPRINTF(HGD_D_DEBUG, "Set port to %d", port);
			break;
		case 's':
			/* XXX overflow? */
			max_upload_size = atoi(optarg) * HGD_MB;
			DPRINTF(HGD_D_DEBUG, "Set max upload size to %d",
			    (int) max_upload_size);
			break;
		case 'S':
			free(ssl_cert_path);
			ssl_cert_path = optarg;
			DPRINTF(HGD_D_DEBUG,
			    "set ssl cert path to '%s'", ssl_cert_path);
			break;
		case 'v':
			hgd_print_version();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		case 'x':
			DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg));
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			break; /* already set but over-rideable */
		case 'y':
			free(vote_sound);
			vote_sound = optarg;
			DPRINTF(HGD_D_DEBUG,
			    "set voteoff sound %s", vote_sound);
			break;
		case 'h':
		default:
			hgd_usage();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		};
	}

	argc -= optind;
	argv += optind;

	/* set up paths */
	xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME);
	xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME);

	umask(~S_IRWXU);
	hgd_mk_state_dir();

	db = hgd_open_db(db_path, 0);
	if (db == NULL)
		hgd_exit_nicely();

	sqlite3_close(db); /* re-opened later */
	db = NULL;

	/* unless the user actively disables SSL, we try to be capable */
	if (crypto_pref != HGD_CRYPTO_PREF_NEVER) {
		if (hgd_setup_ssl_ctx(&method, &ctx, 1,
		    ssl_cert_path, ssl_key_path) == 0) {
			DPRINTF(HGD_D_INFO, "Server is SSL capable");
			ssl_capable = 1;
		} else {
			DPRINTF(HGD_D_WARN, "Server is SSL incapable");
		}
	} else {
		DPRINTF(HGD_D_INFO, "Server was forced SSL incapable");
	}

	/* if -e, but something screwed up in the above, bail */
	if ((crypto_pref == HGD_CRYPTO_PREF_ALWAYS) && (ssl_capable != 1)) {
		DPRINTF(HGD_D_ERROR,
		    "Crypto was forced on, but server is incapable");
		hgd_exit_nicely();
	}

	/* alright, everything looks good, lets be a daemon and background */
	if (background) hgd_daemonise();

	hgd_listen_loop();

	exit_ok = 1;
	hgd_exit_nicely();

	return (EXIT_SUCCESS); /* NOREACH */
}
Example #8
0
void
hgd_service_client(int cli_fd, struct sockaddr_in *cli_addr)
{
	struct hgd_session	 sess;
	char			*recv_line;
	uint8_t			 exit, ssl_dead = 0;

	sess.cli_str = hgd_identify_client(cli_addr);
	sess.sock_fd = cli_fd;
	sess.cli_addr = cli_addr;
	sess.user = NULL;
	sess.ssl = NULL;

	if (sess.cli_str == NULL)
		xasprintf(&sess.cli_str, "unknown"); /* shouldn't happen */

	DPRINTF(HGD_D_INFO, "Client connection: '%s'", sess.cli_str);

	/* oh hai */
	hgd_sock_send_line(cli_fd, sess.ssl, HGD_GREET);

	/* main command recieve loop */
	do {
		recv_line = hgd_sock_recv_line(sess.sock_fd, sess.ssl);
		exit = hgd_parse_line(&sess, recv_line);
		free(recv_line);
		if (num_bad_commands >= HGD_MAX_BAD_COMMANDS) {
			DPRINTF(HGD_D_WARN,"Client abused server, "
			    "kicking '%s'", sess.cli_str);
			/* laters */
			hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE_KICK);
			close(sess.sock_fd);
			exit_ok = 1;
			hgd_exit_nicely();
		}
	} while (!exit && !dying && !restarting);

	/*
	 * client service procs should not respawn as liesteners,
	 * that would suck. This may need tweaking later, as the exit
	 * message may be misinterpreted (?) Handling HUP is hard.
	 */
	if (restarting) {
		dying = 1;
		restarting = 0;
		exit_ok = 1;
	}

	/* laters */
	hgd_sock_send_line(cli_fd, sess.ssl, HGD_BYE);

	/* free up the hgd_session members */
	if (sess.cli_str != NULL)
		free(sess.cli_str);

	if (sess.ssl != NULL) {
		while (!ssl_dead)
			ssl_dead = SSL_shutdown(sess.ssl);

		SSL_free(sess.ssl);
	}

	if (sess.user) {
		if (sess.user->name)
			free(sess.user->name);
		free(sess.user);
	}
}
Example #9
0
File: nchgdc.c Project: Eeketh/hgd
int
main(int argc, char **argv)
{
	struct ui		 u;
	char			*config_path[4] = {NULL, NULL, NULL, NULL};
	int			 num_config = 2;

	memset(&u, 0, sizeof(u));

	hgd_debug = 3; /* XXX config file or getopt */

	host = xstrdup(HGD_DFL_HOST);
#ifdef HAVE_LIBCONFIG
	config_path[0] = NULL;
	xasprintf(&config_path[1], "%s",  HGD_GLOBAL_CFG_DIR HGD_CLI_CFG );
	config_path[2] = hgd_get_XDG_userprefs_location(hgdc);
#endif

	hgd_read_config(config_path + num_config);

	while(num_config > 0) {
		if (config_path[num_config] != NULL) {
			free (config_path[num_config]);
			config_path[num_config] = NULL;
		}
		num_config--;
	}

	if (init_log() != HGD_OK)
		hgd_exit_nicely();

	/* XXX proper dialog box needed */
	if (password == NULL) {
		password = xmalloc(HGD_MAX_PASS_SZ);
		if (readpassphrase("Password: "******"Can't read password");
			hgd_exit_nicely();
		}
	}

	hgd_register_sig_handlers();

	initscr();

	cbreak();
	keypad(stdscr, TRUE);
	noecho();

	if (has_colors()) {
		if (start_color() == ERR)
			DPRINTF(HGD_D_WARN, "Could not initialise colour terminal");
	}

	/* XXX fall back implementations for B+W terms? */
	init_pair(HGD_CPAIR_BARS, COLOR_YELLOW, COLOR_BLUE);
	init_pair(HGD_CPAIR_SELECTED, COLOR_BLACK, COLOR_WHITE);
	init_pair(HGD_CPAIR_DIALOG, COLOR_BLACK, COLOR_CYAN);
	init_pair(HGD_CPAIR_PBAR_BG, COLOR_YELLOW, COLOR_BLACK);

	/* initialise top and bottom bars */
	if (hgd_init_titlebar(&u) != HGD_OK)
		hgd_exit_nicely();
	if (hgd_init_statusbar(&u) != HGD_OK)
		hgd_exit_nicely();

	/* and all content windows */
	if (hgd_init_files_win(&u) != HGD_OK)
		hgd_exit_nicely();
	if (hgd_init_console_win(&u) != HGD_OK)
		hgd_exit_nicely();
	if (hgd_init_playlist_win(&u) != HGD_OK)
		hgd_exit_nicely();

	/* start on the playlist */
	hgd_switch_content(&u, HGD_WIN_PLAYLIST);

	if (user == NULL) user = getenv("USER"); /* XXX duplicated */
	if (hgd_ui_connect(&u) != HGD_OK)
		hgd_exit_nicely();

	/* main event loop */
	DPRINTF(HGD_D_INFO, "nchgdc event loop starting");
	hgd_event_loop(&u);

	DPRINTF(HGD_D_INFO, "Closing down");
	hgd_free_content_win(&u, HGD_WIN_PLAYLIST);
	hgd_free_content_win(&u, HGD_WIN_FILES);
	hgd_free_content_win(&u, HGD_WIN_CONSOLE);
	delwin(u.status);
	delwin(u.title);

	exit_ok = 1;
	hgd_exit_nicely();

	return 0;
}
Example #10
0
int
main(int argc, char **argv)
{
	char			*config_path[4] = {NULL, NULL, NULL, NULL};
	int			 num_config = 2, ch;

	/* syslog as early as possible */
	HGD_INIT_SYSLOG();

#ifdef HAVE_LIBCONFIG
	config_path[0] = NULL;
	xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_SERV_CFG);
	config_path[2] = hgd_get_XDG_userprefs_location(hgdc);
#endif

	hgd_register_sig_handlers();
	state_path = xstrdup(HGD_DFL_DIR);

	DPRINTF(HGD_D_DEBUG, "Parsing options:1");
	while ((ch = getopt(argc, argv, "c:d:hvx:" "c:x:")) != -1) {
		switch (ch) {
		case 'c':
			if (num_config < 3) {
				num_config++;
				DPRINTF(HGD_D_DEBUG, "added config %d %s",
				    num_config, optarg);
				config_path[num_config] = optarg;
			} else {
				DPRINTF(HGD_D_WARN,
				    "Too many config files specified");
				hgd_exit_nicely();
			}
			break;
		case 'x':
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			DPRINTF(HGD_D_DEBUG,
			    "set debug level to %d", hgd_debug);
			break;
		default:
			break; /* next getopt will catch errors */
		};
	}

	hgd_read_config(config_path + num_config);

	while(num_config > 0) {
		if (config_path[num_config] != NULL) {
			free (config_path[num_config]);
			config_path[num_config] = NULL;
		}
		num_config--;
	}

	RESET_GETOPT();

	DPRINTF(HGD_D_DEBUG, "Parsing options:2");
	while ((ch = getopt(argc, argv, "c:d:hvx:" "c:x:")) != -1) {
		switch (ch) {
		case 'c':
			break; /* already handled */
		case 'd':
			free(state_path);
			state_path = xstrdup(optarg);
			DPRINTF(HGD_D_DEBUG, "set hgd dir to '%s'", state_path);
			break;
		case 'v':
			hgd_print_version();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		case 'x':
			DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg));
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			break; /* already set but over-rideable */
		case 'h':
		default:
			hgd_usage();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		};
	}

	argc -= optind;
	argv += optind;

	xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME);
	xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME);

	umask(~S_IRWXU);
	hgd_mk_state_dir();

	if (hgd_parse_command(argc, argv) == -1)
		hgd_exit_nicely();

	exit_ok = 1;
	hgd_exit_nicely();
	_exit (EXIT_SUCCESS); /* NOREACH */
}
Example #11
0
/*
 * Please do not be tempted to move this to mplayer.c --
 * This would cause hgd-admin and hgd-netd to pull in python
 */
int
hgd_play_track(struct hgd_playlist_item *t, uint8_t purge_fs, uint8_t purge_db)
{
	int			status = 0, pid, ret = HGD_FAIL;
	char			*ipc_path = 0, *pipe_arg = 0;
	FILE			*ipc_file;
	struct stat		st;

	DPRINTF(HGD_D_INFO, "Playing '%s' for '%s'", t->filename, t->user);
	if (hgd_mark_playing(t->id) == HGD_FAIL)
		goto clean;

	/*
	 * We will write away the tid of the playing file
	 * hgd-netd uses this to check the user is voting off the track
	 * they think they are.
	 */
	xasprintf(&ipc_path, "%s/%s", state_path, HGD_PLAYING_FILE);

	/* first check the file is non-existent */
	if (stat(ipc_path, &st) < 0) {
		if (errno != ENOENT) {
			DPRINTF(HGD_D_ERROR,
			    "stale tid file: %s: %s", ipc_path, SERROR);
			goto clean;
		}
	} else {
		DPRINTF(HGD_D_ERROR, "stale tid file: %s" , ipc_path);
		goto clean;
	}

	if (hgd_file_open_and_lock(ipc_path, F_WRLCK, &ipc_file) != HGD_OK) {
		DPRINTF(HGD_D_ERROR, "Can't open+lock '%s'", ipc_path);
		goto clean;
	}

	/* try to be secure */
	if (chmod(ipc_path, S_IRUSR | S_IWUSR) != 0)
		DPRINTF(HGD_D_WARN, "Can't secure ipc file: %s", SERROR);

	/* write away tid of current track to a file for hgd-netd */
	if (fprintf(ipc_file, "%d", t->id) < 0) {
		DPRINTF(HGD_D_ERROR, "Failed to write out tid: %s", SERROR);
		goto clean;
	}

	/* unlock */
	if (hgd_file_unlock_and_close(ipc_file) != HGD_OK) {
		DPRINTF(HGD_D_ERROR, "failed to unlock");
		goto clean;
	}

#ifdef HAVE_PYTHON
	hgd_execute_py_hook("pre_play");
#endif

	if (hgd_make_mplayer_input_fifo() != HGD_OK)
		goto clean;

	xasprintf(&pipe_arg, "file=%s", mplayer_fifo_path);

	pid = fork();
	if (pid < 0) {
		DPRINTF(HGD_D_ERROR, "Could not fork: %s", SERROR);
	} else if (!pid) {

		/* child - your the d00d who will play this track */
		execlp(MPLAYER_EXE, MPLAYER_EXE, "-really-quiet", "-slave",
		    "-input", pipe_arg, t->filename, (char *) NULL);

		/* if we get here, the shit hit the fan with execlp */
		DPRINTF(HGD_D_ERROR, "execlp() failed");
		hgd_exit_nicely(); /* child should always exit */
	} else {
		DPRINTF(HGD_D_INFO,
		    "Mplayer spawned, waiting to finish: pid=%d", pid);

		if (waitpid(pid, &status, 0) < 0) {
			/* it is ok for this to fail if we are restarting */
			if (errno != EINTR)
				DPRINTF(HGD_D_WARN, "Could not wait(): %s", SERROR);

			if (restarting || dying) {
				kill(pid, SIGINT);
				if (waitpid(pid, &status, 0) < 0) {
					DPRINTF(HGD_D_WARN, "Could not wait(): %s", SERROR);
				}
			}
		}

		/* unlink ipc file */
		if (hgd_file_open_and_lock(
		    ipc_path, F_WRLCK, &ipc_file) != HGD_OK) {
			DPRINTF(HGD_D_ERROR, "Can't open+lock '%s'", ipc_path);
			goto clean;
		}

		if (unlink(ipc_path) < 0) {
			DPRINTF(HGD_D_ERROR, "can't unlink ipc file %s: %s",
			    ipc_path, SERROR);
			goto clean;
		}

		if (hgd_file_unlock_and_close(ipc_file) != HGD_OK) {
			DPRINTF(HGD_D_ERROR, "failed to unlock+close %s: %s",
			    ipc_path, SERROR);
		}

		/* unlink input pipe */
		if (unlink(mplayer_fifo_path) < 0)
			DPRINTF(HGD_D_WARN,
			    "Could not unlink mplayer input fifo %s", SERROR);

		/* unlink media (but not if restarting, we replay the track) */
		if ((!restarting) && (!dying)
		    && (purge_fs) && (unlink(t->filename) < 0)) {
			DPRINTF(HGD_D_DEBUG,
			    "Deleting finished: %s", t->filename);
			DPRINTF(HGD_D_WARN, "Can't unlink '%s'", ipc_path);
		}
	}
#ifdef HAVE_PYTHON
	hgd_execute_py_hook("post_play");
#endif

	DPRINTF(HGD_D_DEBUG, "Finished playing (exit %d)", status);

	/* if we are restarting, we replay the track on restart */
	if ((!restarting) && (!dying) &&
	    (hgd_mark_finished(t->id, purge_db) == HGD_FAIL))
		DPRINTF(HGD_D_WARN,
		    "Could not purge/mark finished -- trying to continue");

	ret = HGD_OK;

clean:
	if (pipe_arg)
		free(pipe_arg);
	if (ipc_path)
		free(ipc_path);

	return (ret);
}
Example #12
0
int
main(int argc, char **argv)
{
	char			*config_path[4] = {NULL, NULL, NULL, NULL};
	int			 num_config = 2, ch;
	FILE			*hgd_pid;

	/* early as possible */
	hgd_register_sig_handlers();
	HGD_INIT_SYSLOG_DAEMON();

#ifdef HAVE_LIBCONFIG
	config_path[0] = NULL;
	xasprintf(&config_path[1], "%s", HGD_GLOBAL_CFG_DIR HGD_SERV_CFG);
	config_path[2] = hgd_get_XDG_userprefs_location(playd);
#endif

	state_path = xstrdup(HGD_DFL_DIR);

	DPRINTF(HGD_D_DEBUG, "Parsing options:1");
	while ((ch = getopt(argc, argv, "Bc:Cd:hpP:qvx:")) != -1) {
		switch (ch) {
		case 'c':
			if (num_config < 3) {
				num_config++;
				DPRINTF(HGD_D_DEBUG, "added config %d %s",
				    num_config, optarg);
				config_path[num_config] = optarg;
			} else {
				DPRINTF(HGD_D_WARN,
				    "Too many config files specified");
				hgd_exit_nicely();
			}
			break;
		case 'x':
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			DPRINTF(HGD_D_DEBUG,
			    "set debug level to %d", hgd_debug);
			break;
		default:
			break; /* catch badness in next getopt */
		};
	}

	hgd_read_config(config_path + num_config);

	while(num_config > 0) {
		if (config_path[num_config] != NULL) {
			free (config_path[num_config]);
			config_path[num_config] = NULL;
		}
		num_config--;
	}

	RESET_GETOPT();

	if (hgd_cache_exec_context(argv) != HGD_OK)
		hgd_exit_nicely();

	DPRINTF(HGD_D_DEBUG, "Parsing options");
	while ((ch = getopt(argc, argv, "Bc:Cd:hpP:qvx:")) != -1) {
		switch (ch) {
		case 'B':
			background = 0;
			DPRINTF(HGD_D_DEBUG, "Not \"backgrounding\" daemon.");
			break;
		case 'c':
			break; /* already handled */
		case 'C':
			clear_playlist_on_start = 1;
			DPRINTF(HGD_D_DEBUG, "will clear playlist '%s'",
			    state_path);
			break;
		case 'd':
			free(state_path);
			state_path = xstrdup(optarg);
			DPRINTF(HGD_D_DEBUG, "set hgd dir to '%s'", state_path);
			break;
		case 'p':
			DPRINTF(HGD_D_DEBUG, "No purging from fs");
			purge_finished_fs = 0;
			break;
#ifdef HAVE_PYTHON
		case 'P':
			DPRINTF(HGD_D_DEBUG, "Setting python plugin dir");
			if (hgd_py_plugin_dir != NULL)
				free(hgd_py_plugin_dir);
			hgd_py_plugin_dir = xstrdup(optarg);
			break;
#endif
		case 'q':
			DPRINTF(HGD_D_DEBUG, "No purging from db");
			purge_finished_db = 0;
			break;
		case 'v':
			hgd_print_version();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		case 'x':
			DPRINTF(HGD_D_DEBUG, "set debug to %d", atoi(optarg));
			hgd_debug = atoi(optarg);
			if (hgd_debug > 3)
				hgd_debug = 3;
			break; /* already set but over-rideable */
		case 'h':
		default:
			hgd_usage();
			exit_ok = 1;
			hgd_exit_nicely();
			break;
		};
	}

	argc -= optind;
	argv += optind;

	xasprintf(&db_path, "%s/%s", state_path, HGD_DB_NAME);
	xasprintf(&filestore_path, "%s/%s", state_path, HGD_FILESTORE_NAME);
	xasprintf(&mplayer_fifo_path, "%s/%s",
	    state_path, HGD_MPLAYER_PIPE_NAME);

	umask(~S_IRWXU);
	hgd_mk_state_dir();

	if (hgd_check_mplayer_present() != HGD_OK)
		hgd_exit_nicely();

	db = hgd_open_db(db_path, 0);
	if (db == NULL)
		hgd_exit_nicely();

	if (hgd_init_playstate() != HGD_OK)
		hgd_exit_nicely();

	if (clear_playlist_on_start) {
		if (hgd_clear_playlist() != HGD_OK)
			hgd_exit_nicely();
	}

	if (hgd_open_pid_file(&hgd_pid) != HGD_OK) {
		DPRINTF(HGD_D_ERROR, "Can't open PID file");
		return (HGD_FAIL);
	}

	/* start */
	if (background)
		hgd_daemonise();

	/* do the Python dance */
#ifdef HAVE_PYTHON
	if (hgd_embed_py(1) != HGD_OK) {
		DPRINTF(HGD_D_ERROR, "Failed to initialise Python");
		hgd_exit_nicely();
	}
#endif

	if (hgd_write_pid_file(&hgd_pid) != HGD_OK) {
		DPRINTF(HGD_D_ERROR, "Can't write PID away");
		return (HGD_FAIL);
	}

	if (hgd_play_loop() == HGD_OK)
		exit_ok = 1;

	if (hgd_unlink_pid_file() != HGD_OK)
		DPRINTF(HGD_D_ERROR, "Could not unlink pidfile");

	hgd_exit_nicely();
	_exit (EXIT_SUCCESS); /* NOREACH */
}