+++ /dev/null
-/* Copyright (C) 2018 Thomas Balzer */
-
-/* This file is part of tomd. */
-
-/* tomd is free software: you can redistribute it and/or modify */
-/* it under the terms of the GNU General Public License as published by */
-/* the Free Software Foundation, either version 3 of the License, or */
-/* (at your option) any later version. */
-
-/* tomd is distributed in the hope that it will be useful, */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
-/* GNU General Public License for more details. */
-
-/* You should have received a copy of the GNU General Public License */
-/* along with tomd. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#include "../../include/macros.h"
-#include "../../include/manifest.h"
-#include "../../include/job.h"
-
-static void header(void)
-{
- tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer");
- tomd_p("GPL v3 or later license.");
-}
-
-static int sfd;
-static char socket_dirname[100];
-static char socket_filename[100];
-
-static void gen_socket_filename(void)
-{
- uid_t this_user_id =
- getuid();
- sprintf(socket_dirname,
- "/run/user/%d/tomd",
- this_user_id);
- sprintf(socket_filename,
- "/run/user/%d/tomd/socket",
- this_user_id);
-
- tomd_p("making dir '%s'", socket_dirname);
- /* lazy way */
- /* char buf[100]; */
- /* sprintf(buf, "mkdir -p %s", socket_dirname); */
- /* system(buf); */
-
- if(mkdir(socket_dirname, S_IRWXU) != 0){
- if(errno != EEXIST){
- tomd_panic("socket mkdir");
- }else{
- tomd_p("socket dir exists.");
- }
- }
-
- tomd_p("removing file '%s'", socket_filename);
- if(unlink(socket_filename) != 0){
- if(errno == ENOENT){
- tomd_p("socket file doesn't exist");
- }else{
- tomd_panic("socket unlink");
- }
- }
-}
-
-static void socket_init(void)
-{
- gen_socket_filename();
-
- /* listen on socket, respond to requests. */
- /* perform all registered 'tick' operations */
- sfd =
- socket(PF_LOCAL, /* namespace - local unix socket */
- SOCK_STREAM, /* style */
- 0); /* protocol */
-
- if(sfd < 0){
- tomd_panic("socket");
- }
-
- if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1){
- tomd_panic("fnctl");
- }
-
- struct sockaddr_un name;
- size_t size;
-
- name.sun_family = AF_LOCAL;
- strncpy(name.sun_path,
- socket_filename,
- sizeof(name.sun_path));
-
- size = SUN_LEN(&name);
- tomd_p("attempting to bind to '%s'",
- socket_filename);
- if(bind(sfd,
- (struct sockaddr *) &name,
- size) < 0){
- tomd_panic("bind");
- }
-
- tomd_p("initialized tomd socket connections");
-}
-
-static void init(void)
-{
- socket_init();
- load_jobs();
-}
-
-#define SEND_ACK { \
- int size; \
- char ACK[4]; \
- ACK[0] = 'A'; \
- ACK[1] = 'C'; \
- ACK[2] = 'K'; \
- ACK[3] = '\0'; \
- if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
- tomd_p("didn't send as much as we though (%d != %d)", \
- size, sizeof(ACK)); \
- } \
- }
-
-#define CHDIR 0
-#define DONT_CHDIR 1
-#define CLOSE_PIPES 0
-#define DONT_CLOSE_PIPES 1
-
-static void daemonize(void)
-{
- /* daemon is in unistd. */
- /* arg1 - 0 changes dir to / */
- /* arg2 - 0 closes all pipes (/dev/null) */
- /* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE
- PROCESS */
- /* daemon will exit the original process. */
- daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
-}
-
-#define READ_SOCKET { \
- memset(buf, 0, sizeof(buf)); \
- int size = read(asfd, buf, 100); \
- buf[size] = '\0'; \
- }
-
-static int validate_sender(int asfd, char *buf)
-{
- READ_SOCKET;
- if(strcmp(buf, "client:tomc") == 0){
- SEND_ACK;
- return 0;
- }
- tomd_p("received '%s' instead of client:tomc", buf);
- return -1;
-}
-
-enum requests { KILL, STATUS, STOP, START, UNKNOWN};
-#define X(a, b) { a, b }
-static struct {
- char *str;
- enum requests request;
-} request_types[] =
- {
- X("kill", KILL),
- X("status", STATUS),
- X("start", START),
- X("stop", STOP),
- X(NULL, -1)
- };
-#undef X
-
-static void handle_request(int asfd, char *buf)
-{
- READ_SOCKET;
- enum requests request = UNKNOWN;
- int i = 0;
- while(1){
- if(request_types[i].str == NULL){
- break;
- }
-
- tomd_p("loop [%d]: comparing '%s' to '%s'",
- i, buf, request_types[i].str);
- if(strcmp(buf, request_types[i].str) == 0){
- request = request_types[i].request;
- break;
- }
-
- i++;
- }
-
- if(request == UNKNOWN){
- tomd_p("unknown request type!");
- return;
- }
-
- SEND_ACK;
- READ_SOCKET;
- // cross reference given name against known services
- tomd_p("looking up '%s'", buf);
- SEND_ACK;
- struct job *jp = lookup_job(buf);
-#define DOUBLE_DUTY(...) { \
- char tmp[100]; \
- tomd_p(__VA_ARGS__); \
- sprintf(tmp, __VA_ARGS__); \
- int tmplen = strlen(tmp); \
- tomd_p("__debug__:'%s'", tmp); \
- write(asfd, tmp, tmplen); \
- }
- if(jp == NULL){
- DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
- } else {
- tomd_p("-----");
- DOUBLE_DUTY("found job record for '%s'\n", jp->name);
-
- if(request == STATUS){
- if(jp->pid != -1){
- int status = 0;
- int n_pid = waitpid(jp->pid, &status, WNOHANG);
- if(n_pid < 0){
- perror("[tomd] waitpid");
- }else if(n_pid == 0){
- DOUBLE_DUTY("waitpid == 0, check manual\n");
- }else{
- DOUBLE_DUTY("running: %s\n",
- !WIFEXITED(status) ? "yes"
- : "no");
-
- if(WIFEXITED(status)){
- DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status));
- jp->pid = -1;
- jp->last_status = status;
- }
- }
- }else{
- DOUBLE_DUTY("running: no\n");
- DOUBLE_DUTY(" status: %d\n", jp->last_status);
- }
-
- if(jp->pid != -1){
- DOUBLE_DUTY(" pid: %d\n", jp->pid);
- }
- }else{
- DOUBLE_DUTY("don't know how to handle that request.\n");
- }
- }
- tomd_p("-----");
- tomd_p("sending ack.");
- SEND_ACK;
- tomd_p("ack is sent.");
- get_ack:
- READ_SOCKET;
- if(strcmp(buf, "ACK") != 0)
- goto get_ack;
- tomd_p("ack was ack'd.");
-}
-
-static void handle_connection(int asfd)
-{
- char buf[100] = {};
-
- if(validate_sender(asfd, buf) != 0){
- tomd_p("invalid sender.");
- return;
- }
-
- tomd_p("validated client");
- handle_request(asfd, buf);
-
- shutdown(asfd, SHUT_WR);
- close(asfd);
-}
-
-static void run(void)
-{
- /* loop: */
- /* 1 listen */
- /* 2 accept/select */
- /* 3 handle dgram */
- int listen_bool =
- listen(sfd,
- 10); /* max connection limit is 10 for arbitrary reasons */
- if(listen_bool == -1){
- tomd_panic("listen");
- }
-
- for(;;){
- struct sockaddr addr;
- /* sometimes gives EINVAL if not initialized. */
- socklen_t size = sizeof(addr);
- errno = 0;
- int accept_sfd =
- accept(sfd,
- &addr, /* requester info */
- &size); /* len of requester info */
- if(accept_sfd < 0){
- if(errno == EINVAL){
- tomd_p("EINVAL");
- }else if(errno == EWOULDBLOCK || errno == EAGAIN){
- /* no worries */
- }else {
- tomd_panic("accept socket");
- }
- } else {
- handle_connection(accept_sfd);
- }
-
- check_root_job();
- usleep(10);
- }
-}
-
-static void cleanup(void)
-{
- if(sfd >= 0){
- close(sfd);
- }
-}
-
-int main(int argc, char **argv)
-{
- header();
- init();
- /* daemonize(); */
- run_jobs();
- /* silent(); */
- run();
- cleanup();
-
- return EXIT_SUCCESS;
-}