93977d9c3beb1602aaa6c3332e97e71620415e24
[sharpe/samba-autobuild/.git] / ctdb / server / ctdb_fork.c
1 /* 
2    functions to track and manage processes
3
4    Copyright (C) Ronnie Sahlberg 2012
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/wait.h"
22 #include "system/network.h"
23
24 #include <talloc.h>
25 #include <tevent.h>
26
27 #include "lib/util/debug.h"
28
29 #include "ctdb_private.h"
30 #include "ctdb_client.h"
31
32 #include "common/rb_tree.h"
33 #include "common/system.h"
34 #include "common/common.h"
35 #include "common/logging.h"
36
37 void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...)
38 {
39         if (child_name_fmt != NULL) {
40                 va_list ap;
41                 char *t;
42
43                 va_start(ap, child_name_fmt);
44                 t = talloc_vasprintf(mem_ctx, child_name_fmt, ap);
45                 debug_extra = talloc_asprintf(mem_ctx, "%s:", t);
46                 talloc_free(t);
47                 va_end(ap);
48         }
49 }
50
51 void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid)
52 {
53         char *process;
54
55         /* Only CTDB main daemon should track child processes */
56         if (getpid() != ctdb->ctdbd_pid) {
57                 return;
58         }
59
60         process = talloc_asprintf(ctdb->child_processes, "process:%d", (int)pid);
61         trbt_insert32(ctdb->child_processes, pid, process);
62 }
63
64 /*
65  * This function forks a child process and drops the realtime 
66  * scheduler for the child process.
67  */
68 pid_t ctdb_fork(struct ctdb_context *ctdb)
69 {
70         pid_t pid;
71
72         pid = fork();
73         if (pid == -1) {
74                 DEBUG(DEBUG_ERR,
75                       (__location__ " fork() failed (%s)\n", strerror(errno)));
76                 return -1;
77         }
78         if (pid == 0) {
79                 ctdb_set_child_info(ctdb, NULL);
80
81                 /* Close the Unix Domain socket and the TCP socket.
82                  * This ensures that none of the child processes will
83                  * look like the main daemon when it is not running.
84                  * tevent needs to be stopped before closing sockets.
85                  */
86                 if (ctdb->ev != NULL) {
87                         talloc_free(ctdb->ev);
88                         ctdb->ev = NULL;
89                 }
90                 if (ctdb->daemon.sd != -1) {
91                         close(ctdb->daemon.sd);
92                         ctdb->daemon.sd = -1;
93                 }
94                 if (ctdb->methods != NULL) {
95                         ctdb->methods->shutdown(ctdb);
96                 }
97
98                 /* The child does not need to be realtime */
99                 if (ctdb->do_setsched) {
100                         reset_scheduler();
101                 }
102                 ctdb->can_send_controls = false;
103
104                 return 0;
105         }
106
107         ctdb_track_child(ctdb, pid);
108         return pid;
109 }
110
111 static void ctdb_sigchld_handler(struct tevent_context *ev,
112         struct tevent_signal *te, int signum, int count,
113         void *dont_care, 
114         void *private_data)
115 {
116         struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
117         int status;
118         pid_t pid = -1;
119
120         while (pid != 0) {
121                 pid = waitpid(-1, &status, WNOHANG);
122                 if (pid == -1) {
123                         DEBUG(DEBUG_ERR, (__location__ " waitpid() returned error. errno:%d\n", errno));
124                         return;
125                 }
126                 if (pid > 0) {
127                         char *process;
128
129                         if (getpid() != ctdb->ctdbd_pid) {
130                                 continue;
131                         }
132
133                         process = trbt_lookup32(ctdb->child_processes, pid);
134                         if (process == NULL) {
135                                 DEBUG(DEBUG_ERR,("Got SIGCHLD from pid:%d we didn not spawn with ctdb_fork\n", pid));
136                         }
137
138                         DEBUG(DEBUG_DEBUG, ("SIGCHLD from %d %s\n", (int)pid, process));
139                         talloc_free(process);
140                 }
141         }
142 }
143
144
145 struct tevent_signal *
146 ctdb_init_sigchld(struct ctdb_context *ctdb)
147 {
148         struct tevent_signal *se;
149
150         ctdb->child_processes = trbt_create(ctdb, 0);
151
152         se = tevent_add_signal(ctdb->ev, ctdb, SIGCHLD, 0, ctdb_sigchld_handler, ctdb);
153         return se;
154 }
155
156 int
157 ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum)
158 {
159         char *process;
160
161         if (signum == 0) {
162                 return kill(pid, signum);
163         }
164
165         if (getpid() != ctdb->ctdbd_pid) {
166                 return kill(pid, signum);
167         }
168
169         process = trbt_lookup32(ctdb->child_processes, pid);
170         if (process == NULL) {
171                 DEBUG(DEBUG_ERR,("ctdb_kill: trying to kill(%d, %d) a process that does not exist\n", pid, signum));
172                 return 0;
173         }
174
175         return kill(pid, signum);
176 }