fish: Reimplement -i option using new C-based inspection.
[libguestfs.git] / fish / alloc.c
1 /* guestfish - the filesystem interactive shell
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 <inttypes.h>
27 #include <errno.h>
28
29 #include "xstrtol.h"
30
31 #include "fish.h"
32
33 int
34 do_alloc (const char *cmd, int argc, char *argv[])
35 {
36   if (argc != 2) {
37     fprintf (stderr, _("use 'alloc file size' to create an image\n"));
38     return -1;
39   }
40
41   if (alloc_disk (argv[0], argv[1], 1, 0) == -1)
42     return -1;
43
44   return 0;
45 }
46
47 int
48 do_sparse (const char *cmd, int argc, char *argv[])
49 {
50   if (argc != 2) {
51     fprintf (stderr, _("use 'sparse file size' to create a sparse image\n"));
52     return -1;
53   }
54
55   if (alloc_disk (argv[0], argv[1], 1, 1) == -1)
56     return -1;
57
58   return 0;
59 }
60
61 static int parse_size (const char *str, off_t *size_rtn);
62
63 /* This is the underlying allocation function.  It's called from
64  * a few other places in guestfish.
65  */
66 int
67 alloc_disk (const char *filename, const char *size_str, int add, int sparse)
68 {
69   off_t size;
70   int fd;
71   char c = 0;
72
73   if (parse_size (size_str, &size) == -1)
74     return -1;
75
76   if (!guestfs_is_config (g)) {
77     fprintf (stderr, _("can't allocate or add disks after launching\n"));
78     return -1;
79   }
80
81   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
82   if (fd == -1) {
83     perror (filename);
84     return -1;
85   }
86
87   if (!sparse) {                /* Not sparse */
88 #ifdef HAVE_POSIX_FALLOCATE
89     int err = posix_fallocate (fd, 0, size);
90     if (err != 0) {
91       errno = err;
92       perror ("fallocate");
93       close (fd);
94       unlink (filename);
95       return -1;
96     }
97 #else
98     /* Slow emulation of posix_fallocate on platforms which don't have it. */
99     char buffer[BUFSIZ];
100     memset (buffer, 0, sizeof buffer);
101
102     size_t remaining = size;
103     while (remaining > 0) {
104       size_t n = remaining > sizeof buffer ? sizeof buffer : remaining;
105       ssize_t r = write (fd, buffer, n);
106       if (r == -1) {
107         perror ("write");
108         close (fd);
109         unlink (filename);
110         return -1;
111       }
112       remaining -= r;
113     }
114 #endif
115   } else {                      /* Sparse */
116     if (lseek (fd, size-1, SEEK_SET) == (off_t) -1) {
117       perror ("lseek");
118       close (fd);
119       unlink (filename);
120       return -1;
121     }
122
123     if (write (fd, &c, 1) != 1) {
124       perror ("write");
125       close (fd);
126       unlink (filename);
127       return -1;
128     }
129   }
130
131   if (close (fd) == -1) {
132     perror (filename);
133     unlink (filename);
134     return -1;
135   }
136
137   if (add) {
138     if (guestfs_add_drive (g, filename) == -1) {
139       unlink (filename);
140       return -1;
141     }
142   }
143
144   return 0;
145 }
146
147 static int
148 parse_size (const char *str, off_t *size_rtn)
149 {
150   unsigned long long size;
151   strtol_error xerr;
152
153   xerr = xstrtoull (str, NULL, 0, &size, "0kKMGTPEZY");
154   if (xerr != LONGINT_OK) {
155     fprintf (stderr,
156              _("%s: invalid integer parameter (%s returned %d)\n"),
157              "alloc_disk", "xstrtoull", xerr);
158     return -1;
159   }
160
161   /* XXX 32 bit file offsets, if anyone uses them?  GCC should give
162    * a warning here anyhow.
163    */
164   *size_rtn = size;
165
166   return 0;
167 }