ap

Queue manager meant to be used as an audio player
git clone git://jacobedwards.org/ap
Log | Files | Refs | README | LICENSE

main.c (3160B)


      1 /*
      2  * Copyright 2021-2023 Jacob R. Edwards
      3  *
      4  * ap -- audio player
      5  *
      6  * This program is free software: you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, either version 3 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include <sys/socket.h>
     21 #include <sys/wait.h>
     22 
     23 #include <errno.h>
     24 #include <limits.h>
     25 #include <poll.h>
     26 #include <regex.h>
     27 #include <signal.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <unistd.h>
     32 
     33 #include "aps.h"
     34 #include "command.h"
     35 #include "find.h"
     36 #include "log.h"
     37 #include "queue.h"
     38 #include "util.h"
     39 
     40 #include "config.h"
     41 
     42 static struct aps *aps;
     43 
     44 void
     45 die(char *s)
     46 {
     47 	aps_log(NULL, 0, FATAL, NULL, "%s: %s", s, errstr);
     48 	if (aps)
     49 		unlink(aps->con->path);
     50 	exit(1);
     51 }
     52 
     53 void
     54 sigclose(int sig)
     55 {
     56 	aps_log(aps, 0, FATAL, NULL, "close signal");
     57 	aps->close = 1;
     58 }
     59 
     60 void
     61 sigchld(int sig)
     62 {
     63 	int status;
     64 	pid_t pid;
     65 
     66 	while ((pid =
     67 	    waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) {
     68 		if (pid == aps->player->pid) {
     69 			aps_log(aps, 0, INFO, logsubjects[LogPlayer], "player status available");
     70 			pupdate(aps->player, status);
     71 		}
     72 	}
     73 }
     74 
     75 void
     76 sigint(int sig)
     77 {
     78 }
     79 
     80 int
     81 configure(struct aps *aps, char **argv)
     82 {
     83 	int status;
     84 	pid_t pid;
     85 
     86 	pid = fork();
     87 	if (pid < 0)
     88 		die("unable to fork");
     89 
     90 	if (pid == 0) {
     91 		*argv = "apsrc";
     92 		execvp("apc", argv);
     93 		perror("unable to execute apc");
     94 		_exit(1);
     95 	}
     96 
     97 	if (aps_update(aps))
     98 		return 1;
     99 
    100 	while (!aps->close && aps->nfds > 0) {
    101 		if (aps_update(aps) && errno != EINTR)
    102 			return 1;
    103 	}
    104 
    105 	if (waitpid(pid, &status, 0) < 0)
    106 		return 1;
    107 	return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
    108 }
    109 
    110 int
    111 run(struct aps *aps)
    112 {
    113 	while (!aps->close) {
    114 		if (aps->queue) {
    115 			if (aps->player->state == COMPLETE)
    116 				queue_set(aps, aps->queue->next);
    117 			if (aps->player->state == OFF)
    118 				pplay(aps->player, aps->queue->path);
    119 		}
    120 		if (aps_update(aps) && errno != EINTR)
    121 			return 1;
    122 	}
    123 	return 0;
    124 }
    125 
    126 int
    127 main(int argc, char *argv[])
    128 {
    129 	int error;
    130 
    131 #ifdef __OpenBSD__
    132 	if (pledge("stdio rpath cpath proc exec unix", NULL))
    133 		die("pledge");
    134 #endif
    135 
    136         openlog("aps", LOG_PID, LOG_DAEMON);
    137 
    138 	aps = aps_open(name, player);
    139 	if (aps == NULL)
    140 		die("unable to setup server");
    141 
    142 	aps->logmask = logmask(ERROR);
    143 
    144 	aps->coms = commands;
    145 	aps->ncoms = LEN(commands);
    146 
    147 	signal(SIGHUP, SIG_IGN);
    148 	signal(SIGINT, sigint);
    149 	signal(SIGQUIT, sigclose);
    150 	signal(SIGTERM, sigclose);
    151 
    152 	if (configure(aps, argv))
    153 		die("unable to re-configure");
    154 
    155 	signal(SIGCHLD, sigchld);
    156 
    157 	error = fork();
    158 	if (error == -1)
    159 		die("unable to fork");
    160 	else if (error > 0)
    161 		return 0;
    162 
    163 	error = run(aps);
    164 	if (error == 0)
    165 		error = aps->close;
    166 
    167 	aps_close(aps);
    168 	closelog();
    169 
    170 	return error;
    171 }