aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/harddog_user.c
blob: 5eeecf8917c3158b31a6ef960a14a7d9312f4d1b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
 * Licensed under the GPL
 */

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include "user.h"
#include "mconsole.h"
#include "os.h"
#include "choose-mode.h"
#include "mode.h"

struct dog_data {
	int stdin;
	int stdout;
	int close_me[2];
};

static void pre_exec(void *d)
{
	struct dog_data *data = d;

	dup2(data->stdin, 0);
	dup2(data->stdout, 1);
	dup2(data->stdout, 2);
	os_close_file(data->stdin);
	os_close_file(data->stdout);
	os_close_file(data->close_me[0]);
	os_close_file(data->close_me[1]);
}

int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
{
	struct dog_data data;
	int in_fds[2], out_fds[2], pid, n, err;
	char pid_buf[sizeof("nnnnn\0")], c;
	char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
	char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL,
				  NULL };
	char **args = NULL;

	err = os_pipe(in_fds, 1, 0);
	if(err < 0){
		printk("harddog_open - os_pipe failed, err = %d\n", -err);
		goto out;
	}

	err = os_pipe(out_fds, 1, 0);
	if(err < 0){
		printk("harddog_open - os_pipe failed, err = %d\n", -err);
		goto out_close_in;
	}

	data.stdin = out_fds[0];
	data.stdout = in_fds[1];
	data.close_me[0] = out_fds[1];
	data.close_me[1] = in_fds[0];

	if(sock != NULL){
		mconsole_args[2] = sock;
		args = mconsole_args;
	}
	else {
		/* XXX The os_getpid() is not SMP correct */
		sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid()));
		args = pid_args;
	}

	pid = run_helper(pre_exec, &data, args, NULL);

	os_close_file(out_fds[0]);
	os_close_file(in_fds[1]);

	if(pid < 0){
		err = -pid;
		printk("harddog_open - run_helper failed, errno = %d\n", -err);
		goto out_close_out;
	}

	n = os_read_file(in_fds[0], &c, sizeof(c));
	if(n == 0){
		printk("harddog_open - EOF on watchdog pipe\n");
		helper_wait(pid);
		err = -EIO;
		goto out_close_out;
	}
	else if(n < 0){
		printk("harddog_open - read of watchdog pipe failed, "
		       "err = %d\n", -n);
		helper_wait(pid);
		err = n;
		goto out_close_out;
	}
	*in_fd_ret = in_fds[0];
	*out_fd_ret = out_fds[1];
	return 0;

 out_close_in:
	os_close_file(in_fds[0]);
	os_close_file(in_fds[1]);
 out_close_out:
	os_close_file(out_fds[0]);
	os_close_file(out_fds[1]);
 out:
	return err;
}

void stop_watchdog(int in_fd, int out_fd)
{
	os_close_file(in_fd);
	os_close_file(out_fd);
}

int ping_watchdog(int fd)
{
	int n;
	char c = '\n';

	n = os_write_file(fd, &c, sizeof(c));
	if(n != sizeof(c)){
		printk("ping_watchdog - write failed, err = %d\n", -n);
		if(n < 0)
			return n;
		return -EIO;
	}
	return 1;

}