1 /*
2  * storage_util.c: helper functions for the storage driver
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <config.h>
20 
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/statvfs.h>
26 #include <sys/param.h>
27 #include <dirent.h>
28 #ifdef __linux__
29 # include <sys/ioctl.h>
30 # include <linux/fs.h>
31 # define default_mount_opts "nodev,nosuid,noexec"
32 #elif defined(__FreeBSD__)
33 # define default_mount_opts "nosuid,noexec"
34 #else
35 # define default_mount_opts ""
36 #endif
37 
38 #if WITH_BLKID
39 # include <blkid.h>
40 #endif
41 
42 #if WITH_SELINUX
43 # include <selinux/selinux.h>
44 #endif
45 
46 #ifdef FICLONE
47 # define REFLINK_IOC_CLONE FICLONE
48 #elif WITH_LINUX_BTRFS_H
49 # include <linux/btrfs.h>
50 # define REFLINK_IOC_CLONE BTRFS_IOC_CLONE
51 #elif WITH_XFS_XFS_H
52 # include <xfs/xfs.h>
53 # define REFLINK_IOC_CLONE XFS_IOC_CLONE
54 #endif
55 
56 #include "datatypes.h"
57 #include "virerror.h"
58 #include "viralloc.h"
59 #include "internal.h"
60 #include "secret_conf.h"
61 #include "virsecret.h"
62 #include "vircrypto.h"
63 #include "viruuid.h"
64 #include "virstoragefile.h"
65 #include "storage_file_probe.h"
66 #include "storage_util.h"
67 #include "storage_source.h"
68 #include "storage_source_conf.h"
69 #include "virlog.h"
70 #include "virfile.h"
71 #include "viridentity.h"
72 #include "virjson.h"
73 #include "virqemu.h"
74 #include "virstring.h"
75 #include "virxml.h"
76 #include "virfdstream.h"
77 #include "virutil.h"
78 #include "virsecureerase.h"
79 
80 #define VIR_FROM_THIS VIR_FROM_STORAGE
81 
82 VIR_LOG_INIT("storage.storage_util");
83 
84 #ifndef S_IRWXUGO
85 # define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
86 #endif
87 
88 /* virStorageBackendNamespaceInit:
89  * @poolType: virStoragePoolType
90  * @xmlns: Storage Pool specific namespace callback methods
91  *
92  * To be called during storage backend registration to configure the
93  * Storage Pool XML Namespace based on the backend's needs.
94  */
95 int
virStorageBackendNamespaceInit(int poolType,virXMLNamespace * xmlns)96 virStorageBackendNamespaceInit(int poolType,
97                                virXMLNamespace *xmlns)
98 {
99     return virStoragePoolOptionsPoolTypeSetXMLNamespace(poolType, xmlns);
100 }
101 
102 
103 #define READ_BLOCK_SIZE_DEFAULT  (1024 * 1024)
104 #define WRITE_BLOCK_SIZE_DEFAULT (4 * 1024)
105 
106 /*
107  * Perform the O(1) btrfs clone operation, if possible.
108  * Upon success, return 0.  Otherwise, return -1 and set errno.
109  */
110 #ifdef REFLINK_IOC_CLONE
111 static inline int
reflinkCloneFile(int dest_fd,int src_fd)112 reflinkCloneFile(int dest_fd, int src_fd)
113 {
114     return ioctl(dest_fd, REFLINK_IOC_CLONE, src_fd);
115 }
116 #else
117 static inline int
reflinkCloneFile(int dest_fd G_GNUC_UNUSED,int src_fd G_GNUC_UNUSED)118 reflinkCloneFile(int dest_fd G_GNUC_UNUSED,
119                  int src_fd G_GNUC_UNUSED)
120 {
121     errno = ENOTSUP;
122     return -1;
123 }
124 #endif
125 
126 
127 static int ATTRIBUTE_NONNULL(2)
virStorageBackendCopyToFD(virStorageVolDef * vol,virStorageVolDef * inputvol,int fd,unsigned long long * total,bool want_sparse,bool reflink_copy)128 virStorageBackendCopyToFD(virStorageVolDef *vol,
129                           virStorageVolDef *inputvol,
130                           int fd,
131                           unsigned long long *total,
132                           bool want_sparse,
133                           bool reflink_copy)
134 {
135     int amtread = -1;
136     size_t rbytes = READ_BLOCK_SIZE_DEFAULT;
137     int wbytes = 0;
138     int interval;
139     struct stat st;
140     g_autofree char *zerobuf = NULL;
141     g_autofree char *buf = NULL;
142     VIR_AUTOCLOSE inputfd = -1;
143 
144     if ((inputfd = open(inputvol->target.path, O_RDONLY)) < 0) {
145         virReportSystemError(errno,
146                              _("could not open input path '%s'"),
147                              inputvol->target.path);
148         return -1;
149     }
150 
151 #ifdef __linux__
152     if (ioctl(fd, BLKBSZGET, &wbytes) < 0)
153         wbytes = 0;
154 #endif
155     if ((wbytes == 0) && fstat(fd, &st) == 0)
156         wbytes = st.st_blksize;
157     if (wbytes < WRITE_BLOCK_SIZE_DEFAULT)
158         wbytes = WRITE_BLOCK_SIZE_DEFAULT;
159 
160     zerobuf = g_new0(char, wbytes);
161 
162     buf = g_new0(char, rbytes);
163 
164     if (reflink_copy) {
165         if (reflinkCloneFile(fd, inputfd) < 0) {
166             virReportSystemError(errno,
167                                  _("failed to clone files from '%s'"),
168                                  inputvol->target.path);
169             return -1;
170         } else {
171             VIR_DEBUG("btrfs clone finished.");
172             return 0;
173         }
174     }
175 
176     while (amtread != 0) {
177         int amtleft;
178 
179         if (*total < rbytes)
180             rbytes = *total;
181 
182         if ((amtread = saferead(inputfd, buf, rbytes)) < 0) {
183             virReportSystemError(errno,
184                                  _("failed reading from file '%s'"),
185                                  inputvol->target.path);
186             return -1;
187         }
188         *total -= amtread;
189 
190         /* Loop over amt read in 512 byte increments, looking for sparse
191          * blocks */
192         amtleft = amtread;
193         do {
194             int offset = amtread - amtleft;
195             interval = ((wbytes > amtleft) ? amtleft : wbytes);
196 
197             if (want_sparse && memcmp(buf+offset, zerobuf, interval) == 0) {
198                 if (lseek(fd, interval, SEEK_CUR) < 0) {
199                     virReportSystemError(errno,
200                                          _("cannot extend file '%s'"),
201                                          vol->target.path);
202                     return -1;
203                 }
204             } else if (safewrite(fd, buf+offset, interval) < 0) {
205                 virReportSystemError(errno,
206                                      _("failed writing to file '%s'"),
207                                      vol->target.path);
208                 return -1;
209 
210             }
211         } while ((amtleft -= interval) > 0);
212     }
213 
214     if (virFileDataSync(fd) < 0) {
215         virReportSystemError(errno, _("cannot sync data to file '%s'"),
216                              vol->target.path);
217         return -1;
218     }
219 
220     if (VIR_CLOSE(inputfd) < 0) {
221         virReportSystemError(errno,
222                              _("cannot close file '%s'"),
223                              inputvol->target.path);
224         return -1;
225     }
226 
227     return 0;
228 }
229 
230 static int
storageBackendCreateBlockFrom(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)231 storageBackendCreateBlockFrom(virStoragePoolObj *pool G_GNUC_UNUSED,
232                               virStorageVolDef *vol,
233                               virStorageVolDef *inputvol,
234                               unsigned int flags)
235 {
236     unsigned long long remain;
237     struct stat st;
238     gid_t gid;
239     uid_t uid;
240     mode_t mode;
241     bool reflink_copy = false;
242     VIR_AUTOCLOSE fd = -1;
243 
244     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
245                   VIR_STORAGE_VOL_CREATE_REFLINK,
246                   -1);
247 
248     if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
249         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
250                        _("metadata preallocation is not supported for block "
251                          "volumes"));
252         return -1;
253     }
254 
255     if (flags & VIR_STORAGE_VOL_CREATE_REFLINK)
256         reflink_copy = true;
257 
258     if ((fd = open(vol->target.path, O_RDWR)) < 0) {
259         virReportSystemError(errno,
260                              _("cannot create path '%s'"),
261                              vol->target.path);
262         return -1;
263     }
264 
265     remain = vol->target.capacity;
266 
267     if (inputvol) {
268         if (virStorageBackendCopyToFD(vol, inputvol, fd, &remain,
269                                       false, reflink_copy) < 0)
270             return -1;
271     }
272 
273     if (fstat(fd, &st) == -1) {
274         virReportSystemError(errno, _("stat of '%s' failed"),
275                              vol->target.path);
276         return -1;
277     }
278     uid = (vol->target.perms->uid != st.st_uid) ? vol->target.perms->uid
279         : (uid_t)-1;
280     gid = (vol->target.perms->gid != st.st_gid) ? vol->target.perms->gid
281         : (gid_t)-1;
282     if (((uid != (uid_t)-1) || (gid != (gid_t)-1))
283         && (fchown(fd, uid, gid) < 0)) {
284         virReportSystemError(errno,
285                              _("cannot chown '%s' to (%u, %u)"),
286                              vol->target.path, (unsigned int)uid,
287                              (unsigned int)gid);
288         return -1;
289     }
290 
291     mode = (vol->target.perms->mode == (mode_t)-1 ?
292             VIR_STORAGE_DEFAULT_VOL_PERM_MODE : vol->target.perms->mode);
293     if (fchmod(fd, mode) < 0) {
294         virReportSystemError(errno,
295                              _("cannot set mode of '%s' to %04o"),
296                              vol->target.path, mode);
297         return -1;
298     }
299     if (VIR_CLOSE(fd) < 0) {
300         virReportSystemError(errno,
301                              _("cannot close file '%s'"),
302                              vol->target.path);
303         return -1;
304     }
305 
306     return 0;
307 }
308 
309 static int
createRawFile(int fd,virStorageVolDef * vol,virStorageVolDef * inputvol,bool reflink_copy)310 createRawFile(int fd, virStorageVolDef *vol,
311               virStorageVolDef *inputvol,
312               bool reflink_copy)
313 {
314     bool need_alloc = true;
315     unsigned long long pos = 0;
316 
317     /* If the new allocation is lower than the capacity of the original file,
318      * the cloned volume will be sparse */
319     if (inputvol &&
320         vol->target.allocation < inputvol->target.capacity)
321         need_alloc = false;
322 
323     /* Seek to the final size, so the capacity is available upfront
324      * for progress reporting */
325     if (ftruncate(fd, vol->target.capacity) < 0) {
326         virReportSystemError(errno,
327                              _("cannot extend file '%s'"),
328                              vol->target.path);
329         return -1;
330     }
331 
332 /* Avoid issues with older kernel's <linux/fs.h> namespace pollution. */
333 #if WITH_FALLOCATE - 0
334     /* Try to preallocate all requested disk space, but fall back to
335      * other methods if this fails with ENOSYS or EOPNOTSUPP. If allocation
336      * is 0 (or less than 0), then fallocate will fail with EINVAL.
337      * NOTE: do not use posix_fallocate; posix_fallocate falls back
338      * to writing zeroes block by block in case fallocate isn't
339      * available, and since we're going to copy data from another
340      * file it doesn't make sense to write the file twice. */
341     if (vol->target.allocation && need_alloc) {
342         if (fallocate(fd, 0, 0, vol->target.allocation) == 0) {
343             need_alloc = false;
344         } else if (errno != ENOSYS && errno != EOPNOTSUPP) {
345             virReportSystemError(errno,
346                                  _("cannot allocate %llu bytes in file '%s'"),
347                                  vol->target.allocation, vol->target.path);
348             return -1;
349         }
350     }
351 #endif
352 
353     if (inputvol) {
354         unsigned long long remain = inputvol->target.capacity;
355         /* allow zero blocks to be skipped if we've requested sparse
356          * allocation (allocation < capacity) or we have already
357          * been able to allocate the required space. */
358         if (virStorageBackendCopyToFD(vol, inputvol, fd, &remain,
359                                       !need_alloc, reflink_copy) < 0)
360             return -1;
361 
362         /* If the new allocation is greater than the original capacity,
363          * but fallocate failed, fill the rest with zeroes.
364          */
365         pos = inputvol->target.capacity - remain;
366     }
367 
368     if (need_alloc && (vol->target.allocation - pos > 0)) {
369         if (safezero(fd, pos, vol->target.allocation - pos) < 0) {
370             virReportSystemError(errno, _("cannot fill file '%s'"),
371                                  vol->target.path);
372             return -1;
373         }
374     }
375 
376     if (g_fsync(fd) < 0) {
377         virReportSystemError(errno, _("cannot sync data to file '%s'"),
378                              vol->target.path);
379         return -1;
380     }
381 
382     return 0;
383 }
384 
385 static int
storageBackendCreateRaw(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)386 storageBackendCreateRaw(virStoragePoolObj *pool,
387                         virStorageVolDef *vol,
388                         virStorageVolDef *inputvol,
389                         unsigned int flags)
390 {
391     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
392     int operation_flags;
393     bool reflink_copy = false;
394     mode_t open_mode = VIR_STORAGE_DEFAULT_VOL_PERM_MODE;
395     VIR_AUTOCLOSE fd = -1;
396 
397     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
398                   VIR_STORAGE_VOL_CREATE_REFLINK,
399                   -1);
400 
401     if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
402         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
403                        _("metadata preallocation is not supported for raw "
404                          "volumes"));
405         return -1;
406     }
407 
408     if (virStorageSourceHasBacking(&vol->target)) {
409         virReportError(VIR_ERR_NO_SUPPORT, "%s",
410                        _("backing storage not supported for raw volumes"));
411         return -1;
412     }
413 
414     if (flags & VIR_STORAGE_VOL_CREATE_REFLINK)
415         reflink_copy = true;
416 
417 
418     if (vol->target.encryption) {
419         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
420                        _("storage pool does not support encrypted volumes"));
421         return -1;
422     }
423 
424     operation_flags = VIR_FILE_OPEN_FORCE_MODE | VIR_FILE_OPEN_FORCE_OWNER;
425     if (def->type == VIR_STORAGE_POOL_NETFS)
426         operation_flags |= VIR_FILE_OPEN_FORK;
427 
428     if (vol->target.perms->mode != (mode_t)-1)
429         open_mode = vol->target.perms->mode;
430 
431     if ((fd = virFileOpenAs(vol->target.path,
432                             O_RDWR | O_CREAT | O_EXCL,
433                             open_mode,
434                             vol->target.perms->uid,
435                             vol->target.perms->gid,
436                             operation_flags)) < 0) {
437         virReportSystemError(-fd,
438                              _("Failed to create file '%s'"),
439                              vol->target.path);
440         return -1;
441     }
442 
443     /* NB, COW flag can only be toggled when the file is zero-size,
444      * so must go before the createRawFile call allocates payload */
445     if (vol->target.nocow &&
446         virFileSetCOW(vol->target.path, VIR_TRISTATE_BOOL_NO) < 0)
447         goto error;
448 
449     if (createRawFile(fd, vol, inputvol, reflink_copy) < 0) {
450         /* createRawFile already reported the exact error. */
451         goto error;
452     }
453 
454     return 0;
455 
456  error:
457     virFileRemove(vol->target.path,
458                   vol->target.perms->uid,
459                   vol->target.perms->gid);
460     return -1;
461 }
462 
463 
464 static int
virStorageBackendCreateExecCommand(virStoragePoolObj * pool,virStorageVolDef * vol,virCommand * cmd)465 virStorageBackendCreateExecCommand(virStoragePoolObj *pool,
466                                    virStorageVolDef *vol,
467                                    virCommand *cmd)
468 {
469     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
470     struct stat st;
471     gid_t gid;
472     uid_t uid;
473     mode_t mode = (vol->target.perms->mode == (mode_t)-1 ?
474                    VIR_STORAGE_DEFAULT_VOL_PERM_MODE :
475                    vol->target.perms->mode);
476     bool filecreated = false;
477     int ret = -1;
478 
479     if ((def->type == VIR_STORAGE_POOL_NETFS)
480         && (((geteuid() == 0)
481              && (vol->target.perms->uid != (uid_t)-1)
482              && (vol->target.perms->uid != 0))
483             || ((vol->target.perms->gid != (gid_t)-1)
484                 && (vol->target.perms->gid != getegid())))) {
485 
486         virCommandSetUID(cmd, vol->target.perms->uid);
487         virCommandSetGID(cmd, vol->target.perms->gid);
488         virCommandSetUmask(cmd, S_IRWXUGO ^ mode);
489 
490         if (virCommandRun(cmd, NULL) == 0) {
491             /* command was successfully run, check if the file was created */
492             if (stat(vol->target.path, &st) >= 0) {
493                 filecreated = true;
494 
495                 /* seems qemu-img disregards umask and open/creates using 0644.
496                  * If that doesn't match what we expect, then let's try to
497                  * re-open the file and attempt to force the mode change.
498                  */
499                 if (mode != (st.st_mode & S_IRWXUGO)) {
500                     VIR_AUTOCLOSE fd = -1;
501                     int flags = VIR_FILE_OPEN_FORK | VIR_FILE_OPEN_FORCE_MODE;
502 
503                     if ((fd = virFileOpenAs(vol->target.path, O_RDWR, mode,
504                                             vol->target.perms->uid,
505                                             vol->target.perms->gid,
506                                             flags)) >= 0) {
507                         /* Success - means we're good */
508                         ret = 0;
509                         goto cleanup;
510                     }
511                 }
512             }
513         }
514     }
515 
516     if (!filecreated) {
517         /* don't change uid/gid/mode if we retry */
518         virCommandSetUID(cmd, -1);
519         virCommandSetGID(cmd, -1);
520         virCommandSetUmask(cmd, 0);
521 
522         if (virCommandRun(cmd, NULL) < 0)
523             goto cleanup;
524         if (stat(vol->target.path, &st) < 0) {
525             virReportSystemError(errno,
526                                  _("failed to create %s"), vol->target.path);
527             goto cleanup;
528         }
529         filecreated = true;
530     }
531 
532     uid = (vol->target.perms->uid != st.st_uid) ? vol->target.perms->uid
533         : (uid_t)-1;
534     gid = (vol->target.perms->gid != st.st_gid) ? vol->target.perms->gid
535         : (gid_t)-1;
536     if (((uid != (uid_t)-1) || (gid != (gid_t)-1))
537         && (chown(vol->target.path, uid, gid) < 0)) {
538         virReportSystemError(errno,
539                              _("cannot chown %s to (%u, %u)"),
540                              vol->target.path, (unsigned int)uid,
541                              (unsigned int)gid);
542         goto cleanup;
543     }
544 
545     if (mode != (st.st_mode & S_IRWXUGO) &&
546         chmod(vol->target.path, mode) < 0) {
547         virReportSystemError(errno,
548                              _("cannot set mode of '%s' to %04o"),
549                              vol->target.path, mode);
550         goto cleanup;
551     }
552 
553     ret = 0;
554 
555  cleanup:
556     if (ret < 0 && filecreated)
557         virFileRemove(vol->target.path, vol->target.perms->uid,
558                       vol->target.perms->gid);
559     return ret;
560 }
561 
562 /* Create ploop directory with ploop image and DiskDescriptor.xml
563  * if function fails to create image file the directory will be deleted.*/
564 static int
storageBackendCreatePloop(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)565 storageBackendCreatePloop(virStoragePoolObj *pool G_GNUC_UNUSED,
566                           virStorageVolDef *vol,
567                           virStorageVolDef *inputvol,
568                           unsigned int flags)
569 {
570     int ret = -1;
571     g_autoptr(virCommand) cmd = NULL;
572     g_autofree char *create_tool = NULL;
573 
574     virCheckFlags(0, -1);
575 
576     if (inputvol && inputvol->target.format != VIR_STORAGE_FILE_PLOOP) {
577         virReportError(VIR_ERR_INTERNAL_ERROR,
578                        _("unsupported input storage vol type %d"),
579                        inputvol->target.format);
580         return -1;
581     }
582 
583     if (vol->target.encryption) {
584         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
585                        _("encrypted ploop volumes are not supported with "
586                          "ploop init"));
587         return -1;
588     }
589 
590     if (virStorageSourceHasBacking(&vol->target)) {
591         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
592                        _("copy-on-write ploop volumes are not yet supported"));
593         return -1;
594     }
595 
596     create_tool = virFindFileInPath("ploop");
597     if (!create_tool && !inputvol) {
598         virReportError(VIR_ERR_INTERNAL_ERROR,
599                        "%s", _("unable to find ploop, please install "
600                                "ploop tools"));
601         return -1;
602     }
603 
604     if (!inputvol) {
605         if ((virDirCreate(vol->target.path,
606                           (vol->target.perms->mode == (mode_t)-1 ?
607                            VIR_STORAGE_DEFAULT_VOL_PERM_MODE:
608                            vol->target.perms->mode),
609                           vol->target.perms->uid,
610                           vol->target.perms->gid,
611                           0)) < 0) {
612             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
613                            _("error creating directory for ploop volume"));
614             return -1;
615         }
616         cmd = virCommandNewArgList(create_tool, "init", "-s", NULL);
617         virCommandAddArgFormat(cmd, "%lluM", VIR_DIV_UP(vol->target.capacity,
618                                                         (1024 * 1024)));
619         virCommandAddArgList(cmd, "-t", "ext4", NULL);
620         virCommandAddArgFormat(cmd, "%s/root.hds", vol->target.path);
621 
622     } else {
623         vol->target.capacity = inputvol->target.capacity;
624         cmd = virCommandNewArgList("cp", "-r", inputvol->target.path,
625                                    vol->target.path, NULL);
626     }
627     ret = virCommandRun(cmd, NULL);
628     if (ret < 0)
629         virFileDeleteTree(vol->target.path);
630     return ret;
631 }
632 
633 
634 static int
storagePloopResize(virStorageVolDef * vol,unsigned long long capacity)635 storagePloopResize(virStorageVolDef *vol,
636                    unsigned long long capacity)
637 {
638     g_autoptr(virCommand) cmd = NULL;
639     g_autofree char *resize_tool = NULL;
640 
641     resize_tool = virFindFileInPath("ploop");
642     if (!resize_tool) {
643         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
644                        _("unable to find ploop, please install ploop tools"));
645         return -1;
646     }
647     cmd = virCommandNewArgList(resize_tool, "resize", "-s", NULL);
648     virCommandAddArgFormat(cmd, "%lluM", VIR_DIV_UP(capacity, (1024 * 1024)));
649 
650     virCommandAddArgFormat(cmd, "%s/DiskDescriptor.xml", vol->target.path);
651 
652     return virCommandRun(cmd, NULL);
653 }
654 
655 
656 /* The _virStorageBackendQemuImgInfo separates the command line building from
657  * the volume definition so that qemuDomainSnapshotCreateInactiveExternal can
658  * use it without needing to deal with a volume.
659  */
660 struct _virStorageBackendQemuImgInfo {
661     int format;
662     const char *type;
663     const char *inputType;
664     const char *path;
665     unsigned long long size_arg;
666     unsigned long long allocation;
667     unsigned long long clusterSize;
668     bool encryption;
669     bool preallocate;
670     const char *compat;
671     virBitmap *features;
672     bool nocow;
673 
674     const char *backingPath;
675     int backingFormat;
676 
677     const char *inputPath;
678     const char *inputFormatStr;
679     int inputFormat;
680 
681     char *secretAlias;
682 };
683 
684 
685 /**
686  * storageBackendBuildQemuImgEncriptionOpts:
687  * @buf: buffer to build the string into
688  * @encinfo: pointer to encryption info
689  * @alias: alias to use
690  *
691  * Generate the string for id=$alias and any encryption options for
692  * into the buffer.
693  *
694  * Important note, a trailing comma (",") is built into the return since
695  * it's expected other arguments are appended after the id=$alias string.
696  * So either turn something like:
697  *
698  *     "key-secret=$alias,"
699  *
700  * or
701  *     "key-secret=$alias,cipher-alg=twofish-256,cipher-mode=cbc,
702  *     hash-alg=sha256,ivgen-alg=plain64,igven-hash-alg=sha256,"
703  *
704  */
705 static void
storageBackendBuildQemuImgEncriptionOpts(virBuffer * buf,int format,virStorageEncryptionInfoDef * encinfo,const char * alias)706 storageBackendBuildQemuImgEncriptionOpts(virBuffer *buf,
707                                          int format,
708                                          virStorageEncryptionInfoDef *encinfo,
709                                          const char *alias)
710 {
711         const char *encprefix;
712 
713     if (format == VIR_STORAGE_FILE_QCOW2) {
714         virBufferAddLit(buf, "encrypt.format=luks,");
715         encprefix = "encrypt.";
716     } else {
717         encprefix = "";
718     }
719 
720     virBufferAsprintf(buf, "%skey-secret=%s,", encprefix, alias);
721 
722     if (!encinfo->cipher_name)
723         return;
724 
725     virBufferAsprintf(buf, "%scipher-alg=", encprefix);
726     virQEMUBuildBufferEscapeComma(buf, encinfo->cipher_name);
727     virBufferAsprintf(buf, "-%u,", encinfo->cipher_size);
728     if (encinfo->cipher_mode) {
729         virBufferAsprintf(buf, "%scipher-mode=", encprefix);
730         virQEMUBuildBufferEscapeComma(buf, encinfo->cipher_mode);
731         virBufferAddLit(buf, ",");
732     }
733     if (encinfo->cipher_hash) {
734         virBufferAsprintf(buf, "%shash-alg=", encprefix);
735         virQEMUBuildBufferEscapeComma(buf, encinfo->cipher_hash);
736         virBufferAddLit(buf, ",");
737     }
738     if (!encinfo->ivgen_name)
739         return;
740 
741     virBufferAsprintf(buf, "%sivgen-alg=", encprefix);
742     virQEMUBuildBufferEscapeComma(buf, encinfo->ivgen_name);
743     virBufferAddLit(buf, ",");
744 
745     if (encinfo->ivgen_hash) {
746         virBufferAsprintf(buf, "%sivgen-hash-alg=", encprefix);
747         virQEMUBuildBufferEscapeComma(buf, encinfo->ivgen_hash);
748         virBufferAddLit(buf, ",");
749     }
750 }
751 
752 
753 static int
storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDef * encinfo,char ** opts,struct _virStorageBackendQemuImgInfo * info)754 storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDef *encinfo,
755                                 char **opts,
756                                 struct _virStorageBackendQemuImgInfo *info)
757 {
758     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
759 
760     if (info->backingPath)
761         virBufferAsprintf(&buf, "backing_fmt=%s,",
762                           virStorageFileFormatTypeToString(info->backingFormat));
763 
764     if (encinfo) {
765         storageBackendBuildQemuImgEncriptionOpts(&buf, info->format, encinfo,
766                                                  info->secretAlias);
767     }
768 
769     if (info->preallocate) {
770         if (info->size_arg > info->allocation)
771             virBufferAddLit(&buf, "preallocation=metadata,");
772         else
773             virBufferAddLit(&buf, "preallocation=falloc,");
774     }
775 
776     if (info->nocow)
777         virBufferAddLit(&buf, "nocow=on,");
778 
779     if (info->compat)
780         virBufferAsprintf(&buf, "compat=%s,", info->compat);
781     else if (info->format == VIR_STORAGE_FILE_QCOW2)
782         virBufferAddLit(&buf, "compat=0.10,");
783 
784     if (info->clusterSize > 0)
785         virBufferAsprintf(&buf, "cluster_size=%llu,", info->clusterSize);
786 
787     if (info->features && info->format == VIR_STORAGE_FILE_QCOW2) {
788         if (virBitmapIsBitSet(info->features,
789                               VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS)) {
790             if (STREQ_NULLABLE(info->compat, "0.10")) {
791                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
792                                _("lazy_refcounts not supported with compat"
793                                  " level %s"),
794                                info->compat);
795                 return -1;
796             }
797             virBufferAddLit(&buf, "lazy_refcounts,");
798         }
799     }
800 
801     virBufferTrim(&buf, ",");
802 
803     *opts = virBufferContentAndReset(&buf);
804     return 0;
805 }
806 
807 
808 /* storageBackendCreateQemuImgCheckEncryption:
809  * @format: format of file found
810  * @type: TypeToString of format.type
811  * @vol: pointer to volume def
812  *
813  * Ensure the proper setup for encryption.
814  *
815  * Returns 0 on success, -1 on failure w/ error set
816  */
817 static int
storageBackendCreateQemuImgCheckEncryption(int format,const char * type,virStorageVolDef * vol)818 storageBackendCreateQemuImgCheckEncryption(int format,
819                                            const char *type,
820                                            virStorageVolDef *vol)
821 {
822     virStorageEncryption *enc = vol->target.encryption;
823 
824     if (format == VIR_STORAGE_FILE_RAW ||
825         format == VIR_STORAGE_FILE_QCOW2) {
826         if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
827             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
828                            _("unsupported volume encryption format %d"),
829                            vol->target.encryption->format);
830             return -1;
831         }
832         if (enc->nsecrets > 1) {
833             virReportError(VIR_ERR_XML_ERROR, "%s",
834                            _("too many secrets for luks encryption"));
835             return -1;
836         }
837         if (enc->nsecrets == 0) {
838             virReportError(VIR_ERR_XML_ERROR, "%s",
839                            _("no secret provided for luks encryption"));
840             return -1;
841         }
842     } else {
843         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
844                        _("volume encryption unsupported with format %s"), type);
845         return -1;
846     }
847 
848     return 0;
849 }
850 
851 
852 static int
storageBackendCreateQemuImgSetInput(virStorageVolDef * inputvol,virStorageVolEncryptConvertStep convertStep,struct _virStorageBackendQemuImgInfo * info)853 storageBackendCreateQemuImgSetInput(virStorageVolDef *inputvol,
854                                     virStorageVolEncryptConvertStep convertStep,
855                                     struct _virStorageBackendQemuImgInfo *info)
856 {
857     if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CREATE) {
858         if (!(info->inputPath = inputvol->target.path)) {
859             virReportError(VIR_ERR_INVALID_ARG, "%s",
860                            _("missing input volume target path"));
861             return -1;
862         }
863     }
864 
865     info->inputFormat = inputvol->target.format;
866     if (inputvol->type == VIR_STORAGE_VOL_BLOCK)
867         info->inputFormat = VIR_STORAGE_FILE_RAW;
868     if (info->inputFormat == VIR_STORAGE_FILE_ISO)
869         info->inputFormat = VIR_STORAGE_FILE_RAW;
870     if (!(info->inputFormatStr =
871           virStorageFileFormatTypeToString(info->inputFormat))) {
872         virReportError(VIR_ERR_INTERNAL_ERROR,
873                        _("unknown storage vol type %d"),
874                        info->inputFormat);
875         return -1;
876     }
877 
878     return 0;
879 }
880 
881 
882 static int
storageBackendCreateQemuImgSetBacking(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,struct _virStorageBackendQemuImgInfo * info)883 storageBackendCreateQemuImgSetBacking(virStoragePoolObj *pool,
884                                       virStorageVolDef *vol,
885                                       virStorageVolDef *inputvol,
886                                       struct _virStorageBackendQemuImgInfo *info)
887 {
888     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
889     int accessRetCode = -1;
890     g_autofree char *absolutePath = NULL;
891 
892     if (info->format == VIR_STORAGE_FILE_RAW) {
893         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
894                        _("cannot set backing store for raw volume"));
895         return -1;
896     }
897 
898     info->backingFormat = vol->target.backingStore->format;
899     info->backingPath = vol->target.backingStore->path;
900 
901     if (info->preallocate) {
902         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
903                        _("metadata preallocation conflicts with backing"
904                          " store"));
905         return -1;
906     }
907 
908     /* XXX: Not strictly required: qemu-img has an option a different
909      * backing store, not really sure what use it serves though, and it
910      * may cause issues with lvm. Untested essentially.
911      */
912     if (inputvol && virStorageSourceHasBacking(&inputvol->target) &&
913         STRNEQ_NULLABLE(inputvol->target.backingStore->path,
914                         info->backingPath)) {
915         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
916                        _("a different backing store cannot be specified."));
917         return -1;
918     }
919 
920     if (!virStorageFileFormatTypeToString(info->backingFormat)) {
921         virReportError(VIR_ERR_INTERNAL_ERROR,
922                        _("unknown storage vol backing store type %d"),
923                        info->backingFormat);
924         return -1;
925     }
926 
927     /* Convert relative backing store paths to absolute paths for access
928      * validation.
929      */
930     if (*(info->backingPath) != '/')
931         absolutePath = g_strdup_printf("%s/%s", def->target.path, info->backingPath);
932     accessRetCode = access(absolutePath ? absolutePath :
933                            info->backingPath, R_OK);
934     if (accessRetCode != 0) {
935         virReportSystemError(errno,
936                              _("inaccessible backing store volume %s"),
937                              info->backingPath);
938         return -1;
939     }
940 
941     return 0;
942 }
943 
944 
945 static int
storageBackendCreateQemuImgSetOptions(virCommand * cmd,virStorageEncryptionInfoDef * encinfo,struct _virStorageBackendQemuImgInfo * info)946 storageBackendCreateQemuImgSetOptions(virCommand *cmd,
947                                       virStorageEncryptionInfoDef *encinfo,
948                                       struct _virStorageBackendQemuImgInfo *info)
949 {
950     g_autofree char *opts = NULL;
951 
952     if (storageBackendCreateQemuImgOpts(encinfo, &opts, info) < 0)
953         return -1;
954     if (opts)
955         virCommandAddArgList(cmd, "-o", opts, NULL);
956 
957     return 0;
958 }
959 
960 
961 /* Add a secret object to the command line:
962  *    --object secret,id=$secretAlias,file=$secretPath
963  *
964  *    NB: format=raw is assumed
965  */
966 static int
storageBackendCreateQemuImgSecretObject(virCommand * cmd,const char * secretPath,const char * secretAlias)967 storageBackendCreateQemuImgSecretObject(virCommand *cmd,
968                                         const char *secretPath,
969                                         const char *secretAlias)
970 {
971     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
972     g_autofree char *commandStr = NULL;
973 
974     virBufferAsprintf(&buf, "secret,id=%s,file=", secretAlias);
975     virQEMUBuildBufferEscapeComma(&buf, secretPath);
976 
977     commandStr = virBufferContentAndReset(&buf);
978 
979     virCommandAddArgList(cmd, "--object", commandStr, NULL);
980 
981     return 0;
982 }
983 
984 
985 /* Add a --image-opts to the qemu-img resize command line for use
986  * with encryption:
987  *    --image-opts driver=luks,file.filename=$volpath,key-secret=$secretAlias
988  * or
989  *    --image-opts driver=qcow2,file.filename=$volpath,encrypt.key-secret=$secretAlias
990  *
991  */
992 static int
storageBackendResizeQemuImgImageOpts(virCommand * cmd,int format,const char * path,const char * secretAlias)993 storageBackendResizeQemuImgImageOpts(virCommand *cmd,
994                                      int format,
995                                      const char *path,
996                                      const char *secretAlias)
997 {
998     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
999     g_autofree char *commandStr = NULL;
1000     const char *encprefix;
1001     const char *driver;
1002 
1003     if (format == VIR_STORAGE_FILE_QCOW2) {
1004         driver = "qcow2";
1005         encprefix = "encrypt.";
1006     } else {
1007         driver = "luks";
1008         encprefix = "";
1009     }
1010 
1011     virBufferAsprintf(&buf, "driver=%s,%skey-secret=%s,file.filename=",
1012                       driver, encprefix, secretAlias);
1013     virQEMUBuildBufferEscapeComma(&buf, path);
1014 
1015     commandStr = virBufferContentAndReset(&buf);
1016 
1017     virCommandAddArgList(cmd, "--image-opts", commandStr, NULL);
1018 
1019     return 0;
1020 }
1021 
1022 
1023 static int
virStorageBackendCreateQemuImgSetInfo(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,virStorageVolEncryptConvertStep convertStep,struct _virStorageBackendQemuImgInfo * info)1024 virStorageBackendCreateQemuImgSetInfo(virStoragePoolObj *pool,
1025                                       virStorageVolDef *vol,
1026                                       virStorageVolDef *inputvol,
1027                                       virStorageVolEncryptConvertStep convertStep,
1028                                       struct _virStorageBackendQemuImgInfo *info)
1029 {
1030     /* Treat output block devices as 'raw' format */
1031     if (vol->type == VIR_STORAGE_VOL_BLOCK)
1032         info->format = VIR_STORAGE_FILE_RAW;
1033 
1034     if (info->format == VIR_STORAGE_FILE_ISO)
1035         info->format = VIR_STORAGE_FILE_RAW;
1036 
1037     if (!(info->type = virStorageFileFormatTypeToString(info->format))) {
1038         virReportError(VIR_ERR_INTERNAL_ERROR,
1039                        _("unknown storage vol type %d"),
1040                        info->format);
1041         return -1;
1042     }
1043 
1044     if (inputvol &&
1045         !(info->inputType =
1046           virStorageFileFormatTypeToString(inputvol->target.format))) {
1047         virReportError(VIR_ERR_INTERNAL_ERROR,
1048                        _("unknown inputvol storage vol type %d"),
1049                        inputvol->target.format);
1050         return -1;
1051     }
1052 
1053     if (info->preallocate && info->format != VIR_STORAGE_FILE_QCOW2) {
1054         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1055                        _("metadata preallocation only available with qcow2"));
1056         return -1;
1057     }
1058     if (info->compat && info->format != VIR_STORAGE_FILE_QCOW2) {
1059         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1060                        _("compatibility option only available with qcow2"));
1061         return -1;
1062     }
1063     if (info->features && info->format != VIR_STORAGE_FILE_QCOW2) {
1064         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1065                        _("format features only available with qcow2"));
1066         return -1;
1067     }
1068     if (info->format == VIR_STORAGE_FILE_RAW && vol->target.encryption) {
1069         if (vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
1070             info->type = "luks";
1071         } else {
1072             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1073                            _("Only luks encryption is supported for raw files"));
1074             return -1;
1075         }
1076     }
1077     if (inputvol && inputvol->target.format == VIR_STORAGE_FILE_RAW &&
1078         inputvol->target.encryption) {
1079         if (inputvol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
1080             info->inputType = "luks";
1081         } else {
1082             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1083                            _("Only luks encryption is supported for raw files"));
1084             return -1;
1085         }
1086     }
1087 
1088     if (inputvol &&
1089         storageBackendCreateQemuImgSetInput(inputvol, convertStep, info) < 0)
1090         return -1;
1091 
1092     if (virStorageSourceHasBacking(&vol->target) &&
1093         storageBackendCreateQemuImgSetBacking(pool, vol, inputvol, info) < 0)
1094         return -1;
1095 
1096     if (info->encryption &&
1097         storageBackendCreateQemuImgCheckEncryption(info->format, info->type,
1098                                                    vol) < 0)
1099         return -1;
1100 
1101     /* Size in KB */
1102     info->size_arg = VIR_DIV_UP(vol->target.capacity, 1024);
1103 
1104     return 0;
1105 }
1106 
1107 
1108 /* Create a qemu-img virCommand from the supplied arguments */
1109 virCommand *
virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags,const char * create_tool,const char * secretPath,const char * inputSecretPath,virStorageVolEncryptConvertStep convertStep)1110 virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObj *pool,
1111                                          virStorageVolDef *vol,
1112                                          virStorageVolDef *inputvol,
1113                                          unsigned int flags,
1114                                          const char *create_tool,
1115                                          const char *secretPath,
1116                                          const char *inputSecretPath,
1117                                          virStorageVolEncryptConvertStep convertStep)
1118 {
1119     virCommand *cmd = NULL;
1120     struct _virStorageBackendQemuImgInfo info = {
1121         .format = vol->target.format,
1122         .type = NULL,
1123         .inputType = NULL,
1124         .path = vol->target.path,
1125         .allocation = VIR_DIV_UP(vol->target.allocation, 1024),
1126         .encryption = !!vol->target.encryption,
1127         .preallocate = !!(flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA),
1128         .compat = vol->target.compat,
1129         .features = vol->target.features,
1130         .nocow = vol->target.nocow,
1131         .clusterSize = vol->target.clusterSize,
1132         .secretAlias = NULL,
1133     };
1134     virStorageEncryption *enc = vol->target.encryption;
1135     virStorageEncryption *inputenc = inputvol ? inputvol->target.encryption : NULL;
1136     virStorageEncryptionInfoDef *encinfo = NULL;
1137     g_autofree char *inputSecretAlias = NULL;
1138     const char *encprefix;
1139     const char *inputencprefix;
1140 
1141     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL);
1142 
1143     if (enc && (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
1144                 enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) &&
1145         (vol->target.format == VIR_STORAGE_FILE_QCOW ||
1146          vol->target.format == VIR_STORAGE_FILE_QCOW2)) {
1147         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1148                        _("creation of qcow2 encrypted image is not supported"));
1149         goto error;
1150     }
1151 
1152     if (inputenc && inputenc->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
1153         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1154                        _("encryption format of inputvol must be LUKS"));
1155         goto error;
1156     }
1157 
1158     if (virStorageBackendCreateQemuImgSetInfo(pool, vol, inputvol,
1159                                               convertStep, &info) < 0)
1160         goto error;
1161 
1162     cmd = virCommandNew(create_tool);
1163 
1164     /* ignore the backing volume when we're converting a volume
1165      * including when we're doing a two step convert during create */
1166     if (info.inputPath || convertStep == VIR_STORAGE_VOL_ENCRYPT_CREATE)
1167         info.backingPath = NULL;
1168 
1169     /* Converting to use encryption is a two step process - step 1 is to
1170      * create the image and step 2 is to convert it using special arguments */
1171     if (info.inputPath && convertStep == VIR_STORAGE_VOL_ENCRYPT_NONE)
1172         virCommandAddArgList(cmd, "convert", "-f", info.inputFormatStr,
1173                              "-O", info.type, NULL);
1174     else if (info.inputPath && convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT)
1175         virCommandAddArgList(cmd, "convert", "--image-opts", "-n",
1176                              "--target-image-opts", NULL);
1177     else
1178         virCommandAddArgList(cmd, "create", "-f", info.type, NULL);
1179 
1180     if (info.backingPath)
1181         virCommandAddArgList(cmd, "-b", info.backingPath, NULL);
1182 
1183     if (enc) {
1184         if (!secretPath) {
1185             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1186                            _("path to secret data file is required"));
1187             goto error;
1188         }
1189         info.secretAlias = g_strdup_printf("%s_encrypt0", vol->name);
1190         if (storageBackendCreateQemuImgSecretObject(cmd, secretPath,
1191                                                     info.secretAlias) < 0)
1192             goto error;
1193         encinfo = &enc->encinfo;
1194     }
1195 
1196     if (inputenc && convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
1197         if (!inputSecretPath) {
1198             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1199                            _("path to inputvol secret data file is required"));
1200             goto error;
1201         }
1202         inputSecretAlias = g_strdup_printf("%s_encrypt0", inputvol->name);
1203         if (storageBackendCreateQemuImgSecretObject(cmd, inputSecretPath,
1204                                                     inputSecretAlias) < 0)
1205             goto error;
1206     }
1207 
1208     if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
1209         if (storageBackendCreateQemuImgSetOptions(cmd, encinfo, &info) < 0)
1210             goto error;
1211         if (info.inputPath)
1212             virCommandAddArg(cmd, info.inputPath);
1213         virCommandAddArg(cmd, info.path);
1214         if (!info.inputPath && (info.size_arg || !info.backingPath))
1215             virCommandAddArgFormat(cmd, "%lluK", info.size_arg);
1216     } else {
1217         /* source */
1218         if (inputenc) {
1219             if (inputvol->target.format == VIR_STORAGE_FILE_QCOW2)
1220                 inputencprefix = "encrypt.";
1221             else
1222                 inputencprefix = "";
1223             virCommandAddArgFormat(cmd,
1224                                    "driver=%s,file.filename=%s,%skey-secret=%s",
1225                                    info.inputType, info.inputPath, inputencprefix, inputSecretAlias);
1226         } else {
1227             virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s",
1228                                    info.inputType ? info.inputType : "raw",
1229                                    info.inputPath);
1230         }
1231 
1232         /* dest */
1233         if (enc) {
1234             if (vol->target.format == VIR_STORAGE_FILE_QCOW2)
1235                 encprefix = "encrypt.";
1236             else
1237                 encprefix = "";
1238 
1239             virCommandAddArgFormat(cmd,
1240                                    "driver=%s,file.filename=%s,%skey-secret=%s",
1241                                    info.type, info.path, encprefix, info.secretAlias);
1242         } else {
1243             virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s",
1244                                    info.type, info.path);
1245         }
1246     }
1247     VIR_FREE(info.secretAlias);
1248 
1249     return cmd;
1250 
1251  error:
1252     VIR_FREE(info.secretAlias);
1253     virCommandFree(cmd);
1254     return NULL;
1255 }
1256 
1257 
1258 static char *
storageBackendCreateQemuImgSecretPath(virStoragePoolObj * pool,virStorageVolDef * vol)1259 storageBackendCreateQemuImgSecretPath(virStoragePoolObj *pool,
1260                                       virStorageVolDef *vol)
1261 {
1262     virStorageEncryption *enc = vol->target.encryption;
1263     char *secretPath = NULL;
1264     uint8_t *secret = NULL;
1265     size_t secretlen = 0;
1266     virConnectPtr conn = NULL;
1267     VIR_AUTOCLOSE fd = -1;
1268     VIR_IDENTITY_AUTORESTORE virIdentity *oldident = NULL;
1269 
1270     if (!enc) {
1271         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1272                        _("missing encryption description"));
1273         return NULL;
1274     }
1275 
1276     if (enc->nsecrets != 1) {
1277         virReportError(VIR_ERR_INVALID_ARG, "%s",
1278                        _("A single <secret type='passphrase'...> "
1279                          "element is expected in encryption description"));
1280         return NULL;
1281     }
1282 
1283     if (!(oldident = virIdentityElevateCurrent()))
1284         return NULL;
1285 
1286     conn = virGetConnectSecret();
1287     if (!conn)
1288         return NULL;
1289 
1290     if (!(secretPath = virStoragePoolObjBuildTempFilePath(pool, vol)))
1291         goto cleanup;
1292 
1293     if ((fd = g_mkstemp_full(secretPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR)) < 0) {
1294         virReportSystemError(errno, "%s",
1295                              _("failed to open secret file for write"));
1296         goto error;
1297     }
1298 
1299     if (virSecretGetSecretString(conn, &enc->secrets[0]->seclookupdef,
1300                                  VIR_SECRET_USAGE_TYPE_VOLUME,
1301                                  &secret, &secretlen) < 0)
1302         goto error;
1303 
1304     if (safewrite(fd, secret, secretlen) < 0) {
1305         virReportSystemError(errno, "%s",
1306                              _("failed to write secret file"));
1307         goto error;
1308     }
1309 
1310     if ((vol->target.perms->uid != (uid_t)-1) &&
1311         (vol->target.perms->gid != (gid_t)-1)) {
1312         if (chown(secretPath, vol->target.perms->uid,
1313                   vol->target.perms->gid) < 0) {
1314             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1315                            _("failed to chown secret file"));
1316             goto error;
1317         }
1318     }
1319 
1320  cleanup:
1321     virObjectUnref(conn);
1322     virSecureErase(secret, secretlen);
1323     g_free(secret);
1324 
1325     return secretPath;
1326 
1327  error:
1328     unlink(secretPath);
1329     VIR_FREE(secretPath);
1330     goto cleanup;
1331 }
1332 
1333 
1334 static int
storageBackendDoCreateQemuImg(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags,const char * create_tool,const char * secretPath,const char * inputSecretPath,virStorageVolEncryptConvertStep convertStep)1335 storageBackendDoCreateQemuImg(virStoragePoolObj *pool,
1336                               virStorageVolDef *vol,
1337                               virStorageVolDef *inputvol,
1338                               unsigned int flags,
1339                               const char *create_tool,
1340                               const char *secretPath,
1341                               const char *inputSecretPath,
1342                               virStorageVolEncryptConvertStep convertStep)
1343 {
1344     g_autoptr(virCommand) cmd = NULL;
1345 
1346     cmd = virStorageBackendCreateQemuImgCmdFromVol(pool, vol, inputvol,
1347                                                    flags, create_tool,
1348                                                    secretPath, inputSecretPath,
1349                                                    convertStep);
1350     if (!cmd)
1351         return -1;
1352 
1353     return virStorageBackendCreateExecCommand(pool, vol, cmd);
1354 }
1355 
1356 
1357 static int
storageBackendCreateQemuImg(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)1358 storageBackendCreateQemuImg(virStoragePoolObj *pool,
1359                             virStorageVolDef *vol,
1360                             virStorageVolDef *inputvol,
1361                             unsigned int flags)
1362 {
1363     int ret = -1;
1364     virStorageVolEncryptConvertStep convertStep = VIR_STORAGE_VOL_ENCRYPT_NONE;
1365     g_autofree char *create_tool = NULL;
1366     g_autofree char *secretPath = NULL;
1367     g_autofree char *inputSecretPath = NULL;
1368 
1369     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
1370 
1371     create_tool = virFindFileInPath("qemu-img");
1372     if (!create_tool) {
1373         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1374                        _("creation of non-raw file images is "
1375                          "not supported without qemu-img."));
1376         return -1;
1377     }
1378 
1379     if (vol->target.encryption &&
1380         !(secretPath = storageBackendCreateQemuImgSecretPath(pool, vol)))
1381         goto cleanup;
1382 
1383     if (inputvol && inputvol->target.encryption &&
1384         !(inputSecretPath = storageBackendCreateQemuImgSecretPath(pool,
1385                                                                   inputvol)))
1386         goto cleanup;
1387 
1388     /* Using an input file for encryption requires a multi-step process
1389      * to create an image of the same size as the inputvol and then to
1390      * convert the inputvol afterwards. */
1391     if ((secretPath || inputSecretPath) && inputvol)
1392         convertStep = VIR_STORAGE_VOL_ENCRYPT_CREATE;
1393 
1394     do {
1395         ret = storageBackendDoCreateQemuImg(pool, vol, inputvol, flags,
1396                                             create_tool, secretPath,
1397                                             inputSecretPath, convertStep);
1398 
1399         /* Failure to convert, attempt to delete what we created */
1400         if (ret < 0 && convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT)
1401             ignore_value(virFileRemove(vol->target.path,
1402                                        vol->target.perms->uid,
1403                                        vol->target.perms->gid));
1404 
1405         if (ret < 0 || convertStep == VIR_STORAGE_VOL_ENCRYPT_NONE)
1406             goto cleanup;
1407 
1408         if (convertStep == VIR_STORAGE_VOL_ENCRYPT_CREATE)
1409             convertStep = VIR_STORAGE_VOL_ENCRYPT_CONVERT;
1410         else if (convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT)
1411             convertStep = VIR_STORAGE_VOL_ENCRYPT_DONE;
1412     } while (convertStep != VIR_STORAGE_VOL_ENCRYPT_DONE);
1413 
1414  cleanup:
1415     if (secretPath)
1416         unlink(secretPath);
1417     if (inputSecretPath)
1418         unlink(inputSecretPath);
1419     return ret;
1420 }
1421 
1422 
1423 /**
1424  * virStorageBackendCreateVolUsingQemuImg
1425  * @pool: Storage Pool Object
1426  * @vol: Volume definition
1427  * @inputvol: Volume to use for creation
1428  * @flags: Flags for creation options
1429  *
1430  * A shim to storageBackendCreateQemuImg to allow other backends to
1431  * utilize qemu-img processing in order to create or alter the volume.
1432  *
1433  * NB: If a volume target format is not supplied (per usual for some
1434  * backends), temporarily adjust the format to be RAW. Once completed,
1435  * reset the format back to NONE.
1436  *
1437  * Returns: 0 on success, -1 on failure.
1438  */
1439 int
virStorageBackendCreateVolUsingQemuImg(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)1440 virStorageBackendCreateVolUsingQemuImg(virStoragePoolObj *pool,
1441                                        virStorageVolDef *vol,
1442                                        virStorageVolDef *inputvol,
1443                                        unsigned int flags)
1444 {
1445     int ret = -1;
1446     bool changeFormat = false;
1447 
1448     if (vol->target.format == VIR_STORAGE_FILE_NONE) {
1449         vol->target.format = VIR_STORAGE_FILE_RAW;
1450         changeFormat = true;
1451     }
1452 
1453     ret = storageBackendCreateQemuImg(pool, vol, inputvol, flags);
1454 
1455     if (changeFormat)
1456         vol->target.format = VIR_STORAGE_FILE_NONE;
1457 
1458     return ret;
1459 }
1460 
1461 
1462 virStorageBackendBuildVolFrom
virStorageBackendGetBuildVolFromFunction(virStorageVolDef * vol,virStorageVolDef * inputvol)1463 virStorageBackendGetBuildVolFromFunction(virStorageVolDef *vol,
1464                                          virStorageVolDef *inputvol)
1465 {
1466     if (!inputvol)
1467         return NULL;
1468 
1469     /* If either volume is a non-raw file vol, or uses encryption,
1470      * we need to use an external tool for converting
1471      */
1472     if ((vol->type == VIR_STORAGE_VOL_FILE &&
1473          (vol->target.format != VIR_STORAGE_FILE_RAW ||
1474           vol->target.encryption)) ||
1475         (inputvol->type == VIR_STORAGE_VOL_FILE &&
1476          (inputvol->target.format != VIR_STORAGE_FILE_RAW ||
1477           inputvol->target.encryption))) {
1478         return storageBackendCreateQemuImg;
1479     }
1480 
1481     if (vol->type == VIR_STORAGE_VOL_PLOOP)
1482         return storageBackendCreatePloop;
1483     if (vol->type == VIR_STORAGE_VOL_BLOCK)
1484         return storageBackendCreateBlockFrom;
1485     else
1486         return storageBackendCreateRaw;
1487 }
1488 
1489 
1490 struct diskType {
1491     int part_table_type;
1492     unsigned short offset;
1493     unsigned short length;
1494     unsigned long long magic;
1495 };
1496 
1497 
1498 static struct diskType const disk_types[] = {
1499     { VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL },
1500     { VIR_STORAGE_POOL_DISK_GPT,  0x200, 8, 0x5452415020494645ULL },
1501     { VIR_STORAGE_POOL_DISK_DVH,  0x0,   4, 0x41A9E50BULL },
1502     { VIR_STORAGE_POOL_DISK_MAC,  0x0,   2, 0x5245ULL },
1503     { VIR_STORAGE_POOL_DISK_BSD,  0x40,  4, 0x82564557ULL },
1504     { VIR_STORAGE_POOL_DISK_SUN,  0x1fc, 2, 0xBEDAULL },
1505     /*
1506      * NOTE: pc98 is funky; the actual signature is 0x55AA (just like dos), so
1507      * we can't use that.  At the moment I'm relying on the "dummy" IPL
1508      * bootloader data that comes from parted.  Luckily, the chances of running
1509      * into a pc98 machine running libvirt are approximately nil.
1510      */
1511     /*{ 0x1fe, 2, 0xAA55UL },*/
1512     { VIR_STORAGE_POOL_DISK_PC98, 0x0,   8, 0x314C5049000000CBULL },
1513     /*
1514      * NOTE: the order is important here; some other disk types (like GPT and
1515      * and PC98) also have 0x55AA at this offset.  For that reason, the DOS
1516      * one must be the last one.
1517      */
1518     { VIR_STORAGE_POOL_DISK_DOS,  0x1fe, 2, 0xAA55ULL },
1519     { -1,                         0x0,   0, 0x0ULL },
1520 };
1521 
1522 
1523 /*
1524  * virStorageBackendDetectBlockVolFormatFD
1525  * @target: target definition ptr of volume to update
1526  * @fd: fd of storage volume to update,
1527  * @readflags: VolReadErrorMode flags to handle read error after open
1528  *             is successful, but read is not.
1529  *
1530  * Returns 0 for success, -1 on a legitimate error condition, -2 if
1531  * the read error is desired to be ignored (along with appropriate
1532  * VIR_WARN of the issue).
1533  */
1534 static int
virStorageBackendDetectBlockVolFormatFD(virStorageSource * target,int fd,unsigned int readflags)1535 virStorageBackendDetectBlockVolFormatFD(virStorageSource *target,
1536                                         int fd,
1537                                         unsigned int readflags)
1538 {
1539     size_t i;
1540     off_t start;
1541     unsigned char buffer[1024];
1542     ssize_t bytes;
1543 
1544     /* make sure to set the target format "unknown" to begin with */
1545     target->format = VIR_STORAGE_POOL_DISK_UNKNOWN;
1546 
1547     start = lseek(fd, 0, SEEK_SET);
1548     if (start < 0) {
1549         virReportSystemError(errno,
1550                              _("cannot seek to beginning of file '%s'"),
1551                              target->path);
1552         return -1;
1553     }
1554     bytes = saferead(fd, buffer, sizeof(buffer));
1555     if (bytes < 0) {
1556         if (readflags & VIR_STORAGE_VOL_READ_NOERROR) {
1557             VIR_WARN("ignoring failed saferead of file '%s'",
1558                      target->path);
1559             return -2;
1560         } else {
1561             virReportSystemError(errno,
1562                                  _("cannot read beginning of file '%s'"),
1563                                  target->path);
1564             return -1;
1565         }
1566     }
1567 
1568     for (i = 0; disk_types[i].part_table_type != -1; i++) {
1569         if (disk_types[i].offset + disk_types[i].length > bytes)
1570             continue;
1571         if (memcmp(buffer+disk_types[i].offset, &disk_types[i].magic,
1572             disk_types[i].length) == 0) {
1573             target->format = disk_types[i].part_table_type;
1574             break;
1575         }
1576     }
1577 
1578     if (target->format == VIR_STORAGE_POOL_DISK_UNKNOWN)
1579         VIR_DEBUG("cannot determine the target format for '%s'",
1580                   target->path);
1581 
1582     return 0;
1583 }
1584 
1585 
1586 /*
1587  * Allows caller to silently ignore files with improper mode
1588  *
1589  * Returns -1 on error. If VIR_STORAGE_VOL_OPEN_NOERROR is passed, we
1590  * return -2 if file mode is unexpected or the volume is a dangling
1591  * symbolic link.
1592  */
1593 int
virStorageBackendVolOpen(const char * path,struct stat * sb,unsigned int flags)1594 virStorageBackendVolOpen(const char *path, struct stat *sb,
1595                          unsigned int flags)
1596 {
1597     int fd, mode = 0;
1598     g_autofree char *base = g_path_get_basename(path);
1599     bool noerror = (flags & VIR_STORAGE_VOL_OPEN_NOERROR);
1600 
1601     if (g_lstat(path, sb) < 0) {
1602         if (errno == ENOENT) {
1603             if (noerror) {
1604                 VIR_WARN("ignoring missing file '%s'", path);
1605                 return -2;
1606             }
1607             virReportError(VIR_ERR_NO_STORAGE_VOL,
1608                            _("no storage vol with matching path '%s'"),
1609                            path);
1610             return -1;
1611         }
1612         virReportSystemError(errno,
1613                              _("cannot stat file '%s'"),
1614                              path);
1615         return -1;
1616     }
1617 
1618     if (S_ISFIFO(sb->st_mode)) {
1619         if (noerror) {
1620             VIR_WARN("ignoring FIFO '%s'", path);
1621             return -2;
1622         }
1623         virReportError(VIR_ERR_INTERNAL_ERROR,
1624                        _("Volume path '%s' is a FIFO"), path);
1625         return -1;
1626     } else if (S_ISSOCK(sb->st_mode)) {
1627         if (noerror) {
1628             VIR_WARN("ignoring socket '%s'", path);
1629             return -2;
1630         }
1631         virReportError(VIR_ERR_INTERNAL_ERROR,
1632                        _("Volume path '%s' is a socket"), path);
1633         return -1;
1634     }
1635 
1636     /* O_NONBLOCK should only matter during open() for fifos and
1637      * sockets, which we already filtered; but using it prevents a
1638      * TOCTTOU race.  However, later on we will want to read() the
1639      * header from this fd, and virFileRead* routines require a
1640      * blocking fd, so fix it up after verifying we avoided a race.
1641      *
1642      * Use of virFileOpenAs allows this path to open a file using
1643      * the uid and gid as it was created in order to open. Since this
1644      * path is not using O_CREAT or O_TMPFILE, mode is meaningless.
1645      * Opening under user/group is especially important in an NFS
1646      * root-squash environment. If the target path isn't on shared
1647      * file system, the open will fail in the OPEN_FORK path.
1648      */
1649     if ((fd = virFileOpenAs(path, O_RDONLY|O_NONBLOCK|O_NOCTTY,
1650                             0, sb->st_uid, sb->st_gid,
1651                             VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK)) < 0) {
1652         if ((errno == ENOENT || errno == ELOOP) &&
1653             S_ISLNK(sb->st_mode) && noerror) {
1654             VIR_WARN("ignoring dangling symlink '%s'", path);
1655             return -2;
1656         }
1657         if (errno == ENOENT && noerror) {
1658             VIR_WARN("ignoring missing file '%s'", path);
1659             return -2;
1660         }
1661         if (errno == ENXIO && noerror) {
1662             VIR_WARN("ignoring missing fifo '%s'", path);
1663             return -2;
1664         }
1665         if ((errno == EACCES || errno == EPERM) && noerror) {
1666             VIR_WARN("ignoring permission error for '%s'", path);
1667             return -2;
1668         }
1669 
1670         virReportSystemError(errno, _("cannot open volume '%s'"), path);
1671         return -1;
1672     }
1673 
1674     if (fstat(fd, sb) < 0) {
1675         virReportSystemError(errno, _("cannot stat file '%s'"), path);
1676         VIR_FORCE_CLOSE(fd);
1677         return -1;
1678     }
1679 
1680     if (S_ISREG(sb->st_mode)) {
1681         mode = VIR_STORAGE_VOL_OPEN_REG;
1682     } else if (S_ISCHR(sb->st_mode)) {
1683         mode = VIR_STORAGE_VOL_OPEN_CHAR;
1684     } else if (S_ISBLK(sb->st_mode)) {
1685         mode = VIR_STORAGE_VOL_OPEN_BLOCK;
1686     } else if (S_ISDIR(sb->st_mode)) {
1687         mode = VIR_STORAGE_VOL_OPEN_DIR;
1688 
1689         if (STREQ(base, ".") ||
1690             STREQ(base, "..")) {
1691             VIR_FORCE_CLOSE(fd);
1692             if (noerror) {
1693                 VIR_INFO("Skipping special dir '%s'", base);
1694                 return -2;
1695             }
1696             virReportError(VIR_ERR_INTERNAL_ERROR,
1697                            _("Cannot use volume path '%s'"), path);
1698             return -1;
1699         }
1700     } else {
1701         VIR_FORCE_CLOSE(fd);
1702         if (noerror) {
1703             VIR_WARN("ignoring unexpected type for file '%s'", path);
1704             return -2;
1705         }
1706         virReportError(VIR_ERR_INTERNAL_ERROR,
1707                        _("unexpected type for file '%s'"), path);
1708         return -1;
1709     }
1710 
1711     if (virSetBlocking(fd, true) < 0) {
1712         VIR_FORCE_CLOSE(fd);
1713         virReportSystemError(errno, _("unable to set blocking mode for '%s'"),
1714                              path);
1715         return -1;
1716     }
1717 
1718     if (!(mode & flags)) {
1719         VIR_FORCE_CLOSE(fd);
1720         if (noerror) {
1721             VIR_INFO("Skipping volume '%s'", path);
1722             return -2;
1723         }
1724 
1725         virReportError(VIR_ERR_INTERNAL_ERROR,
1726                        _("unexpected storage mode for '%s'"), path);
1727         return -1;
1728     }
1729 
1730     return fd;
1731 }
1732 
1733 /* virStorageIsPloop function checks whether given directory is ploop volume's
1734  * directory.
1735  */
1736 static bool
storageBackendIsPloopDir(char * path)1737 storageBackendIsPloopDir(char *path)
1738 {
1739     g_autofree char *root = NULL;
1740     g_autofree char *desc = NULL;
1741 
1742     root = g_strdup_printf("%s/root.hds", path);
1743     if (!virFileExists(root))
1744         return false;
1745     desc = g_strdup_printf("%s/DiskDescriptor.xml", path);
1746     if (!virFileExists(desc))
1747         return false;
1748 
1749     return true;
1750 }
1751 
1752 /* In case of ploop volumes, path to volume is the path to the ploop
1753  * directory. To get information about allocation, header information
1754  * and etc. we need to perform virStorageBackendVolOpen and
1755  * virStorageBackendUpdateVolTargetFd once again.
1756  */
1757 static int
storageBackendRedoPloopUpdate(virStorageSource * target,struct stat * sb,int * fd,unsigned int flags)1758 storageBackendRedoPloopUpdate(virStorageSource *target, struct stat *sb,
1759                               int *fd, unsigned int flags)
1760 {
1761     g_autofree char *path = NULL;
1762 
1763     path = g_strdup_printf("%s/root.hds", target->path);
1764     VIR_FORCE_CLOSE(*fd);
1765     if ((*fd = virStorageBackendVolOpen(path, sb, flags)) < 0)
1766         return -1;
1767     return virStorageBackendUpdateVolTargetInfoFD(target, *fd, sb);
1768 }
1769 
1770 /*
1771  * storageBackendUpdateVolTargetInfo
1772  * @voltype: Volume type
1773  * @target: target definition ptr of volume to update
1774  * @withBlockVolFormat: true if caller determined a block file
1775  * @openflags: various VolOpenCheckMode flags to handle errors on open
1776  * @readflags: VolReadErrorMode flags to handle read error after open
1777  *             is successful, but read is not.
1778  *
1779  * Returns 0 for success, -1 on a legitimate error condition, and -2
1780  * if the openflags used VIR_STORAGE_VOL_OPEN_NOERROR and some sort of
1781  * open error occurred. It is up to the caller to handle. A -2 may also
1782  * be returned if the caller passed a readflagsflag.
1783  */
1784 static int
storageBackendUpdateVolTargetInfo(virStorageVolType voltype,virStorageSource * target,bool withBlockVolFormat,unsigned int openflags,unsigned int readflags)1785 storageBackendUpdateVolTargetInfo(virStorageVolType voltype,
1786                                   virStorageSource *target,
1787                                   bool withBlockVolFormat,
1788                                   unsigned int openflags,
1789                                   unsigned int readflags)
1790 {
1791     int rc;
1792     struct stat sb;
1793     ssize_t len = VIR_STORAGE_MAX_HEADER;
1794     g_autofree char *buf = NULL;
1795     VIR_AUTOCLOSE fd = -1;
1796 
1797     if ((rc = virStorageBackendVolOpen(target->path, &sb, openflags)) < 0)
1798         return rc;
1799     fd = rc;
1800 
1801     if ((virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb)) < 0)
1802         return -1;
1803 
1804     if ((voltype == VIR_STORAGE_VOL_FILE || voltype == VIR_STORAGE_VOL_BLOCK) &&
1805         target->format != VIR_STORAGE_FILE_NONE) {
1806         if (S_ISDIR(sb.st_mode)) {
1807             if (storageBackendIsPloopDir(target->path)) {
1808                 if ((storageBackendRedoPloopUpdate(target, &sb, &fd,
1809                                                    openflags)) < 0)
1810                     return -1;
1811                 target->format = VIR_STORAGE_FILE_PLOOP;
1812             } else {
1813                 return 0;
1814             }
1815         }
1816 
1817         if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
1818             virReportSystemError(errno, _("cannot seek to start of '%s'"), target->path);
1819             return -1;
1820         }
1821 
1822         if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) {
1823             if (readflags & VIR_STORAGE_VOL_READ_NOERROR) {
1824                 VIR_WARN("ignoring failed header read for '%s'",
1825                          target->path);
1826                 return -2;
1827             } else {
1828                 virReportSystemError(errno,
1829                                      _("cannot read header '%s'"),
1830                                      target->path);
1831                 return -1;
1832             }
1833         }
1834 
1835         if (virStorageSourceUpdateCapacity(target, buf, len) < 0)
1836             return -1;
1837     }
1838 
1839     if (withBlockVolFormat)
1840         return virStorageBackendDetectBlockVolFormatFD(target, fd, readflags);
1841 
1842     return 0;
1843 }
1844 
1845 /*
1846  * virStorageBackendUpdateVolInfo
1847  * @vol: Pointer to a volume storage definition
1848  * @withBlockVolFormat: true if the caller determined a block file
1849  * @openflags: various VolOpenCheckMode flags to handle errors on open
1850  * @readflags: various VolReadErrorMode flags to handle errors on read
1851  *
1852  * Returns 0 for success, -1 on a legitimate error condition, and -2
1853  * if the openflags used VIR_STORAGE_VOL_OPEN_NOERROR and some sort of
1854  * open error occurred. It is up to the caller to handle.
1855  */
1856 int
virStorageBackendUpdateVolInfo(virStorageVolDef * vol,bool withBlockVolFormat,unsigned int openflags,unsigned int readflags)1857 virStorageBackendUpdateVolInfo(virStorageVolDef *vol,
1858                                bool withBlockVolFormat,
1859                                unsigned int openflags,
1860                                unsigned int readflags)
1861 {
1862     int ret;
1863 
1864     if ((ret = storageBackendUpdateVolTargetInfo(vol->type,
1865                                                  &vol->target,
1866                                                  withBlockVolFormat,
1867                                                  openflags, readflags)) < 0)
1868         return ret;
1869 
1870     if (virStorageSourceHasBacking(&vol->target) &&
1871         (ret = storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
1872                                                  vol->target.backingStore,
1873                                                  withBlockVolFormat,
1874                                                  VIR_STORAGE_VOL_OPEN_DEFAULT |
1875                                                  VIR_STORAGE_VOL_OPEN_NOERROR,
1876                                                  readflags)) == -1)
1877         return ret;
1878 
1879     return 0;
1880 }
1881 
1882 /*
1883  * virStorageBackendUpdateVolTargetInfoFD:
1884  * @target: target definition ptr of volume to update
1885  * @fd: fd of storage volume to update, via virStorageBackendOpenVol*, or -1
1886  * @sb: details about file (must match @fd, if that is provided)
1887  *
1888  * Returns 0 for success, -1 on a legitimate error condition.
1889  */
1890 int
virStorageBackendUpdateVolTargetInfoFD(virStorageSource * target,int fd,struct stat * sb)1891 virStorageBackendUpdateVolTargetInfoFD(virStorageSource *target,
1892                                        int fd,
1893                                        struct stat *sb)
1894 {
1895 #if WITH_SELINUX
1896     char *filecon = NULL;
1897 #endif
1898 
1899     if (virStorageSourceUpdateBackingSizes(target, fd, sb) < 0)
1900         return -1;
1901 
1902     if (!target->perms)
1903         target->perms = g_new0(virStoragePerms, 1);
1904     target->perms->mode = sb->st_mode & S_IRWXUGO;
1905     target->perms->uid = sb->st_uid;
1906     target->perms->gid = sb->st_gid;
1907 
1908     if (!target->timestamps)
1909         target->timestamps = g_new0(virStorageTimestamps, 1);
1910 
1911 #ifdef __APPLE__
1912     target->timestamps->atime = sb->st_atimespec;
1913     target->timestamps->btime = sb->st_birthtimespec;
1914     target->timestamps->ctime = sb->st_ctimespec;
1915     target->timestamps->mtime = sb->st_mtimespec;
1916 #else /* ! __APPLE__ */
1917     target->timestamps->atime = sb->st_atim;
1918 # ifdef __linux__
1919     target->timestamps->btime = (struct timespec){0, 0};
1920 # else /* ! __linux__ */
1921 #   ifndef __DragonFly__
1922     target->timestamps->btime = sb->st_birthtim;
1923 #   endif
1924 # endif /* ! __linux__ */
1925     target->timestamps->ctime = sb->st_ctim;
1926     target->timestamps->mtime = sb->st_mtim;
1927 #endif /* ! __APPLE__ */
1928 
1929     target->type = VIR_STORAGE_TYPE_FILE;
1930 
1931     VIR_FREE(target->perms->label);
1932 
1933 #if WITH_SELINUX
1934     /* XXX: make this a security driver call */
1935     if (fd >= 0) {
1936         if (fgetfilecon_raw(fd, &filecon) == -1) {
1937             if (errno != ENODATA && errno != ENOTSUP) {
1938                 virReportSystemError(errno,
1939                                      _("cannot get file context of '%s'"),
1940                                      target->path);
1941                 return -1;
1942             }
1943         } else {
1944             target->perms->label = g_strdup(filecon);
1945             freecon(filecon);
1946         }
1947     }
1948 #endif
1949 
1950     return 0;
1951 }
1952 
1953 bool
virStorageBackendPoolPathIsStable(const char * path)1954 virStorageBackendPoolPathIsStable(const char *path)
1955 {
1956     if (path == NULL || STREQ(path, "/dev") || STREQ(path, "/dev/"))
1957         return false;
1958 
1959     if (!STRPREFIX(path, "/dev/"))
1960         return false;
1961 
1962     return true;
1963 }
1964 
1965 /*
1966  * Given a volume path directly in /dev/XXX, iterate over the
1967  * entries in the directory def->target.path and find the
1968  * first symlink pointing to the volume path.
1969  *
1970  * If, the target.path is /dev/, then return the original volume
1971  * path.
1972  *
1973  * If no symlink is found, then return the original volume path
1974  *
1975  * Typically target.path is one of the /dev/disk/by-XXX dirs
1976  * with stable paths.
1977  *
1978  * If 'loop' is true, we use a timeout loop to give dynamic paths
1979  * a change to appear.
1980  */
1981 char *
virStorageBackendStablePath(virStoragePoolObj * pool,const char * devpath,bool loop)1982 virStorageBackendStablePath(virStoragePoolObj *pool,
1983                             const char *devpath,
1984                             bool loop)
1985 {
1986     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
1987     g_autoptr(DIR) dh = NULL;
1988     struct dirent *dent;
1989     char *stablepath;
1990     int opentries = 0;
1991     int retry = 0;
1992     int direrr;
1993 
1994     /* Logical pools are under /dev but already have stable paths */
1995     if (def->type == VIR_STORAGE_POOL_LOGICAL ||
1996         !virStorageBackendPoolPathIsStable(def->target.path))
1997         goto ret_strdup;
1998 
1999     /* We loop here because /dev/disk/by-{id,path} may not have existed
2000      * before we started this operation, so we have to give it some time to
2001      * get created.
2002      */
2003  reopen:
2004     if (virDirOpenQuiet(&dh, def->target.path) < 0) {
2005         opentries++;
2006         if (loop && errno == ENOENT && opentries < 50) {
2007             g_usleep(100 * 1000);
2008             goto reopen;
2009         }
2010         virReportSystemError(errno,
2011                              _("cannot read dir '%s'"),
2012                              def->target.path);
2013         return NULL;
2014     }
2015 
2016     /* The pool is pointing somewhere like /dev/disk/by-path
2017      * or /dev/disk/by-id, so we need to check all symlinks in
2018      * the target directory and figure out which one points
2019      * to this device node.
2020      *
2021      * And it might need some time till the stable path shows
2022      * up, so add timeout to retry here.  Ignore readdir failures,
2023      * since we have a fallback.
2024      */
2025  retry:
2026     while ((direrr = virDirRead(dh, &dent, NULL)) > 0) {
2027         stablepath = g_strdup_printf("%s/%s", def->target.path, dent->d_name);
2028 
2029         if (virFileLinkPointsTo(stablepath, devpath)) {
2030             return stablepath;
2031         }
2032 
2033         VIR_FREE(stablepath);
2034     }
2035 
2036     if (!direrr && loop && ++retry < 100) {
2037         g_usleep(100 * 1000);
2038         goto retry;
2039     }
2040 
2041  ret_strdup:
2042     /* Couldn't find any matching stable link so give back
2043      * the original non-stable dev path
2044      */
2045 
2046     stablepath = g_strdup(devpath);
2047 
2048     return stablepath;
2049 }
2050 
2051 /* Common/Local File System/Directory Volume API's */
2052 static int
createFileDir(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)2053 createFileDir(virStoragePoolObj *pool,
2054               virStorageVolDef *vol,
2055               virStorageVolDef *inputvol,
2056               unsigned int flags)
2057 {
2058     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
2059     mode_t permmode = VIR_STORAGE_DEFAULT_VOL_PERM_MODE;
2060     unsigned int createflags = 0;
2061 
2062     virCheckFlags(0, -1);
2063 
2064     if (inputvol) {
2065         virReportError(VIR_ERR_INTERNAL_ERROR,
2066                        "%s",
2067                        _("cannot copy from volume to a directory volume"));
2068         return -1;
2069     }
2070 
2071     if (virStorageSourceHasBacking(&vol->target)) {
2072         virReportError(VIR_ERR_NO_SUPPORT, "%s",
2073                        _("backing storage not supported for directories volumes"));
2074         return -1;
2075     }
2076 
2077     if (vol->target.perms->mode != (mode_t)-1)
2078         permmode = vol->target.perms->mode;
2079 
2080     if (def->type == VIR_STORAGE_POOL_NETFS)
2081         createflags |= VIR_DIR_CREATE_AS_UID;
2082 
2083     if (virDirCreate(vol->target.path,
2084                      permmode,
2085                      vol->target.perms->uid,
2086                      vol->target.perms->gid,
2087                      createflags) < 0) {
2088         return -1;
2089     }
2090 
2091     return 0;
2092 }
2093 
2094 
2095 /**
2096  * Set up a volume definition to be added to a pool's volume list, but
2097  * don't do any file creation or allocation. By separating the two processes,
2098  * we allow allocation progress reporting (by polling the volume's 'info'
2099  * function), and can drop the parent pool lock during the (slow) allocation.
2100  */
2101 int
virStorageBackendVolCreateLocal(virStoragePoolObj * pool,virStorageVolDef * vol)2102 virStorageBackendVolCreateLocal(virStoragePoolObj *pool,
2103                                 virStorageVolDef *vol)
2104 {
2105     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
2106 
2107     if (vol->target.format == VIR_STORAGE_FILE_DIR)
2108         vol->type = VIR_STORAGE_VOL_DIR;
2109     else if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
2110         vol->type = VIR_STORAGE_VOL_PLOOP;
2111     else
2112         vol->type = VIR_STORAGE_VOL_FILE;
2113 
2114     /* Volumes within a directory pools are not recursive; do not
2115      * allow escape to ../ or a subdir */
2116     if (strchr(vol->name, '/')) {
2117         virReportError(VIR_ERR_OPERATION_INVALID,
2118                        _("volume name '%s' cannot contain '/'"), vol->name);
2119         return -1;
2120     }
2121 
2122     VIR_FREE(vol->target.path);
2123     vol->target.path = g_strdup_printf("%s/%s", def->target.path, vol->name);
2124 
2125     if (virFileExists(vol->target.path)) {
2126         virReportError(VIR_ERR_OPERATION_INVALID,
2127                        _("volume target path '%s' already exists"),
2128                        vol->target.path);
2129         return -1;
2130     }
2131 
2132     VIR_FREE(vol->key);
2133     vol->key = g_strdup(vol->target.path);
2134     return 0;
2135 }
2136 
2137 
2138 static int
storageBackendVolBuildLocal(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)2139 storageBackendVolBuildLocal(virStoragePoolObj *pool,
2140                             virStorageVolDef *vol,
2141                             virStorageVolDef *inputvol,
2142                             unsigned int flags)
2143 {
2144     virStorageBackendBuildVolFrom create_func;
2145 
2146     if (inputvol) {
2147         if (!(create_func =
2148               virStorageBackendGetBuildVolFromFunction(vol, inputvol)))
2149             return -1;
2150     } else if (vol->target.format == VIR_STORAGE_FILE_RAW &&
2151                vol->target.encryption == NULL) {
2152         create_func = storageBackendCreateRaw;
2153     } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
2154         create_func = createFileDir;
2155     } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
2156         create_func = storageBackendCreatePloop;
2157     } else {
2158         create_func = storageBackendCreateQemuImg;
2159     }
2160 
2161     if (create_func(pool, vol, inputvol, flags) < 0)
2162         return -1;
2163     return 0;
2164 }
2165 
2166 
2167 /**
2168  * Allocate a new file as a volume. This is either done directly
2169  * for raw/sparse files, or by calling qemu-img for
2170  * special kinds of files
2171  */
2172 int
virStorageBackendVolBuildLocal(virStoragePoolObj * pool,virStorageVolDef * vol,unsigned int flags)2173 virStorageBackendVolBuildLocal(virStoragePoolObj *pool,
2174                                virStorageVolDef *vol,
2175                                unsigned int flags)
2176 {
2177     return storageBackendVolBuildLocal(pool, vol, NULL, flags);
2178 }
2179 
2180 
2181 /*
2182  * Create a storage vol using 'inputvol' as input
2183  */
2184 int
virStorageBackendVolBuildFromLocal(virStoragePoolObj * pool,virStorageVolDef * vol,virStorageVolDef * inputvol,unsigned int flags)2185 virStorageBackendVolBuildFromLocal(virStoragePoolObj *pool,
2186                                    virStorageVolDef *vol,
2187                                    virStorageVolDef *inputvol,
2188                                    unsigned int flags)
2189 {
2190     return storageBackendVolBuildLocal(pool, vol, inputvol, flags);
2191 }
2192 
2193 
2194 /**
2195  * Remove a volume - no support for BLOCK and NETWORK yet
2196  */
2197 int
virStorageBackendVolDeleteLocal(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,unsigned int flags)2198 virStorageBackendVolDeleteLocal(virStoragePoolObj *pool G_GNUC_UNUSED,
2199                                 virStorageVolDef *vol,
2200                                 unsigned int flags)
2201 {
2202     virCheckFlags(0, -1);
2203 
2204     switch ((virStorageVolType)vol->type) {
2205     case VIR_STORAGE_VOL_FILE:
2206     case VIR_STORAGE_VOL_DIR:
2207         if (virFileRemove(vol->target.path, vol->target.perms->uid,
2208                           vol->target.perms->gid) < 0) {
2209             /* Silently ignore failures where the vol has already gone away */
2210             if (errno != ENOENT) {
2211                 if (vol->type == VIR_STORAGE_VOL_FILE)
2212                     virReportSystemError(errno,
2213                                          _("cannot unlink file '%s'"),
2214                                          vol->target.path);
2215                 else
2216                     virReportSystemError(errno,
2217                                          _("cannot remove directory '%s'"),
2218                                          vol->target.path);
2219                 return -1;
2220             }
2221         }
2222         break;
2223     case VIR_STORAGE_VOL_PLOOP:
2224         if (virFileDeleteTree(vol->target.path) < 0)
2225             return -1;
2226         break;
2227     case VIR_STORAGE_VOL_BLOCK:
2228     case VIR_STORAGE_VOL_NETWORK:
2229     case VIR_STORAGE_VOL_NETDIR:
2230     case VIR_STORAGE_VOL_LAST:
2231         virReportError(VIR_ERR_NO_SUPPORT,
2232                        _("removing block or network volumes is not supported: %s"),
2233                        vol->target.path);
2234         return -1;
2235     }
2236     return 0;
2237 }
2238 
2239 
2240 /* storageBackendLoadDefaultSecrets:
2241  * @vol: volume being refreshed
2242  *
2243  * If the volume had a secret generated, we need to regenerate the
2244  * encryption secret information
2245  *
2246  * Returns 0 if no secret or secret setup was successful,
2247  * -1 on failures w/ error message set
2248  */
2249 static int
storageBackendLoadDefaultSecrets(virStorageVolDef * vol)2250 storageBackendLoadDefaultSecrets(virStorageVolDef *vol)
2251 {
2252     virSecretPtr sec;
2253     virStorageEncryptionSecret *encsec = NULL;
2254     virConnectPtr conn = NULL;
2255 
2256     if (!vol->target.encryption || vol->target.encryption->nsecrets != 0)
2257         return 0;
2258 
2259     conn = virGetConnectSecret();
2260     if (!conn)
2261         return -1;
2262 
2263     /* The encryption secret for qcow2 and luks volumes use the path
2264      * to the volume, so look for a secret with the path. If not found,
2265      * then we cannot generate the secret after a refresh (or restart).
2266      * This may be the case if someone didn't follow instructions and created
2267      * a usage string that although matched with the secret usage string,
2268      * didn't contain the path to the volume. We won't error in that case,
2269      * but we also cannot find the secret. */
2270     sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME,
2271                                  vol->target.path);
2272     virObjectUnref(conn);
2273     if (!sec)
2274         return 0;
2275 
2276     vol->target.encryption->secrets = g_new0(virStorageEncryptionSecret *, 1);
2277     encsec = g_new0(virStorageEncryptionSecret, 1);
2278 
2279     vol->target.encryption->nsecrets = 1;
2280     vol->target.encryption->secrets[0] = encsec;
2281 
2282     encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
2283     encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID;
2284     virSecretGetUUID(sec, encsec->seclookupdef.u.uuid);
2285     virObjectUnref(sec);
2286 
2287     return 0;
2288 }
2289 
2290 
2291 /**
2292  * Update info about a volume's capacity/allocation
2293  */
2294 int
virStorageBackendVolRefreshLocal(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol)2295 virStorageBackendVolRefreshLocal(virStoragePoolObj *pool G_GNUC_UNUSED,
2296                                  virStorageVolDef *vol)
2297 {
2298     int ret;
2299 
2300     /* Refresh allocation / capacity / permissions info in case its changed */
2301     if ((ret = virStorageBackendUpdateVolInfo(vol, false,
2302                                               VIR_STORAGE_VOL_FS_OPEN_FLAGS,
2303                                               0)) < 0)
2304         return ret;
2305 
2306     /* Load any secrets if possible */
2307     return storageBackendLoadDefaultSecrets(vol);
2308 }
2309 
2310 
2311 static int
storageBackendResizeQemuImg(virStoragePoolObj * pool,virStorageVolDef * vol,unsigned long long capacity)2312 storageBackendResizeQemuImg(virStoragePoolObj *pool,
2313                             virStorageVolDef *vol,
2314                             unsigned long long capacity)
2315 {
2316     int ret = -1;
2317     const char *type;
2318     virStorageEncryption *enc = vol->target.encryption;
2319     g_autoptr(virCommand) cmd = NULL;
2320     g_autofree char *img_tool = NULL;
2321     g_autofree char *secretPath = NULL;
2322     g_autofree char *secretAlias = NULL;
2323 
2324     if (enc && (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
2325                 enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) &&
2326         (vol->target.format == VIR_STORAGE_FILE_QCOW ||
2327          vol->target.format == VIR_STORAGE_FILE_QCOW2)) {
2328         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2329                        _("resize of qcow2 encrypted image is not supported"));
2330         return -1;
2331     }
2332 
2333     img_tool = virFindFileInPath("qemu-img");
2334     if (!img_tool) {
2335         virReportError(VIR_ERR_INTERNAL_ERROR,
2336                        "%s", _("unable to find qemu-img"));
2337         return -1;
2338     }
2339 
2340     if (vol->target.encryption) {
2341         if (vol->target.format == VIR_STORAGE_FILE_RAW)
2342             type = "luks";
2343         else
2344             type = virStorageFileFormatTypeToString(vol->target.format);
2345 
2346         storageBackendLoadDefaultSecrets(vol);
2347 
2348         if (storageBackendCreateQemuImgCheckEncryption(vol->target.format,
2349                                                        type, vol) < 0)
2350             goto cleanup;
2351 
2352         if (!(secretPath =
2353               storageBackendCreateQemuImgSecretPath(pool, vol)))
2354             goto cleanup;
2355 
2356         secretAlias = g_strdup_printf("%s_encrypt0", vol->name);
2357     }
2358 
2359     /* Round capacity as qemu-img resize errors out on sizes which are not
2360      * a multiple of 512 */
2361     capacity = VIR_ROUND_UP(capacity, 512);
2362 
2363     cmd = virCommandNewArgList(img_tool, "resize", NULL);
2364     if (capacity < vol->target.capacity)
2365         virCommandAddArg(cmd, "--shrink");
2366     if (!vol->target.encryption) {
2367         virCommandAddArg(cmd, vol->target.path);
2368     } else {
2369         if (storageBackendCreateQemuImgSecretObject(cmd, secretPath,
2370                                                     secretAlias) < 0)
2371             goto cleanup;
2372 
2373         if (storageBackendResizeQemuImgImageOpts(cmd,
2374                                                  vol->target.format,
2375                                                  vol->target.path,
2376                                                  secretAlias) < 0)
2377             goto cleanup;
2378     }
2379     virCommandAddArgFormat(cmd, "%llu", capacity);
2380 
2381     ret = virCommandRun(cmd, NULL);
2382 
2383  cleanup:
2384     if (secretPath)
2385         unlink(secretPath);
2386     return ret;
2387 }
2388 
2389 
2390 /**
2391  * Resize a volume
2392  */
2393 int
virStorageBackendVolResizeLocal(virStoragePoolObj * pool,virStorageVolDef * vol,unsigned long long capacity,unsigned int flags)2394 virStorageBackendVolResizeLocal(virStoragePoolObj *pool,
2395                                 virStorageVolDef *vol,
2396                                 unsigned long long capacity,
2397                                 unsigned int flags)
2398 {
2399     bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE;
2400 
2401     virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE |
2402                   VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
2403 
2404     if (vol->target.format == VIR_STORAGE_FILE_RAW && !vol->target.encryption) {
2405         return virFileResize(vol->target.path, capacity, pre_allocate);
2406     } else if (vol->target.format == VIR_STORAGE_FILE_RAW && vol->target.encryption) {
2407         if (pre_allocate) {
2408             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2409                            _("preallocate is only supported for an "
2410                              "unencrypted raw volume"));
2411             return -1;
2412         }
2413 
2414         return storageBackendResizeQemuImg(pool, vol, capacity);
2415     } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
2416         return storagePloopResize(vol, capacity);
2417     } else {
2418         if (pre_allocate) {
2419             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2420                            _("preallocate is only supported for raw "
2421                              "type volume"));
2422             return -1;
2423         }
2424 
2425         return storageBackendResizeQemuImg(pool, vol, capacity);
2426     }
2427 }
2428 
2429 
2430 /*
2431  *  Check whether the ploop image has snapshots.
2432  *  return: -1 - failed to check
2433  *           0 - no snapshots
2434  *           1 - at least one snapshot
2435  */
2436 static int
storageBackendPloopHasSnapshots(char * path)2437 storageBackendPloopHasSnapshots(char *path)
2438 {
2439     char *snap_tool = NULL;
2440     g_autoptr(virCommand) cmd = NULL;
2441     g_autofree char *output = NULL;
2442 
2443     snap_tool = virFindFileInPath("ploop");
2444     if (!snap_tool) {
2445         virReportError(VIR_ERR_INTERNAL_ERROR,
2446                        "%s", _("unable to find ploop, please install "
2447                                "ploop tools"));
2448         return -1;
2449     }
2450 
2451     cmd = virCommandNewArgList(snap_tool, "snapshot-list", NULL);
2452     virCommandAddArgFormat(cmd, "%s/DiskDescriptor.xml", path);
2453     virCommandSetOutputBuffer(cmd, &output);
2454 
2455     if (virCommandRun(cmd, NULL) < 0)
2456         return -1;
2457 
2458     if (!strstr(output, "root.hds."))
2459         return 1;
2460 
2461     return 0;
2462 }
2463 
2464 
2465 int
virStorageBackendVolUploadLocal(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,virStreamPtr stream,unsigned long long offset,unsigned long long len,unsigned int flags)2466 virStorageBackendVolUploadLocal(virStoragePoolObj *pool G_GNUC_UNUSED,
2467                                 virStorageVolDef *vol,
2468                                 virStreamPtr stream,
2469                                 unsigned long long offset,
2470                                 unsigned long long len,
2471                                 unsigned int flags)
2472 {
2473     char *target_path = vol->target.path;
2474     bool sparse = flags & VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM;
2475     g_autofree char *path = NULL;
2476 
2477     virCheckFlags(VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM, -1);
2478     /* if volume has target format VIR_STORAGE_FILE_PLOOP
2479      * we need to restore DiskDescriptor.xml, according to
2480      * new contents of volume. This operation will be performed
2481      * when volUpload is fully finished. */
2482     if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
2483         /* Fail if the volume contains snapshots or we failed to check it.*/
2484         int has_snap = storageBackendPloopHasSnapshots(vol->target.path);
2485         if (has_snap < 0) {
2486             return -1;
2487         } else if (!has_snap) {
2488             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2489                            _("can't upload volume, all existing snapshots"
2490                              " will be lost"));
2491             return -1;
2492         }
2493 
2494         path = g_strdup_printf("%s/root.hds", vol->target.path);
2495         target_path = path;
2496     }
2497 
2498     /* Not using O_CREAT because the file is required to already exist at
2499      * this point */
2500     return virFDStreamOpenBlockDevice(stream, target_path,
2501                                       offset, len, sparse, O_WRONLY);
2502 }
2503 
2504 int
virStorageBackendVolDownloadLocal(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,virStreamPtr stream,unsigned long long offset,unsigned long long len,unsigned int flags)2505 virStorageBackendVolDownloadLocal(virStoragePoolObj *pool G_GNUC_UNUSED,
2506                                   virStorageVolDef *vol,
2507                                   virStreamPtr stream,
2508                                   unsigned long long offset,
2509                                   unsigned long long len,
2510                                   unsigned int flags)
2511 {
2512     char *target_path = vol->target.path;
2513     bool sparse = flags & VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM;
2514     g_autofree char *path = NULL;
2515 
2516     virCheckFlags(VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM, -1);
2517     if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
2518         int has_snap = storageBackendPloopHasSnapshots(vol->target.path);
2519         if (has_snap < 0) {
2520             return -1;
2521         } else if (!has_snap) {
2522             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2523                            _("can't download volume, all existing snapshots"
2524                              " will be lost"));
2525             return -1;
2526         }
2527         path = g_strdup_printf("%s/root.hds", vol->target.path);
2528         target_path = path;
2529     }
2530 
2531     return virFDStreamOpenBlockDevice(stream, target_path,
2532                                       offset, len, sparse, O_RDONLY);
2533 }
2534 
2535 
2536 /* If the volume we're wiping is already a sparse file, we simply
2537  * truncate and extend it to its original size, filling it with
2538  * zeroes.  This behavior is guaranteed by POSIX:
2539  *
2540  * https://www.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
2541  *
2542  * If fildes refers to a regular file, the ftruncate() function shall
2543  * cause the size of the file to be truncated to length. If the size
2544  * of the file previously exceeded length, the extra data shall no
2545  * longer be available to reads on the file. If the file previously
2546  * was smaller than this size, ftruncate() shall increase the size of
2547  * the file. If the file size is increased, the extended area shall
2548  * appear as if it were zero-filled.
2549  */
2550 static int
storageBackendVolZeroSparseFileLocal(const char * path,off_t size,int fd)2551 storageBackendVolZeroSparseFileLocal(const char *path,
2552                                      off_t size,
2553                                      int fd)
2554 {
2555     if (ftruncate(fd, 0) < 0) {
2556         virReportSystemError(errno,
2557                              _("Failed to truncate volume with "
2558                                "path '%s' to 0 bytes"),
2559                              path);
2560         return -1;
2561     }
2562 
2563     if (ftruncate(fd, size) < 0) {
2564         virReportSystemError(errno,
2565                              _("Failed to truncate volume with "
2566                                "path '%s' to %ju bytes"),
2567                              path, (uintmax_t)size);
2568         return -1;
2569     }
2570 
2571     return 0;
2572 }
2573 
2574 
2575 static int
storageBackendWipeLocal(const char * path,int fd,unsigned long long wipe_len,size_t writebuf_length,bool zero_end)2576 storageBackendWipeLocal(const char *path,
2577                         int fd,
2578                         unsigned long long wipe_len,
2579                         size_t writebuf_length,
2580                         bool zero_end)
2581 {
2582     unsigned long long remaining = 0;
2583     off_t size;
2584     g_autofree char *writebuf = NULL;
2585 
2586     writebuf = g_new0(char, writebuf_length);
2587 
2588     if (!zero_end) {
2589         if ((size = lseek(fd, 0, SEEK_SET)) < 0) {
2590             virReportSystemError(errno,
2591                                  _("Failed to seek to the start in volume "
2592                                    "with path '%s'"),
2593                                  path);
2594             return -1;
2595         }
2596     } else {
2597         if ((size = lseek(fd, -wipe_len, SEEK_END)) < 0) {
2598             virReportSystemError(errno,
2599                                  _("Failed to seek to %llu bytes to the end "
2600                                    "in volume with path '%s'"),
2601                                  wipe_len, path);
2602             return -1;
2603         }
2604     }
2605 
2606     VIR_DEBUG("wiping start: %zd len: %llu", (ssize_t)size, wipe_len);
2607 
2608     remaining = wipe_len;
2609     while (remaining > 0) {
2610         size_t write_size = MIN(writebuf_length, remaining);
2611         int written = safewrite(fd, writebuf, write_size);
2612 
2613         if (written < 0) {
2614             virReportSystemError(errno,
2615                                  _("Failed to write %zu bytes to "
2616                                    "storage volume with path '%s'"),
2617                                  write_size, path);
2618 
2619             return -1;
2620         }
2621 
2622         remaining -= written;
2623     }
2624 
2625     if (virFileDataSync(fd) < 0) {
2626         virReportSystemError(errno,
2627                              _("cannot sync data to volume with path '%s'"),
2628                              path);
2629         return -1;
2630     }
2631 
2632     VIR_DEBUG("Wrote %llu bytes to volume with path '%s'", wipe_len, path);
2633 
2634     return 0;
2635 }
2636 
2637 
2638 static int
storageBackendVolWipeLocalFile(const char * path,unsigned int algorithm,unsigned long long allocation,bool zero_end)2639 storageBackendVolWipeLocalFile(const char *path,
2640                                unsigned int algorithm,
2641                                unsigned long long allocation,
2642                                bool zero_end)
2643 {
2644     const char *alg_char = NULL;
2645     struct stat st;
2646     VIR_AUTOCLOSE fd = -1;
2647     g_autoptr(virCommand) cmd = NULL;
2648 
2649     fd = open(path, O_RDWR);
2650     if (fd == -1) {
2651         virReportSystemError(errno,
2652                              _("Failed to open storage volume with path '%s'"),
2653                              path);
2654         return -1;
2655     }
2656 
2657     if (fstat(fd, &st) == -1) {
2658         virReportSystemError(errno,
2659                              _("Failed to stat storage volume with path '%s'"),
2660                              path);
2661         return -1;
2662     }
2663 
2664     switch ((virStorageVolWipeAlgorithm) algorithm) {
2665     case VIR_STORAGE_VOL_WIPE_ALG_ZERO:
2666         alg_char = "zero";
2667         break;
2668     case VIR_STORAGE_VOL_WIPE_ALG_NNSA:
2669         alg_char = "nnsa";
2670         break;
2671     case VIR_STORAGE_VOL_WIPE_ALG_DOD:
2672         alg_char = "dod";
2673         break;
2674     case VIR_STORAGE_VOL_WIPE_ALG_BSI:
2675         alg_char = "bsi";
2676         break;
2677     case VIR_STORAGE_VOL_WIPE_ALG_GUTMANN:
2678         alg_char = "gutmann";
2679         break;
2680     case VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER:
2681         alg_char = "schneier";
2682         break;
2683     case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7:
2684         alg_char = "pfitzner7";
2685         break;
2686     case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33:
2687         alg_char = "pfitzner33";
2688         break;
2689     case VIR_STORAGE_VOL_WIPE_ALG_RANDOM:
2690         alg_char = "random";
2691         break;
2692     case VIR_STORAGE_VOL_WIPE_ALG_TRIM:
2693         virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
2694                        _("'trim' algorithm not supported"));
2695         return -1;
2696     case VIR_STORAGE_VOL_WIPE_ALG_LAST:
2697         virReportError(VIR_ERR_INVALID_ARG,
2698                        _("unsupported algorithm %d"),
2699                        algorithm);
2700         return -1;
2701     }
2702 
2703     VIR_DEBUG("Wiping file '%s' with algorithm '%s'", path, alg_char);
2704 
2705     if (algorithm != VIR_STORAGE_VOL_WIPE_ALG_ZERO) {
2706         cmd = virCommandNew(SCRUB);
2707         virCommandAddArgList(cmd, "-f", "-p", alg_char, path, NULL);
2708 
2709         return virCommandRun(cmd, NULL);
2710     }
2711 
2712     if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE))
2713         return storageBackendVolZeroSparseFileLocal(path, st.st_size, fd);
2714 
2715     return storageBackendWipeLocal(path, fd, allocation, st.st_blksize,
2716                                    zero_end);
2717 }
2718 
2719 
2720 static int
storageBackendVolWipePloop(virStorageVolDef * vol,unsigned int algorithm)2721 storageBackendVolWipePloop(virStorageVolDef *vol,
2722                            unsigned int algorithm)
2723 {
2724     g_autoptr(virCommand) cmd = NULL;
2725     g_autofree char *target_path = NULL;
2726     g_autofree char *disk_desc = NULL;
2727     g_autofree char *create_tool = NULL;
2728 
2729     create_tool = virFindFileInPath("ploop");
2730     if (!create_tool) {
2731         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2732                        _("unable to find ploop tools, please install them"));
2733         return -1;
2734     }
2735 
2736     target_path = g_strdup_printf("%s/root.hds", vol->target.path);
2737 
2738     disk_desc = g_strdup_printf("%s/DiskDescriptor.xml", vol->target.path);
2739 
2740     if (storageBackendVolWipeLocalFile(target_path, algorithm,
2741                                        vol->target.allocation, false) < 0)
2742         return -1;
2743 
2744     if (virFileRemove(disk_desc, 0, 0) < 0) {
2745         virReportError(errno, _("Failed to delete DiskDescriptor.xml of volume '%s'"),
2746                        vol->target.path);
2747         return -1;
2748     }
2749     if (virFileRemove(target_path, 0, 0) < 0) {
2750         virReportError(errno, _("failed to delete root.hds of volume '%s'"),
2751                        vol->target.path);
2752         return -1;
2753     }
2754 
2755     cmd = virCommandNewArgList(create_tool, "init", "-s", NULL);
2756 
2757     virCommandAddArgFormat(cmd, "%lluM", VIR_DIV_UP(vol->target.capacity,
2758                                                     (1024 * 1024)));
2759     virCommandAddArgList(cmd, "-t", "ext4", NULL);
2760     virCommandAddArg(cmd, target_path);
2761     return virCommandRun(cmd, NULL);
2762 }
2763 
2764 
2765 int
virStorageBackendVolWipeLocal(virStoragePoolObj * pool G_GNUC_UNUSED,virStorageVolDef * vol,unsigned int algorithm,unsigned int flags)2766 virStorageBackendVolWipeLocal(virStoragePoolObj *pool G_GNUC_UNUSED,
2767                               virStorageVolDef *vol,
2768                               unsigned int algorithm,
2769                               unsigned int flags)
2770 {
2771     int ret = -1;
2772 
2773     virCheckFlags(0, -1);
2774 
2775     VIR_DEBUG("Wiping volume with path '%s' and algorithm %u",
2776               vol->target.path, algorithm);
2777 
2778     if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
2779         ret = storageBackendVolWipePloop(vol, algorithm);
2780     } else {
2781         ret = storageBackendVolWipeLocalFile(vol->target.path, algorithm,
2782                                              vol->target.allocation, false);
2783     }
2784 
2785     return ret;
2786 }
2787 
2788 
2789 /**
2790  * @pool: storage pool to build
2791  * @dir_create_flags: flags for directory creation
2792  *
2793  * Common code to build a directory based storage pool
2794  *
2795  * Returns 0 on success, -1 on failure
2796  */
2797 int
virStorageBackendBuildLocal(virStoragePoolObj * pool)2798 virStorageBackendBuildLocal(virStoragePoolObj *pool)
2799 {
2800     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
2801     char *p = NULL;
2802     mode_t mode;
2803     bool needs_create_as_uid;
2804     unsigned int dir_create_flags;
2805     g_autofree char *parent = NULL;
2806     int ret;
2807 
2808     parent = g_strdup(def->target.path);
2809     if (!(p = strrchr(parent, '/'))) {
2810         virReportError(VIR_ERR_INVALID_ARG,
2811                        _("path '%s' is not absolute"),
2812                        def->target.path);
2813         return -1;
2814     }
2815 
2816     if (p != parent) {
2817         /* assure all directories in the path prior to the final dir
2818          * exist, with default uid/gid/mode. */
2819         *p = '\0';
2820         if (g_mkdir_with_parents(parent, 0777) < 0) {
2821             virReportSystemError(errno, _("cannot create path '%s'"),
2822                                  parent);
2823             return -1;
2824         }
2825     }
2826 
2827     dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST;
2828     needs_create_as_uid = (def->type == VIR_STORAGE_POOL_NETFS);
2829     mode = def->target.perms.mode;
2830 
2831     if (mode == (mode_t)-1 &&
2832         (needs_create_as_uid || !virFileExists(def->target.path)))
2833         mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE;
2834     if (needs_create_as_uid)
2835         dir_create_flags |= VIR_DIR_CREATE_AS_UID;
2836 
2837     /* Now create the final dir in the path with the uid/gid/mode
2838      * requested in the config. If the dir already exists, just set
2839      * the perms. */
2840     ret = virDirCreate(def->target.path,
2841                        mode,
2842                        def->target.perms.uid,
2843                        def->target.perms.gid,
2844                        dir_create_flags);
2845     if (ret < 0)
2846         return -1;
2847 
2848     if (virFileSetCOW(def->target.path,
2849                       def->features.cow) < 0)
2850         return -1;
2851 
2852     return 0;
2853 }
2854 
2855 
2856 /**
2857  * @conn connection to report errors against
2858  * @pool storage pool to delete
2859  *
2860  * Delete a directory based storage pool
2861  *
2862  * Returns 0 on success, -1 on error
2863  */
2864 int
virStorageBackendDeleteLocal(virStoragePoolObj * pool,unsigned int flags)2865 virStorageBackendDeleteLocal(virStoragePoolObj *pool,
2866                              unsigned int flags)
2867 {
2868     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
2869 
2870     virCheckFlags(0, -1);
2871 
2872     /* XXX delete all vols first ? */
2873 
2874     if (rmdir(def->target.path) < 0) {
2875         virReportSystemError(errno,
2876                              _("failed to remove pool '%s'"),
2877                              def->target.path);
2878         return -1;
2879     }
2880 
2881     return 0;
2882 }
2883 
2884 
2885 int
virStorageUtilGlusterExtractPoolSources(const char * host,const char * xml,virStoragePoolSourceList * list,virStoragePoolType pooltype)2886 virStorageUtilGlusterExtractPoolSources(const char *host,
2887                                         const char *xml,
2888                                         virStoragePoolSourceList *list,
2889                                         virStoragePoolType pooltype)
2890 {
2891     g_autoptr(xmlDoc) doc = NULL;
2892     g_autoptr(xmlXPathContext) ctxt = NULL;
2893     virStoragePoolSource *src = NULL;
2894     size_t i;
2895     int nnodes;
2896     g_autofree xmlNodePtr *nodes = NULL;
2897     g_autofree char *volname = NULL;
2898 
2899     if (!(doc = virXMLParseStringCtxt(xml, _("(gluster_cli_output)"), &ctxt)))
2900         return -1;
2901 
2902     if ((nnodes = virXPathNodeSet("//volumes/volume", ctxt, &nodes)) < 0)
2903         return -1;
2904 
2905     for (i = 0; i < nnodes; i++) {
2906         ctxt->node = nodes[i];
2907 
2908         if (!(src = virStoragePoolSourceListNewSource(list)))
2909             return -1;
2910 
2911         if (!(volname = virXPathString("string(./name)", ctxt))) {
2912             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2913                            _("failed to extract gluster volume name"));
2914             return -1;
2915         }
2916 
2917         if (pooltype == VIR_STORAGE_POOL_NETFS) {
2918             src->format = VIR_STORAGE_POOL_NETFS_GLUSTERFS;
2919             src->dir = g_steal_pointer(&volname);
2920         } else if (pooltype == VIR_STORAGE_POOL_GLUSTER) {
2921             src->dir = g_strdup("/");
2922             src->name = g_steal_pointer(&volname);
2923         } else {
2924             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2925                            _("unsupported gluster lookup"));
2926             return -1;
2927         }
2928 
2929         src->hosts = g_new0(virStoragePoolSourceHost, 1);
2930         src->nhost = 1;
2931 
2932         src->hosts[0].name = g_strdup(host);
2933     }
2934 
2935     return nnodes;
2936 }
2937 
2938 
2939 /**
2940  * virStorageBackendFindGlusterPoolSources:
2941  * @host: host to detect volumes on
2942  * @pooltype: type of the pool
2943  * @list: list of storage pool sources to be filled
2944  * @report: report error if the 'gluster' cli tool is missing
2945  *
2946  * Looks up gluster volumes on @host and fills them to @list.
2947  *
2948  * @pooltype allows to influence the specific differences between netfs and
2949  * native gluster pools. Users should pass only VIR_STORAGE_POOL_NETFS or
2950  * VIR_STORAGE_POOL_GLUSTER.
2951  *
2952  * Returns number of volumes on the host on success, or -1 on error.
2953  */
2954 int
virStorageBackendFindGlusterPoolSources(const char * host,virStoragePoolType pooltype,virStoragePoolSourceList * list,bool report)2955 virStorageBackendFindGlusterPoolSources(const char *host,
2956                                         virStoragePoolType pooltype,
2957                                         virStoragePoolSourceList *list,
2958                                         bool report)
2959 {
2960     int rc;
2961     g_autoptr(virCommand) cmd = NULL;
2962     g_autofree char *glusterpath = NULL;
2963     g_autofree char *outbuf = NULL;
2964 
2965     if (!(glusterpath = virFindFileInPath("gluster"))) {
2966         if (report) {
2967             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2968                            _("'gluster' command line tool not found"));
2969             return -1;
2970         } else {
2971             return 0;
2972         }
2973     }
2974 
2975     cmd = virCommandNewArgList(glusterpath,
2976                                "--xml",
2977                                "--log-file=/dev/null",
2978                                "volume", "info", "all", NULL);
2979 
2980     virCommandAddArgFormat(cmd, "--remote-host=%s", host);
2981     virCommandSetOutputBuffer(cmd, &outbuf);
2982 
2983     if (virCommandRun(cmd, &rc) < 0)
2984         return -1;
2985 
2986     if (rc != 0)
2987         return 0;
2988 
2989     return virStorageUtilGlusterExtractPoolSources(host, outbuf, list, pooltype);
2990 }
2991 
2992 
2993 #if WITH_BLKID
2994 
2995 typedef enum {
2996     VIR_STORAGE_BLKID_PROBE_ERROR = -1,
2997     VIR_STORAGE_BLKID_PROBE_UNDEFINED, /* Nothing found */
2998     VIR_STORAGE_BLKID_PROBE_UNKNOWN,   /* Don't know libvirt fs/part type */
2999     VIR_STORAGE_BLKID_PROBE_MATCH,     /* Matches the on disk format */
3000     VIR_STORAGE_BLKID_PROBE_DIFFERENT, /* Format doesn't match on disk format */
3001 } virStorageBackendBLKIDProbeResult;
3002 
3003 /*
3004  * Utility function to probe for a file system on the device using the
3005  * blkid "superblock" (e.g. default) APIs.
3006  *
3007  * NB: In general this helper will handle the virStoragePoolFormatFileSystem
3008  *     format types; however, if called from the Disk path, the initial fstype
3009  *     check will fail forcing the usage of the ProbePart helper.
3010  *
3011  * Returns virStorageBackendBLKIDProbeResult enum
3012  */
3013 static virStorageBackendBLKIDProbeResult
virStorageBackendBLKIDFindFS(blkid_probe probe,const char * device,const char * format)3014 virStorageBackendBLKIDFindFS(blkid_probe probe,
3015                              const char *device,
3016                              const char *format)
3017 {
3018     const char *fstype = NULL;
3019 
3020     /* Make sure we're doing a superblock probe from the start */
3021     blkid_probe_enable_superblocks(probe, true);
3022     blkid_probe_reset_superblocks_filter(probe);
3023 
3024     if (blkid_do_probe(probe) != 0) {
3025         VIR_INFO("No filesystem found on device '%s'", device);
3026         return VIR_STORAGE_BLKID_PROBE_UNDEFINED;
3027     }
3028 
3029     if (blkid_probe_lookup_value(probe, "TYPE", &fstype, NULL) == 0) {
3030         if (STREQ(fstype, format))
3031             return VIR_STORAGE_BLKID_PROBE_MATCH;
3032 
3033         return VIR_STORAGE_BLKID_PROBE_DIFFERENT;
3034     }
3035 
3036     if (blkid_known_fstype(format) == 0)
3037         return VIR_STORAGE_BLKID_PROBE_UNKNOWN;
3038 
3039     return VIR_STORAGE_BLKID_PROBE_ERROR;
3040 }
3041 
3042 
3043 /*
3044  * Utility function to probe for a partition on the device using the
3045  * blkid "partitions" APIs.
3046  *
3047  * NB: In general, this API will be validating the virStoragePoolFormatDisk
3048  *     format types.
3049  *
3050  * Returns virStorageBackendBLKIDProbeResult enum
3051  */
3052 static virStorageBackendBLKIDProbeResult
virStorageBackendBLKIDFindPart(blkid_probe probe,const char * device,const char * format)3053 virStorageBackendBLKIDFindPart(blkid_probe probe,
3054                                const char *device,
3055                                const char *format)
3056 {
3057     const char *pttype = NULL;
3058 
3059     /* A blkid_known_pttype on "dvh" and "pc98" returns a failure;
3060      * however, the blkid_do_probe for "dvh" returns "sgi" and
3061      * for "pc98" it returns "dos". Although "bsd" is recognized,
3062      * it seems that the parted created partition table is not being
3063      * properly recognized. Since each of these will cause problems
3064      * with startup comparison, let's just treat them as UNKNOWN causing
3065      * the caller to fallback to using PARTED */
3066     if (STREQ(format, "dvh") || STREQ(format, "pc98") || STREQ(format, "bsd"))
3067         return VIR_STORAGE_BLKID_PROBE_UNKNOWN;
3068 
3069     /* Make sure we're doing a partitions probe from the start */
3070     blkid_probe_enable_partitions(probe, true);
3071     blkid_probe_reset_partitions_filter(probe);
3072 
3073     if (blkid_do_probe(probe) != 0) {
3074         VIR_INFO("No partition found on device '%s'", device);
3075         return VIR_STORAGE_BLKID_PROBE_UNDEFINED;
3076     }
3077 
3078     if (blkid_probe_lookup_value(probe, "PTTYPE", &pttype, NULL) == 0) {
3079         if (STREQ(pttype, format))
3080             return VIR_STORAGE_BLKID_PROBE_MATCH;
3081 
3082         return VIR_STORAGE_BLKID_PROBE_DIFFERENT;
3083     }
3084 
3085     if (blkid_known_pttype(format) == 0)
3086         return VIR_STORAGE_BLKID_PROBE_UNKNOWN;
3087 
3088     return VIR_STORAGE_BLKID_PROBE_ERROR;
3089 }
3090 
3091 
3092 /*
3093  * @device: Path to device
3094  * @format: Desired format
3095  * @writelabel: True if desire to write the label
3096  *
3097  * Use the blkid_ APIs in order to get details regarding whether a file
3098  * system or partition exists on the disk already.
3099  *
3100  * Returns:
3101  *   -2: Force usage of PARTED for unknown types
3102  *   -1: An error was encountered, with error message set
3103  *    0: No file system found
3104  */
3105 static int
virStorageBackendBLKIDFindEmpty(const char * device,const char * format,bool writelabel)3106 virStorageBackendBLKIDFindEmpty(const char *device,
3107                                 const char *format,
3108                                 bool writelabel)
3109 {
3110     int ret = -1;
3111     int rc;
3112     blkid_probe probe = NULL;
3113 
3114     VIR_DEBUG("Probe for existing filesystem/partition format %s on device %s",
3115               format, device);
3116 
3117     if (!(probe = blkid_new_probe_from_filename(device))) {
3118         virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
3119                        _("Failed to create filesystem probe for device %s"),
3120                        device);
3121         return -1;
3122     }
3123 
3124     /* Look for something on FS, if it either doesn't recognize the
3125      * format type as a valid FS format type or it doesn't find a valid
3126      * format type on the device, then perform the same check using
3127      * partition probing. */
3128     rc = virStorageBackendBLKIDFindFS(probe, device, format);
3129     if (rc == VIR_STORAGE_BLKID_PROBE_UNDEFINED ||
3130         rc == VIR_STORAGE_BLKID_PROBE_UNKNOWN) {
3131 
3132         rc = virStorageBackendBLKIDFindPart(probe, device, format);
3133     }
3134 
3135     switch (rc) {
3136     case VIR_STORAGE_BLKID_PROBE_UNDEFINED:
3137         if (writelabel)
3138             ret = 0;
3139         else
3140             virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
3141                            _("Device '%s' is unrecognized, requires build"),
3142                            device);
3143         break;
3144 
3145     case VIR_STORAGE_BLKID_PROBE_ERROR:
3146         virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
3147                        _("Failed to probe for format type '%s'"), format);
3148         break;
3149 
3150     case VIR_STORAGE_BLKID_PROBE_UNKNOWN:
3151         ret = -2;
3152         break;
3153 
3154     case VIR_STORAGE_BLKID_PROBE_MATCH:
3155         if (writelabel)
3156             virReportError(VIR_ERR_STORAGE_POOL_BUILT,
3157                            _("Device '%s' already formatted using '%s'"),
3158                            device, format);
3159         else
3160             ret = 0;
3161         break;
3162 
3163     case VIR_STORAGE_BLKID_PROBE_DIFFERENT:
3164         if (writelabel)
3165             virReportError(VIR_ERR_STORAGE_POOL_BUILT,
3166                            _("Format of device '%s' does not match the "
3167                              "expected format '%s', forced overwrite is "
3168                              "necessary"),
3169                            device, format);
3170         else
3171             virReportError(VIR_ERR_OPERATION_INVALID,
3172                            _("Format of device '%s' does not match the "
3173                              "expected format '%s'"),
3174                            device, format);
3175         break;
3176     }
3177 
3178     if (ret == 0 && blkid_do_probe(probe) != 1) {
3179         virReportError(VIR_ERR_STORAGE_PROBE_FAILED, "%s",
3180                        _("Found additional probes to run, probing may "
3181                          "be incorrect"));
3182         ret = -1;
3183     }
3184 
3185     blkid_free_probe(probe);
3186 
3187     return ret;
3188 }
3189 
3190 #else /* #if WITH_BLKID */
3191 
3192 static int
virStorageBackendBLKIDFindEmpty(const char * device G_GNUC_UNUSED,const char * format G_GNUC_UNUSED,bool writelabel G_GNUC_UNUSED)3193 virStorageBackendBLKIDFindEmpty(const char *device G_GNUC_UNUSED,
3194                                 const char *format G_GNUC_UNUSED,
3195                                 bool writelabel G_GNUC_UNUSED)
3196 {
3197     return -2;
3198 }
3199 
3200 #endif /* #if WITH_BLKID */
3201 
3202 
3203 #if WITH_STORAGE_DISK
3204 
3205 typedef enum {
3206     VIR_STORAGE_PARTED_ERROR = -1,
3207     VIR_STORAGE_PARTED_MATCH,       /* Valid label found and matches format */
3208     VIR_STORAGE_PARTED_DIFFERENT,   /* Valid label found but not match format */
3209     VIR_STORAGE_PARTED_UNKNOWN,     /* No or unrecognized label */
3210     VIR_STORAGE_PARTED_NOPTTYPE,    /* Did not find the Partition Table type */
3211     VIR_STORAGE_PARTED_PTTYPE_UNK,  /* Partition Table type unknown */
3212 } virStorageBackendPARTEDResult;
3213 
3214 /**
3215  * Check for a valid disk label (partition table) on device using
3216  * the PARTED command
3217  *
3218  * returns virStorageBackendPARTEDResult
3219  */
3220 static virStorageBackendPARTEDResult
virStorageBackendPARTEDFindLabel(const char * device,const char * format)3221 virStorageBackendPARTEDFindLabel(const char *device,
3222                                  const char *format)
3223 {
3224     const char *const args[] = {
3225         device, "print", "--script", NULL,
3226     };
3227     char *start, *end;
3228     int ret = VIR_STORAGE_PARTED_ERROR;
3229     g_autoptr(virCommand) cmd = NULL;
3230     g_autofree char *output = NULL;
3231     g_autofree char *error = NULL;
3232 
3233     cmd = virCommandNew(PARTED);
3234     virCommandAddArgSet(cmd, args);
3235     virCommandAddEnvString(cmd, "LC_ALL=C");
3236     virCommandSetOutputBuffer(cmd, &output);
3237     virCommandSetErrorBuffer(cmd, &error);
3238 
3239     /* if parted succeeds we have a valid partition table */
3240     ret = virCommandRun(cmd, NULL);
3241     if (ret < 0) {
3242         if ((output && strstr(output, "unrecognised disk label")) ||
3243             (error && strstr(error, "unrecognised disk label"))) {
3244             ret = VIR_STORAGE_PARTED_UNKNOWN;
3245         }
3246         return ret;
3247     }
3248 
3249     /* Search for "Partition Table:" in the output. If not present,
3250      * then we cannot validate the partition table type.
3251      */
3252     if (!(start = strstr(output, "Partition Table: ")) ||
3253         !(end = strstr(start, "\n"))) {
3254         VIR_DEBUG("Unable to find tag in output: %s", output);
3255         return VIR_STORAGE_PARTED_NOPTTYPE;
3256     }
3257     start += strlen("Partition Table: ");
3258     *end = '\0';
3259 
3260     /* on disk it's "msdos", but we document/use "dos" so deal with it here */
3261     if (STREQ(start, "msdos"))
3262         start += 2;
3263 
3264     /* Make sure we know about this type */
3265     if (virStoragePoolFormatDiskTypeFromString(start) < 0)
3266         return VIR_STORAGE_PARTED_PTTYPE_UNK;
3267 
3268     /*  Does the on disk match what the pool desired? */
3269     if (STREQ(start, format))
3270         return VIR_STORAGE_PARTED_MATCH;
3271 
3272     return VIR_STORAGE_PARTED_DIFFERENT;
3273 }
3274 
3275 
3276 /**
3277  * Determine whether the label on the disk is valid or in a known format
3278  * for the purpose of rewriting the label during build or being able to
3279  * start a pool on a device.
3280  *
3281  * When 'writelabel' is true, if we find a valid disk label on the device,
3282  * then we shouldn't be attempting to write as the volume may contain
3283  * data. Force the usage of the overwrite flag to the build command in
3284  * order to be certain. When the disk label is unrecognized, then it
3285  * should be safe to write.
3286  *
3287  * When 'writelabel' is false, only if we find a valid disk label on the
3288  * device should we allow the start since for this path we won't be
3289  * rewriting the label.
3290  *
3291  * Return: 0 if it's OK
3292  *         -1 if something's wrong
3293  */
3294 static int
virStorageBackendPARTEDValidLabel(const char * device,const char * format,bool writelabel)3295 virStorageBackendPARTEDValidLabel(const char *device,
3296                                   const char *format,
3297                                   bool writelabel)
3298 {
3299     int ret = -1;
3300     virStorageBackendPARTEDResult check;
3301 
3302     check = virStorageBackendPARTEDFindLabel(device, format);
3303     switch (check) {
3304     case VIR_STORAGE_PARTED_ERROR:
3305         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3306                        _("Error checking for disk label, failed to get "
3307                          "disk partition information"));
3308         break;
3309 
3310     case VIR_STORAGE_PARTED_MATCH:
3311         if (writelabel)
3312             virReportError(VIR_ERR_OPERATION_INVALID,
3313                            _("Disk label already formatted using '%s'"),
3314                            format);
3315         else
3316             ret = 0;
3317         break;
3318 
3319     case VIR_STORAGE_PARTED_DIFFERENT:
3320         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3321                        _("Known, but different label format present, "
3322                          "requires build --overwrite"));
3323         break;
3324 
3325     case VIR_STORAGE_PARTED_UNKNOWN:
3326         if (writelabel)
3327             ret = 0;
3328         else
3329             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3330                            _("Unrecognized disk label found, requires build"));
3331         break;
3332 
3333     case VIR_STORAGE_PARTED_NOPTTYPE:
3334         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3335                        _("Unable to determine Partition Type, "
3336                          "requires build --overwrite"));
3337         break;
3338 
3339     case VIR_STORAGE_PARTED_PTTYPE_UNK:
3340         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3341                        _("Unknown Partition Type, requires build --overwrite"));
3342         break;
3343     }
3344 
3345     return ret;
3346 }
3347 
3348 #else
3349 
3350 static int
virStorageBackendPARTEDValidLabel(const char * device G_GNUC_UNUSED,const char * format G_GNUC_UNUSED,bool writelabel G_GNUC_UNUSED)3351 virStorageBackendPARTEDValidLabel(const char *device G_GNUC_UNUSED,
3352                                   const char *format G_GNUC_UNUSED,
3353                                   bool writelabel G_GNUC_UNUSED)
3354 {
3355     return -2;
3356 }
3357 
3358 
3359 #endif /* #if WITH_STORAGE_DISK */
3360 
3361 
3362 /* virStorageBackendDeviceIsEmpty:
3363  * @devpath: Path to the device to check
3364  * @format: Desired format string
3365  * @writelabel: True if the caller expects to write the label
3366  *
3367  * Check if the @devpath has some sort of known file system using the
3368  * BLKID API if available.
3369  *
3370  * Returns true if the probe deems the device has nothing valid on it
3371  * or when we cannot check and we're not writing the label.
3372  *
3373  * Returns false if the probe finds something
3374  */
3375 bool
virStorageBackendDeviceIsEmpty(const char * devpath,const char * format,bool writelabel)3376 virStorageBackendDeviceIsEmpty(const char *devpath,
3377                                const char *format,
3378                                bool writelabel)
3379 {
3380     int ret;
3381 
3382     if ((ret = virStorageBackendBLKIDFindEmpty(devpath, format,
3383                                                writelabel)) == -2)
3384         ret = virStorageBackendPARTEDValidLabel(devpath, format, writelabel);
3385 
3386     if (ret == -2 && !writelabel)
3387         ret = 0;
3388 
3389     if (ret == -2) {
3390         virReportError(VIR_ERR_OPERATION_INVALID,
3391                        _("Unable to probe '%s' for existing data, "
3392                          "forced overwrite is necessary"),
3393                        devpath);
3394     }
3395 
3396     return ret == 0;
3397 }
3398 
3399 
3400 static int
storageBackendProbeTarget(virStorageSource * target,virStorageEncryption ** encryption)3401 storageBackendProbeTarget(virStorageSource *target,
3402                           virStorageEncryption **encryption)
3403 {
3404     int rc;
3405     struct stat sb;
3406     g_autoptr(virStorageSource) meta = NULL;
3407     VIR_AUTOCLOSE fd = -1;
3408 
3409     if (encryption)
3410         *encryption = NULL;
3411 
3412     if ((rc = virStorageBackendVolOpen(target->path, &sb,
3413                                        VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
3414         return rc; /* Take care to propagate rc, it is not always -1 */
3415     fd = rc;
3416 
3417     if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0)
3418         return -1;
3419 
3420     if (S_ISDIR(sb.st_mode)) {
3421         if (storageBackendIsPloopDir(target->path)) {
3422             if (storageBackendRedoPloopUpdate(target, &sb, &fd,
3423                                               VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0)
3424                 return -1;
3425         } else {
3426             target->format = VIR_STORAGE_FILE_DIR;
3427             return 0;
3428         }
3429     }
3430 
3431     if (!(meta = virStorageSourceGetMetadataFromFD(target->path,
3432                                                    fd,
3433                                                    VIR_STORAGE_FILE_AUTO)))
3434         return -1;
3435 
3436     if (meta->backingStoreRaw) {
3437         /* XXX: Remote storage doesn't play nicely with volumes backed by
3438          * remote storage. To avoid trouble, just fake the backing store is RAW
3439          * and put the string from the metadata as the path of the target. */
3440         if (virStorageSourceNewFromBacking(meta, &target->backingStore) < 0 ||
3441             !virStorageSourceIsLocalStorage(target->backingStore)) {
3442             virObjectUnref(target->backingStore);
3443 
3444             target->backingStore = virStorageSourceNew();
3445             target->backingStore->type = VIR_STORAGE_TYPE_NETWORK;
3446             target->backingStore->path = meta->backingStoreRaw;
3447             meta->backingStoreRaw = NULL;
3448             target->backingStore->format = VIR_STORAGE_FILE_RAW;
3449         }
3450 
3451         if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) {
3452             if ((rc = virStorageFileProbeFormat(target->backingStore->path,
3453                                                 -1, -1)) < 0) {
3454                 /* If the backing file is currently unavailable or is
3455                  * accessed via remote protocol only log an error, fake the
3456                  * format as RAW and continue. Returning -1 here would
3457                  * disable the whole storage pool, making it unavailable for
3458                  * even maintenance. */
3459                 target->backingStore->format = VIR_STORAGE_FILE_RAW;
3460                 virReportError(VIR_ERR_INTERNAL_ERROR,
3461                                _("cannot probe backing volume format: %s"),
3462                                target->backingStore->path);
3463             } else {
3464                 target->backingStore->format = rc;
3465             }
3466         }
3467     }
3468 
3469     target->format = meta->format;
3470 
3471     /* Default to success below this point */
3472     if (meta->capacity)
3473         target->capacity = meta->capacity;
3474 
3475     if (meta->clusterSize > 0)
3476         target->clusterSize = meta->clusterSize;
3477 
3478     if (encryption && meta->encryption) {
3479         if (meta->encryption->payload_offset != -1)
3480             target->capacity -= meta->encryption->payload_offset * 512;
3481 
3482         *encryption = meta->encryption;
3483         meta->encryption = NULL;
3484 
3485         /* XXX ideally we'd fill in secret UUID here
3486          * but we cannot guarantee 'conn' is non-NULL
3487          * at this point in time :-(  So we only fill
3488          * in secrets when someone first queries a vol
3489          */
3490     }
3491 
3492     virBitmapFree(target->features);
3493     target->features = g_steal_pointer(&meta->features);
3494 
3495     if (meta->compat) {
3496         VIR_FREE(target->compat);
3497         target->compat = g_steal_pointer(&meta->compat);
3498     }
3499 
3500     return 0;
3501 }
3502 
3503 
3504 /**
3505  * virStorageBackendRefreshVolTargetUpdate:
3506  * @vol: Volume def that needs updating
3507  *
3508  * Attempt to probe the volume in order to get more details.
3509  *
3510  * Returns 0 on success, -2 to ignore failure, -1 on failure
3511  */
3512 int
virStorageBackendRefreshVolTargetUpdate(virStorageVolDef * vol)3513 virStorageBackendRefreshVolTargetUpdate(virStorageVolDef *vol)
3514 {
3515     int err;
3516 
3517     /* Real value is filled in during probe */
3518     vol->target.format = VIR_STORAGE_FILE_RAW;
3519 
3520     if ((err = storageBackendProbeTarget(&vol->target,
3521                                          &vol->target.encryption)) < 0) {
3522         if (err == -2) {
3523             return -2;
3524         } else if (err == -3) {
3525             /* The backing file is currently unavailable, its format is not
3526              * explicitly specified, the probe to auto detect the format
3527              * failed: continue with faked RAW format, since AUTO will
3528              * break virStorageVolTargetDefFormat() generating the line
3529              * <format type='...'/>. */
3530         } else {
3531             return -1;
3532         }
3533     }
3534 
3535     /* directory based volume */
3536     if (vol->target.format == VIR_STORAGE_FILE_DIR)
3537         vol->type = VIR_STORAGE_VOL_DIR;
3538 
3539     if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
3540         vol->type = VIR_STORAGE_VOL_PLOOP;
3541 
3542     if (virStorageSourceHasBacking(&vol->target)) {
3543         ignore_value(storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
3544                                                        vol->target.backingStore,
3545                                                        false,
3546                                                        VIR_STORAGE_VOL_OPEN_DEFAULT, 0));
3547         /* If this failed, the backing file is currently unavailable,
3548          * the capacity, allocation, owner, group and mode are unknown.
3549          * An error message was raised, but we just continue. */
3550     }
3551 
3552     return 0;
3553 }
3554 
3555 
3556 /**
3557  * Iterate over the pool's directory and enumerate all disk images
3558  * within it. This is non-recursive.
3559  */
3560 int
virStorageBackendRefreshLocal(virStoragePoolObj * pool)3561 virStorageBackendRefreshLocal(virStoragePoolObj *pool)
3562 {
3563     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
3564     g_autoptr(DIR) dir = NULL;
3565     struct dirent *ent;
3566     struct statvfs sb;
3567     struct stat statbuf;
3568     int direrr;
3569     g_autoptr(virStorageVolDef) vol = NULL;
3570     VIR_AUTOCLOSE fd = -1;
3571     g_autoptr(virStorageSource) target = NULL;
3572 
3573     if (virDirOpen(&dir, def->target.path) < 0)
3574         return -1;
3575 
3576     while ((direrr = virDirRead(dir, &ent, def->target.path)) > 0) {
3577         int err;
3578 
3579         if (virStringHasControlChars(ent->d_name)) {
3580             VIR_WARN("Ignoring file '%s' with control characters under '%s'",
3581                      ent->d_name, def->target.path);
3582             continue;
3583         }
3584 
3585         vol = g_new0(virStorageVolDef, 1);
3586 
3587         vol->name = g_strdup(ent->d_name);
3588 
3589         vol->type = VIR_STORAGE_VOL_FILE;
3590         vol->target.path = g_strdup_printf("%s/%s", def->target.path, vol->name);
3591 
3592         vol->key = g_strdup(vol->target.path);
3593 
3594         if ((err = virStorageBackendRefreshVolTargetUpdate(vol)) < 0) {
3595             if (err == -2) {
3596                 /* Silently ignore non-regular files,
3597                  * eg 'lost+found', dangling symbolic link */
3598                 virStorageVolDefFree(vol);
3599                 vol = NULL;
3600                 continue;
3601             }
3602             return -1;
3603         }
3604 
3605         if (virStoragePoolObjAddVol(pool, vol) < 0)
3606             return -1;
3607         vol = NULL;
3608     }
3609     if (direrr < 0)
3610         return -1;
3611 
3612     target = virStorageSourceNew();
3613 
3614     if ((fd = open(def->target.path, O_RDONLY)) < 0) {
3615         virReportSystemError(errno,
3616                              _("cannot open path '%s'"),
3617                              def->target.path);
3618         return -1;
3619     }
3620 
3621     if (fstat(fd, &statbuf) < 0) {
3622         virReportSystemError(errno,
3623                              _("cannot stat path '%s'"),
3624                              def->target.path);
3625         return -1;
3626     }
3627 
3628     if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0)
3629         return -1;
3630 
3631     /* VolTargetInfoFD doesn't update capacity correctly for the pool case */
3632     if (statvfs(def->target.path, &sb) < 0) {
3633         virReportSystemError(errno,
3634                              _("cannot statvfs path '%s'"),
3635                              def->target.path);
3636         return -1;
3637     }
3638 
3639     def->capacity = ((unsigned long long)sb.f_frsize *
3640                      (unsigned long long)sb.f_blocks);
3641     def->available = ((unsigned long long)sb.f_bfree *
3642                       (unsigned long long)sb.f_frsize);
3643     def->allocation = def->capacity - def->available;
3644 
3645     def->target.perms.mode = target->perms->mode;
3646     def->target.perms.uid = target->perms->uid;
3647     def->target.perms.gid = target->perms->gid;
3648     VIR_FREE(def->target.perms.label);
3649     def->target.perms.label = g_strdup(target->perms->label);
3650 
3651     return 0;
3652 }
3653 
3654 
3655 static char *
virStorageBackendSCSISerial(const char * dev,bool isNPIV)3656 virStorageBackendSCSISerial(const char *dev,
3657                             bool isNPIV)
3658 {
3659     int rc;
3660     char *serial = NULL;
3661 
3662     if (isNPIV)
3663         rc = virStorageFileGetNPIVKey(dev, &serial);
3664     else
3665         rc = virStorageFileGetSCSIKey(dev, &serial, true);
3666     if (rc == 0 && serial)
3667         return serial;
3668 
3669     if (rc == -2)
3670         return NULL;
3671 
3672     serial = g_strdup(dev);
3673     return serial;
3674 }
3675 
3676 
3677 /*
3678  * Attempt to create a new LUN
3679  *
3680  * Returns:
3681  *
3682  *  0  => Success
3683  *  -1 => Failure due to some sort of OOM or other fatal issue found when
3684  *        attempting to get/update information about a found volume
3685  *  -2 => Failure to find a stable path, not fatal, caller can try another
3686  */
3687 static int
virStorageBackendSCSINewLun(virStoragePoolObj * pool,uint32_t host G_GNUC_UNUSED,uint32_t bus,uint32_t target,uint32_t lun,const char * dev)3688 virStorageBackendSCSINewLun(virStoragePoolObj *pool,
3689                             uint32_t host G_GNUC_UNUSED,
3690                             uint32_t bus,
3691                             uint32_t target,
3692                             uint32_t lun,
3693                             const char *dev)
3694 {
3695     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
3696     int retval = -1;
3697     g_autoptr(virStorageVolDef) vol = NULL;
3698     g_autofree char *devpath = NULL;
3699 
3700     /* Check if the pool is using a stable target path. The call to
3701      * virStorageBackendStablePath will fail if the pool target path
3702      * isn't stable and just return the strdup'd 'devpath' anyway.
3703      * This would be indistinguishable to failing to find the stable
3704      * path to the device if the virDirRead loop to search the
3705      * target pool path for our devpath had failed.
3706      */
3707     if (!virStorageBackendPoolPathIsStable(def->target.path) &&
3708         !(STREQ(def->target.path, "/dev") ||
3709           STREQ(def->target.path, "/dev/"))) {
3710         virReportError(VIR_ERR_INVALID_ARG,
3711                        _("unable to use target path '%s' for dev '%s'"),
3712                        NULLSTR(def->target.path), dev);
3713         return -1;
3714     }
3715 
3716     vol = g_new0(virStorageVolDef, 1);
3717 
3718     vol->type = VIR_STORAGE_VOL_BLOCK;
3719 
3720     /* 'host' is dynamically allocated by the kernel, first come,
3721      * first served, per HBA. As such it isn't suitable for use
3722      * in the volume name. We only need uniqueness per-pool, so
3723      * just leave 'host' out
3724      */
3725     vol->name = g_strdup_printf("unit:%u:%u:%u", bus, target, lun);
3726 
3727     devpath = g_strdup_printf("/dev/%s", dev);
3728 
3729     VIR_DEBUG("Trying to create volume for '%s'", devpath);
3730 
3731     /* Now figure out the stable path
3732      *
3733      * XXX this method is O(N) because it scans the pool target
3734      * dir every time its run. Should figure out a more efficient
3735      * way of doing this...
3736      */
3737     if ((vol->target.path = virStorageBackendStablePath(pool,
3738                                                         devpath,
3739                                                         true)) == NULL)
3740         return -1;
3741 
3742     if (STREQ(devpath, vol->target.path) &&
3743         !(STREQ(def->target.path, "/dev") ||
3744           STREQ(def->target.path, "/dev/"))) {
3745 
3746         VIR_DEBUG("No stable path found for '%s' in '%s'",
3747                   devpath, def->target.path);
3748 
3749         return -2;
3750     }
3751 
3752     /* Allow a volume read failure to ignore or skip this block file */
3753     if ((retval = virStorageBackendUpdateVolInfo(vol, true,
3754                                                  VIR_STORAGE_VOL_OPEN_DEFAULT,
3755                                                  VIR_STORAGE_VOL_READ_NOERROR)) < 0)
3756         return retval;
3757 
3758     vol->key = virStorageBackendSCSISerial(vol->target.path,
3759                                            (def->source.adapter.type ==
3760                                             VIR_STORAGE_ADAPTER_TYPE_FC_HOST));
3761     if (!vol->key)
3762         return -1;
3763 
3764     def->capacity += vol->target.capacity;
3765     def->allocation += vol->target.allocation;
3766 
3767     if (virStoragePoolObjAddVol(pool, vol) < 0)
3768         return -1;
3769     vol = NULL;
3770 
3771     return 0;
3772 }
3773 
3774 
3775 
3776 static int
getNewStyleBlockDevice(const char * lun_path,const char * block_name G_GNUC_UNUSED,char ** block_device)3777 getNewStyleBlockDevice(const char *lun_path,
3778                        const char *block_name G_GNUC_UNUSED,
3779                        char **block_device)
3780 {
3781     g_autoptr(DIR) block_dir = NULL;
3782     struct dirent *block_dirent = NULL;
3783     int direrr;
3784     g_autofree char *block_path = NULL;
3785 
3786     block_path = g_strdup_printf("%s/block", lun_path);
3787 
3788     VIR_DEBUG("Looking for block device in '%s'", block_path);
3789 
3790     if (virDirOpen(&block_dir, block_path) < 0)
3791         return -1;
3792 
3793     while ((direrr = virDirRead(block_dir, &block_dirent, block_path)) > 0) {
3794         *block_device = g_strdup(block_dirent->d_name);
3795 
3796         VIR_DEBUG("Block device is '%s'", *block_device);
3797 
3798         break;
3799     }
3800 
3801     if (direrr < 0)
3802         return -1;
3803 
3804     return 0;
3805 }
3806 
3807 
3808 static int
getOldStyleBlockDevice(const char * lun_path G_GNUC_UNUSED,const char * block_name,char ** block_device)3809 getOldStyleBlockDevice(const char *lun_path G_GNUC_UNUSED,
3810                        const char *block_name,
3811                        char **block_device)
3812 {
3813     char *blockp = NULL;
3814 
3815     /* old-style; just parse out the sd */
3816     if (!(blockp = strrchr(block_name, ':'))) {
3817         /* Hm, wasn't what we were expecting; have to give up */
3818         virReportError(VIR_ERR_INTERNAL_ERROR,
3819                        _("Failed to parse block name %s"),
3820                        block_name);
3821         return -1;
3822     } else {
3823         blockp++;
3824         *block_device = g_strdup(blockp);
3825 
3826         VIR_DEBUG("Block device is '%s'", *block_device);
3827     }
3828 
3829     return 0;
3830 }
3831 
3832 
3833 /*
3834  * Search a device entry for the "block" file
3835  *
3836  * Returns
3837  *
3838  *   0 => Found it
3839  *   -1 => Fatal error
3840  *   -2 => Didn't find in lun_path directory
3841  */
3842 static int
getBlockDevice(uint32_t host,uint32_t bus,uint32_t target,uint32_t lun,char ** block_device)3843 getBlockDevice(uint32_t host,
3844                uint32_t bus,
3845                uint32_t target,
3846                uint32_t lun,
3847                char **block_device)
3848 {
3849     g_autoptr(DIR) lun_dir = NULL;
3850     struct dirent *lun_dirent = NULL;
3851     int direrr;
3852     g_autofree char *lun_path = NULL;
3853 
3854     *block_device = NULL;
3855 
3856     lun_path = g_strdup_printf("/sys/bus/scsi/devices/%u:%u:%u:%u", host, bus,
3857                                target, lun);
3858 
3859     if (virDirOpen(&lun_dir, lun_path) < 0)
3860         return -1;
3861 
3862     while ((direrr = virDirRead(lun_dir, &lun_dirent, lun_path)) > 0) {
3863         if (STRPREFIX(lun_dirent->d_name, "block")) {
3864             if (strlen(lun_dirent->d_name) == 5) {
3865                 if (getNewStyleBlockDevice(lun_path,
3866                                            lun_dirent->d_name,
3867                                            block_device) < 0)
3868                     return -1;
3869             } else {
3870                 if (getOldStyleBlockDevice(lun_path,
3871                                            lun_dirent->d_name,
3872                                            block_device) < 0)
3873                     return -1;
3874             }
3875             break;
3876         }
3877     }
3878     if (direrr < 0)
3879         return -1;
3880 
3881     if (!*block_device)
3882         return -2;
3883 
3884     return 0;
3885 }
3886 
3887 
3888 /* Function to check if the type file in the given sysfs_path is a
3889  * Direct-Access device (i.e. type 0).  Return -1 on failure, type of
3890  * the device otherwise.
3891  */
3892 static int
getDeviceType(uint32_t host,uint32_t bus,uint32_t target,uint32_t lun,int * type)3893 getDeviceType(uint32_t host,
3894               uint32_t bus,
3895               uint32_t target,
3896               uint32_t lun,
3897               int *type)
3898 {
3899     char typestr[3];
3900     char *gottype, *p;
3901     FILE *typefile;
3902     g_autofree char *type_path = NULL;
3903 
3904     type_path = g_strdup_printf("/sys/bus/scsi/devices/%u:%u:%u:%u/type", host,
3905                                 bus, target, lun);
3906 
3907     typefile = fopen(type_path, "r");
3908     if (typefile == NULL) {
3909         virReportSystemError(errno,
3910                              _("Could not find typefile '%s'"),
3911                              type_path);
3912         /* there was no type file; that doesn't seem right */
3913         return -1;
3914     }
3915 
3916     gottype = fgets(typestr, 3, typefile);
3917     VIR_FORCE_FCLOSE(typefile);
3918 
3919     if (gottype == NULL) {
3920         virReportSystemError(errno,
3921                              _("Could not read typefile '%s'"),
3922                              type_path);
3923         /* we couldn't read the type file; have to give up */
3924         return -1;
3925     }
3926 
3927     /* we don't actually care about p, but if you pass NULL and the last
3928      * character is not \0, virStrToLong_i complains
3929      */
3930     if (virStrToLong_i(typestr, &p, 10, type) < 0) {
3931         virReportError(VIR_ERR_INTERNAL_ERROR,
3932                        _("Device type '%s' is not an integer"),
3933                        typestr);
3934         /* Hm, type wasn't an integer; seems strange */
3935         return -1;
3936     }
3937 
3938     VIR_DEBUG("Device type is %d", *type);
3939 
3940     return 0;
3941 }
3942 
3943 
3944 /*
3945  * Process a Logical Unit entry from the scsi host device directory
3946  *
3947  * Returns:
3948  *
3949  *  0  => Found a valid entry
3950  *  -1 => Some sort of fatal error
3951  *  -2 => non-fatal error or a non-disk entry
3952  */
3953 static int
processLU(virStoragePoolObj * pool,uint32_t host,uint32_t bus,uint32_t target,uint32_t lun)3954 processLU(virStoragePoolObj *pool,
3955           uint32_t host,
3956           uint32_t bus,
3957           uint32_t target,
3958           uint32_t lun)
3959 {
3960     int retval = -1;
3961     int device_type;
3962     g_autofree char *block_device = NULL;
3963 
3964     VIR_DEBUG("Processing LU %u:%u:%u:%u",
3965               host, bus, target, lun);
3966 
3967     if (getDeviceType(host, bus, target, lun, &device_type) < 0) {
3968         virReportError(VIR_ERR_INTERNAL_ERROR,
3969                        _("Failed to determine if %u:%u:%u:%u is a Direct-Access LUN"),
3970                        host, bus, target, lun);
3971         return -1;
3972     }
3973 
3974     /* We don't create volumes for devices other than disk and cdrom
3975      * devices, but finding a device that isn't one of those types
3976      * isn't an error, either. */
3977     if (!(device_type == VIR_STORAGE_DEVICE_TYPE_DISK ||
3978           device_type == VIR_STORAGE_DEVICE_TYPE_ROM))
3979         return -2;
3980 
3981     VIR_DEBUG("%u:%u:%u:%u is a Direct-Access LUN",
3982               host, bus, target, lun);
3983 
3984     if ((retval = getBlockDevice(host, bus, target, lun, &block_device)) < 0) {
3985         VIR_DEBUG("Failed to find block device for this LUN");
3986         return retval;
3987     }
3988 
3989     retval = virStorageBackendSCSINewLun(pool, host, bus, target, lun,
3990                                          block_device);
3991     if (retval < 0) {
3992         VIR_DEBUG("Failed to create new storage volume for %u:%u:%u:%u",
3993                   host, bus, target, lun);
3994         return retval;
3995     }
3996 
3997     VIR_DEBUG("Created new storage volume for %u:%u:%u:%u successfully",
3998               host, bus, target, lun);
3999 
4000     return retval;
4001 }
4002 
4003 
4004 int
virStorageBackendSCSIFindLUs(virStoragePoolObj * pool,uint32_t scanhost)4005 virStorageBackendSCSIFindLUs(virStoragePoolObj *pool,
4006                               uint32_t scanhost)
4007 {
4008     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
4009     int retval = 0;
4010     uint32_t bus, target, lun;
4011     const char *device_path = "/sys/bus/scsi/devices";
4012     g_autoptr(DIR) devicedir = NULL;
4013     struct dirent *lun_dirent = NULL;
4014     char devicepattern[64];
4015     int found = 0;
4016 
4017     VIR_DEBUG("Discovering LUs on host %u", scanhost);
4018 
4019     virWaitForDevices();
4020 
4021     if (virDirOpen(&devicedir, device_path) < 0)
4022         return -1;
4023 
4024     g_snprintf(devicepattern, sizeof(devicepattern), "%u:%%u:%%u:%%u\n", scanhost);
4025 
4026     while ((retval = virDirRead(devicedir, &lun_dirent, device_path)) > 0) {
4027         int rc;
4028 
4029         if (sscanf(lun_dirent->d_name, devicepattern,
4030                    &bus, &target, &lun) != 3) {
4031             continue;
4032         }
4033 
4034         VIR_DEBUG("Found possible LU '%s'", lun_dirent->d_name);
4035 
4036         rc = processLU(pool, scanhost, bus, target, lun);
4037         if (rc == -1) {
4038             retval = -1;
4039             break;
4040         }
4041         if (rc == 0)
4042             found++;
4043     }
4044 
4045     if (retval < 0)
4046         return -1;
4047 
4048     VIR_DEBUG("Found %d LUs for pool %s", found, def->name);
4049 
4050     return found;
4051 }
4052 
4053 
4054 /*
4055  * @path: Path to the device to initialize
4056  * @size: Size to be cleared
4057  *
4058  * Zero out possible partition table information for the specified
4059  * bytes from the start of the @path and from the end of @path
4060  *
4061  * Returns 0 on success, -1 on failure with error message set
4062  */
4063 int
virStorageBackendZeroPartitionTable(const char * path,unsigned long long size)4064 virStorageBackendZeroPartitionTable(const char *path,
4065                                     unsigned long long size)
4066 {
4067     if (storageBackendVolWipeLocalFile(path, VIR_STORAGE_VOL_WIPE_ALG_ZERO,
4068                                        size, false) < 0)
4069         return -1;
4070 
4071     return storageBackendVolWipeLocalFile(path, VIR_STORAGE_VOL_WIPE_ALG_ZERO,
4072                                           size, true);
4073 }
4074 
4075 
4076 /**
4077  * virStorageBackendFileSystemGetPoolSource
4078  * @pool: storage pool object pointer
4079  *
4080  * Allocate/return a string representing the FS storage pool source.
4081  * It is up to the caller to VIR_FREE the allocated string
4082  */
4083 char *
virStorageBackendFileSystemGetPoolSource(virStoragePoolObj * pool)4084 virStorageBackendFileSystemGetPoolSource(virStoragePoolObj *pool)
4085 {
4086     virStoragePoolDef *def = virStoragePoolObjGetDef(pool);
4087     char *src = NULL;
4088 
4089     if (def->type == VIR_STORAGE_POOL_NETFS) {
4090         if (def->source.format == VIR_STORAGE_POOL_NETFS_CIFS) {
4091             src = g_strdup_printf("//%s/%s", def->source.hosts[0].name,
4092                                   def->source.dir);
4093         } else {
4094             src = g_strdup_printf("%s:%s", def->source.hosts[0].name,
4095                                   def->source.dir);
4096         }
4097     } else {
4098         src = g_strdup(def->source.devices[0].path);
4099     }
4100     return src;
4101 }
4102 
4103 
4104 static void
virStorageBackendFileSystemMountAddOptions(virCommand * cmd,virStoragePoolDef * def,const char * providedOpts)4105 virStorageBackendFileSystemMountAddOptions(virCommand *cmd,
4106                                            virStoragePoolDef *def,
4107                                            const char *providedOpts)
4108 {
4109     g_autofree char *mountOpts = NULL;
4110     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
4111 
4112     if (*default_mount_opts != '\0')
4113         virBufferAsprintf(&buf, "%s,", default_mount_opts);
4114 
4115     if (providedOpts)
4116         virBufferAsprintf(&buf, "%s,", providedOpts);
4117 
4118     if (def->namespaceData) {
4119         size_t i;
4120         virStoragePoolFSMountOptionsDef *opts = def->namespaceData;
4121         char uuidstr[VIR_UUID_STRING_BUFLEN];
4122 
4123         for (i = 0; i < opts->noptions; i++)
4124             virBufferAsprintf(&buf, "%s,", opts->options[i]);
4125 
4126         virUUIDFormat(def->uuid, uuidstr);
4127         VIR_WARN("Storage Pool name='%s' uuid='%s' is tainted by custom "
4128                  "mount_opts from XML", def->name, uuidstr);
4129     }
4130 
4131     virBufferTrim(&buf, ",");
4132     mountOpts = virBufferContentAndReset(&buf);
4133 
4134     if (mountOpts)
4135         virCommandAddArgList(cmd, "-o", mountOpts, NULL);
4136 }
4137 
4138 
4139 static void
virStorageBackendFileSystemMountNFSArgs(virCommand * cmd,const char * src,virStoragePoolDef * def,const char * nfsVers)4140 virStorageBackendFileSystemMountNFSArgs(virCommand *cmd,
4141                                         const char *src,
4142                                         virStoragePoolDef *def,
4143                                         const char *nfsVers)
4144 {
4145     virStorageBackendFileSystemMountAddOptions(cmd, def, nfsVers);
4146     virCommandAddArgList(cmd, src, def->target.path, NULL);
4147 }
4148 
4149 
4150 static void
virStorageBackendFileSystemMountGlusterArgs(virCommand * cmd,const char * src,virStoragePoolDef * def)4151 virStorageBackendFileSystemMountGlusterArgs(virCommand *cmd,
4152                                             const char *src,
4153                                             virStoragePoolDef *def)
4154 {
4155     const char *fmt;
4156 
4157     fmt = virStoragePoolFormatFileSystemNetTypeToString(def->source.format);
4158     virStorageBackendFileSystemMountAddOptions(cmd, def, "direct-io-mode=1");
4159     virCommandAddArgList(cmd, "-t", fmt, src, def->target.path, NULL);
4160 }
4161 
4162 
4163 static void
virStorageBackendFileSystemMountCIFSArgs(virCommand * cmd,const char * src,virStoragePoolDef * def)4164 virStorageBackendFileSystemMountCIFSArgs(virCommand *cmd,
4165                                          const char *src,
4166                                          virStoragePoolDef *def)
4167 {
4168     const char *fmt;
4169 
4170     fmt = virStoragePoolFormatFileSystemNetTypeToString(def->source.format);
4171     virStorageBackendFileSystemMountAddOptions(cmd, def, "guest");
4172     virCommandAddArgList(cmd, "-t", fmt, src, def->target.path, NULL);
4173 }
4174 
4175 
4176 static void
virStorageBackendFileSystemMountDefaultArgs(virCommand * cmd,const char * src,virStoragePoolDef * def,const char * nfsVers)4177 virStorageBackendFileSystemMountDefaultArgs(virCommand *cmd,
4178                                             const char *src,
4179                                             virStoragePoolDef *def,
4180                                             const char *nfsVers)
4181 {
4182     const char *fmt;
4183 
4184     if (def->type == VIR_STORAGE_POOL_FS)
4185         fmt = virStoragePoolFormatFileSystemTypeToString(def->source.format);
4186     else
4187         fmt = virStoragePoolFormatFileSystemNetTypeToString(def->source.format);
4188     virStorageBackendFileSystemMountAddOptions(cmd, def, nfsVers);
4189     virCommandAddArgList(cmd, "-t", fmt, src, def->target.path, NULL);
4190 }
4191 
4192 
4193 virCommand *
virStorageBackendFileSystemMountCmd(const char * cmdstr,virStoragePoolDef * def,const char * src)4194 virStorageBackendFileSystemMountCmd(const char *cmdstr,
4195                                     virStoragePoolDef *def,
4196                                     const char *src)
4197 {
4198     /* 'mount -t auto' doesn't seem to auto determine nfs (or cifs),
4199      *  while plain 'mount' does. We have to craft separate argvs to
4200      *  accommodate this */
4201     bool netauto = (def->type == VIR_STORAGE_POOL_NETFS &&
4202                     def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
4203     bool glusterfs = (def->type == VIR_STORAGE_POOL_NETFS &&
4204                       def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
4205     bool cifsfs = (def->type == VIR_STORAGE_POOL_NETFS &&
4206                    def->source.format == VIR_STORAGE_POOL_NETFS_CIFS);
4207     virCommand *cmd = NULL;
4208     g_autofree char *nfsVers = NULL;
4209 
4210     if (def->type == VIR_STORAGE_POOL_NETFS && def->source.protocolVer > 0)
4211         nfsVers = g_strdup_printf("nfsvers=%u", def->source.protocolVer);
4212 
4213     cmd = virCommandNew(cmdstr);
4214     if (netauto)
4215         virStorageBackendFileSystemMountNFSArgs(cmd, src, def, nfsVers);
4216     else if (glusterfs)
4217         virStorageBackendFileSystemMountGlusterArgs(cmd, src, def);
4218     else if (cifsfs)
4219         virStorageBackendFileSystemMountCIFSArgs(cmd, src, def);
4220     else
4221         virStorageBackendFileSystemMountDefaultArgs(cmd, src, def, nfsVers);
4222     return cmd;
4223 }
4224 
4225 
4226 virCommand *
virStorageBackendLogicalChangeCmd(const char * cmdstr,virStoragePoolDef * def,bool on)4227 virStorageBackendLogicalChangeCmd(const char *cmdstr,
4228                                   virStoragePoolDef *def,
4229                                   bool on)
4230 {
4231     return virCommandNewArgList(cmdstr,
4232                                 on ? "-aly" : "-aln",
4233                                 def->source.name,
4234                                 NULL);
4235 }
4236