f181b8d7e594dad28329969696625c46e71f71d9
[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 }