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