1 /*
2 * Copyright 2004-2012 Red Hat, Inc.
3 *
4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions
6 * of the GNU General Public License v2 or (at your option) any later version.
7 */
8
9 #include "dlm_daemon.h"
10
11 static int run_agent(char *agent, char *args, int *pid_out)
12 {
13 int pid, len;
14 int pw_fd = -1; /* parent write file descriptor */
15 int cr_fd = -1; /* child read file descriptor */
16 int pfd[2];
17
18 len = strlen(args);
19
|
(1) Event cond_false: |
Condition "pipe(pfd)", taking false branch. |
20 if (pipe(pfd))
|
(2) Event if_end: |
End of if statement. |
21 return -errno;
22
23 cr_fd = pfd[0];
24 pw_fd = pfd[1];
25
26 pid = fork();
|
(3) Event cond_false: |
Condition "pid < 0", taking false branch. |
27 if (pid < 0) {
28 close(cr_fd);
29 close(pw_fd);
30 return -errno;
|
(4) Event if_end: |
End of if statement. |
31 }
32
|
(5) Event cond_false: |
Condition "pid", taking false branch. |
33 if (pid) {
34 /* parent */
35 int ret;
36
37 do {
38 ret = write(pw_fd, args, len);
39 } while (ret < 0 && errno == EINTR);
40
41 if (ret != len)
42 goto fail;
43
44 close(cr_fd);
45 close(pw_fd);
46
47 *pid_out = pid;
48 return 0;
|
(6) Event else_branch: |
Reached else branch. |
49 } else {
50 /* child */
51 int c_stdout, c_stderr;
52
53 /* redirect agent stdout/stderr to /dev/null */
54 close(1);
|
(7) Event open_fn: |
Returning handle opened by "open". [Note: The source code implementation of the function has been overridden by a user model.] |
|
(8) Event var_assign: |
Assigning: "c_stdout" = handle returned from "open("/dev/null", 1)". |
| Also see events: |
[leaked_handle] |
55 c_stdout = open("/dev/null", O_WRONLY);
|
(9) Event cond_false: |
Condition "c_stdout < 0", taking false branch. |
56 if (c_stdout < 0)
|
(10) Event if_end: |
End of if statement. |
57 goto fail;
58 close(2);
59 c_stderr = open("/dev/null", O_WRONLY);
|
(11) Event cond_true: |
Condition "c_stderr < 0", taking true branch. |
60 if (c_stderr < 0)
|
(12) Event goto: |
Jumping to label "fail". |
|
(13) Event leaked_handle: |
Handle variable "c_stdout" going out of scope leaks the handle. |
| Also see events: |
[open_fn][var_assign] |
61 goto fail;
62
63 /* redirect agent stdin from parent */
64 close(0);
65 if (dup(cr_fd) < 0)
66 goto fail;
67
68 close(cr_fd);
69 close(pw_fd);
70
71 execlp(agent, agent, NULL);
72 exit(EXIT_FAILURE);
73 }
74 fail:
75 close(cr_fd);
76 close(pw_fd);
77 return -1;
78 }
79
80 int fence_request(int nodeid, uint64_t fail_walltime, uint64_t fail_monotime,
81 struct fence_config *fc, int reason, int *pid_out)
82 {
83 struct fence_device *dev;
84 char args[FENCE_CONFIG_ARGS_MAX];
85 char extra[FENCE_CONFIG_NAME_MAX];
86 int rv, pid = -1;
87
88 memset(args, 0, sizeof(args));
89
90 memset(extra, 0, sizeof(extra));
91 snprintf(extra, sizeof(extra)-1, "fail_time=%llu\n", (unsigned long long)fail_walltime);
92
93 dev = fc->dev[fc->pos];
94 if (!dev) {
95 log_error("fence request %d no config pos %d", nodeid, fc->pos);
96 return -1;
97 }
98
99 rv = fence_config_agent_args(fc, extra, args);
100 if (rv < 0) {
101 log_error("fence request %d config args error %d", nodeid, rv);
102 return rv;
103 }
104
105 rv = run_agent(dev->agent, args, &pid);
106 if (rv < 0) {
107 log_error("fence request %d pid %d %s time %llu %s %s run error %d",
108 nodeid, pid, reason_str(reason), (unsigned long long)fail_walltime,
109 dev->name, dev->agent, rv);
110 return rv;
111 }
112
113 log_error("fence request %d pid %d %s time %llu %s %s",
114 nodeid, pid, reason_str(reason), (unsigned long long)fail_walltime,
115 dev->name, dev->agent);
116
117 *pid_out = pid;
118 return 0;
119 }
120
121 /*
122 * if pid has exited, return 0
123 * result is 0 for success, non-zero for fail
124 * success if pid exited with exit status 0
125 * fail if pid exited with non-zero exit status, or was terminated by signal
126 *
127 * if pid is running, return -EAGAIN
128 *
129 * other error, return -EXXX
130 */
131
132 int fence_result(int nodeid, int pid, int *result)
133 {
134 int status, rv;
135
136 rv = waitpid(pid, &status, WNOHANG);
137
138 if (rv < 0) {
139 /* shouldn't happen */
140 log_error("fence result %d pid %d waitpid %d errno %d",
141 nodeid, pid, rv, errno);
142 return rv;
143 }
144
145 if (!rv) {
146 /* pid still running, has not changed state */
147 return -EAGAIN;
148 }
149
150 if (rv == pid) {
151 /* pid state has changed */
152
153 if (WIFEXITED(status)) {
154 /* pid exited with an exit code */
155 *result = WEXITSTATUS(status);
156
157 log_error("fence result %d pid %d result %d exit status",
158 nodeid, pid, *result);
159 return 0;
160 }
161 if (WIFSIGNALED(status)) {
162 /* pid terminated due to a signal */
163 *result = -1;
164
165 log_error("fence result %d pid %d result %d term signal %d",
166 nodeid, pid, *result, WTERMSIG(status));
167 return 0;
168 }
169
170 /* pid state changed but still running */
171 return -EAGAIN;
172 }
173
174 /* shouldn't happen */
175 log_error("fence result %d pid %d waitpid rv %d", nodeid, pid, rv);
176 return -1;
177 }
178
179 int unfence_node(int nodeid)
180 {
181 struct fence_config config;
182 struct fence_device *dev;
183 char args[FENCE_CONFIG_ARGS_MAX];
184 char action[FENCE_CONFIG_NAME_MAX];
185 int rv, i, pid, status;
186 int error = 0;
187
188 memset(&config, 0, sizeof(config));
189
190 rv = fence_config_init(&config, nodeid, (char *)CONF_FILE_PATH);
191 if (rv == -ENOENT) {
192 /* file doesn't exist or doesn't contain config for nodeid */
193 return 0;
194 }
195 if (rv < 0) {
196 /* there's a problem with the config */
197 log_error("unfence %d fence_config_init error %d", nodeid, rv);
198 return rv;
199 }
200
201 memset(action, 0, sizeof(action));
202 snprintf(action, FENCE_CONFIG_NAME_MAX-1, "action=on\n");
203
204 for (i = 0; i < FENCE_CONFIG_DEVS_MAX; i++) {
205 dev = config.dev[i];
206 if (!dev)
207 break;
208 if (!dev->unfence)
209 continue;
210
211 config.pos = i;
212
213 memset(args, 0, sizeof(args));
214
215 rv = fence_config_agent_args(&config, action, args);
216 if (rv < 0) {
217 log_error("unfence %d config args error %d", nodeid, rv);
218 error = -1;
219 break;
220 }
221
222 rv = run_agent(dev->agent, args, &pid);
223 if (rv < 0) {
224 log_error("unfence %d %s %s run error %d", nodeid,
225 dev->name, dev->agent, rv);
226 error = -1;
227 break;
228 }
229
230 log_error("unfence %d pid %d %s %s", nodeid, pid,
231 dev->name, dev->agent);
232
233 rv = waitpid(pid, &status, 0);
234 if (rv < 0) {
235 log_error("unfence %d pid %d waitpid errno %d",
236 nodeid, pid, errno);
237 error = -1;
238 break;
239 }
240
241 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
242 log_error("unfence %d pid %d error status %d",
243 nodeid, pid, status);
244 error = -1;
245 break;
246 }
247 }
248
249 fence_config_free(&config);
250
251 return error;
252 }
253
254