Add aug-ls command (non-generated code).
[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) + 8;
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   int r;
94
95   NEED_AUG (-1);
96
97   r = aug_defvar (aug, name, expr);
98   if (r == -1) {
99     reply_with_error ("Augeas defvar failed");
100     return -1;
101   }
102   return r;
103 }
104
105 guestfs_aug_defnode_ret *
106 do_aug_defnode (const char *name, const char *expr, const char *val)
107 {
108   static guestfs_aug_defnode_ret r;
109   int created;
110
111   NEED_AUG (NULL);
112
113   r.nrnodes = aug_defnode (aug, name, expr, val, &created);
114   if (r.nrnodes == -1) {
115     reply_with_error ("Augeas defnode failed");
116     return NULL;
117   }
118   r.created = created;
119   return &r;
120 }
121
122 char *
123 do_aug_get (const char *path)
124 {
125   const char *value = NULL;
126   char *v;
127   int r;
128
129   NEED_AUG (NULL);
130
131   r = aug_get (aug, path, &value);
132   if (r == 0) {
133     reply_with_error ("no matching node");
134     return NULL;
135   }
136   if (r != 1) {
137     reply_with_error ("Augeas get failed");
138     return NULL;
139   }
140
141   /* value can still be NULL here, eg. try with path == "/augeas".
142    * I don't understand this case, and it seems to contradict the
143    * documentation.
144    */
145   if (value == NULL) {
146     reply_with_error ("Augeas returned NULL match");
147     return NULL;
148   }
149
150   /* The value is an internal Augeas string, so we must copy it. GC FTW. */
151   v = strdup (value);
152   if (v == NULL) {
153     reply_with_perror ("strdup");
154     return NULL;
155   }
156
157   return v;                     /* Caller frees. */
158 }
159
160 int
161 do_aug_set (const char *path, const char *val)
162 {
163   int r;
164
165   NEED_AUG (-1);
166
167   r = aug_set (aug, path, val);
168   if (r == -1) {
169     reply_with_error ("Augeas set failed");
170     return -1;
171   }
172
173   return 0;
174 }
175
176 int
177 do_aug_insert (const char *path, const char *label, int before)
178 {
179   int r;
180
181   NEED_AUG (-1);
182
183   r = aug_insert (aug, path, label, before);
184   if (r == -1) {
185     reply_with_error ("Augeas insert failed");
186     return -1;
187   }
188
189   return 0;
190 }
191
192 int
193 do_aug_rm (const char *path)
194 {
195   int r;
196
197   NEED_AUG (-1);
198
199   r = aug_rm (aug, path);
200   if (r == -1) {
201     reply_with_error ("Augeas rm failed");
202     return -1;
203   }
204
205   return r;
206 }
207
208 int
209 do_aug_mv (const char *src, const char *dest)
210 {
211   int r;
212
213   NEED_AUG (-1);
214
215   r = aug_mv (aug, src, dest);
216   if (r == -1) {
217     reply_with_error ("Augeas mv failed");
218     return -1;
219   }
220
221   return 0;
222 }
223
224 char **
225 do_aug_match (const char *path)
226 {
227   char **matches = NULL;
228   void *vp;
229   int r;
230
231   NEED_AUG (NULL);
232
233   r = aug_match (aug, path, &matches);
234   if (r == -1) {
235     reply_with_error ("Augeas match failed");
236     return NULL;
237   }
238
239   /* This returns an array of length r, which we must extend
240    * and add a terminating NULL.
241    */
242   vp = realloc (matches, sizeof (char *) * (r+1));
243   if (vp == NULL) {
244     reply_with_perror ("realloc");
245     free (vp);
246     return NULL;
247   }
248   matches = vp;
249   matches[r] = NULL;
250
251   return matches;               /* Caller frees. */
252 }
253
254 int
255 do_aug_save (void)
256 {
257   NEED_AUG (-1);
258
259   if (aug_save (aug) == -1) {
260     reply_with_error ("Augeas save failed");
261     return -1;
262   }
263
264   return 0;
265 }
266
267 int
268 do_aug_load (void)
269 {
270   NEED_AUG (-1);
271
272   if (aug_load (aug) == -1) {
273     reply_with_error ("Augeas load failed");
274     return -1;
275   }
276
277   return 0;
278 }
279
280 /* Simpler version of aug-match, which also sorts the output. */
281 char **
282 do_aug_ls (const char *path)
283 {
284   char **matches;
285   char *buf;
286   int len;
287
288   NEED_AUG (NULL);
289
290   ABS_PATH (path, NULL);
291
292   len = strlen (path);
293
294   if (len > 1 &&
295       (path[len-1] == '/' || path[len-1] == ']' || path[len-1] == '*')) {
296     reply_with_error ("don't use aug-ls with a path that ends with / ] *");
297     return NULL;
298   }
299
300   if (len == 1)
301     /* we know path must be "/" because of ABS_PATH above */
302     matches = do_aug_match ("/");
303   else {
304     len += 3;                   /* / * + terminating \0 */
305     buf = malloc (len);
306     if (buf == NULL) {
307       reply_with_perror ("malloc");
308       return NULL;
309     }
310
311     snprintf (buf, len, "%s/*", path);
312     matches = do_aug_match (buf);
313     free (buf);
314   }
315
316   if (matches == NULL)
317     return NULL;                /* do_aug_match has already sent the error */
318
319   sort_strings (matches, count_strings (matches));
320   return matches;               /* Caller frees. */
321 }