tests: modprobe fat instead of ext2 module.
[libguestfs.git] / daemon / ext2.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 <unistd.h>
24 #include <ctype.h>
25
26 #include "../src/guestfs_protocol.h"
27 #include "daemon.h"
28 #include "actions.h"
29
30 char **
31 do_tune2fs_l (const char *device)
32 {
33   int r;
34   char *out, *err;
35   char *p, *pend, *colon;
36   char **ret = NULL;
37   int size = 0, alloc = 0;
38
39   r = command (&out, &err, "/sbin/tune2fs", "-l", device, NULL);
40   if (r == -1) {
41     reply_with_error ("tune2fs: %s", err);
42     free (err);
43     free (out);
44     return NULL;
45   }
46   free (err);
47
48   p = out;
49
50   /* Discard the first line if it contains "tune2fs ...". */
51   if (strncmp (p, "tune2fs ", 8) == 0) {
52     p = strchr (p, '\n');
53     if (p) p++;
54     else {
55       reply_with_error ("tune2fs: truncated output");
56       free (out);
57       return NULL;
58     }
59   }
60
61   /* Read the lines and split into "key: value". */
62   while (*p) {
63     pend = strchrnul (p, '\n');
64     if (*pend == '\n') {
65       *pend = '\0';
66       pend++;
67     }
68
69     if (!*p) continue;
70
71     colon = strchr (p, ':');
72     if (colon) {
73       *colon = '\0';
74
75       do { colon++; } while (*colon && isspace (*colon));
76
77       if (add_string (&ret, &size, &alloc, p) == -1) {
78         free (out);
79         return NULL;
80       }
81       if (strcmp (colon, "<none>") == 0 ||
82           strcmp (colon, "<not available>") == 0 ||
83           strcmp (colon, "(none)") == 0) {
84         if (add_string (&ret, &size, &alloc, "") == -1) {
85           free (out);
86           return NULL;
87         }
88       } else {
89         if (add_string (&ret, &size, &alloc, colon) == -1) {
90           free (out);
91           return NULL;
92         }
93       }
94     }
95     else {
96       if (add_string (&ret, &size, &alloc, p) == -1) {
97         free (out);
98         return NULL;
99       }
100       if (add_string (&ret, &size, &alloc, "") == -1) {
101         free (out);
102         return NULL;
103       }
104     }
105
106     p = pend;
107   }
108
109   free (out);
110
111   if (add_string (&ret, &size, &alloc, NULL) == -1)
112     return NULL;
113
114   return ret;
115 }
116
117 int
118 do_set_e2label (const char *device, const char *label)
119 {
120   int r;
121   char *err;
122
123   r = command (NULL, &err, "/sbin/e2label", device, label, NULL);
124   if (r == -1) {
125     reply_with_error ("e2label: %s", err);
126     free (err);
127     return -1;
128   }
129
130   free (err);
131   return 0;
132 }
133
134 char *
135 do_get_e2label (const char *device)
136 {
137   int r, len;
138   char *out, *err;
139
140   r = command (&out, &err, "/sbin/e2label", device, NULL);
141   if (r == -1) {
142     reply_with_error ("e2label: %s", err);
143     free (out);
144     free (err);
145     return NULL;
146   }
147
148   free (err);
149
150   /* Remove any trailing \n from the label. */
151   len = strlen (out);
152   if (len > 0 && out[len-1] == '\n')
153     out[len-1] = '\0';
154
155   return out;                   /* caller frees */
156 }
157
158 int
159 do_set_e2uuid (const char *device, const char *uuid)
160 {
161   int r;
162   char *err;
163
164   r = command (NULL, &err, "/sbin/tune2fs", "-U", uuid, device, NULL);
165   if (r == -1) {
166     reply_with_error ("tune2fs -U: %s", err);
167     free (err);
168     return -1;
169   }
170
171   free (err);
172   return 0;
173 }
174
175 char *
176 do_get_e2uuid (const char *device)
177 {
178   int r;
179   char *out, *err, *p, *q;
180
181   /* It's not so straightforward to get the volume UUID.  We have
182    * to use tune2fs -l and then look for a particular string in
183    * the output.
184    */
185
186   r = command (&out, &err, "/sbin/tune2fs", "-l", device, NULL);
187   if (r == -1) {
188     reply_with_error ("tune2fs -l: %s", err);
189     free (out);
190     free (err);
191     return NULL;
192   }
193
194   free (err);
195
196   /* Look for /\nFilesystem UUID:\s+/ in the output. */
197   p = strstr (out, "\nFilesystem UUID:");
198   if (p == NULL) {
199     reply_with_error ("no Filesystem UUID in the output of tune2fs -l");
200     free (out);
201     return NULL;
202   }
203
204   p += 17;
205   while (*p && isspace (*p))
206     p++;
207   if (!*p) {
208     reply_with_error ("malformed Filesystem UUID in the output of tune2fs -l");
209     free (out);
210     return NULL;
211   }
212
213   /* Now 'p' hopefully points to the start of the UUID. */
214   q = p;
215   while (*q && (isxdigit (*q) || *q == '-'))
216     q++;
217   if (!*q) {
218     reply_with_error ("malformed Filesystem UUID in the output of tune2fs -l");
219     free (out);
220     return NULL;
221   }
222
223   *q = '\0';
224
225   p = strdup (p);
226   if (!p) {
227     reply_with_perror ("strdup");
228     free (out);
229     return NULL;
230   }
231
232   free (out);
233   return p;                     /* caller frees */
234 }
235
236 int
237 do_resize2fs (const char *device)
238 {
239   char *err;
240   int r;
241
242   r = command (NULL, &err, "/sbin/resize2fs", device, NULL);
243   if (r == -1) {
244     reply_with_error ("resize2fs: %s", err);
245     free (err);
246     return -1;
247   }
248
249   free (err);
250   return 0;
251 }
252
253 int
254 do_e2fsck_f (const char *device)
255 {
256   char *err;
257   int r;
258
259   r = command (NULL, &err, "/sbin/e2fsck", "-p", "-f", device, NULL);
260   if (r == -1) {
261     reply_with_error ("e2fsck: %s", err);
262     free (err);
263     return -1;
264   }
265
266   free (err);
267   return 0;
268 }
269
270 int
271 do_mke2journal (int blocksize, const char *device)
272 {
273   char *err;
274   int r;
275
276   char blocksize_s[32];
277   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
278
279   r = command (NULL, &err,
280                "/sbin/mke2fs", "-O", "journal_dev", "-b", blocksize_s,
281                device, NULL);
282   if (r == -1) {
283     reply_with_error ("mke2journal: %s", err);
284     free (err);
285     return -1;
286   }
287
288   free (err);
289   return 0;
290 }
291
292 int
293 do_mke2journal_L (int blocksize, const char *label, const char *device)
294 {
295   char *err;
296   int r;
297
298   char blocksize_s[32];
299   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
300
301   r = command (NULL, &err,
302                "/sbin/mke2fs", "-O", "journal_dev", "-b", blocksize_s,
303                "-L", label,
304                device, NULL);
305   if (r == -1) {
306     reply_with_error ("mke2journal_L: %s", err);
307     free (err);
308     return -1;
309   }
310
311   free (err);
312   return 0;
313 }
314
315 int
316 do_mke2journal_U (int blocksize, const char *uuid, const char *device)
317 {
318   char *err;
319   int r;
320
321   char blocksize_s[32];
322   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
323
324   r = command (NULL, &err,
325                "/sbin/mke2fs", "-O", "journal_dev", "-b", blocksize_s,
326                "-U", uuid,
327                device, NULL);
328   if (r == -1) {
329     reply_with_error ("mke2journal_U: %s", err);
330     free (err);
331     return -1;
332   }
333
334   free (err);
335   return 0;
336 }
337
338 int
339 do_mke2fs_J (const char *fstype, int blocksize, const char *device,
340              const char *journal)
341 {
342   char *err;
343   int r;
344
345   char blocksize_s[32];
346   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
347
348   int len = strlen (journal);
349   char jdev[len+32];
350   snprintf (jdev, len+32, "device=%s", journal);
351
352   r = command (NULL, &err,
353                "/sbin/mke2fs", "-t", fstype, "-J", jdev, "-b", blocksize_s,
354                device, NULL);
355   if (r == -1) {
356     reply_with_error ("mke2fs_J: %s", err);
357     free (err);
358     return -1;
359   }
360
361   free (err);
362   return 0;
363 }
364
365 int
366 do_mke2fs_JL (const char *fstype, int blocksize, const char *device,
367               const char *label)
368 {
369   char *err;
370   int r;
371
372   char blocksize_s[32];
373   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
374
375   int len = strlen (label);
376   char jdev[len+32];
377   snprintf (jdev, len+32, "device=LABEL=%s", label);
378
379   r = command (NULL, &err,
380                "/sbin/mke2fs", "-t", fstype, "-J", jdev, "-b", blocksize_s,
381                device, NULL);
382   if (r == -1) {
383     reply_with_error ("mke2fs_JL: %s", err);
384     free (err);
385     return -1;
386   }
387
388   free (err);
389   return 0;
390 }
391
392 int
393 do_mke2fs_JU (const char *fstype, int blocksize, const char *device,
394               const char *uuid)
395 {
396   char *err;
397   int r;
398
399   char blocksize_s[32];
400   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
401
402   int len = strlen (uuid);
403   char jdev[len+32];
404   snprintf (jdev, len+32, "device=UUID=%s", uuid);
405
406   r = command (NULL, &err,
407                "/sbin/mke2fs", "-t", fstype, "-J", jdev, "-b", blocksize_s,
408                device, NULL);
409   if (r == -1) {
410     reply_with_error ("mke2fs_JU: %s", err);
411     free (err);
412     return -1;
413   }
414
415   free (err);
416   return 0;
417 }