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