avoid leak upon failed realloc
[libguestfs.git] / daemon / augeas.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
26 #ifdef HAVE_AUGEAS
27 #include <augeas.h>
28 #endif
29
30 #include "daemon.h"
31 #include "actions.h"
32
33 #ifdef HAVE_AUGEAS
34 /* The Augeas handle.  We maintain a single handle per daemon, which
35  * is all that is necessary and reduces the complexity of the API
36  * considerably.
37  */
38 static augeas *aug = NULL;
39 #endif
40
41 #define NEED_AUG(errcode)                                               \
42   do {                                                                  \
43     if (!aug) {                                                         \
44       reply_with_error ("%s: you must call 'aug-init' first to initialize Augeas", __func__); \
45       return (errcode);                                                 \
46     }                                                                   \
47   }                                                                     \
48   while (0)
49
50 /* We need to rewrite the root path so it is based at /sysroot. */
51 int
52 do_aug_init (char *root, int flags)
53 {
54 #ifdef HAVE_AUGEAS
55   char *buf;
56   int len;
57
58   NEED_ROOT (-1);
59   ABS_PATH (root, -1);
60
61   if (aug) {
62     aug_close (aug);
63     aug = NULL;
64   }
65
66   len = strlen (root) + 9;
67   buf = malloc (len);
68   if (!buf) {
69     reply_with_perror ("malloc");
70     return -1;
71   }
72   snprintf (buf, len, "/sysroot%s", root);
73
74   aug = aug_init (buf, NULL, flags);
75   free (buf);
76
77   if (!aug) {
78     reply_with_error ("Augeas initialization failed");
79     return -1;
80   }
81
82   return 0;
83 #else
84   reply_with_error ("%s is not available", __func__);
85   return -1;
86 #endif
87 }
88
89 int
90 do_aug_close (void)
91 {
92 #ifdef HAVE_AUGEAS
93   NEED_AUG(-1);
94
95   aug_close (aug);
96   aug = NULL;
97
98   return 0;
99 #else
100   reply_with_error ("%s is not available", __func__);
101   return -1;
102 #endif
103 }
104
105 int
106 do_aug_defvar (char *name, char *expr)
107 {
108 #ifdef HAVE_AUG_DEFVAR
109   int r;
110
111   NEED_AUG (-1);
112
113   r = aug_defvar (aug, name, expr);
114   if (r == -1) {
115     reply_with_error ("Augeas defvar failed");
116     return -1;
117   }
118   return r;
119 #else
120   reply_with_error ("%s is not available", __func__);
121   return -1;
122 #endif
123 }
124
125 guestfs_aug_defnode_ret *
126 do_aug_defnode (char *name, char *expr, char *val)
127 {
128 #ifdef HAVE_AUG_DEFNODE
129   static guestfs_aug_defnode_ret r;
130   int created;
131
132   NEED_AUG (NULL);
133
134   r.nrnodes = aug_defnode (aug, name, expr, val, &created);
135   if (r.nrnodes == -1) {
136     reply_with_error ("Augeas defnode failed");
137     return NULL;
138   }
139   r.created = created;
140   return &r;
141 #else
142   reply_with_error ("%s is not available", __func__);
143   return NULL;
144 #endif
145 }
146
147 char *
148 do_aug_get (char *path)
149 {
150 #ifdef HAVE_AUGEAS
151   const char *value = NULL;
152   char *v;
153   int r;
154
155   NEED_AUG (NULL);
156
157   r = aug_get (aug, path, &value);
158   if (r == 0) {
159     reply_with_error ("no matching node");
160     return NULL;
161   }
162   if (r != 1) {
163     reply_with_error ("Augeas get failed");
164     return NULL;
165   }
166
167   /* value can still be NULL here, eg. try with path == "/augeas".
168    * I don't understand this case, and it seems to contradict the
169    * documentation.
170    */
171   if (value == NULL) {
172     reply_with_error ("Augeas returned NULL match");
173     return NULL;
174   }
175
176   /* The value is an internal Augeas string, so we must copy it. GC FTW. */
177   v = strdup (value);
178   if (v == NULL) {
179     reply_with_perror ("strdup");
180     return NULL;
181   }
182
183   return v;                     /* Caller frees. */
184 #else
185   reply_with_error ("%s is not available", __func__);
186   return NULL;
187 #endif
188 }
189
190 int
191 do_aug_set (char *path, char *val)
192 {
193 #ifdef HAVE_AUGEAS
194   int r;
195
196   NEED_AUG (-1);
197
198   r = aug_set (aug, path, val);
199   if (r == -1) {
200     reply_with_error ("Augeas set failed");
201     return -1;
202   }
203
204   return 0;
205 #else
206   reply_with_error ("%s is not available", __func__);
207   return -1;
208 #endif
209 }
210
211 int
212 do_aug_insert (char *path, char *label, int before)
213 {
214 #ifdef HAVE_AUGEAS
215   int r;
216
217   NEED_AUG (-1);
218
219   r = aug_insert (aug, path, label, before);
220   if (r == -1) {
221     reply_with_error ("Augeas insert failed");
222     return -1;
223   }
224
225   return 0;
226 #else
227   reply_with_error ("%s is not available", __func__);
228   return -1;
229 #endif
230 }
231
232 int
233 do_aug_rm (char *path)
234 {
235 #ifdef HAVE_AUGEAS
236   int r;
237
238   NEED_AUG (-1);
239
240   r = aug_rm (aug, path);
241   if (r == -1) {
242     reply_with_error ("Augeas rm failed");
243     return -1;
244   }
245
246   return r;
247 #else
248   reply_with_error ("%s is not available", __func__);
249   return -1;
250 #endif
251 }
252
253 int
254 do_aug_mv (char *src, char *dest)
255 {
256 #ifdef HAVE_AUGEAS
257   int r;
258
259   NEED_AUG (-1);
260
261   r = aug_mv (aug, src, dest);
262   if (r == -1) {
263     reply_with_error ("Augeas mv failed");
264     return -1;
265   }
266
267   return 0;
268 #else
269   reply_with_error ("%s is not available", __func__);
270   return -1;
271 #endif
272 }
273
274 char **
275 do_aug_match (char *path)
276 {
277 #ifdef HAVE_AUGEAS
278   char **matches = NULL;
279   void *vp;
280   int r;
281
282   NEED_AUG (NULL);
283
284   r = aug_match (aug, path, &matches);
285   if (r == -1) {
286     reply_with_error ("Augeas match failed");
287     return NULL;
288   }
289
290   /* This returns an array of length r, which we must extend
291    * and add a terminating NULL.
292    */
293   vp = realloc (matches, sizeof (char *) * (r+1));
294   if (vp == NULL) {
295     reply_with_perror ("realloc");
296     free (vp);
297     return NULL;
298   }
299   matches = vp;
300   matches[r] = NULL;
301
302   return matches;               /* Caller frees. */
303 #else
304   reply_with_error ("%s is not available", __func__);
305   return NULL;
306 #endif
307 }
308
309 int
310 do_aug_save (void)
311 {
312 #ifdef HAVE_AUGEAS
313   NEED_AUG (-1);
314
315   if (aug_save (aug) == -1) {
316     reply_with_error ("Augeas save failed");
317     return -1;
318   }
319
320   return 0;
321 #else
322   reply_with_error ("%s is not available", __func__);
323   return -1;
324 #endif
325 }
326
327 int
328 do_aug_load (void)
329 {
330 #ifdef HAVE_AUG_LOAD
331   NEED_AUG (-1);
332
333   if (aug_load (aug) == -1) {
334     reply_with_error ("Augeas load failed");
335     return -1;
336   }
337
338   return 0;
339 #else
340   reply_with_error ("%s is not available", __func__);
341   return -1;
342 #endif
343 }
344
345 /* Simpler version of aug-match, which also sorts the output. */
346 char **
347 do_aug_ls (char *path)
348 {
349 #ifdef HAVE_AUGEAS
350   char **matches;
351   char *buf;
352   int len;
353
354   NEED_AUG (NULL);
355
356   ABS_PATH (path, NULL);
357
358   len = strlen (path);
359
360   if (len > 1 &&
361       (path[len-1] == '/' || path[len-1] == ']' || path[len-1] == '*')) {
362     reply_with_error ("don't use aug-ls with a path that ends with / ] *");
363     return NULL;
364   }
365
366   if (len == 1)
367     /* we know path must be "/" because of ABS_PATH above */
368     matches = do_aug_match ("/");
369   else {
370     len += 3;                   /* / * + terminating \0 */
371     buf = malloc (len);
372     if (buf == NULL) {
373       reply_with_perror ("malloc");
374       return NULL;
375     }
376
377     snprintf (buf, len, "%s/*", path);
378     matches = do_aug_match (buf);
379     free (buf);
380   }
381
382   if (matches == NULL)
383     return NULL;                /* do_aug_match has already sent the error */
384
385   sort_strings (matches, count_strings (matches));
386   return matches;               /* Caller frees. */
387 #else
388   reply_with_error ("%s is not available", __func__);
389   return NULL;
390 #endif
391 }