Use AC_GNU_SOURCE in daemon. Don't need _GNU_SOURCE in C files any more.
[libguestfs.git] / daemon / file.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 <fcntl.h>
26 #include <sys/stat.h>
27
28 #include "../src/guestfs_protocol.h"
29 #include "daemon.h"
30 #include "actions.h"
31
32 int
33 do_touch (const char *path)
34 {
35   int fd;
36
37   NEED_ROOT (-1);
38   ABS_PATH (path, -1);
39
40   CHROOT_IN;
41   fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY, 0666);
42   CHROOT_OUT;
43
44   if (fd == -1) {
45     reply_with_perror ("open: %s", path);
46     return -1;
47   }
48
49   if (futimens (fd, NULL) == -1) {
50     reply_with_perror ("futimens: %s", path);
51     close (fd);
52     return -1;
53   }
54
55   close (fd);
56   return 0;
57 }
58
59 char *
60 do_cat (const char *path)
61 {
62   int fd;
63   int alloc, size, r, max;
64   char *buf, *buf2;
65
66   NEED_ROOT (NULL);
67   ABS_PATH (path,NULL);
68
69   CHROOT_IN;
70   fd = open (path, O_RDONLY);
71   CHROOT_OUT;
72
73   if (fd == -1) {
74     reply_with_perror ("open: %s", path);
75     return NULL;
76   }
77
78   /* Read up to GUESTFS_MESSAGE_MAX - <overhead> bytes.  If it's
79    * larger than that, we need to return an error instead (for
80    * correctness).
81    */
82   max = GUESTFS_MESSAGE_MAX - 1000;
83   buf = NULL;
84   size = alloc = 0;
85
86   for (;;) {
87     if (size >= alloc) {
88       alloc += 8192;
89       if (alloc > max) {
90         reply_with_error ("cat: %s: file is too large for message buffer",
91                           path);
92         free (buf);
93         close (fd);
94         return NULL;
95       }
96       buf2 = realloc (buf, alloc);
97       if (buf2 == NULL) {
98         reply_with_perror ("realloc");
99         free (buf);
100         close (fd);
101         return NULL;
102       }
103       buf = buf2;
104     }
105
106     r = read (fd, buf + size, alloc - size);
107     if (r == -1) {
108       reply_with_perror ("read: %s", path);
109       free (buf);
110       close (fd);
111       return NULL;
112     }
113     if (r == 0) {
114       buf[size] = '\0';
115       break;
116     }
117     if (r > 0)
118       size += r;
119   }
120
121   if (close (fd) == -1) {
122     reply_with_perror ("close: %s", path);
123     free (buf);
124     return NULL;
125   }
126
127   return buf;                   /* caller will free */
128 }
129
130 char **
131 do_read_lines (const char *path)
132 {
133   char **r = NULL;
134   int size = 0, alloc = 0;
135   FILE *fp;
136   char *line = NULL;
137   size_t len = 0;
138   ssize_t n;
139
140   NEED_ROOT (NULL);
141   ABS_PATH (path, NULL);
142
143   CHROOT_IN;
144   fp = fopen (path, "r");
145   CHROOT_OUT;
146
147   if (!fp) {
148     reply_with_perror ("fopen: %s", path);
149     return NULL;
150   }
151
152   while ((n = getline (&line, &len, fp)) != -1) {
153     /* Remove either LF or CRLF. */
154     if (n >= 2 && line[n-2] == '\r' && line[n-1] == '\n')
155       line[n-2] = '\0';
156     else if (n >= 1 && line[n-1] == '\n')
157       line[n-1] = '\0';
158
159     if (add_string (&r, &size, &alloc, line) == -1) {
160       free (line);
161       fclose (fp);
162       return NULL;
163     }
164   }
165
166   free (line);
167
168   if (add_string (&r, &size, &alloc, NULL) == -1) {
169     fclose (fp);
170     return NULL;
171   }
172
173   if (fclose (fp) == EOF) {
174     reply_with_perror ("fclose: %s", path);
175     free_strings (r);
176     return NULL;
177   }
178
179   return r;
180 }
181
182 int
183 do_rm (const char *path)
184 {
185   int r;
186
187   NEED_ROOT (-1);
188   ABS_PATH (path, -1);
189
190   CHROOT_IN;
191   r = unlink (path);
192   CHROOT_OUT;
193
194   if (r == -1) {
195     reply_with_perror ("unlink: %s", path);
196     return -1;
197   }
198
199   return 0;
200 }
201
202 int
203 do_chmod (int mode, const char *path)
204 {
205   int r;
206
207   NEED_ROOT (-1);
208   ABS_PATH (path, -1);
209
210   CHROOT_IN;
211   r = chmod (path, mode);
212   CHROOT_OUT;
213
214   if (r == -1) {
215     reply_with_perror ("chmod: %s: 0%o", path, mode);
216     return -1;
217   }
218
219   return 0;
220 }
221
222 int
223 do_chown (int owner, int group, const char *path)
224 {
225   int r;
226
227   NEED_ROOT (-1);
228   ABS_PATH (path, -1);
229
230   CHROOT_IN;
231   r = chown (path, owner, group);
232   CHROOT_OUT;
233
234   if (r == -1) {
235     reply_with_perror ("chown: %s: %d.%d", path, owner, group);
236     return -1;
237   }
238
239   return 0;
240 }
241
242 int
243 do_exists (const char *path)
244 {
245   int r;
246
247   NEED_ROOT (-1);
248   ABS_PATH (path, -1);
249
250   CHROOT_IN;
251   r = access (path, F_OK);
252   CHROOT_OUT;
253
254   return r == 0;
255 }
256
257 int
258 do_is_file (const char *path)
259 {
260   int r;
261   struct stat buf;
262
263   NEED_ROOT (-1);
264   ABS_PATH (path, -1);
265
266   CHROOT_IN;
267   r = lstat (path, &buf);
268   CHROOT_OUT;
269
270   if (r == -1) {
271     if (errno != ENOENT && errno != ENOTDIR) {
272       reply_with_perror ("stat: %s", path);
273       return -1;
274     }
275     else
276       return 0;                 /* Not a file. */
277   }
278
279   return S_ISREG (buf.st_mode);
280 }
281
282 int
283 do_write_file (const char *path, const char *content, int size)
284 {
285   int fd;
286
287   NEED_ROOT (-1);
288   ABS_PATH (path, -1);
289
290   if (size == 0)
291     size = strlen (content);
292
293   CHROOT_IN;
294   fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666);
295   CHROOT_OUT;
296
297   if (fd == -1) {
298     reply_with_perror ("open: %s", path);
299     return -1;
300   }
301
302   if (xwrite (fd, content, size) == -1) {
303     reply_with_perror ("write");
304     close (fd);
305     return -1;
306   }
307
308   if (close (fd) == -1) {
309     reply_with_perror ("close: %s", path);
310     return -1;
311   }
312
313   return 0;
314 }
315
316 /* This runs the 'file' command. */
317 char *
318 do_file (const char *path)
319 {
320   char *out, *err;
321   int r, len, freeit = 0;
322   char *buf;
323
324   NEED_ROOT_OR_IS_DEVICE (path, NULL);
325   ABS_PATH (path, NULL);
326
327   if (strncmp (path, "/dev/", 5) == 0)
328     buf = (char *) path;
329   else {
330     len = strlen (path) + 9;
331     buf = malloc (len);
332     if (!buf) {
333       reply_with_perror ("malloc");
334       return NULL;
335     }
336     snprintf (buf, len, "/sysroot%s", path);
337     freeit = 1;
338   }
339
340   /* file(1) manpage claims "file returns 0 on success, and non-zero on
341    * error", but this is evidently not true.  It always returns 0, in
342    * every scenario I can think up.  So check the target is readable
343    * first.
344    */
345   if (access (buf, R_OK) == -1) {
346     if (freeit) free (buf);
347     reply_with_perror ("access: %s", path);
348     return NULL;
349   }
350
351   r = command (&out, &err, "file", "-bsL", buf, NULL);
352   if (freeit) free (buf);
353
354   if (r == -1) {
355     free (out);
356     reply_with_error ("file: %s: %s", path, err);
357     free (err);
358     return NULL;
359   }
360   free (err);
361
362   /* We need to remove the trailing \n from output of file(1). */
363   len = strlen (out);
364   if (out[len-1] == '\n')
365     out[len-1] = '\0';
366
367   return out;                   /* caller frees */
368 }