fish: Allows win:... paths to work with drives mounted anywhere.
[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_clear (const char *path)
214 {
215 #ifdef HAVE_AUGEAS
216   int r;
217
218   NEED_AUG (-1);
219
220   r = aug_set (aug, path, NULL);
221   if (r == -1) {
222     reply_with_error ("Augeas clear failed");
223     return -1;
224   }
225
226   return 0;
227 #else
228   NOT_AVAILABLE (-1);
229 #endif
230 }
231
232 int
233 do_aug_insert (const char *path, const char *label, int before)
234 {
235 #ifdef HAVE_AUGEAS
236   int r;
237
238   NEED_AUG (-1);
239
240   r = aug_insert (aug, path, label, before);
241   if (r == -1) {
242     reply_with_error ("Augeas insert failed");
243     return -1;
244   }
245
246   return 0;
247 #else
248   NOT_AVAILABLE (-1);
249 #endif
250 }
251
252 int
253 do_aug_rm (const char *path)
254 {
255 #ifdef HAVE_AUGEAS
256   int r;
257
258   NEED_AUG (-1);
259
260   r = aug_rm (aug, path);
261   if (r == -1) {
262     reply_with_error ("Augeas rm failed");
263     return -1;
264   }
265
266   return r;
267 #else
268   NOT_AVAILABLE (-1);
269 #endif
270 }
271
272 int
273 do_aug_mv (const char *src, const char *dest)
274 {
275 #ifdef HAVE_AUGEAS
276   int r;
277
278   NEED_AUG (-1);
279
280   r = aug_mv (aug, src, dest);
281   if (r == -1) {
282     reply_with_error ("Augeas mv failed");
283     return -1;
284   }
285
286   return 0;
287 #else
288   NOT_AVAILABLE (-1);
289 #endif
290 }
291
292 char **
293 do_aug_match (const char *path)
294 {
295 #ifdef HAVE_AUGEAS
296   char **matches = NULL;
297   void *vp;
298   int r;
299
300   NEED_AUG (NULL);
301
302   r = aug_match (aug, path, &matches);
303   if (r == -1) {
304     reply_with_error ("Augeas match failed");
305     return NULL;
306   }
307
308   /* This returns an array of length r, which we must extend
309    * and add a terminating NULL.
310    */
311   vp = realloc (matches, sizeof (char *) * (r+1));
312   if (vp == NULL) {
313     reply_with_perror ("realloc");
314     free (vp);
315     return NULL;
316   }
317   matches = vp;
318   matches[r] = NULL;
319
320   return matches;               /* Caller frees. */
321 #else
322   NOT_AVAILABLE (NULL);
323 #endif
324 }
325
326 int
327 do_aug_save (void)
328 {
329 #ifdef HAVE_AUGEAS
330   NEED_AUG (-1);
331
332   if (aug_save (aug) == -1) {
333     reply_with_error ("Augeas save failed");
334     return -1;
335   }
336
337   return 0;
338 #else
339   NOT_AVAILABLE (-1);
340 #endif
341 }
342
343 int
344 do_aug_load (void)
345 {
346 #ifdef HAVE_AUG_LOAD
347   NEED_AUG (-1);
348
349   if (aug_load (aug) == -1) {
350     reply_with_error ("Augeas load failed");
351     return -1;
352   }
353
354   return 0;
355 #else
356   NOT_AVAILABLE (-1);
357 #endif
358 }
359
360 /* Simpler version of aug-match, which also sorts the output. */
361 char **
362 do_aug_ls (const char *path)
363 {
364 #ifdef HAVE_AUGEAS
365   char **matches;
366   char *buf;
367   int len;
368
369   NEED_AUG (NULL);
370
371   /* Note that path might also be a previously defined variable
372    * (defined with aug_defvar).  See RHBZ#580016.
373    */
374
375   len = strlen (path);
376
377   if (len > 1 &&
378       (path[len-1] == '/' || path[len-1] == ']' || path[len-1] == '*')) {
379     reply_with_error ("don't use aug-ls with a path that ends with / ] *");
380     return NULL;
381   }
382
383   if (STREQ (path, "/"))
384     matches = do_aug_match ("/*");
385   else {
386     len += 3;                   /* / * + terminating \0 */
387     buf = malloc (len);
388     if (buf == NULL) {
389       reply_with_perror ("malloc");
390       return NULL;
391     }
392
393     snprintf (buf, len, "%s/*", path);
394     matches = do_aug_match (buf);
395     free (buf);
396   }
397
398   if (matches == NULL)
399     return NULL;                /* do_aug_match has already sent the error */
400
401   sort_strings (matches, count_strings ((void *) matches));
402   return matches;               /* Caller frees. */
403 #else
404   NOT_AVAILABLE (NULL);
405 #endif
406 }