libamxp  1.4.0
Patterns C Implementation
amxp_proc_ctrl.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdlib.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <limits.h>
63 #include <sys/inotify.h>
64 #include <unistd.h>
65 #include <fcntl.h>
66 #include <errno.h>
67 
68 #include <amxc/amxc.h>
69 #include <amxc/amxc_macros.h>
70 #include <amxp/amxp.h>
71 
72 #define PROC_CHILDREN "/proc/%d/task/%d/children"
73 
74 static void amxp_proc_ctrl_free_char(amxc_array_it_t* it) {
75  char* txt = (char*) amxc_array_it_get_data(it);
76  free(txt);
77 }
78 
80  void* data) {
81  amxp_proc_ctrl_t* proc = (amxp_proc_ctrl_t*) data;
82  amxc_var_t pid;
83  amxc_var_init(&pid);
84  amxc_var_set(uint32_t, &pid, proc->proc->pid);
85  amxp_sigmngr_emit_signal(NULL, "proc:disable", &pid);
86  amxp_proc_ctrl_stop(proc);
87 
88  amxc_var_clean(&pid);
89 }
90 
91 static void amxp_proc_ctrl_stopped(UNUSED const char* const event_name,
92  UNUSED const amxc_var_t* const event_data,
93  void* const priv) {
94  amxp_proc_ctrl_t* proc = (amxp_proc_ctrl_t*) priv;
95  amxc_var_t pid;
96  amxc_var_init(&pid);
97 
98  when_null(proc, leave);
99 
100  amxc_var_set(uint32_t, &pid, proc->proc->pid);
101  amxp_timer_stop(proc->timer);
103 
104  amxp_sigmngr_emit_signal(NULL, "proc:stopped", &pid);
105 
106 leave:
107  amxc_var_clean(&pid);
108 }
109 
111  int retval = -1;
112  FILE* fp = NULL;
113  amxc_string_t file;
114  pid_t ppid = 0;
115  ssize_t read = 0;
116  char* line = NULL;
117  size_t len = 0;
118 
119  amxc_string_init(&file, 0);
120 
121  ppid = amxp_subproc_get_pid(proc->proc);
122  amxc_var_set_type(&proc->child_proc_pids, AMXC_VAR_ID_LIST);
123 
124  amxc_string_setf(&file, PROC_CHILDREN, ppid, ppid);
125  fp = fopen(amxc_string_get(&file, 0), "r");
126  if(fp == NULL) {
127  goto leave;
128  }
129 
130  read = getline(&line, &len, fp);
131  if(read == -1) {
132  free(line);
133  goto leave;
134  }
135 
136  amxc_var_push(ssv_string_t, &proc->child_proc_pids, line);
137  amxc_var_cast(&proc->child_proc_pids, AMXC_VAR_ID_LIST);
138 
139  retval = 0;
140 
141 leave:
142  if(fp != NULL) {
143  fclose(fp);
144  }
145  amxc_string_clean(&file);
146  return retval;
147 }
148 
150  int retval = -1;
151  amxc_llist_t children;
152 
153  amxc_llist_init(&children);
154  retval = amxp_proci_findf(&children,
155  "ppid == %d", amxp_subproc_get_pid(proc->proc));
156 
157  when_failed(retval, leave);
158  amxc_var_set_type(&proc->child_proc_pids, AMXC_VAR_ID_LIST);
159 
160  amxc_llist_iterate(it, (&children)) {
161  amxp_proc_info_t* pi = amxc_container_of(it, amxp_proc_info_t, it);
162  amxc_var_add(int32_t, &proc->child_proc_pids, pi->pid);
163  }
164 
165 leave:
166  amxc_llist_clean(&children, amxp_proci_free_it);
167  return retval;
168 }
169 
171  int retval = -1;
172  when_null(proc, leave);
173  when_null(cmd_build_fn, leave);
174 
175  *proc = (amxp_proc_ctrl_t*) calloc(1, sizeof(amxp_proc_ctrl_t));
176  when_null(*proc, leave);
177 
178  when_failed(amxp_subproc_new(&(*proc)->proc), leave);
179  when_failed(amxp_timer_new(&(*proc)->timer, amxp_proc_ctrl_timer_callback, *proc), leave);
180  when_failed(amxc_array_init(&(*proc)->cmd, 10), leave);
181  when_failed(amxc_var_init(&(*proc)->child_proc_pids), leave);
182 
183  (*proc)->build = cmd_build_fn;
184  amxp_slot_connect((*proc)->proc->sigmngr, "stop", NULL, amxp_proc_ctrl_stopped, *proc);
185 
186  retval = 0;
187 
188 leave:
189  if((retval != 0) &&
190  ((proc != NULL) && (*proc != NULL))) {
191  amxp_subproc_delete(&(*proc)->proc);
192  amxp_timer_delete(&(*proc)->timer);
193  amxc_array_clean(&(*proc)->cmd, NULL);
194  amxc_var_clean(&(*proc)->child_proc_pids);
195  free(*proc);
196  *proc = NULL;
197  }
198  return retval;
199 }
200 
202  when_null(proc, leave);
203  when_null(*proc, leave);
204 
205  amxp_slot_disconnect((*proc)->proc->sigmngr, "stop", amxp_proc_ctrl_stopped);
206 
207  amxp_proc_ctrl_stop(*proc);
208  amxp_subproc_delete(&(*proc)->proc);
209  amxp_timer_delete(&(*proc)->timer);
210  amxc_array_clean(&(*proc)->cmd, amxp_proc_ctrl_free_char);
211  amxc_var_clean(&(*proc)->child_proc_pids);
212 
213  free(*proc);
214  *proc = NULL;
215 
216 leave:
217  return;
218 }
219 
220 int amxp_proc_ctrl_start(amxp_proc_ctrl_t* proc, uint32_t minutes, amxc_var_t* settings) {
221  int retval = -1;
222  when_null(proc, leave);
223 
224  amxc_array_clean(&proc->cmd, amxp_proc_ctrl_free_char);
225  retval = proc->build(&proc->cmd, settings);
226  when_failed(retval, leave);
227  when_true(amxc_array_is_empty(&proc->cmd), leave);
228 
229  retval = amxp_subproc_astart(proc->proc, &proc->cmd);
230  when_failed(retval, leave);
231 
232  if(minutes != 0) {
233  amxp_timer_start(proc->timer, minutes * 60 * 1000);
234  }
235 
236  retval = 0;
237 
238 leave:
239  return retval;
240 }
241 
243  int retval = -1;
244  when_null(proc, leave);
245 
246  amxp_timer_stop(proc->timer);
247 
250 
251  amxp_subproc_kill(proc->proc, SIGTERM);
252  retval = amxp_subproc_wait(proc->proc, 2000);
253  if(retval == 1) {
254  // not stopped after waiting for 2 seconds
255  // forcekill
256  amxp_subproc_kill(proc->proc, SIGKILL);
257  retval = amxp_subproc_wait(proc->proc, 2000);
258  }
259 
260 leave:
261  return retval;
262 }
263 
265  when_null(proc, leave);
266 
267  if(minutes == 0) {
268  amxp_timer_stop(proc->timer);
269  } else {
270  if(amxp_subproc_is_running(proc->proc)) {
271  // reset timer to new duration time
272  amxp_timer_start(proc->timer, minutes * 60 * 1000);
273  }
274  }
275 
276 leave:
277  return;
278 }
279 
281  when_null(proc, leave);
282 
283  if(amxc_var_type_of(&proc->child_proc_pids) == AMXC_VAR_ID_LIST) {
284  amxc_var_for_each(child_pid, (&proc->child_proc_pids)) {
285  pid_t pid = amxc_var_dyncast(uint32_t, child_pid);
286  kill(pid, SIGTERM);
287  }
288  }
289 
290 leave:
291  return;
292 }
293 
295  int retval = -1;
296  when_null(proc, leave);
297 
298  when_false(amxp_subproc_is_running(proc->proc), leave);
300  if(retval == 0) {
301  goto leave;
302  }
303 
305 
306 leave:
307  if(retval == 0) {
308  const amxc_llist_t* list = amxc_var_constcast(amxc_llist_t, &proc->child_proc_pids);
309  retval = amxc_llist_size(list);
310  }
311  return retval;
312 }
static int amxp_proc_ctrl_get_child_pids_scan_proc(amxp_proc_ctrl_t *proc)
static void amxp_proc_ctrl_timer_callback(UNUSED amxp_timer_t *const timer, void *data)
static void amxp_proc_ctrl_stopped(UNUSED const char *const event_name, UNUSED const amxc_var_t *const event_data, void *const priv)
#define PROC_CHILDREN
static int amxp_proc_ctrl_get_child_pids_proc_children(amxp_proc_ctrl_t *proc)
static void amxp_proc_ctrl_free_char(amxc_array_it_t *it)
#define UNUSED
Definition: main.c:68
int amxp_proc_ctrl_stop(amxp_proc_ctrl_t *proc)
Stops the child process.
void amxp_proc_ctrl_set_active_duration(amxp_proc_ctrl_t *proc, uint32_t minutes)
Sets the active time durations.
int(* amxp_proc_ctrl_cmd_t)(amxc_array_t *cmd, amxc_var_t *settings)
Command builder callback function signature.
int amxp_proc_ctrl_new(amxp_proc_ctrl_t **proc, amxp_proc_ctrl_cmd_t cmd_build_fn)
Allocates and initializes an amxp_proc_ctrl_t.
int amxp_proc_ctrl_start(amxp_proc_ctrl_t *proc, uint32_t minutes, amxc_var_t *settings)
Launches the child process.
void amxp_proc_ctrl_delete(amxp_proc_ctrl_t **proc)
Clean-up and frees previously allocated memory.
void amxp_proc_ctrl_stop_childs(amxp_proc_ctrl_t *proc)
Stop all child processes of the child process.
int amxp_proc_ctrl_get_child_pids(amxp_proc_ctrl_t *proc)
Fetches the process ids of the children of the launched child process.
void amxp_proci_free_it(amxc_llist_it_t *it)
Delete a amxp_proc_info_t by it is linked list iterator.
int amxp_proci_findf(amxc_llist_t *result, const char *filter,...)
Build a linked list of running processes.
int amxp_sigmngr_emit_signal(const amxp_signal_mngr_t *const sig_mngr, const char *name, const amxc_var_t *const data)
Emits a signal.
Definition: amxp_signal.c:514
int amxp_slot_disconnect(amxp_signal_mngr_t *const sig_mngr, const char *const sig_name, amxp_slot_fn_t fn)
Disconnects a slot from (a) signal(s).
Definition: amxp_slot.c:380
int amxp_slot_connect(amxp_signal_mngr_t *const sig_mngr, const char *const sig_name, const char *const expression, amxp_slot_fn_t fn, void *const priv)
Connects a slot (function) to a named signal of a signal manager.
Definition: amxp_slot.c:300
bool amxp_subproc_is_running(const amxp_subproc_t *const subproc)
Checks if the child process is running.
Definition: amxp_subproc.c:423
int amxp_subproc_new(amxp_subproc_t **subproc)
Constructor function, creates a new child process data structure.
Definition: amxp_subproc.c:215
int amxp_subproc_kill(const amxp_subproc_t *const subproc, const int sig)
Sends a Linux signal to the child process.
Definition: amxp_subproc.c:391
int amxp_subproc_wait(amxp_subproc_t *subproc, int timeout_msec)
Waits until the child process has stopped.
Definition: amxp_subproc.c:428
int amxp_subproc_astart(amxp_subproc_t *const subproc, amxc_array_t *cmd)
Start a child process.
Definition: amxp_subproc.c:365
int amxp_subproc_delete(amxp_subproc_t **subproc)
Destructor function, deletes a child process data structure.
Definition: amxp_subproc.c:239
pid_t amxp_subproc_get_pid(const amxp_subproc_t *const subproc)
Get the PID of a child process.
Definition: amxp_subproc.c:415
int amxp_timer_start(amxp_timer_t *timer, unsigned int timeout_msec)
Starts or resets a timer.
Definition: amxp_timer.c:296
int amxp_timer_stop(amxp_timer_t *timer)
Stops the timer.
Definition: amxp_timer.c:319
void amxp_timer_delete(amxp_timer_t **timer)
Deletes a timer.
Definition: amxp_timer.c:247
int amxp_timer_new(amxp_timer_t **timer, amxp_timer_cb_t cb, void *priv)
Allocate and initializes a new timer.
Definition: amxp_timer.c:229
Structure containing the child process control.
amxp_proc_ctrl_cmd_t build
amxc_array_t cmd
amxp_timer_t * timer
amxc_var_t child_proc_pids
amxp_subproc_t * proc
The timer type.
Definition: amxp_timer.h:163
Structure containing the process information.
int32_t pid