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