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