1 /*
2  * Copyright (c) 2008, XenSource Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of XenSource Inc. nor the names of its contributors
13  *       may be used to endorse or promote products derived from this software
14  *       without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdio.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/wait.h>
35 
36 #include "tap-ctl.h"
37 #include "blktap2.h"
38 
39 static pid_t
__tap_ctl_spawn(int * readfd)40 __tap_ctl_spawn(int *readfd)
41 {
42 	int err, child, channel[2];
43 	char *tapdisk;
44 
45 	if (pipe(channel)) {
46 		EPRINTF("pipe failed: %d\n", errno);
47 		return -errno;
48 	}
49 
50 	if ((child = fork()) == -1) {
51 		EPRINTF("fork failed: %d\n", errno);
52 		return -errno;
53 	}
54 
55 	if (child) {
56 		close(channel[1]);
57 		*readfd = channel[0];
58 		return child;
59 	}
60 
61 	if (dup2(channel[1], STDOUT_FILENO) == -1) {
62 		EPRINTF("dup2 failed: %d\n", errno);
63 		exit(errno);
64 	}
65 
66 	if (dup2(channel[1], STDERR_FILENO) == -1) {
67 		EPRINTF("dup2 failed: %d\n", errno);
68 		exit(errno);
69 	}
70 
71 	close(channel[0]);
72 	close(channel[1]);
73 
74 	tapdisk = getenv("TAPDISK2");
75 	if (!tapdisk)
76 		tapdisk = "tapdisk2";
77 
78 	execlp(tapdisk, tapdisk, NULL);
79 
80 	EPRINTF("exec failed\n");
81 	exit(1);
82 }
83 
84 pid_t
tap_ctl_get_pid(const int id)85 tap_ctl_get_pid(const int id)
86 {
87 	int err;
88 	tapdisk_message_t message;
89 
90 	memset(&message, 0, sizeof(message));
91 	message.type = TAPDISK_MESSAGE_PID;
92 
93 	err = tap_ctl_connect_send_and_receive(id, &message, 2);
94 	if (err)
95 		return err;
96 
97 	return message.u.tapdisk_pid;
98 }
99 
100 static int
tap_ctl_wait(pid_t child)101 tap_ctl_wait(pid_t child)
102 {
103 	pid_t pid;
104 	int status;
105 
106 	pid = waitpid(child, &status, 0);
107 	if (pid < 0) {
108 		EPRINTF("wait(%d) failed, err %d\n", child, errno);
109 		return -errno;
110 	}
111 
112 	if (WIFEXITED(status)) {
113 		int code = WEXITSTATUS(status);
114 		if (code)
115 			EPRINTF("tapdisk2[%d] failed, status %d\n", child, code);
116 		return -code;
117 	}
118 
119 	if (WIFSIGNALED(status)) {
120 		int signo = WTERMSIG(status);
121 		EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo);
122 		return -EINTR;
123 	}
124 
125 	EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status);
126 	return -EAGAIN;
127 }
128 
129 static int
tap_ctl_get_child_id(int readfd)130 tap_ctl_get_child_id(int readfd)
131 {
132 	int id;
133 	FILE *f;
134 
135 	f = fdopen(readfd, "r");
136 	if (!f) {
137 		EPRINTF("fdopen failed: %d\n", errno);
138 		return -1;
139 	}
140 
141 	errno = 0;
142 	if (fscanf(f, BLKTAP2_CONTROL_DIR"/"
143 		   BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) {
144 		errno = (errno ? : EINVAL);
145 		EPRINTF("parsing id failed: %d\n", errno);
146 		id = -1;
147 	}
148 
149 	fclose(f);
150 	return id;
151 }
152 
153 int
tap_ctl_spawn(void)154 tap_ctl_spawn(void)
155 {
156 	pid_t child;
157 	int err, id, readfd;
158 
159 	readfd = -1;
160 
161 	child = __tap_ctl_spawn(&readfd);
162 	if (child < 0)
163 		return child;
164 
165 	err = tap_ctl_wait(child);
166 	if (err)
167 		return err;
168 
169 	id = tap_ctl_get_child_id(readfd);
170 	if (id < 0)
171 		EPRINTF("get_id failed, child %d err %d\n", child, errno);
172 
173 	return id;
174 }
175