change almost all uses: s/IS_DEVICE/RESOLVE_DEVICE/
[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 (char *path)
34 {
35   int fd;
36   int r;
37
38   NEED_ROOT (-1);
39   ABS_PATH (path, -1);
40
41   CHROOT_IN;
42   fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY, 0666);
43   CHROOT_OUT;
44
45   if (fd == -1) {
46     reply_with_perror ("open: %s", path);
47     return -1;
48   }
49
50 #ifdef HAVE_FUTIMENS
51   r = futimens (fd, NULL);
52 #else
53   r = futimes (fd, NULL);
54 #endif
55   if (r == -1) {
56     reply_with_perror ("futimens: %s", path);
57     close (fd);
58     return -1;
59   }
60
61   if (close (fd) == -1) {
62     reply_with_perror ("close: %s", path);
63     return -1;
64   }
65
66   return 0;
67 }
68
69 char *
70 do_cat (char *path)
71 {
72   int fd;
73   int alloc, size, r, max;
74   char *buf, *buf2;
75
76   NEED_ROOT (NULL);
77   ABS_PATH (path,NULL);
78
79   CHROOT_IN;
80   fd = open (path, O_RDONLY);
81   CHROOT_OUT;
82
83   if (fd == -1) {
84     reply_with_perror ("open: %s", path);
85     return NULL;
86   }
87
88   /* Read up to GUESTFS_MESSAGE_MAX - <overhead> bytes.  If it's
89    * larger than that, we need to return an error instead (for
90    * correctness).
91    */
92   max = GUESTFS_MESSAGE_MAX - 1000;
93   buf = NULL;
94   size = alloc = 0;
95
96   for (;;) {
97     if (size >= alloc) {
98       alloc += 8192;
99       if (alloc > max) {
100         reply_with_error ("cat: %s: file is too large for message buffer",
101                           path);
102         free (buf);
103         close (fd);
104         return NULL;
105       }
106       buf2 = realloc (buf, alloc);
107       if (buf2 == NULL) {
108         reply_with_perror ("realloc");
109         free (buf);
110         close (fd);
111         return NULL;
112       }
113       buf = buf2;
114     }
115
116     r = read (fd, buf + size, alloc - size);
117     if (r == -1) {
118       reply_with_perror ("read: %s", path);
119       free (buf);
120       close (fd);
121       return NULL;
122     }
123     if (r == 0) {
124       buf[size] = '\0';
125       break;
126     }
127     if (r > 0)
128       size += r;
129   }
130
131   if (close (fd) == -1) {
132     reply_with_perror ("close: %s", path);
133     free (buf);
134     return NULL;
135   }
136
137   return buf;                   /* caller will free */
138 }
139
140 char **
141 do_read_lines (char *path)
142 {
143   char **r = NULL;
144   int size = 0, alloc = 0;
145   FILE *fp;
146   char *line = NULL;
147   size_t len = 0;
148   ssize_t n;
149
150   NEED_ROOT (NULL);
151   ABS_PATH (path, NULL);
152
153   CHROOT_IN;
154   fp = fopen (path, "r");
155   CHROOT_OUT;
156
157   if (!fp) {
158     reply_with_perror ("fopen: %s", path);
159     return NULL;
160   }
161
162   while ((n = getline (&line, &len, fp)) != -1) {
163     /* Remove either LF or CRLF. */
164     if (n >= 2 && line[n-2] == '\r' && line[n-1] == '\n')
165       line[n-2] = '\0';
166     else if (n >= 1 && line[n-1] == '\n')
167       line[n-1] = '\0';
168
169     if (add_string (&r, &size, &alloc, line) == -1) {
170       free (line);
171       fclose (fp);
172       return NULL;
173     }
174   }
175
176   free (line);
177
178   if (add_string (&r, &size, &alloc, NULL) == -1) {
179     fclose (fp);
180     return NULL;
181   }
182
183   if (fclose (fp) == EOF) {
184     reply_with_perror ("fclose: %s", path);
185     free_strings (r);
186     return NULL;
187   }
188
189   return r;
190 }
191
192 int
193 do_rm (char *path)
194 {
195   int r;
196
197   NEED_ROOT (-1);
198   ABS_PATH (path, -1);
199
200   CHROOT_IN;
201   r = unlink (path);
202   CHROOT_OUT;
203
204   if (r == -1) {
205     reply_with_perror ("unlink: %s", path);
206     return -1;
207   }
208
209   return 0;
210 }
211
212 int
213 do_chmod (int mode, char *path)
214 {
215   int r;
216
217   NEED_ROOT (-1);
218   ABS_PATH (path, -1);
219
220   CHROOT_IN;
221   r = chmod (path, mode);
222   CHROOT_OUT;
223
224   if (r == -1) {
225     reply_with_perror ("chmod: %s: 0%o", path, mode);
226     return -1;
227   }
228
229   return 0;
230 }
231
232 int
233 do_chown (int owner, int group, char *path)
234 {
235   int r;
236
237   NEED_ROOT (-1);
238   ABS_PATH (path, -1);
239
240   CHROOT_IN;
241   r = chown (path, owner, group);
242   CHROOT_OUT;
243
244   if (r == -1) {
245     reply_with_perror ("chown: %s: %d.%d", path, owner, group);
246     return -1;
247   }
248
249   return 0;
250 }
251
252 int
253 do_exists (char *path)
254 {
255   int r;
256
257   NEED_ROOT (-1);
258   ABS_PATH (path, -1);
259
260   CHROOT_IN;
261   r = access (path, F_OK);
262   CHROOT_OUT;
263
264   return r == 0;
265 }
266
267 int
268 do_is_file (char *path)
269 {
270   int r;
271   struct stat buf;
272
273   NEED_ROOT (-1);
274   ABS_PATH (path, -1);
275
276   CHROOT_IN;
277   r = lstat (path, &buf);
278   CHROOT_OUT;
279
280   if (r == -1) {
281     if (errno != ENOENT && errno != ENOTDIR) {
282       reply_with_perror ("stat: %s", path);
283       return -1;
284     }
285     else
286       return 0;                 /* Not a file. */
287   }
288
289   return S_ISREG (buf.st_mode);
290 }
291
292 int
293 do_write_file (char *path, char *content, int size)
294 {
295   int fd;
296
297   NEED_ROOT (-1);
298   ABS_PATH (path, -1);
299
300   if (size == 0)
301     size = strlen (content);
302
303   CHROOT_IN;
304   fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666);
305   CHROOT_OUT;
306
307   if (fd == -1) {
308     reply_with_perror ("open: %s", path);
309     return -1;
310   }
311
312   if (xwrite (fd, content, size) == -1) {
313     reply_with_perror ("write");
314     close (fd);
315     return -1;
316   }
317
318   if (close (fd) == -1) {
319     reply_with_perror ("close: %s", path);
320     return -1;
321   }
322
323   return 0;
324 }
325
326 char *
327 do_read_file (char *path, size_t *size_r)
328 {
329   int fd;
330   struct stat statbuf;
331   char *r;
332
333   NEED_ROOT (NULL);
334   ABS_PATH (path, NULL);
335
336   CHROOT_IN;
337   fd = open (path, O_RDONLY);
338   CHROOT_OUT;
339
340   if (fd == -1) {
341     reply_with_perror ("open: %s", path);
342     return NULL;
343   }
344
345   if (fstat (fd, &statbuf) == -1) {
346     reply_with_perror ("fstat: %s", path);
347     close (fd);
348     return NULL;
349   }
350
351   *size_r = statbuf.st_size;
352   /* The actual limit on messages is smaller than this.  This
353    * check just limits the amount of memory we'll try and allocate
354    * here.  If the message is larger than the real limit, that will
355    * be caught later when we try to serialize the message.
356    */
357   if (*size_r >= GUESTFS_MESSAGE_MAX) {
358     reply_with_error ("read_file: %s: file is too large for the protocol, use guestfs_download instead", path);
359     close (fd);
360     return NULL;
361   }
362   r = malloc (*size_r);
363   if (r == NULL) {
364     reply_with_perror ("malloc");
365     close (fd);
366     return NULL;
367   }
368
369   if (xread (fd, r, *size_r) == -1) {
370     reply_with_perror ("read: %s", path);
371     close (fd);
372     free (r);
373     return NULL;
374   }
375
376   if (close (fd) == -1) {
377     reply_with_perror ("close: %s", path);
378     free (r);
379     return NULL;
380   }
381
382   return r;
383 }
384
385 /* This runs the 'file' command. */
386 char *
387 do_file (char *path)
388 {
389   char *out, *err;
390   int r, freeit = 0;
391   char *buf;
392   int len;
393
394   NEED_ROOT_OR_IS_DEVICE (path, return NULL);
395
396   if (strncmp (path, "/dev/", 5) == 0)
397     buf = (char *) path;
398   else {
399     buf = sysroot_path (path);
400     if (!buf) {
401       reply_with_perror ("malloc");
402       return NULL;
403     }
404     freeit = 1;
405   }
406
407   /* file(1) manpage claims "file returns 0 on success, and non-zero on
408    * error", but this is evidently not true.  It always returns 0, in
409    * every scenario I can think up.  So check the target is readable
410    * first.
411    */
412   if (access (buf, R_OK) == -1) {
413     if (freeit) free (buf);
414     reply_with_perror ("access: %s", path);
415     return NULL;
416   }
417
418   r = command (&out, &err, "file", "-zbsL", buf, NULL);
419   if (freeit) free (buf);
420
421   if (r == -1) {
422     free (out);
423     reply_with_error ("file: %s: %s", path, err);
424     free (err);
425     return NULL;
426   }
427   free (err);
428
429   /* We need to remove the trailing \n from output of file(1). */
430   len = strlen (out);
431   if (out[len-1] == '\n')
432     out[len-1] = '\0';
433
434   return out;                   /* caller frees */
435 }
436
437 /* zcat | file */
438 char *
439 do_zfile (char *method, char *path)
440 {
441   int len;
442   const char *zcat;
443   char *cmd;
444   FILE *fp;
445   char line[256];
446
447   NEED_ROOT (NULL);
448   ABS_PATH (path, NULL);
449
450   if (strcmp (method, "gzip") == 0 || strcmp (method, "compress") == 0)
451     zcat = "zcat";
452   else if (strcmp (method, "bzip2") == 0)
453     zcat = "bzcat";
454   else {
455     reply_with_error ("zfile: unknown method");
456     return NULL;
457   }
458
459   if (asprintf_nowarn (&cmd, "%s %R | file -bsL -", zcat, path) == -1) {
460     reply_with_perror ("asprintf");
461     return NULL;
462   }
463
464   if (verbose)
465     fprintf (stderr, "%s\n", cmd);
466
467   fp = popen (cmd, "r");
468   if (fp == NULL) {
469     reply_with_perror ("%s", cmd);
470     free (cmd);
471     return NULL;
472   }
473
474   free (cmd);
475
476   if (fgets (line, sizeof line, fp) == NULL) {
477     reply_with_perror ("zfile: fgets");
478     fclose (fp);
479     return NULL;
480   }
481
482   if (fclose (fp) == -1) {
483     reply_with_perror ("zfile: fclose");
484     return NULL;
485   }
486
487   len = strlen (line);
488   if (len > 0 && line[len-1] == '\n')
489     line[len-1] = '\0';
490
491   return strdup (line);
492 }