/[public]/qemu-start/trunk/qemu-start.c
ViewVC logotype

Diff of /qemu-start/trunk/qemu-start.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 290 Revision 295
28#include <fcntl.h> 28#include <fcntl.h>
29#include <unistd.h> 29#include <unistd.h>
30#include <stdlib.h> 30#include <stdlib.h>
31#include <net/if.h> 31#include <net/if.h>
32#include <linux/if_tun.h> 32#include <linux/if_tun.h>
33#include <sys/wait.h>
34#include <errno.h>
35
36/* This define is present in recent glibc, it is not available on sarge */
37#ifndef HOST_NAME_MAX
38#define HOST_NAME_MAX 64
39#endif
33 40
34#define QEMU "/usr/bin/qemu" 41#define QEMU "/usr/bin/qemu"
35#define USER "qemu" 42#define USER "qemu"
43
44/*
45 * This function merges the xauthority data of the current X context
46 * into the QEMU user's .Xauthority file.
47 */
48void fix_xauthority(void) {
49 struct passwd *userdata;
50 int pfd[2];
51 char *xauthfile;
52 char *display;
53 char *newdisplay;
54 char *hostname;
55// int status1, status2;
56 int status,pid;
57 pid_t cpid1, cpid2;
58
59 if (pipe(pfd)) {
60 perror("pipe failed");
61 exit(1);
62 }
63
64 cpid1 = fork();
65 if (cpid1 < 0) {
66 perror("first fork failed");
67 exit(1);
68 }
69
70 /* Child: will execute the xauth extract */
71 if (cpid1 == 0) {
72 /* Child may run as original process starter */
73 if (setgroups(0, NULL)) {
74 perror("setgroups failed");
75 exit(1);
76 }
77 if (setgid(getgid())) {
78 perror("setgid failed");
79 exit(1);
80 }
81 if (setuid(getuid())) {
82 perror("setuid failed");
83 exit(1);
84 }
85
86 /* Write side of pipe corresponds to stdout */
87 if (dup2(pfd[1],1) < 0) {
88 perror("dup2 failed");
89 exit(1);
90 }
91 if (close(pfd[0])) {
92 perror("close of pfd[0] failed");
93 exit(1);
94 }
95 if (close(pfd[1])) {
96 perror("close of pfd[1] failed");
97 exit(1);
98 }
99
100 userdata = getpwuid(getuid());
101 if (!userdata) {
102 fprintf(stderr, "No user '%s'\n", USER);
103 exit(1);
104 }
105
106
107 /* Get xauthority file to use */
108 if (! (xauthfile = getenv("XAUTHORITY"))) {
109 if (asprintf(&xauthfile,"%s/.Xauthority",userdata->pw_dir) < 1) {
110 perror("Constructing xauthority filename failed");
111 exit(1);
112 }
113 }
114
115 /* Get display */
116 if (! (display = getenv("DISPLAY"))) {
117 perror("No DISPLAY variable found\n");
118 exit(1);
119 }
120
121 /* Substitution: if display starts with `localhost', substitute
122 `localhost' by `HOSTNAME/unix'. */
123 if (strstr(display,"localhost") == display) {
124 hostname = malloc(HOST_NAME_MAX+1);
125 if (gethostname(hostname,HOST_NAME_MAX+1)) {
126 perror("Getting hostname failed");
127 exit(1);
128 }
129
130 if (!(newdisplay = malloc(strlen(hostname) + 5 + strlen(display)-9 + 1))) {
131 perror("Allocating new display failed");
132 exit(1);
133 }
134 strcpy(newdisplay,hostname);
135 strcpy(newdisplay + strlen(hostname),"/unix");
136 strcpy(newdisplay + strlen(hostname) + 5, display + 9);
137 display = newdisplay;
138 } else if (! (display = strdup(display))) {
139 perror("strdup DISPLAY failed");
140 exit(1);
141 }
142
143 execl("/usr/bin/X11/xauth","/usr/bin/X11/xauth","-f",xauthfile,"extract","-",display,NULL);
144 exit(1);
145 }
146
147
148 cpid2 = fork();
149 if (cpid2 < 0) {
150 perror("second fork failed");
151 exit(1);
152 }
153
154 /* Child: will execute the xauth merge */
155 if (cpid2 == 0) {
156 /* Get userid data. */
157 userdata = getpwnam(USER);
158 if (!userdata) {
159 fprintf(stderr, "No user '%s'\n", USER);
160 exit(1);
161 }
162
163 if (setgroups(0, NULL)) {
164 perror("setgroups failed");
165 exit(1);
166 }
167
168 /* Child may run as qemu user */
169 if (setgid(userdata->pw_gid)) {
170 perror("setgid failed");
171 exit(1);
172 }
173 if (setuid(userdata->pw_uid)) {
174 perror("setuid failed");
175 exit(1);
176 }
177 /* Read side of pipe is stdin */
178 if (dup2(pfd[0],0) < 0) {
179 perror("dup2 failed");
180 exit(1);
181 }
182 if (close(pfd[0])) {
183 perror("close of pfd[0] failed");
184 exit(1);
185 }
186 if (close(pfd[1])) {
187 perror("close of pfd[1] failed");
188 exit(1);
189 }
190
191 if (asprintf(&xauthfile,"%s/.Xauthority",userdata->pw_dir) < 1) {
192 perror("Constructing xauthority filename failed");
193 exit(1);
194 }
195
196 execl("/usr/bin/X11/xauth","/usr/bin/X11/xauth","-f",xauthfile,"merge","-",NULL);
197 exit(1);
198 }
199
200 if (close(pfd[0])) {
201 perror("close of pfd[0] failed");
202 exit(1);
203 }
204 if (close(pfd[1])) {
205 perror("close of pfd[1] failed");
206 exit(1);
207 }
208
209 while(1) {
210
211 pid = wait(&status);
212 if ((pid < 1) && (errno == ECHILD))
213 break;
214 if (pid < 1) {
215 perror("wait failed");
216 exit(1);
217 }
218 if (! WIFEXITED(status) || WEXITSTATUS(status)) {
219 fprintf(stderr,"Child returned error");
220 exit(1);
221 }
222 }
223}
224
36 225
37/* Tiny code to open tap/tun device, and hand the fd to qemu. 226/* Tiny code to open tap/tun device, and hand the fd to qemu.
38 Run as root, drops to given user. */ 227 Run as root, drops to given user. */
39int main(int argc, char *argv[]) 228int main(int argc, char *argv[])
40{ 229{
41 struct ifreq ifr; 230 struct ifreq ifr;
42 struct passwd *userdata; 231 struct passwd *userdata;
43 char *newargs[argc + 2]; 232 char *newargs[argc + 2];
44 int i,fd,vlan,tapnr; 233 int i,fd,vlan,tapnr;
45 char *ptr; 234 char *ptr;
46 char *command;
47 char *display; 235 char *display;
48 236
49 /* Check parameters */ 237 /* Check parameters */
50 if (argc < 4) { 238 if (argc < 4) {
51 fprintf(stderr, "Usage: qemu-start TAPDEVNR VLAN SYSTEM <qemu options>...\n"); 239 fprintf(stderr, "Usage: qemu-start TAPDEVNR VLAN SYSTEM <qemu options>...\n");
57 } 245 }
58 246
59 /* First parameter: TAPDEVNR */ 247 /* First parameter: TAPDEVNR */
60 tapnr = strtol(argv[1],&ptr,0); 248 tapnr = strtol(argv[1],&ptr,0);
61 if (*ptr) { 249 if (*ptr) {
62 fprintf(stderr, "Invalid value for TAPDEVNR parameter (use a number!)\n"); 250 fprintf(stderr, "Invalid value `%s' for TAPDEVNR parameter (use a number!)\n",argv[1]);
63 exit(1); 251 exit(1);
64 } 252 }
65 253
66 /* Second parameter: VLAN */ 254 /* Second parameter: VLAN */
67 vlan = strtol(argv[2],&ptr,0); 255 vlan = strtol(argv[2],&ptr,0);
68 if (*ptr) { 256 if (*ptr) {
69 fprintf(stderr, "Invalid value for VLAN parameter (use a number!)\n"); 257 fprintf(stderr, "Invalid value `%s' for VLAN parameter (use a number!)\n", argv[2]);
70 exit(1); 258 exit(1);
71 } 259 }
260
261 /* Third parameter: System type */
262 if (index(argv[3],'/')) {
263 fprintf(stderr, "Invalid value `%s' for system (may not contain a slash character)\n", argv[3]);
264 exit(1);
265 }
266
267 /* Export the xauth data */
268 fix_xauthority();
72 269
73 /* Open /dev/net/tun */ 270 /* Open /dev/net/tun */
74 fd = open("/dev/net/tun", O_RDWR); 271 fd = open("/dev/net/tun", O_RDWR);
75 if (fd < 0) { 272 if (fd < 0) {
76 perror("Could not open /dev/net/tun"); 273 perror("Could not open /dev/net/tun");
85 if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) { 282 if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
86 perror("Could not get tap device"); 283 perror("Could not get tap device");
87 exit(1); 284 exit(1);
88 } 285 }
89 286
90 /* Fix X-display */ 287 /* Get userid data. */
91 userdata = getpwuid(getuid());
92 setuid(0);
93 setgid(0);
94 asprintf(&command,"xauth -f ~%s/.Xauthority extract - $(echo $DISPLAY|sed \"s,^localhost,$(hostname)/unix,\") | xauth -f ~%s/.Xauthority merge -; chown %s: ~%s/.Xauthority",userdata->pw_name,USER,USER,USER);
95 system(command);
96
97 /* Set correct userid. */
98 userdata = getpwnam(USER); 288 userdata = getpwnam(USER);
99 if (!userdata) { 289 if (!userdata) {
100 fprintf(stderr, "No user '%s'\n", USER); 290 fprintf(stderr, "No user '%s'\n", USER);
101 exit(1); 291 exit(1);
102 } 292 }
293
294 /* Change to QEMU user */
103 setgroups(0, NULL); 295 if (setgroups(0, NULL)) {
296 perror("setgroups failed");
297 exit(1);
298 }
104 setgid(userdata->pw_gid); 299 if (setgid(userdata->pw_gid)) {
300 perror("setgid failed");
301 exit(1);
302 }
105 if (setuid(userdata->pw_uid) != 0) { 303 if (setuid(userdata->pw_uid)) {
106 perror("setting uid"); 304 perror("setuid failed");
107 exit(1); 305 exit(1);
108 } 306 }
109 307
110 /* Clean the environment */ 308 /* Clean the environment */
111 display=getenv("DISPLAY"); 309 if(!(display=getenv("DISPLAY"))) {
310 perror("Getting DISPLAY failed");
311 exit(1);
312 }
112 clearenv(); 313 if(clearenv()) {
314 perror("Clearing environment failed");
315 exit(1);
316 }
113 setenv("HOME",userdata->pw_dir,1); 317 if(setenv("HOME",userdata->pw_dir,1) ||
114 setenv("DISPLAY",display,1); 318 setenv("DISPLAY",display,1) ||
115 setenv("PATH","/usr/bin:/bin:/usr/local/bin",1); 319 setenv("PATH","/usr/bin:/bin:/usr/local/bin",1) ||
116 setenv("LOGNAME",userdata->pw_name,1); 320 setenv("LOGNAME",userdata->pw_name,1) ||
117 setenv("USER",userdata->pw_name,1); 321 setenv("USER",userdata->pw_name,1)) {
322 perror("Setting environment failed");
323 exit(1);
324 }
118 325
119 /* Create the right qemu invocation */ 326 /* Create the right qemu invocation */
120 if (!strlen(argv[3])) 327 if (!strlen(argv[3]))
121 newargs[0] = QEMU; 328 newargs[0] = QEMU;
122 else
123 asprintf(&newargs[0],"%s-system-%s",QEMU,argv[3]); 329 else if (asprintf(&newargs[0],"%s-system-%s",QEMU,argv[3]) < 0) {
330 perror("Preparing qemu executable filename failed");
331 exit(1);
332 }
124 newargs[1] = "-net"; 333 newargs[1] = "-net";
125 asprintf(&newargs[2],"nic,vlan=%d",vlan); 334 if (asprintf(&newargs[2],"nic,vlan=%d",vlan) < 0) {
335 perror("Preparing nic argument failed");
336 exit(1);
337 }
126 newargs[3] = "-net"; 338 newargs[3] = "-net";
127 asprintf(&newargs[4],"tap,fd=%d,vlan=%d",fd,vlan); 339 if (asprintf(&newargs[4],"tap,fd=%d,vlan=%d",fd,vlan) < 0) {
340 perror("Preparing tap argument failed");
341 exit(1);
342 }
128 for (i = 4; i <= argc; i++) 343 for (i = 4; i <= argc; i++)
129 newargs[i+1] = argv[i]; 344 newargs[i+1] = argv[i];
130 345
131 execvp(newargs[0], newargs); 346 execvp(newargs[0], newargs);
347 perror('Execution of qemu failed');
132 exit(1); 348 exit(1);
133} 349}
350

Legend:
Removed from v.290  
changed lines
  Added in v.295

frodo@frodo.looijaard.name
ViewVC Help
Powered by ViewVC 1.1.26