
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

static void run_cmd(char const *cmd)
{
	syslog(LOG_INFO, "Running %s", cmd);
	int rtc = system(cmd);
	if (rtc == -1)
		syslog(LOG_ALERT, "Cannot system(%s): %s", cmd, strerror(errno));
	else if (WIFEXITED(rtc))
	{
		rtc = WEXITSTATUS(rtc);
		syslog(rtc? LOG_ERR: LOG_INFO, "%s returned %d", cmd, rtc);
	}
	else
		syslog(LOG_CRIT, "%s terminated with status %#x", cmd, rtc);
}

static void fork_cmd(char const *cmd)
{
	int tries = 3;
	while (tries --> 0)
	{
		int pid = fork();
		if (pid == 0) // parent
			return;

		if (pid > 0)  // child
		{
			run_cmd(cmd);
			exit(0);
		}

		syslog(LOG_ERR, "Cannot fork, will %s: %s",
			tries? "retry": "abort",
			strerror(errno));
		if (tries)
			sleep(1);
		else
			abort();
	}
}

int main(int argc, char *argv[])
/*
* Call whatever commands given on the command line, then hibernate.
* Possible commands can be:
*
*  "xscreensaver-command -lock"
*  --fork slock
*  "sleep 1"
*  "xset dpms force off"
*  ...
*
* The --fork option is a hack for not waiting completion of the next
* command.  It would have been nice to just append ampersand (&) to
* the command, but OpenBox actions remove all ampersands.
*/
{
	seteuid(getuid()); // drop privileges to run arguments

	// since August 2023 daemon goes to /var/log/syslog 
	openlog(argv[0], LOG_ODELAY, LOG_DAEMON);
	syslog(LOG_INFO, "Started");

	int fork_next = 0;
	for (int i = 1; i < argc; ++i)
	{
		if (fork_next)
		{
			fork_next = 0;
			fork_cmd(argv[i]);
		}
		else if (strcmp("--fork", argv[i]) == 0)
			fork_next = 1;
		else
			run_cmd(argv[i]);
	}

	if (seteuid(0) || setuid(0))
		syslog(LOG_ERR, "Cannot set(e)uid(0): %s", strerror(errno));

//	run_cmd("/sbin/pm-suspend");
	run_cmd("/sbin/pm-hibernate");

	closelog();
	return 0;
}
