f7665623aac09e88291ad260d3bd2ef6d47ccdb5
[tlb/tomd.git] / src / tomc / main.c
1 /* Copyright (C) 2018 Thomas Balzer */
2
3 /* This file is part of tomd. */
4
5 /* tomd is free software: you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, either version 3 of the License, or */
8 /* (at your option) any later version. */
9
10 /* tomd is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
14
15 /* You should have received a copy of the GNU General Public License */
16 /* along with tomd. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <sys/un.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23
24 #include "../../include/macros.h"
25
26 static int sfd;
27
28 static void header(void)
29 {
30 tomc_p("Tom's Client, Copyright (C) 2018 Thomas Balzer");
31 tomc_p("GPL v3 or later license.");
32 }
33
34 static void init(void)
35 {
36 /* init socket connection */
37 sfd =
38 socket(PF_LOCAL,
39 SOCK_STREAM,
40 0);
41 if(sfd < 0){
42 perror("socket");
43 exit(EXIT_FAILURE);
44 }
45
46 struct sockaddr_un addr;
47 addr.sun_family = AF_LOCAL;
48 sprintf(addr.sun_path, "/run/user/1000/tomd/socket");
49
50 if(connect(sfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) != 0){
51 perror("connect");
52 exit(EXIT_FAILURE);
53 }
54 }
55
56 static char *default_name = "no_name";
57 static struct{
58 char status, stop, kill, start;
59 char *name;
60 } options;
61
62 static void extract_options(int argc, char **argv)
63 {
64 /* -status <name> Get status - if we thought we ran it, current real status */
65 /* -stop <name> Run provided command to gently stop */
66 /* -kill <name> Aggressive killing of process (signal 15) */
67 /* -start <name> Run name */
68 if(argc == 1){
69 /* only tomc given */
70 tomc_p("no args given.");
71 exit(EXIT_SUCCESS);
72 }
73
74 options.name = NULL;
75
76 for(int i = 1;
77 i < argc;
78 i++){
79 char *arg = argv[i];
80 #define X(op) {if(strcmp("-" #op, arg) == 0){options.op = 1; continue;}}
81 X(status);
82 X(stop);
83 X(kill);
84 X(start);
85 #undef X
86 /* assume last non option was the name */
87 options.name = arg;
88 }
89
90 if(options.name == NULL){
91 options.name = default_name;
92 }
93 }
94
95 static void print_options(void)
96 {
97 tomc_p("---------");
98 tomc_p(" name: %s", options.name);
99 tomc_p(" kill: %d", options.kill);
100 tomc_p("status: %d", options.status);
101 tomc_p(" stop: %d", options.stop);
102 tomc_p(" start: %d", options.start);
103 tomc_p("---------");
104 }
105
106 static char write_buf[100];
107 static char socket_buf[100];
108
109 #define SOCK_WRITE(X) { \
110 strcpy(write_buf, X); \
111 int write_len = strlen(write_buf); \
112 ssize_t wrote = \
113 write(sfd, write_buf, write_len); \
114 tomc_p("wrote '%s' (%d)", write_buf, write_len); \
115 if(wrote != write_len){ \
116 perror("[tomc] write size mismatch"); \
117 exit(EXIT_FAILURE); \
118 }}
119
120
121 #define SOCK_READ { \
122 int size = read(sfd, socket_buf, 100); \
123 if(read == 0) { \
124 tomc_p("didn't actually get anything."); \
125 socket_buf[0] = '\0'; \
126 } \
127 socket_buf[size] = '\0'; \
128 }
129 #define SOCK_READ_X(X){ \
130 SOCK_READ; \
131 if(strcmp(socket_buf, X) != 0){ \
132 tomc_p("protocol error. instead of ACK we got '%s'", socket_buf); \
133 exit(EXIT_FAILURE); \
134 } \
135 tomc_p("got an ACK"); \
136 }
137 #define SOCK_ACK {SOCK_READ_X("ACK")};
138 #define SOCK_REQUEST(X) { \
139 SOCK_WRITE(X); \
140 SOCK_ACK; \
141 SOCK_WRITE(options.name); \
142 SOCK_ACK; \
143 SOCK_READ; \
144 tomc_p("tomd reports '%s'", socket_buf); \
145 }
146
147 static void write_client(void)
148 {
149 SOCK_WRITE("client:tomc");
150 SOCK_ACK;
151 }
152
153 static void write_requests(void)
154 {
155 write_client();
156
157 /* go through options to figure out what we want to do */
158 if(options.kill){
159 SOCK_REQUEST("kill");
160
161 if(options.start == 1 ||
162 options.stop == 1){
163 tomc_p("can only kill and status at once.");
164 }
165 } else {
166 if(options.start){
167 if(options.stop){
168 tomc_p("can't start and stop at once.");
169 }
170 SOCK_REQUEST("start");
171 }
172 if(options.stop){
173 SOCK_REQUEST("stop");
174 }
175 }
176
177 if(options.status){
178 SOCK_REQUEST("status");
179 }
180 }
181
182 int main(int argc, char **argv)
183 {
184 header();
185 extract_options(argc, argv);
186 print_options();
187 init();
188 write_requests();
189
190 return EXIT_SUCCESS;
191 }