Version 1.10.6.
[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 run_alloc (const char *cmd, size_t 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 run_sparse (const char *cmd, size_t 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 /* This is the underlying allocation function.  It's called from
62  * a few other places in guestfish.
63  */
64 int
65 alloc_disk (const char *filename, const char *size_str, int add, int sparse)
66 {
67   off_t size;
68   int fd;
69   char c = 0;
70
71   if (parse_size (size_str, &size) == -1)
72     return -1;
73
74   if (!guestfs_is_config (g)) {
75     fprintf (stderr, _("can't allocate or add disks after launching\n"));
76     return -1;
77   }
78
79   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
80   if (fd == -1) {
81     perror (filename);
82     return -1;
83   }
84
85   if (!sparse) {                /* Not sparse */
86 #ifdef HAVE_POSIX_FALLOCATE
87     int err = posix_fallocate (fd, 0, size);
88     if (err != 0) {
89       errno = err;
90       perror ("fallocate");
91       close (fd);
92       unlink (filename);
93       return -1;
94     }
95 #else
96     /* Slow emulation of posix_fallocate on platforms which don't have it. */
97     char buffer[BUFSIZ];
98     memset (buffer, 0, sizeof buffer);
99
100     size_t remaining = size;
101     while (remaining > 0) {
102       size_t n = remaining > sizeof buffer ? sizeof buffer : remaining;
103       ssize_t r = write (fd, buffer, n);
104       if (r == -1) {
105         perror ("write");
106         close (fd);
107         unlink (filename);
108         return -1;
109       }
110       remaining -= r;
111     }
112 #endif
113   } else {                      /* Sparse */
114     if (lseek (fd, size-1, SEEK_SET) == (off_t) -1) {
115       perror ("lseek");
116       close (fd);
117       unlink (filename);
118       return -1;
119     }
120
121     if (write (fd, &c, 1) != 1) {
122       perror ("write");
123       close (fd);
124       unlink (filename);
125       return -1;
126     }
127   }
128
129   if (close (fd) == -1) {
130     perror (filename);
131     unlink (filename);
132     return -1;
133   }
134
135   if (add) {
136     if (guestfs_add_drive_opts (g, filename,
137                                 GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
138                                 -1) == -1) {
139       unlink (filename);
140       return -1;
141     }
142   }
143
144   return 0;
145 }
146
147 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              "parse_size", "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 }