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