c27d1b6e12082781e4e7b322a88f8a17775bb66f
[libguestfs.git] / daemon / guestfsd.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc. 
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <rpc/types.h>
26 #include <rpc/xdr.h>
27 #include <getopt.h>
28 #include <netdb.h>
29
30 static void xwrite (int sock, const void *buf, size_t len);
31 static void usage (void);
32
33 /* Also in guestfs.c */
34 #define VMCHANNEL_PORT "6666"
35 #define VMCHANNEL_ADDR "10.0.2.4"
36
37 int
38 main (int argc, char *argv[])
39 {
40   static const char *options = "fh:p:?";
41   static struct option long_options[] = {
42     { "foreground", 0, 0, 'f' },
43     { "help", 0, 0, '?' },
44     { "host", 1, 0, 'h' },
45     { "port", 1, 0, 'p' },
46     { 0, 0, 0, 0 }
47   };
48   int c, n, r;
49   int dont_fork = 0;
50   const char *host = NULL;
51   const char *port = NULL;
52   FILE *fp;
53   char buf[4096];
54   char *p, *p2;
55   int sock;
56   struct addrinfo *res, *rr;
57   struct addrinfo hints;
58   XDR xdr;
59   unsigned len;
60
61   for (;;) {
62     c = getopt_long (argc, argv, options, long_options, NULL);
63     if (c == -1) break;
64
65     switch (c) {
66     case 'f':
67       dont_fork = 1;
68       break;
69
70     case 'h':
71       host = optarg;
72       break;
73
74     case 'p':
75       port = optarg;
76       break;
77
78     case '?':
79       usage ();
80       exit (0);
81
82     default:
83       fprintf (stderr, "guestfsd: unexpected command line option 0x%x\n", c);
84       exit (1);
85     }
86   }
87
88   if (optind < argc) {
89     usage ();
90     exit (1);
91   }
92
93   /* If host and port aren't set yet, try /proc/cmdline. */
94   if (!host || !port) {
95     fp = fopen ("/proc/cmdline", "r");
96     if (fp == NULL) {
97       perror ("/proc/cmdline");
98       goto next;
99     }
100     n = fread (buf, 1, sizeof buf - 1, fp);
101     fclose (fp);
102     buf[n] = '\0';
103
104     p = strstr (buf, "guestfs=");
105
106     if (p) {
107       p += 8;
108       p2 = strchr (p, ':');
109       if (p2) {
110         *p2++ = '\0';
111         host = p;
112         r = strcspn (p2, " \n");
113         p2[r] = '\0';
114         port = p2;
115       }
116     }
117   }
118
119  next:
120   /* Can't parse /proc/cmdline, so use built-in defaults. */
121   if (!host || !port) {
122     host = VMCHANNEL_ADDR;
123     port = VMCHANNEL_PORT;
124   }
125
126   /* Resolve the hostname. */
127   memset (&hints, 0, sizeof hints);
128   hints.ai_socktype = SOCK_STREAM;
129   hints.ai_flags = AI_ADDRCONFIG;
130   r = getaddrinfo (host, port, &hints, &res);
131   if (r != 0) {
132     fprintf (stderr, "%s:%s: %s\n", host, port, gai_strerror (r));
133     exit (1);
134   }
135
136   /* Connect to the given TCP socket. */
137   sock = -1;
138   for (rr = res; rr != NULL; rr = rr->ai_next) {
139     sock = socket (rr->ai_family, rr->ai_socktype, rr->ai_protocol);
140     if (sock != -1) {
141       if (connect (sock, rr->ai_addr, rr->ai_addrlen) == 0)
142         break;
143       perror ("connect");
144
145       close (sock);
146       sock = -1;
147     }
148   }
149   freeaddrinfo (res);
150
151   if (sock == -1) {
152     fprintf (stderr, "connection to %s:%s failed\n", host, port);
153     exit (1);
154   }
155
156   /* Send the magic length message which indicates that
157    * userspace is up inside the guest.
158    */
159   len = 0xf5f55ff5;
160   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
161   if (!xdr_uint32_t (&xdr, &len)) {
162     fprintf (stderr, "xdr_uint32_t failed\n");
163     exit (1);
164   }
165
166   xwrite (sock, buf, xdr_getpos (&xdr));
167
168   xdr_destroy (&xdr);
169
170   /* XXX Fork into the background. */
171
172
173
174
175
176
177
178
179
180   sleep (1000000);
181
182   exit (0);
183 }
184
185 static void
186 xwrite (int sock, const void *buf, size_t len)
187 {
188   int r;
189
190   while (len > 0) {
191     r = write (sock, buf, len);
192     if (r == -1) {
193       perror ("write");
194       exit (1);
195     }
196     buf += r;
197     len -= r;
198   }
199 }
200
201 static void
202 usage (void)
203 {
204   fprintf (stderr, "guestfsd [-f] [-h host -p port]\n");
205 }