124 lines
3.2 KiB
C
124 lines
3.2 KiB
C
/*
|
|
* Copyright (c) 2024 Jonas 'Sortie' Termansen.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* service.c
|
|
* Start and stop services.
|
|
*/
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
#include <err.h>
|
|
#include <getopt.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
static int open_local_client_socket(const char* path, int flags)
|
|
{
|
|
size_t path_length = strlen(path);
|
|
size_t addr_size = offsetof(struct sockaddr_un, sun_path) + path_length + 1;
|
|
struct sockaddr_un* sockaddr = malloc(addr_size);
|
|
if ( !sockaddr )
|
|
return -1;
|
|
sockaddr->sun_family = AF_LOCAL;
|
|
strcpy(sockaddr->sun_path, path);
|
|
int fd = socket(AF_LOCAL, SOCK_STREAM | flags, 0);
|
|
if ( fd < 0 )
|
|
return free(sockaddr), -1;
|
|
if ( connect(fd, (const struct sockaddr*) sockaddr, addr_size) < 0 )
|
|
return close(fd), free(sockaddr), -1;
|
|
free(sockaddr);
|
|
return fd;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
const char* init_socket = getenv("INIT_SOCKET");
|
|
if ( !init_socket )
|
|
init_socket = "/var/run/init";
|
|
|
|
bool raw = false;
|
|
const char* source = "local";
|
|
|
|
const struct option longopts[] =
|
|
{
|
|
{"source", required_argument, NULL, 't'},
|
|
{"raw", no_argument, NULL, 'r'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
const char* opts = "rs:";
|
|
int opt;
|
|
while ( (opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1 )
|
|
{
|
|
switch ( opt )
|
|
{
|
|
case 'r': raw = true; break;
|
|
case 's': source = optarg; break;
|
|
default: return 2;
|
|
}
|
|
}
|
|
|
|
int fd = open_local_client_socket(init_socket, 0);
|
|
if ( fd < 0 )
|
|
err(1, "%s", init_socket);
|
|
|
|
if ( raw )
|
|
{
|
|
for ( int i = optind; i < argc; i++ )
|
|
{
|
|
if ( dprintf(fd, "%s%c", argv[i], i + 1 == argc ? '\n' : ' ') < 0 )
|
|
err(1, "%s", init_socket);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if ( argc - optind < 2 )
|
|
errx(1, "usage: <daemon> <command>");
|
|
|
|
const char* daemon = argv[optind++];
|
|
const char* command = argv[optind++];
|
|
|
|
if ( !strcmp(command, "enable") )
|
|
{
|
|
// TODO: Option for not writing out a new config.
|
|
if ( dprintf(fd, "require %s %s start\n", source, daemon) < 0 )
|
|
err(1, "%s", init_socket);
|
|
}
|
|
else if ( !strcmp(command, "disable") )
|
|
{
|
|
// TODO: Option for not writing out a new config.
|
|
if ( dprintf(fd, "unrequire %s %s\n", source, daemon) < 0 )
|
|
err(1, "%s", init_socket);
|
|
}
|
|
else if ( !strcmp(command, "start") )
|
|
{
|
|
if ( dprintf(fd, "require %s %s start\n", source, daemon) < 0 )
|
|
err(1, "%s", init_socket);
|
|
}
|
|
else if ( !strcmp(command, "stop") )
|
|
{
|
|
if ( dprintf(fd, "unrequire %s %s stop\n", source, daemon) < 0 )
|
|
err(1, "%s", init_socket);
|
|
}
|
|
else
|
|
errx(1, "unknown command: %s", command);
|
|
|
|
return 0;
|
|
}
|