| Jeff Dike | 5bbcbec | 2007-02-10 01:43:58 -0800 | [diff] [blame] | 1 | /* | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 2 |  * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3 |  * Licensed under the GPL | 
 | 4 |  */ | 
 | 5 |  | 
 | 6 | #include <stdio.h> | 
 | 7 | #include <unistd.h> | 
 | 8 | #include <errno.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | #include "os.h" | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 10 | #include "user.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 |  | 
 | 12 | struct dog_data { | 
 | 13 | 	int stdin; | 
 | 14 | 	int stdout; | 
 | 15 | 	int close_me[2]; | 
 | 16 | }; | 
 | 17 |  | 
 | 18 | static void pre_exec(void *d) | 
 | 19 | { | 
 | 20 | 	struct dog_data *data = d; | 
 | 21 |  | 
 | 22 | 	dup2(data->stdin, 0); | 
 | 23 | 	dup2(data->stdout, 1); | 
 | 24 | 	dup2(data->stdout, 2); | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 25 | 	close(data->stdin); | 
 | 26 | 	close(data->stdout); | 
 | 27 | 	close(data->close_me[0]); | 
 | 28 | 	close(data->close_me[1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | } | 
 | 30 |  | 
 | 31 | int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | 
 | 32 | { | 
 | 33 | 	struct dog_data data; | 
 | 34 | 	int in_fds[2], out_fds[2], pid, n, err; | 
 | 35 | 	char pid_buf[sizeof("nnnnn\0")], c; | 
 | 36 | 	char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; | 
| Jeff Dike | 5bbcbec | 2007-02-10 01:43:58 -0800 | [diff] [blame] | 37 | 	char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 | 				  NULL }; | 
 | 39 | 	char **args = NULL; | 
 | 40 |  | 
 | 41 | 	err = os_pipe(in_fds, 1, 0); | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 42 | 	if (err < 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | 		printk("harddog_open - os_pipe failed, err = %d\n", -err); | 
 | 44 | 		goto out; | 
 | 45 | 	} | 
 | 46 |  | 
 | 47 | 	err = os_pipe(out_fds, 1, 0); | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 48 | 	if (err < 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | 		printk("harddog_open - os_pipe failed, err = %d\n", -err); | 
 | 50 | 		goto out_close_in; | 
 | 51 | 	} | 
 | 52 |  | 
 | 53 | 	data.stdin = out_fds[0]; | 
 | 54 | 	data.stdout = in_fds[1]; | 
 | 55 | 	data.close_me[0] = out_fds[1]; | 
 | 56 | 	data.close_me[1] = in_fds[0]; | 
 | 57 |  | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 58 | 	if (sock != NULL) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | 		mconsole_args[2] = sock; | 
 | 60 | 		args = mconsole_args; | 
 | 61 | 	} | 
 | 62 | 	else { | 
 | 63 | 		/* XXX The os_getpid() is not SMP correct */ | 
| Jeff Dike | 6aa802c | 2007-10-16 01:26:56 -0700 | [diff] [blame] | 64 | 		sprintf(pid_buf, "%d", os_getpid()); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | 		args = pid_args; | 
 | 66 | 	} | 
 | 67 |  | 
| Jeff Dike | c439901 | 2007-07-15 23:38:56 -0700 | [diff] [blame] | 68 | 	pid = run_helper(pre_exec, &data, args); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 |  | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 70 | 	close(out_fds[0]); | 
 | 71 | 	close(in_fds[1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 |  | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 73 | 	if (pid < 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | 		err = -pid; | 
 | 75 | 		printk("harddog_open - run_helper failed, errno = %d\n", -err); | 
 | 76 | 		goto out_close_out; | 
 | 77 | 	} | 
 | 78 |  | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 79 | 	n = read(in_fds[0], &c, sizeof(c)); | 
 | 80 | 	if (n == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | 		printk("harddog_open - EOF on watchdog pipe\n"); | 
| Al Viro | c63f702 | 2007-12-23 20:01:04 +0000 | [diff] [blame] | 82 | 		helper_wait(pid, 1, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | 		err = -EIO; | 
 | 84 | 		goto out_close_out; | 
 | 85 | 	} | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 86 | 	else if (n < 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | 		printk("harddog_open - read of watchdog pipe failed, " | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 88 | 		       "err = %d\n", errno); | 
| Al Viro | c63f702 | 2007-12-23 20:01:04 +0000 | [diff] [blame] | 89 | 		helper_wait(pid, 1, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | 		err = n; | 
 | 91 | 		goto out_close_out; | 
 | 92 | 	} | 
 | 93 | 	*in_fd_ret = in_fds[0]; | 
 | 94 | 	*out_fd_ret = out_fds[1]; | 
| Jeff Dike | 5bbcbec | 2007-02-10 01:43:58 -0800 | [diff] [blame] | 95 | 	return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 |  | 
 | 97 |  out_close_in: | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 98 | 	close(in_fds[0]); | 
 | 99 | 	close(in_fds[1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 |  out_close_out: | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 101 | 	close(out_fds[0]); | 
 | 102 | 	close(out_fds[1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 |  out: | 
| Jeff Dike | 5bbcbec | 2007-02-10 01:43:58 -0800 | [diff] [blame] | 104 | 	return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | } | 
 | 106 |  | 
 | 107 | void stop_watchdog(int in_fd, int out_fd) | 
 | 108 | { | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 109 | 	close(in_fd); | 
 | 110 | 	close(out_fd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | } | 
 | 112 |  | 
 | 113 | int ping_watchdog(int fd) | 
 | 114 | { | 
 | 115 | 	int n; | 
 | 116 | 	char c = '\n'; | 
 | 117 |  | 
| Jeff Dike | 8ca842c | 2007-10-16 01:27:08 -0700 | [diff] [blame] | 118 | 	n = write(fd, &c, sizeof(c)); | 
 | 119 | 	if (n != sizeof(c)) { | 
 | 120 | 		printk("ping_watchdog - write failed, ret = %d, err = %d\n", | 
 | 121 | 		       n, errno); | 
 | 122 | 		if (n < 0) | 
| Jeff Dike | 5bbcbec | 2007-02-10 01:43:58 -0800 | [diff] [blame] | 123 | 			return n; | 
 | 124 | 		return -EIO; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | 	} | 
 | 126 | 	return 1; | 
 | 127 |  | 
 | 128 | } |