Add InitSquashFS test type, for tests that just use the squashfs (/dev/sdd).
[libguestfs.git] / daemon / tar.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 <fcntl.h>
25
26 #include "../src/guestfs_protocol.h"
27 #include "daemon.h"
28 #include "actions.h"
29
30 static int
31 fwrite_cb (void *fp_ptr, const void *buf, int len)
32 {
33   FILE *fp = *(FILE **)fp_ptr;
34   return fwrite (buf, len, 1, fp) == 1 ? 0 : -1;
35 }
36
37 /* Has one FileIn parameter. */
38 int
39 do_tar_in (char *dir)
40 {
41   int err, r, len;
42   FILE *fp;
43   char *cmd;
44
45   if (!root_mounted || dir[0] != '/') {
46     cancel_receive ();
47     reply_with_error ("tar-in: root must be mounted and path must be absolute");
48     return -1;
49   }
50
51   /* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
52   len = 2 * strlen (dir) + sysroot_len + 32;
53   cmd = malloc (len);
54   if (!cmd) {
55     err = errno;
56     cancel_receive ();
57     errno = err;
58     reply_with_perror ("malloc");
59     return -1;
60   }
61   strcpy (cmd, "tar -C ");
62   strcat (cmd, sysroot);
63   shell_quote (cmd+15, len-15, dir);
64   strcat (cmd, " -xf -");
65
66   fp = popen (cmd, "w");
67   if (fp == NULL) {
68     err = errno;
69     cancel_receive ();
70     errno = err;
71     reply_with_perror ("%s", cmd);
72     free (cmd);
73     return -1;
74   }
75   free (cmd);
76
77   r = receive_file (fwrite_cb, &fp);
78   if (r == -1) {                /* write error */
79     err = errno;
80     cancel_receive ();
81     errno = err;
82     reply_with_perror ("write: %s", dir);
83     pclose (fp);
84     return -1;
85   }
86   if (r == -2) {                /* cancellation from library */
87     pclose (fp);
88     /* Do NOT send any error. */
89     return -1;
90   }
91
92   if (pclose (fp) != 0) {
93     err = errno;
94     cancel_receive ();
95     errno = err;
96     reply_with_perror ("pclose: %s", dir);
97     return -1;
98   }
99
100   return 0;
101 }
102
103 /* Has one FileOut parameter. */
104 int
105 do_tar_out (char *dir)
106 {
107   int r, len;
108   FILE *fp;
109   char *cmd;
110   char buf[GUESTFS_MAX_CHUNK_SIZE];
111
112   NEED_ROOT (-1);
113   ABS_PATH (dir, -1);
114
115   /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
116   len = 2 * strlen (dir) + sysroot_len + 32;
117   cmd = malloc (len);
118   if (!cmd) {
119     reply_with_perror ("malloc");
120     return -1;
121   }
122   strcpy (cmd, "tar -C ");
123   strcat (cmd, sysroot);
124   shell_quote (cmd+15, len-15, dir);
125   strcat (cmd, " -cf - .");
126
127   fp = popen (cmd, "r");
128   if (fp == NULL) {
129     reply_with_perror ("%s", cmd);
130     free (cmd);
131     return -1;
132   }
133   free (cmd);
134
135   /* Now we must send the reply message, before the file contents.  After
136    * this there is no opportunity in the protocol to send any error
137    * message back.  Instead we can only cancel the transfer.
138    */
139   reply (NULL, NULL);
140
141   while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
142     if (send_file_write (buf, r) < 0) {
143       pclose (fp);
144       return -1;
145     }
146   }
147
148   if (ferror (fp)) {
149     perror (dir);
150     send_file_end (1);          /* Cancel. */
151     pclose (fp);
152     return -1;
153   }
154
155   if (pclose (fp) != 0) {
156     perror (dir);
157     send_file_end (1);          /* Cancel. */
158     return -1;
159   }
160
161   send_file_end (0);            /* Normal end of file. */
162   return 0;
163 }
164
165 /* Has one FileIn parameter. */
166 int
167 do_tgz_in (char *dir)
168 {
169   int err, r, len;
170   FILE *fp;
171   char *cmd;
172
173   if (!root_mounted || dir[0] != '/') {
174     cancel_receive ();
175     reply_with_error ("tar-in: root must be mounted and path must be absolute");
176     return -1;
177   }
178
179   /* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
180   len = 2 * strlen (dir) + sysroot_len + 32;
181   cmd = malloc (len);
182   if (!cmd) {
183     err = errno;
184     cancel_receive ();
185     errno = err;
186     reply_with_perror ("malloc");
187     return -1;
188   }
189   strcpy (cmd, "tar -C ");
190   strcat (cmd, sysroot);
191   shell_quote (cmd+15, len-15, dir);
192   strcat (cmd, " -zxf -");
193
194   fp = popen (cmd, "w");
195   if (fp == NULL) {
196     err = errno;
197     cancel_receive ();
198     errno = err;
199     reply_with_perror ("%s", cmd);
200     free (cmd);
201     return -1;
202   }
203   free (cmd);
204
205   r = receive_file (fwrite_cb, &fp);
206   if (r == -1) {                /* write error */
207     err = errno;
208     cancel_receive ();
209     errno = err;
210     reply_with_perror ("write: %s", dir);
211     pclose (fp);
212     return -1;
213   }
214   if (r == -2) {                /* cancellation from library */
215     pclose (fp);
216     /* Do NOT send any error. */
217     return -1;
218   }
219
220   if (pclose (fp) != 0) {
221     err = errno;
222     cancel_receive ();
223     errno = err;
224     reply_with_perror ("pclose: %s", dir);
225     return -1;
226   }
227
228   return 0;
229 }
230
231 /* Has one FileOut parameter. */
232 int
233 do_tgz_out (char *dir)
234 {
235   int r, len;
236   FILE *fp;
237   char *cmd;
238   char buf[GUESTFS_MAX_CHUNK_SIZE];
239
240   NEED_ROOT (-1);
241   ABS_PATH (dir, -1);
242
243   /* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
244   len = 2 * strlen (dir) + sysroot_len + 32;
245   cmd = malloc (len);
246   if (!cmd) {
247     reply_with_perror ("malloc");
248     return -1;
249   }
250   strcpy (cmd, "tar -C ");
251   strcat (cmd, sysroot);
252   shell_quote (cmd+15, len-15, dir);
253   strcat (cmd, " -zcf - .");
254
255   fp = popen (cmd, "r");
256   if (fp == NULL) {
257     reply_with_perror ("%s", cmd);
258     free (cmd);
259     return -1;
260   }
261   free (cmd);
262
263   /* Now we must send the reply message, before the file contents.  After
264    * this there is no opportunity in the protocol to send any error
265    * message back.  Instead we can only cancel the transfer.
266    */
267   reply (NULL, NULL);
268
269   while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
270     if (send_file_write (buf, r) < 0) {
271       pclose (fp);
272       return -1;
273     }
274   }
275
276   if (ferror (fp)) {
277     perror (dir);
278     send_file_end (1);          /* Cancel. */
279     pclose (fp);
280     return -1;
281   }
282
283   if (pclose (fp) != 0) {
284     perror (dir);
285     send_file_end (1);          /* Cancel. */
286     return -1;
287   }
288
289   send_file_end (0);            /* Normal end of file. */
290   return 0;
291 }