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