mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 16:26:17 +00:00
Compare commits
461 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af706846f | ||
|
|
3b0e432875 | ||
|
|
44092e06ce | ||
|
|
87690b10ff | ||
|
|
f5544e8c93 | ||
|
|
2f0a4d7c18 | ||
|
|
349300af08 | ||
|
|
b48e416d27 | ||
|
|
cfda2693c6 | ||
|
|
ca11cd104d | ||
|
|
848db89b7f | ||
|
|
288a24eebe | ||
|
|
883aea9b1d | ||
|
|
c43f762257 | ||
|
|
424fe36d32 | ||
|
|
0a49838135 | ||
|
|
685c5fb3b1 | ||
|
|
45840581d6 | ||
|
|
45599a8895 | ||
|
|
24fdf05d30 | ||
|
|
c9ef854f83 | ||
|
|
008be5dbfa | ||
|
|
e327351304 | ||
|
|
09b4cc45a3 | ||
|
|
e4ef9a8281 | ||
|
|
a7107854ba | ||
|
|
3acf6768f0 | ||
|
|
c2013308ed | ||
|
|
f4d5f3d6a2 | ||
|
|
142b874ce8 | ||
|
|
f2b90b374f | ||
|
|
1a06ac25f5 | ||
|
|
b72daebaf4 | ||
|
|
2cf0b5c19b | ||
|
|
abe07ce2ca | ||
|
|
6a7327dfa9 | ||
|
|
c396d4cd32 | ||
|
|
e3546ad2ce | ||
|
|
6582d4ad9f | ||
|
|
a3de6eddd4 | ||
|
|
dfa25a46e3 | ||
|
|
f9f3c7c5ac | ||
|
|
dee1dd64c3 | ||
|
|
e73cd348c8 | ||
|
|
3cdca7616a | ||
|
|
33c087ea9c | ||
|
|
289fd29f0b | ||
|
|
ba0199c487 | ||
|
|
3dcb572bda | ||
|
|
d0a8cca9a1 | ||
|
|
387b232126 | ||
|
|
667482ca9a | ||
|
|
2287b988ee | ||
|
|
ecda39bed4 | ||
|
|
1cb38ab924 | ||
|
|
288b2b2d4f | ||
|
|
6fa1177b0a | ||
|
|
1a2e03c323 | ||
|
|
ce49e1fdc0 | ||
|
|
599f5d7ddc | ||
|
|
5f5ce4f59f | ||
|
|
b050d7e4bf | ||
|
|
68990840b6 | ||
|
|
f2b1a01e76 | ||
|
|
72f5a6b004 | ||
|
|
75f2fcd687 | ||
|
|
806289ec66 | ||
|
|
b2eef58571 | ||
|
|
8e76cb4512 | ||
|
|
02a4e5ac6a | ||
|
|
2a090e0667 | ||
|
|
429ffda329 | ||
|
|
30702c7f54 | ||
|
|
f55a2dbf29 | ||
|
|
8b90f55dc7 | ||
|
|
d6ea2f5911 | ||
|
|
a9ad3088bf | ||
|
|
bb276e8a26 | ||
|
|
a28a430b10 | ||
|
|
c50cde67cc | ||
|
|
c36ced5e21 | ||
|
|
6185aa4e38 | ||
|
|
dce94f3e26 | ||
|
|
b13c935bbd | ||
|
|
3c34db9808 | ||
|
|
df7f57a193 | ||
|
|
924aa44c1f | ||
|
|
6c9a7fe561 | ||
|
|
b98de580c9 | ||
|
|
05ba393724 | ||
|
|
69e0f86cab | ||
|
|
186bb67c6e | ||
|
|
97be29893e | ||
|
|
62d940d2dd | ||
|
|
55ce68784f | ||
|
|
71de9ef039 | ||
|
|
a535befbeb | ||
|
|
66df6ae908 | ||
|
|
f8941b09e6 | ||
|
|
dc4c959ce1 | ||
|
|
43b6d75a08 | ||
|
|
f750c3e72d | ||
|
|
9c32c73afd | ||
|
|
766393d854 | ||
|
|
6641758221 | ||
|
|
612a3f06b4 | ||
|
|
cec0c55a35 | ||
|
|
856c2f6a47 | ||
|
|
ae3011d518 | ||
|
|
bf1c3196b5 | ||
|
|
2af946b3bf | ||
|
|
af1c53d104 | ||
|
|
e7c78881fc | ||
|
|
c83221a869 | ||
|
|
694a091d3f | ||
|
|
e7e2b56569 | ||
|
|
b1df9a9df1 | ||
|
|
33ec3eca29 | ||
|
|
a2b88b8637 | ||
|
|
85dd52f470 | ||
|
|
e29a130d8f | ||
|
|
04acc32abf | ||
|
|
87c9ec881c | ||
|
|
0fd925da77 | ||
|
|
df656c9d5a | ||
|
|
3e4d3f415c | ||
|
|
1b644ad64e | ||
|
|
50a3fa5f42 | ||
|
|
e9d3074294 | ||
|
|
368b4c6480 | ||
|
|
b17c3a7eb3 | ||
|
|
0b285cd8a6 | ||
|
|
6e4f9be492 | ||
|
|
49622ab63b | ||
|
|
5e5026b730 | ||
|
|
2f8960f784 | ||
|
|
cd40cf7139 | ||
|
|
becc4fecf4 | ||
|
|
c64e99782f | ||
|
|
350c478d7b | ||
|
|
02159e9aa8 | ||
|
|
fe3798f366 | ||
|
|
d44752a110 | ||
|
|
7a968beb46 | ||
|
|
99e5ffd1de | ||
|
|
d9efcfb556 | ||
|
|
1b5b397da8 | ||
|
|
d16bb6b70c | ||
|
|
e73944faf4 | ||
|
|
bb0617859f | ||
|
|
74297e6109 | ||
|
|
52c3edd5e0 | ||
|
|
801487f2a7 | ||
|
|
22d82d00b4 | ||
|
|
0ee24ccf8a | ||
|
|
3a895ba794 | ||
|
|
ef33ea359d | ||
|
|
6557d0c082 | ||
|
|
a568dec4cf | ||
|
|
43b37d02a1 | ||
|
|
0a50e64435 | ||
|
|
bb1f665d7f | ||
|
|
ed41fcd75c | ||
|
|
06b39b8098 | ||
|
|
2c8e7ba9b4 | ||
|
|
9ae639948a | ||
|
|
f9381847f1 | ||
|
|
6e7cbb09a9 | ||
|
|
8136ca3719 | ||
|
|
7de25c2bca | ||
|
|
c44c5ee268 | ||
|
|
ba08a51094 | ||
|
|
59f01c4a70 | ||
|
|
ed354e8f8b | ||
|
|
a4a2a181c2 | ||
|
|
f7789acdab | ||
|
|
6039689344 | ||
|
|
0120a087f4 | ||
|
|
3e9e40aee3 | ||
|
|
09442d0588 | ||
|
|
d08f5ebd9a | ||
|
|
ac2f6c4ef2 | ||
|
|
4236929fbb | ||
|
|
9b7de52d58 | ||
|
|
66351f7494 | ||
|
|
8e2b920fe6 | ||
|
|
7d8b97559b | ||
|
|
7f5bedd53b | ||
|
|
3adb0d6d01 | ||
|
|
e78a2c5df3 | ||
|
|
26df366d3b | ||
|
|
b9ee8baa49 | ||
|
|
617eb88c5e | ||
|
|
a6a703253b | ||
|
|
d01ac17559 | ||
|
|
3f1e7f1078 | ||
|
|
93feaa4ae8 | ||
|
|
ce7cffa85a | ||
|
|
1ea7752e95 | ||
|
|
4c5c555eeb | ||
|
|
c29660588f | ||
|
|
1ea73f4bdf | ||
|
|
db30fe0cb0 | ||
|
|
b6cbd980fb | ||
|
|
5ff3845d28 | ||
|
|
fe939cf842 | ||
|
|
6e3aab2f0c | ||
|
|
34e77af1bf | ||
|
|
76266be549 | ||
|
|
556e109765 | ||
|
|
f8b92c0668 | ||
|
|
a885dd025d | ||
|
|
4a6c8021b5 | ||
|
|
d02610853d | ||
|
|
ff0269e80f | ||
|
|
cd1558b89e | ||
|
|
680450f3b4 | ||
|
|
ff80a54011 | ||
|
|
455d6b1845 | ||
|
|
fadec0687f | ||
|
|
4136850f3c | ||
|
|
7953128ca6 | ||
|
|
d950e1a3bc | ||
|
|
1ca842d98b | ||
|
|
37796d70bf | ||
|
|
b49eefdb15 | ||
|
|
9d6aa8b537 | ||
|
|
907fbfff53 | ||
|
|
4ede94ab7b | ||
|
|
6ee164d47a | ||
|
|
27e6347b75 | ||
|
|
0b7acf50b6 | ||
|
|
e27295c578 | ||
|
|
7ef461948e | ||
|
|
04723b4dd1 | ||
|
|
a4953090e1 | ||
|
|
1a2465c187 | ||
|
|
2101324965 | ||
|
|
6566621345 | ||
|
|
b7ab6de628 | ||
|
|
61162bdce1 | ||
|
|
b10a6cfe24 | ||
|
|
175d6ba432 | ||
|
|
065861ce6b | ||
|
|
8671cfa343 | ||
|
|
a1c89bf03d | ||
|
|
c7ba91761c | ||
|
|
70514c7f7e | ||
|
|
0f849029d1 | ||
|
|
e9d83e94a2 | ||
|
|
7e71c9fb34 | ||
|
|
2a8de9001e | ||
|
|
5c513060b1 | ||
|
|
b793fafcb7 | ||
|
|
6902f093ff | ||
|
|
0e0eec76d9 | ||
|
|
cbfa394bfc | ||
|
|
5c6895bda1 | ||
|
|
87d1f7714f | ||
|
|
c598e14052 | ||
|
|
989d3c7691 | ||
|
|
9021351c8e | ||
|
|
52b7418670 | ||
|
|
f0f8d7ce78 | ||
|
|
23f8bd4fac | ||
|
|
db554cf271 | ||
|
|
4f7d1b3ae7 | ||
|
|
77c57ab843 | ||
|
|
1399005d7e | ||
|
|
e84d6e6102 | ||
|
|
4215d0ca68 | ||
|
|
7ba0e10501 | ||
|
|
7d976657e6 | ||
|
|
b0abf10b9f | ||
|
|
754e819438 | ||
|
|
6e7f052ef4 | ||
|
|
bcb933a0c1 | ||
|
|
72aaf56fed | ||
|
|
ec6a4de37a | ||
|
|
954e315d21 | ||
|
|
6c5577e403 | ||
|
|
cd47df1fe5 | ||
|
|
0e79b9dd03 | ||
|
|
09c4f94c9d | ||
|
|
bbb637f962 | ||
|
|
ee61d16e3e | ||
|
|
45b4271579 | ||
|
|
05444da983 | ||
|
|
b3cf5d1d96 | ||
|
|
a43f88b1c5 | ||
|
|
942e139562 | ||
|
|
93d4fddaef | ||
|
|
984431a9ef | ||
|
|
f226133c1a | ||
|
|
ef2276654e | ||
|
|
47b929b789 | ||
|
|
d5817537fa | ||
|
|
007c2f236d | ||
|
|
b1a89d3b1c | ||
|
|
3877cab329 | ||
|
|
20fd81147d | ||
|
|
df983d1994 | ||
|
|
e4495b24bc | ||
|
|
c3afef3eec | ||
|
|
09f3913734 | ||
|
|
9c9ceec6b7 | ||
|
|
1703c6841b | ||
|
|
e527aed895 | ||
|
|
e0a3a7c1e5 | ||
|
|
d6c0ff055d | ||
|
|
8ad8e1075b | ||
|
|
d538af8a0a | ||
|
|
4255db65e5 | ||
|
|
20a562321c | ||
|
|
94d90f03e2 | ||
|
|
59b296fecc | ||
|
|
30029b7ffb | ||
|
|
5f54da6fdf | ||
|
|
5e770c8f6a | ||
|
|
7b7cfa62e3 | ||
|
|
cab1a0c1d9 | ||
|
|
8fb2306be4 | ||
|
|
6e7f95b669 | ||
|
|
7d6b5bb837 | ||
|
|
dd58db7329 | ||
|
|
a7d7e8176f | ||
|
|
3045c0cbaf | ||
|
|
c78ec7e085 | ||
|
|
ca056d53bd | ||
|
|
f9bafde5e7 | ||
|
|
f473a173b8 | ||
|
|
f631e84102 | ||
|
|
c98ef8d089 | ||
|
|
a0a4ee5245 | ||
|
|
72dd398679 | ||
|
|
7e25e0780e | ||
|
|
4075ed9247 | ||
|
|
776ffbfaec | ||
|
|
4940bd9a9e | ||
|
|
d012b729fa | ||
|
|
9e27a1556c | ||
|
|
5e4f03ccf2 | ||
|
|
0d18a8b407 | ||
|
|
791ad3e9e6 | ||
|
|
6c1aca5ae2 | ||
|
|
4b20a20d33 | ||
|
|
42bffcd00a | ||
|
|
ec3b75e5ff | ||
|
|
63c324e6c4 | ||
|
|
27b995c841 | ||
|
|
1dd9bf73b7 | ||
|
|
63c50c7847 | ||
|
|
be4a3d77c4 | ||
|
|
908c45567c | ||
|
|
950951c67d | ||
|
|
233055974d | ||
|
|
071de5ccfb | ||
|
|
3a8a62c3e4 | ||
|
|
cd3b626a33 | ||
|
|
5a3da36626 | ||
|
|
98b64650c8 | ||
|
|
acb85dafb1 | ||
|
|
aab796c608 | ||
|
|
27c81f3175 | ||
|
|
ded72a96f0 | ||
|
|
f3976de591 | ||
|
|
d3068a3aff | ||
|
|
a0d874725d | ||
|
|
abb1d46636 | ||
|
|
ec8939fd47 | ||
|
|
085b86a95a | ||
|
|
875dc11364 | ||
|
|
ed5a083891 | ||
|
|
4d8bdf0357 | ||
|
|
159e8f8c3a | ||
|
|
f956457b5d | ||
|
|
28e34290ff | ||
|
|
533082e282 | ||
|
|
ebc86ae6d7 | ||
|
|
e18e20793f | ||
|
|
2974b5d666 | ||
|
|
64b229e8ff | ||
|
|
d8f14591d1 | ||
|
|
312d02afe4 | ||
|
|
aa83e7c7b8 | ||
|
|
111f444d69 | ||
|
|
9637bddc33 | ||
|
|
24c4178749 | ||
|
|
2c68aca9d7 | ||
|
|
9c8e47247b | ||
|
|
c61b589f9b | ||
|
|
9fd41abd40 | ||
|
|
a710c42f0f | ||
|
|
a0e9d310d1 | ||
|
|
d4763a2e24 | ||
|
|
ce828c6afc | ||
|
|
0d2d26d8e7 | ||
|
|
3f08d50863 | ||
|
|
05a67bcc25 | ||
|
|
7d89baa3e9 | ||
|
|
f58b6c5953 | ||
|
|
20e23ab2a3 | ||
|
|
e051b270a2 | ||
|
|
bff29314df | ||
|
|
60d744e32f | ||
|
|
406e372469 | ||
|
|
67d59d0153 | ||
|
|
1881be1e56 | ||
|
|
3a72944597 | ||
|
|
7718cb5afe | ||
|
|
5ede0b21b0 | ||
|
|
c9e0ff8831 | ||
|
|
604f9a79db | ||
|
|
3e7dcc384a | ||
|
|
beebade874 | ||
|
|
11e111ec01 | ||
|
|
9ae248e03f | ||
|
|
6c9aaf394f | ||
|
|
bcdaa46313 | ||
|
|
a9d70d1ae4 | ||
|
|
364ee94b8d | ||
|
|
5af94b5692 | ||
|
|
741c8606db | ||
|
|
4a877452f5 | ||
|
|
4b5d27869f | ||
|
|
bfddae7cee | ||
|
|
e73cf67762 | ||
|
|
6628cc7ef6 | ||
|
|
eca01c3105 | ||
|
|
d1ad89520e | ||
|
|
a34072e25b | ||
|
|
fa162417ed | ||
|
|
2434a86da4 | ||
|
|
3f88f88c80 | ||
|
|
8be9743e74 | ||
|
|
034d393bb1 | ||
|
|
62f98d64a5 | ||
|
|
5b70120293 | ||
|
|
f07e89c5f9 | ||
|
|
05103cc693 | ||
|
|
8237ac89c5 | ||
|
|
4ad6b28d83 | ||
|
|
eab324bbbb | ||
|
|
6f02e33c6f | ||
|
|
79339798b3 | ||
|
|
11b6293d1b | ||
|
|
c4ad2c0ce3 | ||
|
|
22fe98ad9f | ||
|
|
eca2dd2e8c | ||
|
|
486efb002a | ||
|
|
448a02373d | ||
|
|
1571aef9cc | ||
|
|
62e775c350 | ||
|
|
27f6878e2a | ||
|
|
95df8a7c0c | ||
|
|
a9051eb98e | ||
|
|
956e30effa | ||
|
|
2aa731e7c4 | ||
|
|
d7a806ca1a | ||
|
|
e92f9666de | ||
|
|
52cd07a0ac |
57
.gitignore
vendored
57
.gitignore
vendored
@@ -45,6 +45,15 @@ Makefile.in
|
||||
/appliance/stamp-supermin
|
||||
/appliance/supermin.d
|
||||
/autom4te.cache
|
||||
/bash/virt-cat
|
||||
/bash/virt-df
|
||||
/bash/virt-edit
|
||||
/bash/virt-filesystems
|
||||
/bash/virt-format
|
||||
/bash/virt-inspector
|
||||
/bash/virt-ls
|
||||
/bash/virt-sysprep
|
||||
/bash/virt-sparsify
|
||||
/build-aux
|
||||
/cat/stamp-virt-*.pod
|
||||
/cat/virt-cat
|
||||
@@ -96,17 +105,18 @@ Makefile.in
|
||||
/erlang/guestfs.beam
|
||||
/erlang/guestfs.erl
|
||||
/erlang/test.img
|
||||
/examples/copy_over
|
||||
/examples/create_disk
|
||||
/examples/display_icon
|
||||
/examples/copy-over
|
||||
/examples/create-disk
|
||||
/examples/debug-logging
|
||||
/examples/display-icon
|
||||
/examples/guestfs-examples.3
|
||||
/examples/guestfs-faq.1
|
||||
/examples/guestfs-performance.1
|
||||
/examples/guestfs-recipes.1
|
||||
/examples/guestfs-testing.1
|
||||
/examples/inspect_vm
|
||||
/examples/libvirt_auth
|
||||
/examples/mount_local
|
||||
/examples/inspect-vm
|
||||
/examples/libvirt-auth
|
||||
/examples/mount-local
|
||||
/examples/stamp-guestfs-examples.pod
|
||||
/examples/stamp-guestfs-faq.pod
|
||||
/examples/stamp-guestfs-performance.pod
|
||||
@@ -123,6 +133,7 @@ Makefile.in
|
||||
/fish/guestfish.1
|
||||
/fish/guestfish-actions.pod
|
||||
/fish/guestfish-commands.pod
|
||||
/fish/guestfish-prepopts.pod
|
||||
/fish/prepopts.c
|
||||
/fish/prepopts.h
|
||||
/fish/rc_protocol.c
|
||||
@@ -141,7 +152,11 @@ Makefile.in
|
||||
/format/virt-format.1
|
||||
/fuse/guestmount
|
||||
/fuse/guestmount.1
|
||||
/fuse/guestunmount
|
||||
/fuse/guestunmount.1
|
||||
/fuse/stamp-guestmount.pod
|
||||
/fuse/stamp-guestunmount.pod
|
||||
/fuse/test-guestunmount-fd
|
||||
/generator/.depend
|
||||
/generator/files-generated.txt
|
||||
/generator/generator
|
||||
@@ -160,8 +175,9 @@ Makefile.in
|
||||
/guestfsd-in-wine.log
|
||||
/haskell/Bindtests
|
||||
/haskell/Bindtests.hs
|
||||
/haskell/Guestfs005Load
|
||||
/haskell/Guestfs010Basic
|
||||
/haskell/Guestfs010Load
|
||||
/haskell/Guestfs030Config
|
||||
/haskell/Guestfs050LVCreate
|
||||
/haskell/Guestfs.hs
|
||||
/html/guestfish.1.html
|
||||
/html/guestfs.3.html
|
||||
@@ -180,6 +196,7 @@ Makefile.in
|
||||
/html/guestfs-testing.1.html
|
||||
/html/guestfsd.8.html
|
||||
/html/guestmount.1.html
|
||||
/html/guestunmount.1.html
|
||||
/html/libguestfs-make-fixed-appliance.1.html
|
||||
/html/libguestfs-test-tool.1.html
|
||||
/html/virt-alignment-scan.1.html
|
||||
@@ -251,6 +268,7 @@ Makefile.in
|
||||
/ocaml/guestfs.mli
|
||||
/ocamlinit-stamp
|
||||
/ocaml/META
|
||||
/ocaml/stamp-mlguestfs
|
||||
/ocaml/t/guestfs_005_load.bc
|
||||
/ocaml/t/guestfs_005_load.opt
|
||||
/ocaml/t/guestfs_010_basic.bc
|
||||
@@ -292,6 +310,7 @@ Makefile.in
|
||||
/php/extension/config.sub
|
||||
/php/extension/configure
|
||||
/php/extension/configure.in
|
||||
/php/extension/env
|
||||
/php/extension/guestfs_php.c
|
||||
/php/extension/guestfs_php_*.diff
|
||||
/php/extension/guestfs_php_*.exp
|
||||
@@ -319,6 +338,7 @@ Makefile.in
|
||||
/po-docs/po4a.conf
|
||||
/po-docs/*/*.pod
|
||||
/po-docs/*/stamp-update-po
|
||||
/podwrapper.1
|
||||
/podwrapper.pl
|
||||
/po/*.gmo
|
||||
/python/bindtests.py
|
||||
@@ -334,8 +354,8 @@ Makefile.in
|
||||
/rescue/virt-rescue
|
||||
/rescue/virt-rescue.1
|
||||
/resize/.depend
|
||||
/resize/resize_gettext.ml
|
||||
/resize/resize_utils_tests
|
||||
/resize/common_gettext.ml
|
||||
/resize/common_utils_tests
|
||||
/resize/stamp-virt-resize.pod
|
||||
/resize/virt-resize
|
||||
/resize/virt-resize.1
|
||||
@@ -344,6 +364,7 @@ Makefile.in
|
||||
/ruby/examples/guestfs-ruby.3
|
||||
/ruby/examples/stamp-guestfs-ruby.pod
|
||||
/ruby/ext/guestfs/extconf.h
|
||||
/ruby/ext/guestfs/extconf.rb
|
||||
/ruby/ext/guestfs/_guestfs.bundle
|
||||
/ruby/ext/guestfs/_guestfs.c
|
||||
/ruby/ext/guestfs/_guestfs.so
|
||||
@@ -351,23 +372,25 @@ Makefile.in
|
||||
/ruby/Rakefile
|
||||
/run
|
||||
/sparsify/.depend
|
||||
/sparsify/sparsify_gettext.ml
|
||||
/sparsify/stamp-virt-sparsify.pod
|
||||
/sparsify/virt-sparsify
|
||||
/sparsify/virt-sparsify.1
|
||||
/src/actions-?.c
|
||||
/src/actions-variants.c
|
||||
/src/bindtests.c
|
||||
/src/cleanup-structs.c
|
||||
/src/errnostring.c
|
||||
/src/errnostring-gperf.c
|
||||
/src/errnostring-gperf.gperf
|
||||
/src/errnostring.h
|
||||
/src/event-string.c
|
||||
/src/free-structs.c
|
||||
/src/guestfs.3
|
||||
/src/guestfs-actions.pod
|
||||
/src/guestfs-availability.pod
|
||||
/src/guestfs.h
|
||||
/src/guestfs-internal-actions.h
|
||||
/src/guestfs-internal-frontend-cleanups.h
|
||||
/src/guestfs_protocol.c
|
||||
/src/guestfs_protocol.h
|
||||
/src/guestfs_protocol.x
|
||||
@@ -383,7 +406,6 @@ Makefile.in
|
||||
/sysprep/stamp-script2.sh
|
||||
/sysprep/stamp-virt-sysprep.pod
|
||||
/sysprep/sysprep-extra-options.pod
|
||||
/sysprep/sysprep_gettext.ml
|
||||
/sysprep/sysprep-operations.pod
|
||||
/sysprep/virt-sysprep
|
||||
/sysprep/virt-sysprep.1
|
||||
@@ -398,12 +420,14 @@ Makefile.in
|
||||
/tests/c-api/test-create-handle
|
||||
/tests/c-api/test-debug-to-file
|
||||
/tests/c-api/test-environment
|
||||
/tests/c-api/test-event-string
|
||||
/tests/c-api/test*.img
|
||||
/tests/c-api/test-just-header
|
||||
/tests/c-api/test-just-header-cxx
|
||||
/tests/c-api/test-last-errno
|
||||
/tests/c-api/test.log
|
||||
/tests/c-api/test-private-data
|
||||
/tests/c-api/test-pwd
|
||||
/tests/c-api/tests
|
||||
/tests/c-api/tests.c
|
||||
/tests/c-api/test*.tmp
|
||||
@@ -421,20 +445,28 @@ Makefile.in
|
||||
/tests/data/initrd-x86_64.img.gz
|
||||
/tests/data/test-grep.txt.gz
|
||||
/tests/data/test.iso
|
||||
/tests/guests/blank-*.img
|
||||
/tests/guests/debian.img
|
||||
/tests/guests/fedora.img
|
||||
/tests/guests/fedora-btrfs.img
|
||||
/tests/guests/fedora-md1.img
|
||||
/tests/guests/fedora-md2.img
|
||||
/tests/guests/guests.xml
|
||||
/tests/guests/guests-all-good.xml
|
||||
/tests/guests/guest-aux/fedora-name.db
|
||||
/tests/guests/guest-aux/fedora-packages.db
|
||||
/tests/guests/stamp-fedora-md.img
|
||||
/tests/guests/ubuntu.img
|
||||
/tests/guests/windows.img
|
||||
/tests/mount-local/test-parallel-mount-local
|
||||
/tests/mountable/test-internal-parse-mountable
|
||||
/tests/parallel/test-parallel
|
||||
/tests/regressions/rhbz501893
|
||||
/tests/regressions/rhbz790721
|
||||
/tests/regressions/rhbz914931
|
||||
/tests/rsync/rsyncd.pid
|
||||
/tests/syslinux/extlinux-guest.img
|
||||
/tests/syslinux/syslinux-guest.img
|
||||
/test-tool/libguestfs-test-tool
|
||||
/test-tool/libguestfs-test-tool.1
|
||||
/test-tool/libguestfs-test-tool-helper
|
||||
@@ -442,4 +474,3 @@ Makefile.in
|
||||
/tools/test.img
|
||||
/tools/virt-*.1
|
||||
/tools/virt-*.pl
|
||||
/valgrind.log*
|
||||
|
||||
2
.gnulib
2
.gnulib
Submodule .gnulib updated: 4a8c422f31...076ac82d1d
2
AUTHORS
2
AUTHORS
@@ -10,7 +10,9 @@ Erik Nolte <erik_nolte@acm.org>
|
||||
Evaggelos Balaskas <ebalaskas@ebalaskas.gr>
|
||||
Geert Warrink <geert.warrink@onsnet.nu>
|
||||
Guido Günther <agx@sigxcpu.org>
|
||||
Hilko Bengen <bengen@debian.org>
|
||||
Hilko Bengen <bengen@hilluzination.de>
|
||||
infernix <infernix@infernix.net>
|
||||
Jaswinder Singh <jsingh@redhat.com>
|
||||
Jim Meyering <meyering@redhat.com>
|
||||
Jiri Popelka <jpopelka@redhat.com>
|
||||
|
||||
186
BUGS
186
BUGS
@@ -1,5 +1,5 @@
|
||||
NOTE: This file is automatically generated from "update-bugs.sh".
|
||||
Last updated: 2012-12-13
|
||||
Last updated: 2013-04-17
|
||||
|
||||
This contains a local list of the bugs that are open against
|
||||
libguestfs. Bugs are tracked in the Red Hat Bugzilla database
|
||||
@@ -107,9 +107,6 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
806179 NEW https://bugzilla.redhat.com/show_bug.cgi?id=806179
|
||||
RFE: support inspection of icon for more Windows guests
|
||||
|
||||
808193 NEW https://bugzilla.redhat.com/show_bug.cgi?id=808193
|
||||
g.launch() crashes on RHEL 5
|
||||
|
||||
812970 NEW https://bugzilla.redhat.com/show_bug.cgi?id=812970
|
||||
virt-rescue cannot set ><rescue> prompt, on Ubuntu 12.04
|
||||
|
||||
@@ -143,30 +140,15 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
837941 NEW https://bugzilla.redhat.com/show_bug.cgi?id=837941
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
838081 NEW https://bugzilla.redhat.com/show_bug.cgi?id=838081
|
||||
ocaml/t/guestfs_500_parallel_mount_local crashes in caml_thread_reinitialize
|
||||
|
||||
845234 NEW https://bugzilla.redhat.com/show_bug.cgi?id=845234
|
||||
RFE: virt-ls on Windows guest doesn't support drive letters
|
||||
|
||||
846676 NEW https://bugzilla.redhat.com/show_bug.cgi?id=846676
|
||||
guestfs_launch() hangs with Debian qemu-kvm 1.1.0
|
||||
|
||||
848464 NEW https://bugzilla.redhat.com/show_bug.cgi?id=848464
|
||||
gobject javascript bindings cannot use 64 bit integers
|
||||
|
||||
857763 NEW https://bugzilla.redhat.com/show_bug.cgi?id=857763
|
||||
libguestfs 'file-architecture' returns 'ARM' for arm binaries
|
||||
|
||||
863696 NEW https://bugzilla.redhat.com/show_bug.cgi?id=863696
|
||||
[F18] libguestfs fails to mount a disk image file(in this case qcow2) as 'root'
|
||||
|
||||
864871 NEW https://bugzilla.redhat.com/show_bug.cgi?id=864871
|
||||
libvirt error: could not create appliance through libvirt: unable to set security context 'unconfined_u:object_r:svirt_image_t:s0:cXXX,cYYY' on '.../console.sock'
|
||||
|
||||
865923 NEW https://bugzilla.redhat.com/show_bug.cgi?id=865923
|
||||
Check that new qemu -machine option doesn't break libguestfs.
|
||||
|
||||
866994 NEW https://bugzilla.redhat.com/show_bug.cgi?id=866994
|
||||
tgz-out causes memory leak in guestfsd
|
||||
|
||||
@@ -176,6 +158,120 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
880806 NEW https://bugzilla.redhat.com/show_bug.cgi?id=880806
|
||||
virt-df with two -a options displays incorrect disk image name
|
||||
|
||||
887826 NEW https://bugzilla.redhat.com/show_bug.cgi?id=887826
|
||||
RFE: virt-sparsify cannot handle multi-disk virtual machines (eg. if they use LVM, MD, LDM, etc)
|
||||
|
||||
889089 NEW https://bugzilla.redhat.com/show_bug.cgi?id=889089
|
||||
Block device /dev/sd* didn't translate to /dev/vd*
|
||||
|
||||
890027 NEW https://bugzilla.redhat.com/show_bug.cgi?id=890027
|
||||
virt-sysprep: Setting the hostname on Fedora 18 is stupidly over-complicated
|
||||
|
||||
891909 NEW https://bugzilla.redhat.com/show_bug.cgi?id=891909
|
||||
Can't make install with non-standard prefix as non-root
|
||||
|
||||
892271 NEW https://bugzilla.redhat.com/show_bug.cgi?id=892271
|
||||
virt-format fail to format the same disk more than twice with lvm enable
|
||||
|
||||
892272 NEW https://bugzilla.redhat.com/show_bug.cgi?id=892272
|
||||
Specify QEMU interface emulation will break libguestfs
|
||||
|
||||
892275 NEW https://bugzilla.redhat.com/show_bug.cgi?id=892275
|
||||
checksums-out fail to compute the checksums of all regular files in directory
|
||||
|
||||
892291 NEW https://bugzilla.redhat.com/show_bug.cgi?id=892291
|
||||
guestmount: link() incorrectly returns ENOENT, when it should be EXDEV
|
||||
|
||||
892834 NEW https://bugzilla.redhat.com/show_bug.cgi?id=892834
|
||||
guestmount: rename() incorrectly follows symbolic links
|
||||
|
||||
895898 NEW https://bugzilla.redhat.com/show_bug.cgi?id=895898
|
||||
RFE: Allow interface to be specified with libvirt attach-method
|
||||
|
||||
895946 NEW https://bugzilla.redhat.com/show_bug.cgi?id=895946
|
||||
Got incorrect block count number when resize ntfs file system via "ntfsresize_opts"
|
||||
|
||||
903890 NEW https://bugzilla.redhat.com/show_bug.cgi?id=903890
|
||||
scrub-freespace didn't remove the scrub file, cause the file system 100% full
|
||||
|
||||
903972 NEW https://bugzilla.redhat.com/show_bug.cgi?id=903972
|
||||
Command "acl-set-file" is inconvenient to use
|
||||
|
||||
903987 NEW https://bugzilla.redhat.com/show_bug.cgi?id=903987
|
||||
Command "acl-set-file" is inconvenient to use
|
||||
|
||||
905322 NEW https://bugzilla.redhat.com/show_bug.cgi?id=905322
|
||||
"No such file or directory" when execute "hivex-commit"
|
||||
|
||||
906190 NEW https://bugzilla.redhat.com/show_bug.cgi?id=906190
|
||||
Need add a line break behind the output of command "hivex-value-value"
|
||||
|
||||
906766 NEW https://bugzilla.redhat.com/show_bug.cgi?id=906766
|
||||
virt-resize cannot resize RHEL 5 guest with GPT partition table type
|
||||
|
||||
906777 NEW https://bugzilla.redhat.com/show_bug.cgi?id=906777
|
||||
In tests, set_label sometimes fails
|
||||
|
||||
908255 NEW https://bugzilla.redhat.com/show_bug.cgi?id=908255
|
||||
error message didn't translate to user language
|
||||
|
||||
909666 NEW https://bugzilla.redhat.com/show_bug.cgi?id=909666
|
||||
Unexpected non-tail recursion in recv_from_daemon results in stack overflow in very long-running API calls that send progress messages
|
||||
|
||||
909667 NEW https://bugzilla.redhat.com/show_bug.cgi?id=909667
|
||||
Unexpected non-tail recursion in recv_from_daemon results in stack overflow in very long-running API calls that send progress messages
|
||||
|
||||
910115 NEW https://bugzilla.redhat.com/show_bug.cgi?id=910115
|
||||
RFE: support ntfsresize --bad-sectors option in virt-resize
|
||||
|
||||
910269 NEW https://bugzilla.redhat.com/show_bug.cgi?id=910269
|
||||
Tracker: Bugs in other packages that stop libguestfs working on current Rawhide
|
||||
|
||||
910270 NEW https://bugzilla.redhat.com/show_bug.cgi?id=910270
|
||||
Tracker: Bugs in other packages that stop libguestfs working on Fedora 18
|
||||
|
||||
911674 NEW https://bugzilla.redhat.com/show_bug.cgi?id=911674
|
||||
swapon label test fails (RHEL 7 only)
|
||||
|
||||
911678 NEW https://bugzilla.redhat.com/show_bug.cgi?id=911678
|
||||
libguestfs: error: cpio command failed: Resource temporarily unavailable (RHEL 7 only)
|
||||
|
||||
913774 NEW https://bugzilla.redhat.com/show_bug.cgi?id=913774
|
||||
libguestfs: could not create appliance through libvirt when URI is qemu:///system or running as root (which causes system to be used implicitly)
|
||||
|
||||
913815 NEW https://bugzilla.redhat.com/show_bug.cgi?id=913815
|
||||
febootstrap: no ext2 root device found when running libguestfs-test-tools
|
||||
|
||||
916130 NEW https://bugzilla.redhat.com/show_bug.cgi?id=916130
|
||||
libguestfs can't rebuild in mock
|
||||
|
||||
917706 NEW https://bugzilla.redhat.com/show_bug.cgi?id=917706
|
||||
guestfs_umount_local is not thread safe
|
||||
|
||||
920617 NEW https://bugzilla.redhat.com/show_bug.cgi?id=920617
|
||||
RFE: virt-inspector (or another tool) should produce OVF output for oVirt / RHEV
|
||||
|
||||
921299 NEW https://bugzilla.redhat.com/show_bug.cgi?id=921299
|
||||
virt-p2v fails with permissions problem on kernel module.
|
||||
|
||||
921710 NEW https://bugzilla.redhat.com/show_bug.cgi?id=921710
|
||||
9p support should be disabled in libguestfs in RHEL 7
|
||||
|
||||
922891 NEW https://bugzilla.redhat.com/show_bug.cgi?id=922891
|
||||
Tracker: Bugs in other packages that stop libguestfs working on Fedora 19
|
||||
|
||||
923355 NEW https://bugzilla.redhat.com/show_bug.cgi?id=923355
|
||||
guestfish prints literal "n" in error messages
|
||||
|
||||
927447 NEW https://bugzilla.redhat.com/show_bug.cgi?id=927447
|
||||
[suse] virt tools hang on disk image, but libguestfs-test-tool runs OK
|
||||
|
||||
950444 NEW https://bugzilla.redhat.com/show_bug.cgi?id=950444
|
||||
inspection fails if libosinfo is not installed
|
||||
|
||||
953001 NEW https://bugzilla.redhat.com/show_bug.cgi?id=953001
|
||||
Rebuild libguestfs to pick up libk5radius -> libkrad rename in Kerberos V
|
||||
|
||||
503134 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=503134
|
||||
guestfish's list splitting does not recognize internal quoting
|
||||
|
||||
@@ -194,50 +290,30 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
803643 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=803643
|
||||
inspect-is-multipart return false when inspection results should be true
|
||||
|
||||
(58 bugs)
|
||||
(90 bugs)
|
||||
|
||||
--------------------------------------------------
|
||||
These bugs are in the VERIFIED state.
|
||||
Bugs in MODIFIED, POST or ON_QA state are fixed.
|
||||
You can help by testing the fixes.
|
||||
|
||||
801640 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=801640
|
||||
[RFE] the error reported by resize2fs-M need to be more clear
|
||||
889536 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=889536
|
||||
[RFE]It's better to emphasize "libguestfs-winsupport" in V2V manpage or error output
|
||||
|
||||
816839 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=816839
|
||||
data overflow error when debug progress -1
|
||||
889537 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=889537
|
||||
Libguestfs live support should be disabled in RHEL 7 packages
|
||||
|
||||
822626 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=822626
|
||||
virt-ls error: "libguestfs: error: checksum: path: parameter cannot be NULL"
|
||||
|
||||
830135 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=830135
|
||||
libguestfs should support mount-local APIs in RHEL 6 (for OpenStack)
|
||||
|
||||
836501 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=836501
|
||||
dependency on fuse suggested
|
||||
|
||||
837691 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=837691
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
838609 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=838609
|
||||
guestmount + fusermount allows a race condition when unmounting and immediately using the disk image
|
||||
|
||||
853763 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=853763
|
||||
virt-sparsify should use a more robust method to detect the input format
|
||||
|
||||
858126 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858126
|
||||
virt-inspector fail to work with some windows guests
|
||||
|
||||
858128 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858128
|
||||
libguestfs fail to list devices added by add-drive-ro-with-if twice
|
||||
|
||||
858648 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858648
|
||||
889538 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=889538
|
||||
libguestfs can not be installed with recent iptables
|
||||
|
||||
880805 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=880805
|
||||
virt-df with two -a options displays incorrect disk image name
|
||||
909573 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=909573
|
||||
patch libguestfs to use 'supermin' instead of 'febootstrap' in RHEL 7
|
||||
|
||||
883338 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=883338
|
||||
Missing #include <locale.h> in fuse/guestmount.c
|
||||
947438 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=947438
|
||||
Some obsolete tools should be removed from libguestfs RHEL 7 package
|
||||
|
||||
(13 bugs)
|
||||
949486 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=949486
|
||||
libguestfs-1.20.5-3.el7.x86_64 dependency problem
|
||||
|
||||
(6 bugs)
|
||||
|
||||
End of BUGS file.
|
||||
|
||||
145
Makefile.am
145
Makefile.am
@@ -1,5 +1,5 @@
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -30,9 +30,7 @@ SUBDIRS += tests/data generator src examples po
|
||||
if ENABLE_DAEMON
|
||||
SUBDIRS += daemon
|
||||
endif
|
||||
if ENABLE_APPLIANCE
|
||||
SUBDIRS += appliance
|
||||
endif
|
||||
|
||||
# Tests - order is important.
|
||||
if ENABLE_APPLIANCE
|
||||
@@ -43,6 +41,7 @@ SUBDIRS += tests/tmpdirs
|
||||
SUBDIRS += tests/protocol
|
||||
SUBDIRS += tests/parallel
|
||||
SUBDIRS += tests/disks
|
||||
SUBDIRS += tests/mountable
|
||||
SUBDIRS += tests/lvm
|
||||
SUBDIRS += tests/luks
|
||||
SUBDIRS += tests/md
|
||||
@@ -57,6 +56,8 @@ SUBDIRS += tests/rsync
|
||||
SUBDIRS += tests/bigdirs
|
||||
SUBDIRS += tests/disk-labels
|
||||
SUBDIRS += tests/hotplug
|
||||
SUBDIRS += tests/nbd
|
||||
SUBDIRS += tests/syslinux
|
||||
SUBDIRS += tests/regressions
|
||||
endif
|
||||
|
||||
@@ -69,6 +70,9 @@ SUBDIRS += fish
|
||||
# virt-tools in C.
|
||||
SUBDIRS += align cat df edit format inspector rescue
|
||||
|
||||
# bash-completion
|
||||
SUBDIRS += bash
|
||||
|
||||
# Language bindings.
|
||||
if HAVE_PERL
|
||||
SUBDIRS += perl perl/examples
|
||||
@@ -191,6 +195,7 @@ HTMLFILES = \
|
||||
html/guestfsd.8.html \
|
||||
html/guestfish.1.html \
|
||||
html/guestmount.1.html \
|
||||
html/guestunmount.1.html \
|
||||
html/libguestfs-make-fixed-appliance.1.html \
|
||||
html/libguestfs-test-tool.1.html \
|
||||
html/virt-alignment-scan.1.html \
|
||||
@@ -241,7 +246,7 @@ dist-hook:
|
||||
$(top_srcdir)/update-bugs.sh > BUGS-t
|
||||
mv BUGS-t BUGS
|
||||
cp BUGS $(distdir)/BUGS
|
||||
git shortlog -se | awk -F'\t' '{print $$2}' > AUTHORS-t
|
||||
git shortlog -se | awk -F'\t' '{print $$2}' | sort -f > AUTHORS-t
|
||||
mv AUTHORS-t AUTHORS
|
||||
cp AUTHORS $(distdir)/AUTHORS
|
||||
|
||||
@@ -288,13 +293,31 @@ stamp-guestfs-release-notes.pod: guestfs-release-notes.pod
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# NB. podwrapper is an internal tool, so the man page mustn't be installed.
|
||||
noinst_MANS = podwrapper.1
|
||||
podwrapper.1: podwrapper.pl
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man $@-t \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
mv $@-t $@
|
||||
|
||||
# Make clean.
|
||||
|
||||
CLEANFILES = \
|
||||
*~ \
|
||||
html/*.html \
|
||||
pod2htm?.tmp \
|
||||
podwrapper.1 \
|
||||
qemu-wrapper.sh \
|
||||
stamp-guestfs-release-notes.pod
|
||||
stamp-guestfs-release-notes.pod \
|
||||
tmp/guestfs.* \
|
||||
tmp/run-* \
|
||||
tmp/valgrind-*.log
|
||||
|
||||
clean-local:
|
||||
-rm -rf tmp/libguestfs??????
|
||||
|
||||
# If you don't want to run all of the tests ('make check') then this
|
||||
# will just run libguestfs-test-tool for a quick check. Note this
|
||||
@@ -307,48 +330,53 @@ quickcheck:
|
||||
|
||||
extra-tests:
|
||||
$(MAKE) -j1 \
|
||||
valgrind \
|
||||
valgrind-local-guests \
|
||||
check-with-appliance \
|
||||
check-valgrind \
|
||||
check-valgrind-local-guests \
|
||||
check-direct \
|
||||
check-valgrind-direct \
|
||||
check-with-upstream-qemu \
|
||||
check-with-upstream-libvirt \
|
||||
check-slow
|
||||
|
||||
check-valgrind: build-test-guests
|
||||
@for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
@errors=0; \
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) -C `dirname $$f` $@; \
|
||||
$(MAKE) -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
$(MAKE) -C `dirname $$f` $@ || (( errors++ )); \
|
||||
done; \
|
||||
exit $$(( $$errors ? 1 : 0 ))
|
||||
|
||||
check-valgrind-local-guests:
|
||||
@GUESTS=`$(top_builddir)/run ./pick-guests.pl 5`; \
|
||||
errors=0; \
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) GUESTS="$$GUESTS" -C `dirname $$f` $@; \
|
||||
$(MAKE) GUESTS="$$GUESTS" -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
$(MAKE) GUESTS="$$GUESTS" -C `dirname $$f` $@ || (( errors++ )); \
|
||||
done; \
|
||||
exit $$(( $$errors ? 1 : 0 ))
|
||||
|
||||
check-slow: build-test-guests
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) -C `dirname $$f` $@; \
|
||||
$(MAKE) -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
|
||||
build-test-guests:
|
||||
$(MAKE) -C tests/guests check
|
||||
|
||||
check-with-appliance:
|
||||
@method=`$(top_builddir)/run ./fish/guestfish get-attach-method`; \
|
||||
if [ "$$method" != "appliance" ]; then \
|
||||
$(MAKE) LIBGUESTFS_ATTACH_METHOD=appliance check || exit $$?; \
|
||||
check-direct:
|
||||
@backend=`$(top_builddir)/run ./fish/guestfish get-backend`; \
|
||||
if [ "$$backend" != "direct" ]; then \
|
||||
$(MAKE) LIBGUESTFS_BACKEND=direct check || exit $$?; \
|
||||
fi
|
||||
|
||||
check-with-appliance: check-direct
|
||||
|
||||
check-valgrind-direct:
|
||||
@backend=`$(top_builddir)/run ./fish/guestfish get-backend`; \
|
||||
if [ "$$backend" != "direct" ]; then \
|
||||
$(MAKE) LIBGUESTFS_BACKEND=direct check-valgrind || exit $$?; \
|
||||
fi
|
||||
|
||||
check-valgrind-with-appliance: check-valgrind-direct
|
||||
|
||||
QEMUDIR = $(HOME)/d/qemu
|
||||
QEMUBINARY = $(QEMUDIR)/x86_64-softmmu/qemu-system-x86_64
|
||||
|
||||
check-with-upstream-qemu:
|
||||
@if $(QEMUBINARY) --help >/dev/null 2>&1; then \
|
||||
$(MAKE) check-with-upstream-qemu-1 || exit $$?; \
|
||||
fi
|
||||
rm -f $(top_builddir)/qemu-wrapper.sh
|
||||
$(MAKE) check-with-upstream-qemu-1 || exit $$?
|
||||
|
||||
check-with-upstream-qemu-1: $(top_builddir)/qemu-wrapper.sh
|
||||
$(QEMUBINARY) --version
|
||||
@@ -363,30 +391,61 @@ $(top_builddir)/qemu-wrapper.sh: Makefile
|
||||
LIBVIRTDIR = $(HOME)/d/libvirt
|
||||
|
||||
check-with-upstream-libvirt:
|
||||
@method=`$(top_builddir)/run ./fish/guestfish get-attach-method`; \
|
||||
if [ "$$method" = "libvirt" ] && [ -x "$(LIBVIRTDIR)/run" ]; then \
|
||||
@backend=`$(top_builddir)/run ./fish/guestfish get-backend`; \
|
||||
if [ "$$backend" = "libvirt" ] && [ -x "$(LIBVIRTDIR)/run" ]; then \
|
||||
$(LIBVIRTDIR)/run $(MAKE) check || exit $$?; \
|
||||
fi
|
||||
|
||||
check-slow: build-test-guests
|
||||
@errors=0; \
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) -C `dirname $$f` $@; \
|
||||
$(MAKE) -C `dirname $$f` $@ || (( errors++ )); \
|
||||
done; \
|
||||
exit $$(( $$errors ? 1 : 0 ))
|
||||
|
||||
build-test-guests:
|
||||
$(MAKE) -C tests/guests check
|
||||
|
||||
# Print subdirs.
|
||||
#
|
||||
# If you want to selectively run tests, or if the test suite fails half
|
||||
# way through, use:
|
||||
#
|
||||
# make print-subdirs
|
||||
#
|
||||
# to print the subdirectories, select the ones you want to run / the
|
||||
# remaining ones, and do:
|
||||
#
|
||||
# make check SUBDIRS="..."
|
||||
|
||||
print-subdirs:
|
||||
@echo $(SUBDIRS)
|
||||
|
||||
# Provide help on common Makefile targets.
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo "make Build everything."
|
||||
@echo "make Build everything."
|
||||
@echo
|
||||
@echo "make check Run the standard tests."
|
||||
@echo "make check-valgrind Run a subset of the tests under valgrind."
|
||||
@echo "make check-valgrind-local-guests Test under valgrind using local guests."
|
||||
@echo "make check-with-appliance Test using appliance attach-method."
|
||||
@echo "make check-with-upstream-qemu Test using upstream qemu."
|
||||
@echo "make check-with-upstream-libvirt Test using upstream libvirt."
|
||||
@echo "make check-slow Slow/long-running tests."
|
||||
@echo "make extra-tests Same as check-* (but not 'make check')"
|
||||
@echo "make syntax-check Check syntax and style problems in the code."
|
||||
@echo "make check Run the standard tests"
|
||||
@echo "make -k check ... and display all errors at once."
|
||||
@echo
|
||||
@echo "make install Install everything."
|
||||
@echo "make extra-tests Runs all of the following tests:"
|
||||
@echo " make check-valgrind Run a subset of the tests under valgrind."
|
||||
@echo " make check-valgrind-local-guests Test under valgrind using local guests."
|
||||
@echo " make check-direct Test using direct backend."
|
||||
@echo " make check-valgrind-direct Test valgrind + direct backend."
|
||||
@echo " make check-with-upstream-qemu Test using upstream qemu."
|
||||
@echo " make check-with-upstream-libvirt Test using upstream libvirt."
|
||||
@echo " make check-slow Slow/long-running tests."
|
||||
@echo
|
||||
@echo "make clean Clean everything."
|
||||
@echo "make syntax-check Check syntax and style problems in the code."
|
||||
@echo "make print-subdirs Print subdirectories."
|
||||
@echo
|
||||
@echo "make install Install everything."
|
||||
@echo
|
||||
@echo "make clean Clean everything."
|
||||
@echo
|
||||
@echo "To run programs without installing:"
|
||||
@echo " ./run ./fish/guestfish [or any other program]"
|
||||
|
||||
318
README
318
README
@@ -41,134 +41,188 @@ Debian/Ubuntu users:
|
||||
|
||||
The full requirements are described below.
|
||||
|
||||
For basic functionality and the C tools:
|
||||
|
||||
- look at appliance/packagelist.in and install as many of the packages
|
||||
that apply to your distro as possible
|
||||
|
||||
- QEMU >= 1.1.0.
|
||||
|
||||
- kernel >= 2.6.34 with virtio-serial support enabled.
|
||||
|
||||
- virtio-block and virtio-net drivers should be compiled into your
|
||||
host kernel (strictly speaking this is optional, but you will have
|
||||
to make complex changes to the ./configure command line to get it
|
||||
to work if you don't have virtio)
|
||||
|
||||
- febootstrap >= 3.20
|
||||
|
||||
Notes: (1) febootstrap 2.x WILL NOT WORK
|
||||
(2) febootstrap 3.x is distro-independent, and is required on
|
||||
Debian and other distros as well as Fedora
|
||||
(3) that is the minimum version, but later versions are better
|
||||
|
||||
- XDR, rpcgen (on Linux these are provided by glibc)
|
||||
|
||||
- cpio
|
||||
|
||||
- gperf
|
||||
|
||||
- pcre (Perl Compatible Regular Expressions C library)
|
||||
|
||||
- genisoimage (NOT mkisofs any more)
|
||||
|
||||
- hivex >= 1.2.7 (http://libguestfs.org/download) (optional)
|
||||
|
||||
- libmagic (the library that corresponds to the 'file' command) (optional)
|
||||
|
||||
- libvirt (optional, >= 0.10.2 to use the libvirt launch method)
|
||||
|
||||
- libxml2 (optional)
|
||||
|
||||
- libconfig (optional)
|
||||
|
||||
- augeas >= 0.5.0 (http://augeas.net/) (optional)
|
||||
|
||||
- Berkeley DB 'db_dump' and 'db_load' utilities
|
||||
(db4-utils or db4.X-util or similar) (optional)
|
||||
|
||||
- systemtap/DTrace userspace probes (optional)
|
||||
http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
|
||||
|
||||
- perl Pod::Man and Pod::Simple are required. These are used to
|
||||
generate man pages and other documentation. Every recent Perl
|
||||
distribution ought to include both.
|
||||
|
||||
- Readline to have nicer command-line editing in guestfish (optional)
|
||||
|
||||
- xmllint (part of libxml2) to validate virt-inspector
|
||||
RELAX NG schema (optional)
|
||||
|
||||
- OCaml compiler. Optional when compiling from the tarball, but
|
||||
mandatory if you compile from git.
|
||||
|
||||
- ocaml-gettext if you want to translate OCaml tools (optional)
|
||||
|
||||
- po4a for translating manpages and POD files.
|
||||
This is optional when compiling from the tarball, but mandatory
|
||||
if you compile from git.
|
||||
|
||||
- getfacl, getfattr libraries and programs (optional)
|
||||
|
||||
- Linux capabilities library (libcap) (optional)
|
||||
|
||||
- libldm and ldmtool (optional)
|
||||
This is used to handle Windows dynamic disks.
|
||||
|
||||
- yajl >= 2 (optional)
|
||||
JSON parser, needed to handle the output of ldmtool.
|
||||
|
||||
- netpbm, icoutils (optional)
|
||||
These programs are used to render icons from guests.
|
||||
|
||||
- Perl Expect module (optional)
|
||||
This is used to test virt-rescue.
|
||||
|
||||
To build FUSE support in the core library, and guestmount:
|
||||
|
||||
- FUSE libraries and kernel module (optional)
|
||||
|
||||
To build language bindings:
|
||||
|
||||
- OCaml compiler to build the OCaml bindings (optional, but see above)
|
||||
|
||||
- Perl if you want to build the perl bindings (optional)
|
||||
|
||||
- Python if you want to build the python bindings (optional)
|
||||
|
||||
- Ruby, rake if you want to build the ruby bindings (optional)
|
||||
|
||||
- Java, JNI, jpackage-utils if you want to build the java
|
||||
bindings (optional)
|
||||
|
||||
- GHC if you want to build the Haskell bindings (optional)
|
||||
|
||||
- PHP, phpize if you want to build the PHP bindings (optional)
|
||||
|
||||
To build the Perl tools:
|
||||
|
||||
- Perl Sys::Virt module (optional)
|
||||
|
||||
- Perl Win::Hivex module (optional)
|
||||
|
||||
- Perl Pod::Usage module (optional)
|
||||
|
||||
- Perl Test::More module (from perl Test::Simple) (optional)
|
||||
|
||||
- Perl String::ShellQuote module (optional)
|
||||
|
||||
- perl-libintl for translating perl code (optional)
|
||||
R = Required
|
||||
O = Optional
|
||||
+==============+=============+===+=========================================+
|
||||
| Package name | Min.version | | Notes |
|
||||
+==============+=============+===+=========================================+
|
||||
| Install as many packages listed in appliance/packagelist.in as possible. |
|
||||
| This installs the disk management tools required by the appliance. The |
|
||||
| list below is *additional* packages needed on the host. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| qemu | 1.2.0 | R | 1.1 may work, but has broken virtio-scsi|
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| qemu-img | | R | |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| kernel | 2.6.34 | R | Make sure the following are enabled |
|
||||
| | | | compiled in or as a module: |
|
||||
| | | | - virtio-pci |
|
||||
| | | | - virtio-serial |
|
||||
| | | | - virtio-block |
|
||||
| | | | - virtio-net |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| supermin | 4.1.0 | R | This is required on all distros. |
|
||||
| febootstrap | 3.20 | | 'supermin' is the new name for |
|
||||
| | | | 'febootstrap'. |
|
||||
| | | | For alternatives, see: |
|
||||
| | | | libguestfs.org/download/binaries/appliance/
|
||||
| | | | febootstrap 2.x WILL NOT WORK |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| glibc | | R | We use various glibc-isms. |
|
||||
| | | | Also glibc provides XDR, rpcgen. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| GCC or LLVM | | R | We use __attribute__((cleanup)). |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Perl | | R | Various build and test programs need |
|
||||
| | | | Perl. Not needed at runtime except if |
|
||||
| | | | you need to run a handful of virt-* |
|
||||
| | | | tools that are still written in Perl. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Pod::Man | | R | Part of Perl core. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Pod::Simple | | R | Part of Perl core. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| OCaml | |R/O| Required if compiling from git. |
|
||||
| | | | Optional if compiling from tarball. |
|
||||
| | | | To build generated files and OCaml bindings.
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| autotools | |R/O| Required if compiling from git. |
|
||||
| | | | Optional if compiling from tarball. |
|
||||
| | | | Autotools-based build system. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| cpio | | R | |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| gperf | | R | |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| PCRE | | R | Perl-compatible Regular Expression lib. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| genisoimage | | R | mkisofs may work. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libxml2 | | R | Popular XML library. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| po4a | |R/O| Required if compiling from git. |
|
||||
| | | | Optional if compiling from tarball. |
|
||||
| | | | For localizing man pages. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| hivex | 1.2.7 | O | Windows Registry hive parser. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libmagic | | O | The library used by the 'file' command. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libvirt | | O | >= 0.10.2 is needed if you want to use |
|
||||
| | | | libvirt to manage transient VMs. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| xmllint | | O | Part of libxml2. Used for tests only. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libconfig | | O | Used to parse libguestfs's own config |
|
||||
| | | | files eg. /etc/libguestfs-tools.conf. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libselinux | | O | Used by the libvirt backend to securely |
|
||||
| | | | confine the appliance (sVirt). |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| augeas | 0.5.0 | O | To inspect configuration of Linux guests.
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| db utils | | O | db_dump, db_load etc. Usually found in |
|
||||
| | | | a package called db-utils, db4-utils, |
|
||||
| | | | db4.X-utils, Berkeley DB utils, etc. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| systemtap | | O | For userspace probes. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| readline | | O | For nicer command line in guestfish. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| acl | | O | Library (libacl) and programs for |
|
||||
| | | | handling POSIX ACLs. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libcap | | O | Library (libcap) and programs for |
|
||||
| | | | handling Linux capabilities. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| libldm | | O | Library (libldm) and 'ldmtool' for |
|
||||
| | | | handling Windows Dynamic Disks. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| yajl | 2 | O | JSON parser for parsing output of |
|
||||
| | | | ldmtool and qemu-img info commands. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| gdisk | | O | GPT disk support. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| netpbm | | O | Render icons from guests. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| icoutils | | O | Render icons from Windows guests. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Expect | | O | Perl module used to test virt-rescue. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| FUSE | | O | fusermount, libfuse, and kernel module |
|
||||
| | | | are all needed if you want guestmount |
|
||||
| | | | and/or 'mount-local' support. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| static glibc | | O | Used for testing only. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| qemu-nbd | | O | Used for testing only. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| findlib | | O | For the OCaml bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| ocaml-gettext| | O | For localizing OCaml virt-* tools. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Python | 2.2 | O | For the Python bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Ruby | | O | >= 1.9 is better than 1.8. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| rake | | O | For the Ruby bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| rubygem-minitest | O | For the Ruby bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Java | 1.6 | O | Java + JNI + jpackage-utils are needed |
|
||||
| | | | for the Java bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| GHC | | O | For the Haskell bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| PHP | | O | For the PHP bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| phpize | | O | For the PHP bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| glib2 | | O | For the GObject bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| gobject-introspection | O | For the GObject bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| gjs | | O | For testing the GObject bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| LUA | | O | For the LUA bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Erlang | | O | For the Erlang bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| erl_interface| | O | For the Erlang bindings. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| valgrind | | O | For testing for memory problems. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Sys::Virt | | O | Perl bindings for libvirt. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Win::Hivex | | O | Perl bindings for hivex. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Pod::Usage | | O | Perl module used by tests. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| Test::More | | O | Perl module used by tests. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| String::Shellquote | O | Perl module used by some virt-* tools. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| XML::XPath | | O | Perl module used by some virt-* tools. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| XML::XPath::XMLParser | O | Perl module used by some virt-* tools. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| perl-libintl | | O | Perl module for localization. |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| bash-completion | O | For tab-completion of commands in bash. |
|
||||
+==============+=============+===+=========================================+
|
||||
R = Required
|
||||
O = Optional
|
||||
|
||||
|
||||
Building
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Then make the daemon, library and root filesystem:
|
||||
Build the daemon, library and root filesystem:
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
Finally run the tests:
|
||||
Run the tests:
|
||||
|
||||
make check
|
||||
|
||||
@@ -186,11 +240,20 @@ some libvirt guests installed, that these guests' disks are accessible
|
||||
by the current user, and these tests may fail for other reasons which
|
||||
are not necessarily because of real problems.
|
||||
|
||||
If everything works, you can install the library and tools by running
|
||||
this command as root:
|
||||
make help
|
||||
|
||||
lists all 'make' targets.
|
||||
|
||||
You may install the library by running the following command as root.
|
||||
However *most users should probably not do this*. Instead, './run'
|
||||
the programs from the build directory as described below.
|
||||
|
||||
make install
|
||||
|
||||
Distro packagers should use this instead:
|
||||
|
||||
make INSTALLDIRS=vendor [DESTDIR=...] install
|
||||
|
||||
You can run guestfish, guestmount and the virt tools without needing
|
||||
to install, using the "./run" script in the top directory. This
|
||||
script sets up some environment variables. For example:
|
||||
@@ -204,8 +267,7 @@ command will also work:
|
||||
|
||||
../run ./guestfish [...]
|
||||
|
||||
You can also make a symlink (note: NOT a hard link) from your $PATH to
|
||||
the run script, eg:
|
||||
You can also make a link from your $PATH to the run script, eg:
|
||||
|
||||
cd ~/bin
|
||||
ln -s ~/libguestfs/run libguestfs-run
|
||||
@@ -289,7 +351,7 @@ distributions. Non-Linux ports are trickier, but we will accept
|
||||
patches if they aren't too invasive.
|
||||
|
||||
The main porting issues are with the dependencies needed to build the
|
||||
appliance. You will need to port the febootstrap first
|
||||
appliance. You will need to port febootstrap first
|
||||
(http://people.redhat.com/~rjones/febootstrap/).
|
||||
|
||||
|
||||
@@ -324,11 +386,11 @@ For example:
|
||||
--with-qemu-options="-M versatilepb -cpu arm926"
|
||||
./configure \
|
||||
--with-qemu="qemu-system-arm" \
|
||||
--with-qemu-options="-M vexpress-a9 -cpu cortex-a9"
|
||||
--with-qemu-options="-M vexpress-a15 -cpu cortex-a15"
|
||||
|
||||
Note that since virtio is required by libguestfs, and virtio is a
|
||||
PCI-based architecture, whatever architecture qemu emulates must
|
||||
support PCI also.
|
||||
PCI-based architecture, whatever architecture qemu emulates MUST
|
||||
support PCI.
|
||||
|
||||
For PPC64 you will need to specify the IBM pSeries machine type:
|
||||
|
||||
@@ -343,7 +405,7 @@ attention to the qemu command line and kernel output.
|
||||
Copyright and license information
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
Copyright (C) 2009-2013 Red Hat Inc.
|
||||
|
||||
The library is distributed under the LGPLv2+. The programs are
|
||||
distributed under the GPLv2+. Please see the files COPYING and
|
||||
|
||||
16
TODO
16
TODO
@@ -361,14 +361,14 @@ Interactive disk creator
|
||||
|
||||
An interactive disk creator program.
|
||||
|
||||
Attach method for disconnected operation
|
||||
----------------------------------------
|
||||
Backend for disconnected operation
|
||||
----------------------------------
|
||||
|
||||
http://libguestfs.org/guestfs.3.html#guestfs_set_attach_method
|
||||
http://libguestfs.org/guestfs.3.html#guestfs_set_backend
|
||||
|
||||
"Librarian" has an idea that he should be able to attach to a regular
|
||||
appliance, but disconnect from it and reconnect to it later. This
|
||||
would be some sort of modified attach method (see link above).
|
||||
would be some sort of modified backend (see link above).
|
||||
|
||||
The complexity here is that we would no longer have access to
|
||||
stdin/stdout (or we'd have to direct that somewhere else).
|
||||
@@ -427,7 +427,7 @@ Launch remote sessions over ssh
|
||||
-------------------------------
|
||||
|
||||
We had an idea you could add a launch method that uses ssh, ie. all
|
||||
febootstrap and qemu commands happen the same as now, but prefixed by
|
||||
supermin and qemu commands happen the same as now, but prefixed by
|
||||
ssh so it happens on a remote machine.
|
||||
|
||||
Note that proper remote support and integration with libvirt is
|
||||
@@ -490,7 +490,7 @@ Optimize the appliance
|
||||
|
||||
Pass -cpu host. Anything else?
|
||||
|
||||
[The libvirt attach-method uses 'host-model' which is basically
|
||||
[The libvirt backend uses 'host-model' which is basically
|
||||
the same as this]
|
||||
|
||||
Sort out partitioning
|
||||
@@ -534,8 +534,8 @@ as data is reliably written out when g.sync, g.shutdown or g.close
|
||||
return. Also in libguestfs we effectively control the whole stack, so
|
||||
we can ensure write barriers happen when we want.
|
||||
|
||||
libvirt attach-method
|
||||
---------------------
|
||||
libvirt backend
|
||||
---------------
|
||||
|
||||
Since libguestfs 1.19.24 this mostly works. Here are some suggested
|
||||
items to work on:
|
||||
|
||||
@@ -19,6 +19,7 @@ include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-virt-alignment-scan.sh \
|
||||
test-virt-alignment-scan-guests.sh \
|
||||
virt-alignment-scan.pod
|
||||
|
||||
CLEANFILES = stamp-virt-alignment-scan.pod
|
||||
@@ -26,6 +27,12 @@ CLEANFILES = stamp-virt-alignment-scan.pod
|
||||
bin_PROGRAMS = virt-alignment-scan
|
||||
|
||||
SHARED_SOURCE_FILES = \
|
||||
../df/domains.c \
|
||||
../df/domains.h \
|
||||
../df/estimate-max-threads.c \
|
||||
../df/estimate-max-threads.h \
|
||||
../df/parallel.c \
|
||||
../df/parallel.h \
|
||||
../fish/config.c \
|
||||
../fish/domain.c \
|
||||
../fish/inspect.c \
|
||||
@@ -35,26 +42,32 @@ SHARED_SOURCE_FILES = \
|
||||
|
||||
virt_alignment_scan_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
domains.c \
|
||||
scan.c \
|
||||
scan.h
|
||||
scan.c
|
||||
|
||||
virt_alignment_scan_CFLAGS = \
|
||||
virt_alignment_scan_CPPFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
-DGUESTFS_PRIVATE=1 \
|
||||
-I$(top_srcdir)/src -I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/df \
|
||||
-I$(top_srcdir)/fish \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\"
|
||||
|
||||
virt_alignment_scan_CFLAGS = \
|
||||
-pthread \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(GPROF_CFLAGS) $(GCOV_CFLAGS) \
|
||||
$(LIBCONFIG_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS) \
|
||||
$(LIBVIRT_CFLAGS)
|
||||
|
||||
virt_alignment_scan_LDADD = \
|
||||
$(LIBCONFIG_LIBS) \
|
||||
$(top_builddir)/src/libutils.la \
|
||||
$(top_builddir)/src/libguestfs.la \
|
||||
../gnulib/lib/libgnu.la \
|
||||
$(LIBXML2_LIBS) \
|
||||
$(LIBVIRT_LIBS) \
|
||||
../gnulib/lib/libgnu.la \
|
||||
-lm
|
||||
|
||||
# Manual pages and HTML files for the website.
|
||||
@@ -79,7 +92,8 @@ TESTS =
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS += \
|
||||
test-virt-alignment-scan.sh
|
||||
test-virt-alignment-scan.sh \
|
||||
test-virt-alignment-scan-guests.sh
|
||||
endif
|
||||
|
||||
check-valgrind:
|
||||
|
||||
359
align/domains.c
359
align/domains.c
@@ -1,359 +0,0 @@
|
||||
/* virt-alignment-scan
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
#include <libvirt/libvirt.h>
|
||||
#include <libvirt/virterror.h>
|
||||
#endif
|
||||
|
||||
#include "progname.h"
|
||||
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
#define GUESTFS_PRIVATE_FOR_EACH_DISK 1
|
||||
#endif
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
#include "scan.h"
|
||||
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
|
||||
/* The list of domains and disks that we build up in
|
||||
* get_domains_from_libvirt.
|
||||
*/
|
||||
struct disk {
|
||||
struct disk *next;
|
||||
char *filename;
|
||||
char *format; /* could be NULL */
|
||||
};
|
||||
|
||||
struct domain {
|
||||
char *name;
|
||||
char *uuid;
|
||||
struct disk *disks;
|
||||
size_t nr_disks;
|
||||
};
|
||||
|
||||
struct domain *domains = NULL;
|
||||
size_t nr_domains;
|
||||
|
||||
static int
|
||||
compare_domain_names (const void *p1, const void *p2)
|
||||
{
|
||||
const struct domain *d1 = p1;
|
||||
const struct domain *d2 = p2;
|
||||
|
||||
return strcmp (d1->name, d2->name);
|
||||
}
|
||||
|
||||
static void
|
||||
free_domain (struct domain *domain)
|
||||
{
|
||||
struct disk *disk, *next;
|
||||
|
||||
for (disk = domain->disks; disk; disk = next) {
|
||||
next = disk->next;
|
||||
free (disk->filename);
|
||||
free (disk->format);
|
||||
free (disk);
|
||||
}
|
||||
|
||||
free (domain->name);
|
||||
free (domain->uuid);
|
||||
}
|
||||
|
||||
static void add_domains_by_id (virConnectPtr conn, int *ids, size_t n);
|
||||
static void add_domains_by_name (virConnectPtr conn, char **names, size_t n);
|
||||
static void add_domain (virDomainPtr dom);
|
||||
static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *domain_vp);
|
||||
static size_t add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r);
|
||||
static void reset_guestfs_handle (void);
|
||||
|
||||
void
|
||||
get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
{
|
||||
virErrorPtr err;
|
||||
virConnectPtr conn;
|
||||
int n;
|
||||
size_t i, count, errors;
|
||||
const char *prefix;
|
||||
|
||||
nr_domains = 0;
|
||||
domains = NULL;
|
||||
|
||||
/* Get the list of all domains. */
|
||||
conn = virConnectOpenReadOnly (libvirt_uri);
|
||||
if (!conn) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n = virConnectNumOfDomains (conn);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of running domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int ids[n];
|
||||
n = virConnectListDomains (conn, ids, n);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list running domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
add_domains_by_id (conn, ids, n);
|
||||
|
||||
n = virConnectNumOfDefinedDomains (conn);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of inactive domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *names[n];
|
||||
n = virConnectListDefinedDomains (conn, names, n);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list inactive domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
add_domains_by_name (conn, names, n);
|
||||
|
||||
/* You must free these even though the libvirt documentation doesn't
|
||||
* mention it.
|
||||
*/
|
||||
for (i = 0; i < (size_t) n; ++i)
|
||||
free (names[i]);
|
||||
|
||||
virConnectClose (conn);
|
||||
|
||||
/* No domains? */
|
||||
if (nr_domains == 0)
|
||||
return;
|
||||
|
||||
/* Sort the domains alphabetically by name for display. */
|
||||
qsort (domains, nr_domains, sizeof (struct domain), compare_domain_names);
|
||||
|
||||
errors = 0;
|
||||
for (i = 0; i < nr_domains; ++i) {
|
||||
if (domains[i].disks == NULL)
|
||||
continue;
|
||||
|
||||
count = add_disks_to_handle_reverse (domains[i].disks, &errors);
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
if (guestfs_launch (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
prefix = !uuid ? domains[i].name : domains[i].uuid;
|
||||
|
||||
/* Perform the scan. */
|
||||
scan (worst_alignment_ptr, prefix);
|
||||
|
||||
if (i < nr_domains - 1)
|
||||
reset_guestfs_handle ();
|
||||
}
|
||||
|
||||
/* Free up domains structure. */
|
||||
for (i = 0; i < nr_domains; ++i)
|
||||
free_domain (&domains[i]);
|
||||
free (domains);
|
||||
|
||||
if (errors > 0) {
|
||||
fprintf (stderr, _("%s: failed to analyze a disk, see error(s) above\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domains_by_id (virConnectPtr conn, int *ids, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ids[i] != 0) { /* RHBZ#538041 */
|
||||
dom = virDomainLookupByID (conn, ids[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domains_by_name (virConnectPtr conn, char **names, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
dom = virDomainLookupByName (conn, names[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domain (virDomainPtr dom)
|
||||
{
|
||||
struct domain *domain;
|
||||
|
||||
domains = realloc (domains, (nr_domains + 1) * sizeof (struct domain));
|
||||
if (domains == NULL) {
|
||||
perror ("realloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
domain = &domains[nr_domains];
|
||||
nr_domains++;
|
||||
|
||||
domain->name = strdup (virDomainGetName (dom));
|
||||
if (domain->name == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char uuid[VIR_UUID_STRING_BUFLEN];
|
||||
if (virDomainGetUUIDString (dom, uuid) == 0) {
|
||||
domain->uuid = strdup (uuid);
|
||||
if (domain->uuid == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
domain->uuid = NULL;
|
||||
|
||||
domain->disks = NULL;
|
||||
int n = guestfs___for_each_disk (g, dom, add_disk, domain);
|
||||
if (n == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
domain->nr_disks = n;
|
||||
}
|
||||
|
||||
static int
|
||||
add_disk (guestfs_h *g,
|
||||
const char *filename, const char *format, int readonly,
|
||||
void *domain_vp)
|
||||
{
|
||||
struct domain *domain = domain_vp;
|
||||
struct disk *disk;
|
||||
|
||||
disk = malloc (sizeof *disk);
|
||||
if (disk == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
disk->next = domain->disks;
|
||||
domain->disks = disk;
|
||||
|
||||
disk->filename = strdup (filename);
|
||||
if (disk->filename == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
if (format) {
|
||||
disk->format = strdup (format);
|
||||
if (disk->format == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
disk->format = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r)
|
||||
{
|
||||
size_t nr_disks_added;
|
||||
|
||||
if (disk == NULL)
|
||||
return 0;
|
||||
|
||||
nr_disks_added = add_disks_to_handle_reverse (disk->next, errors_r);
|
||||
|
||||
struct guestfs_add_drive_opts_argv optargs = { .bitmask = 0 };
|
||||
|
||||
optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
|
||||
optargs.readonly = 1;
|
||||
|
||||
if (disk->format) {
|
||||
optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
|
||||
optargs.format = disk->format;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive_opts_argv (g, disk->filename, &optargs) == -1) {
|
||||
(*errors_r)++;
|
||||
return nr_disks_added;
|
||||
}
|
||||
|
||||
return nr_disks_added+1;
|
||||
}
|
||||
|
||||
/* Close and reopen the libguestfs handle. */
|
||||
static void
|
||||
reset_guestfs_handle (void)
|
||||
{
|
||||
/* Copy the settings from the old handle. */
|
||||
int verbose = guestfs_get_verbose (g);
|
||||
int trace = guestfs_get_trace (g);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
g = guestfs_create ();
|
||||
if (g == NULL) {
|
||||
fprintf (stderr, _("guestfs_create: failed to create handle\n"));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
guestfs_set_verbose (g, verbose);
|
||||
guestfs_set_trace (g, trace);
|
||||
}
|
||||
|
||||
#endif
|
||||
160
align/scan.c
160
align/scan.c
@@ -25,20 +25,32 @@
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <assert.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
#include <libvirt/libvirt.h>
|
||||
#include <libvirt/virterror.h>
|
||||
#endif
|
||||
|
||||
#include "progname.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
#include "scan.h"
|
||||
#include "parallel.h"
|
||||
#include "domains.h"
|
||||
|
||||
/* This just needs to be larger than any alignment we care about. */
|
||||
static size_t worst_alignment = UINT_MAX;
|
||||
static pthread_mutex_t worst_alignment_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int scan (guestfs_h *g, const char *prefix, FILE *fp);
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
static int scan_work (guestfs_h *g, size_t i, FILE *fp);
|
||||
#endif
|
||||
|
||||
/* These globals are shared with options.c. */
|
||||
guestfs_h *g;
|
||||
@@ -52,12 +64,7 @@ const char *libvirt_uri = NULL;
|
||||
int inspector = 0;
|
||||
|
||||
static int quiet = 0; /* --quiet */
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
return (char *) s;
|
||||
}
|
||||
static int uuid = 0; /* --uuid */
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
usage (int status)
|
||||
@@ -78,6 +85,7 @@ usage (int status)
|
||||
" -d|--domain guest Add disks from libvirt guest\n"
|
||||
" --format[=raw|..] Force disk format for -a option\n"
|
||||
" --help Display brief help\n"
|
||||
" -P nr_threads Use at most nr_threads\n"
|
||||
" -q|--quiet No output, just exit code\n"
|
||||
" -v|--verbose Verbose messages\n"
|
||||
" -V|--version Display version and exit\n"
|
||||
@@ -92,22 +100,20 @@ usage (int status)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
/* Set global program name that is not polluted with libtool artifacts. */
|
||||
set_program_name (argv[0]);
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
enum { HELP_OPTION = CHAR_MAX + 1 };
|
||||
|
||||
static const char *options = "a:c:d:qvVx";
|
||||
static const char *options = "a:c:d:P:qvVx";
|
||||
static const struct option long_options[] = {
|
||||
{ "add", 1, 0, 'a' },
|
||||
{ "connect", 1, 0, 'c' },
|
||||
{ "domain", 1, 0, 'd' },
|
||||
{ "format", 2, 0, 0 },
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "long-options", 0, 0, 0 },
|
||||
{ "quiet", 0, 0, 'q' },
|
||||
{ "uuid", 0, 0, 0, },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
@@ -119,10 +125,9 @@ main (int argc, char *argv[])
|
||||
const char *format = NULL;
|
||||
int c;
|
||||
int option_index;
|
||||
int uuid = 0;
|
||||
/* This just needs to be larger than any alignment we care about. */
|
||||
size_t worst_alignment = UINT_MAX;
|
||||
int exit_code;
|
||||
size_t max_threads = 0;
|
||||
int r;
|
||||
|
||||
g = guestfs_create ();
|
||||
if (g == NULL) {
|
||||
@@ -130,15 +135,15 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argv[0] = bad_cast (program_name);
|
||||
|
||||
for (;;) {
|
||||
c = getopt_long (argc, argv, options, long_options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 0: /* options which are long only */
|
||||
if (STREQ (long_options[option_index].name, "format")) {
|
||||
if (STREQ (long_options[option_index].name, "long-options"))
|
||||
display_long_options (long_options);
|
||||
else if (STREQ (long_options[option_index].name, "format")) {
|
||||
if (!optarg || STREQ (optarg, ""))
|
||||
format = NULL;
|
||||
else
|
||||
@@ -164,6 +169,13 @@ main (int argc, char *argv[])
|
||||
OPTION_d;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
if (sscanf (optarg, "%zu", &max_threads) != 1) {
|
||||
fprintf (stderr, _("%s: -P option is not numeric\n"), program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
@@ -200,16 +212,25 @@ main (int argc, char *argv[])
|
||||
if (optind != argc)
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
/* The user didn't specify any drives to scan. */
|
||||
/* virt-alignment-scan has two modes. If the user didn't specify
|
||||
* any drives, then we do the scan on every libvirt guest. That's
|
||||
* the if-clause below. If the user specified domains/drives, then
|
||||
* we assume they belong to a single guest. That's the else-clause
|
||||
* below.
|
||||
*/
|
||||
if (drvs == NULL) {
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
get_domains_from_libvirt (uuid, &worst_alignment);
|
||||
#if defined(HAVE_LIBVIRT)
|
||||
get_all_libvirt_domains (libvirt_uri);
|
||||
r = start_threads (max_threads, g, scan_work);
|
||||
free_domains ();
|
||||
if (r == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
#else
|
||||
fprintf (stderr, _("%s: compiled without support for libvirt and/or libxml2.\n"),
|
||||
fprintf (stderr, _("%s: compiled without support for libvirt.\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
#endif
|
||||
} else {
|
||||
} else { /* Single guest. */
|
||||
if (uuid) {
|
||||
fprintf (stderr, _("%s: --uuid option cannot be used with -a or -d\n"),
|
||||
program_name);
|
||||
@@ -226,9 +247,12 @@ main (int argc, char *argv[])
|
||||
free_drives (drvs);
|
||||
|
||||
/* Perform the scan. */
|
||||
scan (&worst_alignment, NULL);
|
||||
r = scan (g, NULL, stdout);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
if (r == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Decide on an appropriate exit code. */
|
||||
@@ -242,30 +266,30 @@ main (int argc, char *argv[])
|
||||
exit (exit_code);
|
||||
}
|
||||
|
||||
void
|
||||
scan (size_t *worst_alignment, const char *prefix)
|
||||
static int
|
||||
scan (guestfs_h *g, const char *prefix, FILE *fp)
|
||||
{
|
||||
char **devices, *p;
|
||||
size_t i, j;
|
||||
size_t alignment;
|
||||
uint64_t start;
|
||||
struct guestfs_partition_list *parts;
|
||||
int err;
|
||||
|
||||
devices = guestfs_list_devices (g);
|
||||
CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g);
|
||||
if (devices == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
return -1;
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
parts = guestfs_part_list (g, devices[i]);
|
||||
CLEANUP_FREE char *name = NULL;
|
||||
|
||||
CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *parts =
|
||||
guestfs_part_list (g, devices[i]);
|
||||
if (parts == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
return -1;
|
||||
|
||||
/* Canonicalize the name of the device for printing. */
|
||||
p = guestfs_canonical_device_name (g, devices[i]);
|
||||
if (p == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
free (devices[i]);
|
||||
devices[i] = p;
|
||||
name = guestfs_canonical_device_name (g, devices[i]);
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
|
||||
for (j = 0; j < parts->len; ++j) {
|
||||
/* Start offset of the partition in bytes. */
|
||||
@@ -273,10 +297,10 @@ scan (size_t *worst_alignment, const char *prefix)
|
||||
|
||||
if (!quiet) {
|
||||
if (prefix)
|
||||
printf ("%s:", prefix);
|
||||
fprintf (fp, "%s:", prefix);
|
||||
|
||||
printf ("%s%d %12" PRIu64 " ",
|
||||
devices[i], (int) parts->val[j].part_num, start);
|
||||
fprintf (fp, "%s%d %12" PRIu64 " ",
|
||||
name, (int) parts->val[j].part_num, start);
|
||||
}
|
||||
|
||||
/* What's the alignment? */
|
||||
@@ -288,30 +312,60 @@ scan (size_t *worst_alignment, const char *prefix)
|
||||
|
||||
if (!quiet) {
|
||||
if (alignment < 10)
|
||||
printf ("%12" PRIu64 " ", UINT64_C(1) << alignment);
|
||||
fprintf (fp, "%12" PRIu64 " ", UINT64_C(1) << alignment);
|
||||
else if (alignment < 64)
|
||||
printf ("%12" PRIu64 "K ", UINT64_C(1) << (alignment - 10));
|
||||
fprintf (fp, "%12" PRIu64 "K ", UINT64_C(1) << (alignment - 10));
|
||||
else
|
||||
printf ("- ");
|
||||
fprintf (fp, "- ");
|
||||
}
|
||||
|
||||
if (alignment < *worst_alignment)
|
||||
*worst_alignment = alignment;
|
||||
err = pthread_mutex_lock (&worst_alignment_mutex);
|
||||
assert (err == 0);
|
||||
if (alignment < worst_alignment)
|
||||
worst_alignment = alignment;
|
||||
err = pthread_mutex_unlock (&worst_alignment_mutex);
|
||||
assert (err == 0);
|
||||
|
||||
if (alignment < 12) { /* Bad in general: < 4K alignment */
|
||||
if (!quiet)
|
||||
printf ("bad (%s)\n", _("alignment < 4K"));
|
||||
fprintf (fp, "bad (%s)\n", _("alignment < 4K"));
|
||||
} else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */
|
||||
if (!quiet)
|
||||
printf ("bad (%s)\n", _("alignment < 64K"));
|
||||
fprintf (fp, "bad (%s)\n", _("alignment < 64K"));
|
||||
} else {
|
||||
if (!quiet)
|
||||
printf ("ok\n");
|
||||
fprintf (fp, "ok\n");
|
||||
}
|
||||
}
|
||||
|
||||
guestfs_free_partition_list (parts);
|
||||
free (devices[i]);
|
||||
}
|
||||
free (devices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LIBVIRT)
|
||||
|
||||
/* The multi-threaded version. This callback is called from the code
|
||||
* in "parallel.c".
|
||||
*/
|
||||
|
||||
static int
|
||||
scan_work (guestfs_h *g, size_t i, FILE *fp)
|
||||
{
|
||||
struct guestfs___add_libvirt_dom_argv optargs;
|
||||
|
||||
optargs.bitmask =
|
||||
GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK |
|
||||
GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK;
|
||||
optargs.readonly = 1;
|
||||
optargs.readonlydisk = "read";
|
||||
|
||||
if (guestfs___add_libvirt_dom (g, domains[i].dom, &optargs) == -1)
|
||||
return -1;
|
||||
|
||||
if (guestfs_launch (g) == -1)
|
||||
return -1;
|
||||
|
||||
return scan (g, !uuid ? domains[i].name : domains[i].uuid, fp);
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBVIRT */
|
||||
|
||||
35
align/test-virt-alignment-scan-guests.sh
Executable file
35
align/test-virt-alignment-scan-guests.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
export LANG=C
|
||||
|
||||
if [ -n "$SKIP_TEST_VIRT_ALIGNMENT_SCAN_GUESTS_SH" ]; then
|
||||
echo "$0: skipping test because SKIP_TEST_VIRT_ALIGNMENT_SCAN_GUESTS_SH is set."
|
||||
exit 77
|
||||
fi
|
||||
|
||||
guestsdir="$(cd ../tests/guests && pwd)"
|
||||
libvirt_uri="test://$guestsdir/guests-all-good.xml"
|
||||
|
||||
$VG ./virt-alignment-scan -c "$libvirt_uri"
|
||||
r=$?
|
||||
|
||||
# 0, 2 and 3 are reasonable non-error exit codes. Others are errors.
|
||||
if [ $r -ne 0 -a $r -ne 2 -a $r -ne 3 ]; then
|
||||
exit $r
|
||||
fi
|
||||
@@ -16,6 +16,8 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
export LANG=C
|
||||
|
||||
$VG ./virt-alignment-scan -a ../tests/guests/fedora.img
|
||||
r=$?
|
||||
|
||||
|
||||
@@ -117,6 +117,12 @@ Add I<file> which should be a disk image from a virtual machine.
|
||||
The format of the disk image is auto-detected. To override this and
|
||||
force a particular format use the I<--format=..> option.
|
||||
|
||||
=item B<-a URI>
|
||||
|
||||
=item B<--add URI>
|
||||
|
||||
Add a remote disk. See L<guestfish(1)/ADDING REMOTE STORAGE>.
|
||||
|
||||
=item B<-c> URI
|
||||
|
||||
=item B<--connect> URI
|
||||
@@ -158,6 +164,18 @@ If you have untrusted raw-format guest disk images, you should use
|
||||
this option to specify the disk format. This avoids a possible
|
||||
security problem with malicious guests (CVE-2010-3851).
|
||||
|
||||
=item B<-P> nr_threads
|
||||
|
||||
Since libguestfs 1.22, virt-alignment-scan is multithreaded and
|
||||
examines guests in parallel. By default the number of threads to use
|
||||
is chosen based on the amount of free memory available at the time
|
||||
that virt-alignment-scan is started. You can force
|
||||
virt-alignment-scan to use at most C<nr_threads> by using the I<-P>
|
||||
option.
|
||||
|
||||
Note that I<-P 0> means to autodetect, and I<-P 1> means to use a
|
||||
single thread.
|
||||
|
||||
=item B<-q>
|
||||
|
||||
=item B<--quiet>
|
||||
|
||||
@@ -35,15 +35,23 @@ superminfsdir = $(libdir)/guestfs/supermin.d
|
||||
|
||||
fs_DATA =
|
||||
superminfs_DATA = \
|
||||
supermin.d/base.img \
|
||||
supermin.d/daemon.img \
|
||||
supermin.d/init.img \
|
||||
supermin.d/hostfiles \
|
||||
supermin.d/udev-rules.img
|
||||
|
||||
# This used to be a configure-generated file (as is update.sh still).
|
||||
# However config.status always touches the destination file, which
|
||||
# means the appliance got rebuilt too often.
|
||||
if ENABLE_DAEMON
|
||||
superminfs_DATA += \
|
||||
supermin.d/daemon.img
|
||||
endif
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
superminfs_DATA += \
|
||||
supermin.d/base.img \
|
||||
supermin.d/hostfiles
|
||||
endif
|
||||
|
||||
# This used to be a configure-generated file. However config.status
|
||||
# always touches the destination file, which means the appliance got
|
||||
# rebuilt too often.
|
||||
make.sh: make.sh.in $(top_builddir)/config.log $(top_builddir)/config.status
|
||||
cd $(top_builddir) && \
|
||||
./config.status --file=appliance/$@-t:appliance/$<
|
||||
@@ -51,7 +59,7 @@ make.sh: make.sh.in $(top_builddir)/config.log $(top_builddir)/config.status
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
PACKAGELIST_CPP_FLAGS = -D$(DISTRO)=1
|
||||
PACKAGELIST_CPP_FLAGS = -D$(DISTRO)=1 -DEXTRA_PACKAGES="$(EXTRA_PACKAGES)"
|
||||
if VALGRIND_DAEMON
|
||||
PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1
|
||||
endif
|
||||
@@ -100,7 +108,7 @@ supermin.d/udev-rules.img: 99-guestfs-serial.rules
|
||||
rm -f $@ $@-t
|
||||
rm -rf tmp-u
|
||||
mkdir -p tmp-u/etc/udev/rules.d
|
||||
for f in $^; do ln $$f tmp-u/etc/udev/rules.d/$$f; done
|
||||
for f in $^; do ln $$f tmp-u/etc/udev/rules.d/$$(basename $$f); done
|
||||
( cd tmp-u && find | cpio --quiet -o -H newc ) > $@-t
|
||||
rm -rf tmp-u
|
||||
mv $@-t $@
|
||||
|
||||
@@ -10,6 +10,16 @@ RUNLEVEL=S
|
||||
PREVLEVEL=N
|
||||
export RUNLEVEL PREVLEVEL
|
||||
|
||||
# Try to print a stack trace for segfaults inside the appliance.
|
||||
for d in /lib64 /lib; do
|
||||
f=$d/libSegFault.so
|
||||
if [ -f "$f" ]; then
|
||||
LD_PRELOAD=$f
|
||||
export LD_PRELOAD
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
mkdir -p /sysroot
|
||||
|
||||
if [ ! -d /proc ]; then rm -f /proc; fi
|
||||
@@ -18,6 +28,9 @@ mount -t proc /proc /proc
|
||||
if [ ! -d /sys ]; then rm -f /sys; fi
|
||||
mkdir -p /sys
|
||||
mount -t sysfs /sys /sys
|
||||
# taken from initramfs-tools/init --Hilko Bengen
|
||||
mkdir -p /run
|
||||
mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run
|
||||
mkdir -p /run/lock
|
||||
|
||||
# devtmpfs is required since udev 176
|
||||
|
||||
@@ -15,11 +15,33 @@ libguestfs-make-fixed-appliance - Make a "fixed appliance" for libguestfs
|
||||
libguestfs-make-fixed-appliance lets you make a pre-built binary
|
||||
appliance for libguestfs.
|
||||
|
||||
B<Note that ordinary users should not need to run this tool>. The
|
||||
only reason to use it is if you want to make a self-contained
|
||||
libguestfs appliance that can be copied to another machine or platform
|
||||
that doesn't support L<febootstrap(8)>. To understand why you might
|
||||
need to use this tool, read the section L</FIXED APPLIANCE> below.
|
||||
B<Note that ordinary users should not need to run this tool>.
|
||||
|
||||
Some reasons why you I<might> want to use this include:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
You want to make a self-contained libguestfs appliance that can be
|
||||
copied to another machine or platform that doesn't support
|
||||
L<supermin(8)>.
|
||||
|
||||
=item *
|
||||
|
||||
You have multiple users on the same machine and want to avoid the
|
||||
storage duplication and start-up overhead of having multiple cached
|
||||
copies of the appliance.
|
||||
|
||||
=item *
|
||||
|
||||
You want to have very predictable performance from libguestfs (see
|
||||
L<guestfs-performance(1)>).
|
||||
|
||||
=back
|
||||
|
||||
For deeper understanding of why you might need this tool, read the
|
||||
section L</FIXED APPLIANCE> below.
|
||||
|
||||
Instead of running this tool, you can download fixed appliances from
|
||||
L<http://libguestfs.org/download/binaries/appliance/>. These
|
||||
@@ -107,21 +129,21 @@ looking for an appliance. The path is built into libguestfs, or can
|
||||
be set using the C<LIBGUESTFS_PATH> environment variable.
|
||||
|
||||
Normally a supermin appliance is located on this path (see
|
||||
L<febootstrap(8)/SUPERMIN APPLIANCE>). libguestfs reconstructs this
|
||||
into a full appliance by running L<febootstrap-supermin-helper(8)>.
|
||||
L<supermin(8)/SUPERMIN APPLIANCE>). libguestfs reconstructs this
|
||||
into a full appliance by running L<supermin-helper(8)>.
|
||||
|
||||
However, a simpler "fixed appliance" can also be used. libguestfs
|
||||
detects this by looking for a directory on the path containing four
|
||||
files called C<kernel>, C<initrd>, C<root> and C<README.fixed> (note
|
||||
the C<README.fixed> file must be present as well).
|
||||
|
||||
If the fixed appliance is found, libguestfs skips febootstrap entirely
|
||||
If the fixed appliance is found, libguestfs skips supermin entirely
|
||||
and just runs qemu with the kernel, initrd and root disk from the
|
||||
fixed appliance.
|
||||
|
||||
Thus the fixed appliance can be used when a platform or Linux distro
|
||||
does not support febootstrap. You build the fixed appliance on a
|
||||
platform that does support febootstrap, and copy it over, and use that
|
||||
does not support supermin. You build the fixed appliance on a
|
||||
platform that does support supermin, and copy it over, and use that
|
||||
to run libguestfs.
|
||||
|
||||
=head1 LICENSING
|
||||
@@ -144,8 +166,8 @@ libguestfs, please see the L<guestfs(3)> manual page.
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfs(3)>,
|
||||
L<febootstrap(8)>,
|
||||
L<febootstrap-supermin-helper(8)>,
|
||||
L<supermin(8)>,
|
||||
L<supermin-helper(8)>,
|
||||
L<xz(1)>,
|
||||
L<http://libguestfs.org/>,
|
||||
L<http://qemu.org/>.
|
||||
@@ -156,4 +178,4 @@ Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
Copyright (C) 2009-2013 Red Hat Inc.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -27,13 +27,18 @@ while read regexp <&5; do
|
||||
done
|
||||
exec 5<&-
|
||||
|
||||
# Run febootstrap on the package list.
|
||||
if [ "x@FEBOOTSTRAP_YUM_CONFIG@" != "xno" ]; then
|
||||
extra="--yum-config @FEBOOTSTRAP_YUM_CONFIG@"
|
||||
# Run supermin on the package list.
|
||||
# NB: Keep using --yum-config (deprecated alias) here since both old
|
||||
# and new supermin still support it.
|
||||
if [ "x@SUPERMIN_PACKAGER_CONFIG@" != "xno" ]; then
|
||||
extra="--yum-config @SUPERMIN_PACKAGER_CONFIG@"
|
||||
fi
|
||||
if [ "x@SUPERMIN_EXTRA_OPTIONS@" != "xno" ]; then
|
||||
extra="$extra @SUPERMIN_EXTRA_OPTIONS@"
|
||||
fi
|
||||
|
||||
echo @FEBOOTSTRAP@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
@FEBOOTSTRAP@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
echo @SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
@SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
|
||||
# Remove some things that we don't want in the appliance. This is
|
||||
# copied from the old febootstrap-minimize. However minimization is
|
||||
@@ -41,10 +46,6 @@ echo @FEBOOTSTRAP@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
< supermin.d/hostfiles \
|
||||
grep -v '^/usr/lib/locale' |
|
||||
grep -v '^/usr/share/locale' |
|
||||
grep -v '^/usr/lib/gconv' |
|
||||
grep -v '^/usr/lib64/gconv' |
|
||||
grep -v '^/usr/bin/localedef' |
|
||||
grep -v '^/usr/sbin/build-locale-archive' |
|
||||
grep -v '^/usr/share/man/' |
|
||||
grep -v '^/usr/share/doc/' |
|
||||
grep -v '^/usr/share/info/' |
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
*
|
||||
* There is also a list of packages which are excluded if they appear
|
||||
* as dependencies of the packages below. See: excludelist.in
|
||||
*
|
||||
* To add arbitrary extra packages, use:
|
||||
*
|
||||
* ./configure --with-extra-packages="gdb valgrind [etc]"
|
||||
*/
|
||||
|
||||
/* Basically the same with a few minor tweaks. */
|
||||
@@ -35,14 +39,17 @@
|
||||
iproute
|
||||
iputils
|
||||
kernel
|
||||
libcap
|
||||
libldm /* only Fedora has this for now, but we should add it to others later*/
|
||||
MAKEDEV
|
||||
nilfs-utils
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
openssh-clients
|
||||
pcre
|
||||
reiserfs-utils
|
||||
libselinux
|
||||
syslinux-extlinux
|
||||
systemd /* for /sbin/reboot and udevd */
|
||||
vim-minimal
|
||||
xz
|
||||
@@ -55,6 +62,7 @@
|
||||
btrfs-tools
|
||||
cryptsetup
|
||||
e2fsprogs
|
||||
extlinux
|
||||
genisoimage
|
||||
gfs-tools
|
||||
gfs2-tools
|
||||
@@ -62,14 +70,19 @@
|
||||
hfsplus
|
||||
iproute
|
||||
libaugeas0
|
||||
libcap2
|
||||
libhivex0
|
||||
libpcre3
|
||||
libyajl2
|
||||
linux-image
|
||||
/* syslinux 'suggests' mtools, but in reality it's a hard dependency: */
|
||||
mtools
|
||||
nilfs-tools
|
||||
ntfs-3g
|
||||
ntfsprogs
|
||||
openssh-client
|
||||
reiserfsprogs
|
||||
sysvinit /* for /sbin/reboot */
|
||||
ufsutils
|
||||
vim-tiny
|
||||
xz-utils
|
||||
@@ -86,11 +99,13 @@
|
||||
hivex
|
||||
iproute2
|
||||
iputils
|
||||
libcap
|
||||
linux
|
||||
lrzip
|
||||
nilfs-utils
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
pcre
|
||||
reiserfsprogs
|
||||
systemd
|
||||
vim
|
||||
@@ -111,6 +126,7 @@ dosfstools
|
||||
file
|
||||
findutils
|
||||
gawk
|
||||
gdisk
|
||||
grep
|
||||
gzip
|
||||
jfsutils
|
||||
@@ -136,6 +152,7 @@ rsync
|
||||
scrub
|
||||
sed
|
||||
strace
|
||||
syslinux
|
||||
tar
|
||||
udev
|
||||
util-linux
|
||||
@@ -152,7 +169,5 @@ zerofree
|
||||
valgrind
|
||||
#endif
|
||||
|
||||
/* Enable this to add useful debugging tools to the appliance. */
|
||||
#if 0
|
||||
gdb
|
||||
#endif
|
||||
/* Define this by doing: ./configure --with-extra-packages="..." */
|
||||
EXTRA_PACKAGES
|
||||
|
||||
68
bash/Makefile.am
Normal file
68
bash/Makefile.am
Normal file
@@ -0,0 +1,68 @@
|
||||
# libguestfs
|
||||
# Copyright (C) 2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
scripts = \
|
||||
guestfish \
|
||||
guestmount \
|
||||
virt-alignment-scan \
|
||||
virt-cat \
|
||||
virt-df \
|
||||
virt-edit \
|
||||
virt-filesystems \
|
||||
virt-format \
|
||||
virt-inspector \
|
||||
virt-ls \
|
||||
virt-rescue \
|
||||
virt-resize \
|
||||
virt-sparsify \
|
||||
virt-sysprep
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
$(scripts)
|
||||
|
||||
# Some of the scripts are simply symbolic links.
|
||||
virt-cat:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-df:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-edit:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-filesystems:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-format:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-inspector:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-ls:
|
||||
ln -sf virt-alignment-scan $@
|
||||
virt-sysprep:
|
||||
ln -sf virt-alignment-scan $@
|
||||
|
||||
virt-sparsify:
|
||||
ln -sf virt-resize $@
|
||||
|
||||
if HAVE_BASH_COMPLETION
|
||||
|
||||
# Bash completion script.
|
||||
|
||||
bashcompletiondir = $(BASH_COMPLETIONS_DIR)
|
||||
bashcompletion_DATA = $(scripts)
|
||||
|
||||
endif
|
||||
3
bash/README
Normal file
3
bash/README
Normal file
@@ -0,0 +1,3 @@
|
||||
This directory contains the scripts for tab-completing commands in
|
||||
bash. Note these new-style demand-loaded scripts require
|
||||
'bash-completion' >= 1.99.
|
||||
72
bash/guestfish
Normal file
72
bash/guestfish
Normal file
@@ -0,0 +1,72 @@
|
||||
# guestfish bash completion script -*- shell-script -*-
|
||||
# Copyright (C) 2010-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# List all local libvirt domains.
|
||||
_guestfs_virsh_list ()
|
||||
{
|
||||
local flag_ro=$1 flags
|
||||
|
||||
if [ "$flag_ro" -eq 1 ]; then
|
||||
flags="--all"
|
||||
else
|
||||
flags="--inactive"
|
||||
fi
|
||||
virsh list $flags | head -n -1 | tail -n +3 | awk '{print $2}'
|
||||
}
|
||||
|
||||
_guestfish ()
|
||||
{
|
||||
local cur prev words cword split
|
||||
local longopts flag_ro=0 c=1 word cmds doms
|
||||
|
||||
_init_completion -s || return
|
||||
|
||||
longopts="$(guestfish --long-options)"
|
||||
|
||||
# See if user has specified certain options anywhere on the
|
||||
# command line before the current word.
|
||||
while [ $c -lt $COMP_CWORD ]; do
|
||||
word="${COMP_WORDS[c]}"
|
||||
case "$word" in
|
||||
-r|--ro) flag_ro=1 ;;
|
||||
esac
|
||||
c=$((++c))
|
||||
done
|
||||
|
||||
case "$prev" in
|
||||
-a|--add)
|
||||
COMPREPLY=( $(compgen "$cur") )
|
||||
return ;;
|
||||
-d|--domain)
|
||||
doms=$(_guestfs_virsh_list "$flag_ro")
|
||||
COMPREPLY=( $(compgen -W "$doms" -- "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
--*)
|
||||
# --options
|
||||
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
|
||||
return ;;
|
||||
*)
|
||||
# Might be a guestfish command.
|
||||
cmds=$(guestfish -h| head -n -1 | tail -n +2 | awk '{print $1}')
|
||||
COMPREPLY=( $(compgen -W "$cmds" -- "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
} &&
|
||||
complete -o default -F _guestfish guestfish
|
||||
67
bash/guestmount
Normal file
67
bash/guestmount
Normal file
@@ -0,0 +1,67 @@
|
||||
# guestmount bash completion script -*- shell-script -*-
|
||||
# Copyright (C) 2010-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# List all local libvirt domains.
|
||||
_guestfs_virsh_list ()
|
||||
{
|
||||
local flag_ro=$1 flags
|
||||
|
||||
if [ "$flag_ro" -eq 1 ]; then
|
||||
flags="--all"
|
||||
else
|
||||
flags="--inactive"
|
||||
fi
|
||||
virsh list $flags | head -n -1 | tail -n +3 | awk '{print $2}'
|
||||
}
|
||||
|
||||
_guestmount ()
|
||||
{
|
||||
local cur prev words cword split
|
||||
local longopts flag_ro=0 c=1 word doms
|
||||
|
||||
_init_completion -s || return
|
||||
|
||||
longopts="$(guestmount --long-options)"
|
||||
|
||||
# See if user has specified certain options anywhere on the
|
||||
# command line before the current word.
|
||||
while [ $c -lt $COMP_CWORD ]; do
|
||||
word="${COMP_WORDS[c]}"
|
||||
case "$word" in
|
||||
-r|--ro) flag_ro=1 ;;
|
||||
esac
|
||||
c=$((++c))
|
||||
done
|
||||
|
||||
case "$prev" in
|
||||
-d|--domain)
|
||||
doms=$(_guestfs_virsh_list "$flag_ro")
|
||||
COMPREPLY=( $(compgen -W "$doms" -- "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
--*)
|
||||
# --options
|
||||
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
|
||||
return ;;
|
||||
*)
|
||||
COMPREPLY=( $(compgen "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
} &&
|
||||
complete -o default -F _guestmount guestmount
|
||||
108
bash/virt-alignment-scan
Normal file
108
bash/virt-alignment-scan
Normal file
@@ -0,0 +1,108 @@
|
||||
# virt-tools bash completion script -*- shell-script -*-
|
||||
# Copyright (C) 2010-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# List all local libvirt domains.
|
||||
_guestfs_virsh_list ()
|
||||
{
|
||||
local flag_ro=$1 flags
|
||||
|
||||
if [ "$flag_ro" -eq 1 ]; then
|
||||
flags="--all"
|
||||
else
|
||||
flags="--inactive"
|
||||
fi
|
||||
virsh list $flags | head -n -1 | tail -n +3 | awk '{print $2}'
|
||||
}
|
||||
|
||||
_guestfs_virttools ()
|
||||
{
|
||||
local cur prev words cword split
|
||||
local longopts="$1" flag_ro="$2" doms
|
||||
|
||||
_init_completion -s || return
|
||||
|
||||
case "$prev" in
|
||||
-d|--domain)
|
||||
doms=$(_guestfs_virsh_list "$flag_ro")
|
||||
COMPREPLY=( $(compgen -W "$doms" -- "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
--*)
|
||||
# --options
|
||||
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
|
||||
return ;;
|
||||
*)
|
||||
COMPREPLY=( $(compgen "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_virt_alignment_scan ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-alignment-scan --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_alignment_scan virt-alignment-scan
|
||||
|
||||
_virt_cat ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-cat --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_cat virt-cat
|
||||
|
||||
_virt_df ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-df --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_df virt-df
|
||||
|
||||
_virt_edit ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-edit --long-options)" 0
|
||||
} &&
|
||||
complete -o default -F _virt_edit virt-edit
|
||||
|
||||
_virt_filesystems ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-filesystems --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_filesystems virt-filesystems
|
||||
|
||||
_virt_format ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-format --long-options)" 0
|
||||
} &&
|
||||
complete -o default -F _virt_format virt-format
|
||||
|
||||
_virt_inspector ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-inspector --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_inspector virt-inspector
|
||||
|
||||
_virt_ls ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-ls --long-options)" 1
|
||||
} &&
|
||||
complete -o default -F _virt_ls virt-ls
|
||||
|
||||
_virt_sysprep ()
|
||||
{
|
||||
_guestfs_virttools "$(virt-sysprep --long-options)" 0
|
||||
} &&
|
||||
complete -o default -F _virt_sysprep virt-sysprep
|
||||
67
bash/virt-rescue
Normal file
67
bash/virt-rescue
Normal file
@@ -0,0 +1,67 @@
|
||||
# virt-rescue bash completion script -*- shell-script -*-
|
||||
# Copyright (C) 2010-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# List all local libvirt domains.
|
||||
_guestfs_virsh_list ()
|
||||
{
|
||||
local flag_ro=$1 flags
|
||||
|
||||
if [ "$flag_ro" -eq 1 ]; then
|
||||
flags="--all"
|
||||
else
|
||||
flags="--inactive"
|
||||
fi
|
||||
virsh list $flags | head -n -1 | tail -n +3 | awk '{print $2}'
|
||||
}
|
||||
|
||||
_virt_rescue ()
|
||||
{
|
||||
local cur prev words cword split
|
||||
local longopts flag_ro=0 c=1 word doms
|
||||
|
||||
_init_completion -s || return
|
||||
|
||||
longopts="$(virt-rescue --long-options)"
|
||||
|
||||
# See if user has specified certain options anywhere on the
|
||||
# command line before the current word.
|
||||
while [ $c -lt $COMP_CWORD ]; do
|
||||
word="${COMP_WORDS[c]}"
|
||||
case "$word" in
|
||||
-r|--ro) flag_ro=1 ;;
|
||||
esac
|
||||
c=$((++c))
|
||||
done
|
||||
|
||||
case "$prev" in
|
||||
-d|--domain)
|
||||
doms=$(_guestfs_virsh_list "$flag_ro")
|
||||
COMPREPLY=( $(compgen -W "$doms" -- "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
--*)
|
||||
# --options
|
||||
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
|
||||
return ;;
|
||||
*)
|
||||
COMPREPLY=( $(compgen "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
} &&
|
||||
complete -o default -F _virt_rescue virt-rescue
|
||||
46
bash/virt-resize
Normal file
46
bash/virt-resize
Normal file
@@ -0,0 +1,46 @@
|
||||
# virt-resize, virt-sparsify bash completion script -*- shell-script -*-
|
||||
# Copyright (C) 2010-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
_guestfs_options_only ()
|
||||
{
|
||||
local cur prev words cword split
|
||||
local longopts="$1"
|
||||
|
||||
_init_completion -s || return
|
||||
|
||||
case "$cur" in
|
||||
--*)
|
||||
# --options
|
||||
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
|
||||
return ;;
|
||||
*)
|
||||
COMPREPLY=( $(compgen "$cur") )
|
||||
return ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_virt_resize ()
|
||||
{
|
||||
_guestfs_options_only "$(virt-resize --long-options)"
|
||||
} &&
|
||||
complete -o default -F _virt_resize virt-resize
|
||||
|
||||
_virt_sparsify ()
|
||||
{
|
||||
_guestfs_options_only "$(virt-sparsify --long-options)"
|
||||
} &&
|
||||
complete -o default -F _virt_sparsify virt-sparsify
|
||||
@@ -38,6 +38,8 @@ gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
|
||||
|
||||
modules='
|
||||
accept4
|
||||
areadlink
|
||||
areadlinkat
|
||||
arpa_inet
|
||||
byteswap
|
||||
c-ctype
|
||||
@@ -68,13 +70,13 @@ maintainer-makefile
|
||||
manywarnings
|
||||
memmem
|
||||
mkdtemp
|
||||
mkstemps
|
||||
netdb
|
||||
netinet_in
|
||||
openat
|
||||
perror
|
||||
pipe2
|
||||
pread
|
||||
progname
|
||||
read-file
|
||||
readlink
|
||||
select
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -
|
||||
# bugs-in-changelog.sh
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -41,57 +41,75 @@ virt_cat_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
virt-cat.c
|
||||
|
||||
virt_cat_CFLAGS = \
|
||||
virt_cat_CPPFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(top_srcdir)/src -I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/fish \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib
|
||||
|
||||
virt_cat_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(GPROF_CFLAGS) $(GCOV_CFLAGS) \
|
||||
$(LIBCONFIG_CFLAGS)
|
||||
$(LIBCONFIG_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
virt_cat_LDADD = \
|
||||
$(LIBCONFIG_LIBS) \
|
||||
$(top_builddir)/src/libutils.la \
|
||||
$(top_builddir)/src/libguestfs.la \
|
||||
$(LIBXML2_LIBS) \
|
||||
$(LIBVIRT_LIBS) \
|
||||
../gnulib/lib/libgnu.la
|
||||
|
||||
virt_filesystems_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
virt-filesystems.c
|
||||
|
||||
virt_filesystems_CFLAGS = \
|
||||
virt_filesystems_CPPFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(top_srcdir)/src -I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/fish \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib
|
||||
|
||||
virt_filesystems_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(GPROF_CFLAGS) $(GCOV_CFLAGS) \
|
||||
$(LIBCONFIG_CFLAGS)
|
||||
$(LIBCONFIG_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
virt_filesystems_LDADD = \
|
||||
$(LIBCONFIG_LIBS) \
|
||||
$(top_builddir)/src/libutils.la \
|
||||
$(top_builddir)/src/libguestfs.la \
|
||||
$(LIBXML2_LIBS) \
|
||||
$(LIBVIRT_LIBS) \
|
||||
../gnulib/lib/libgnu.la
|
||||
|
||||
virt_ls_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
virt-ls.c
|
||||
|
||||
virt_ls_CFLAGS = \
|
||||
virt_ls_CPPFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(top_srcdir)/src -I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/fish \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib
|
||||
|
||||
virt_ls_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(GPROF_CFLAGS) $(GCOV_CFLAGS) \
|
||||
$(LIBCONFIG_CFLAGS)
|
||||
$(LIBCONFIG_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
virt_ls_LDADD = \
|
||||
$(LIBCONFIG_LIBS) \
|
||||
$(top_builddir)/src/libutils.la \
|
||||
$(top_builddir)/src/libguestfs.la \
|
||||
$(LIBXML2_LIBS) \
|
||||
$(LIBVIRT_LIBS) \
|
||||
../gnulib/lib/libgnu.la
|
||||
|
||||
# Manual pages and HTML files for the website.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <assert.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "progname.h"
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
@@ -45,15 +45,10 @@ int echo_keys = 0;
|
||||
const char *libvirt_uri = NULL;
|
||||
int inspector = 1;
|
||||
|
||||
static int do_cat (int argc, char *argv[]);
|
||||
static int is_windows (guestfs_h *g, const char *root);
|
||||
static char *windows_path (guestfs_h *g, const char *root, const char *filename);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
usage (int status)
|
||||
{
|
||||
@@ -88,9 +83,6 @@ usage (int status)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
/* Set global program name that is not polluted with libtool artifacts. */
|
||||
set_program_name (argv[0]);
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
||||
textdomain (PACKAGE);
|
||||
@@ -106,6 +98,7 @@ main (int argc, char *argv[])
|
||||
{ "format", 2, 0, 0 },
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "keys-from-stdin", 0, 0, 0 },
|
||||
{ "long-options", 0, 0, 0 },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -114,6 +107,7 @@ main (int argc, char *argv[])
|
||||
struct drv *drv;
|
||||
const char *format = NULL;
|
||||
int c;
|
||||
int r;
|
||||
int option_index;
|
||||
|
||||
g = guestfs_create ();
|
||||
@@ -122,15 +116,15 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argv[0] = bad_cast (program_name);
|
||||
|
||||
for (;;) {
|
||||
c = getopt_long (argc, argv, options, long_options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 0: /* options which are long only */
|
||||
if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
if (STREQ (long_options[option_index].name, "long-options"))
|
||||
display_long_options (long_options);
|
||||
else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
keys_from_stdin = 1;
|
||||
} else if (STREQ (long_options[option_index].name, "echo-keys")) {
|
||||
echo_keys = 1;
|
||||
@@ -240,24 +234,34 @@ main (int argc, char *argv[])
|
||||
/* Free up data structures, no longer needed after this point. */
|
||||
free_drives (drvs);
|
||||
|
||||
r = do_cat (argc - optind, &argv[optind]);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int
|
||||
do_cat (int argc, char *argv[])
|
||||
{
|
||||
unsigned errors = 0;
|
||||
int windows;
|
||||
char *root, **roots;
|
||||
int windows, i;
|
||||
char *root;
|
||||
|
||||
/* Get root mountpoint. See: fish/inspect.c:inspect_mount */
|
||||
roots = guestfs_inspect_get_roots (g);
|
||||
CLEANUP_FREE_STRING_LIST char **roots = guestfs_inspect_get_roots (g);
|
||||
|
||||
assert (roots);
|
||||
assert (roots[0] != NULL);
|
||||
assert (roots[1] == NULL);
|
||||
root = roots[0];
|
||||
free (roots);
|
||||
|
||||
/* Windows? Special handling is required. */
|
||||
windows = is_windows (g, root);
|
||||
|
||||
for (; optind < argc; optind++) {
|
||||
char *filename_to_free = NULL;
|
||||
const char *filename = argv[optind];
|
||||
for (i = 0; i < argc; ++i) {
|
||||
CLEANUP_FREE char *filename_to_free = NULL;
|
||||
const char *filename = argv[i];
|
||||
|
||||
if (windows) {
|
||||
filename = filename_to_free = windows_path (g, root, filename);
|
||||
@@ -269,15 +273,9 @@ main (int argc, char *argv[])
|
||||
|
||||
if (guestfs_download (g, filename, "/dev/stdout") == -1)
|
||||
errors++;
|
||||
|
||||
free (filename_to_free);
|
||||
}
|
||||
|
||||
free (root);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return errors == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -78,6 +78,12 @@ them with separate I<-a> options.
|
||||
The format of the disk image is auto-detected. To override this and
|
||||
force a particular format use the I<--format=..> option.
|
||||
|
||||
=item B<-a URI>
|
||||
|
||||
=item B<--add URI>
|
||||
|
||||
Add a remote disk. See L<guestfish(1)/ADDING REMOTE STORAGE>.
|
||||
|
||||
=item B<-c> URI
|
||||
|
||||
=item B<--connect> URI
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
@@ -31,7 +32,6 @@
|
||||
|
||||
#include "c-ctype.h"
|
||||
#include "human.h"
|
||||
#include "progname.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
@@ -80,12 +80,6 @@ static void do_output_end (void);
|
||||
static struct guestfs_lvm_pv_list *get_pvs (void);
|
||||
static void free_pvs (void);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
usage (int status)
|
||||
{
|
||||
@@ -137,9 +131,6 @@ usage (int status)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
/* Set global program name that is not polluted with libtool artifacts. */
|
||||
set_program_name (argv[0]);
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
||||
textdomain (PACKAGE);
|
||||
@@ -162,9 +153,10 @@ main (int argc, char *argv[])
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "human-readable", 0, 0, 'h' },
|
||||
{ "keys-from-stdin", 0, 0, 0 },
|
||||
{ "long", 0, 0, 'l' },
|
||||
{ "logical-volumes", 0, 0, 0 },
|
||||
{ "logvols", 0, 0, 0 },
|
||||
{ "long", 0, 0, 'l' },
|
||||
{ "long-options", 0, 0, 0 },
|
||||
{ "lvs", 0, 0, 0 },
|
||||
{ "no-title", 0, 0, 0 },
|
||||
{ "parts", 0, 0, 0 },
|
||||
@@ -197,15 +189,15 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argv[0] = bad_cast (program_name);
|
||||
|
||||
for (;;) {
|
||||
c = getopt_long (argc, argv, options, long_options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 0: /* options which are long only */
|
||||
if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
if (STREQ (long_options[option_index].name, "long-options"))
|
||||
display_long_options (long_options);
|
||||
else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
keys_from_stdin = 1;
|
||||
} else if (STREQ (long_options[option_index].name, "echo-keys")) {
|
||||
echo_keys = 1;
|
||||
@@ -379,9 +371,6 @@ static int is_md (char *device);
|
||||
static char **parents_of_md (char *device);
|
||||
static char **parents_of_vg (char *vg);
|
||||
|
||||
static void free_strings (char **strings);
|
||||
static size_t count_strings (char **strings);
|
||||
|
||||
static void
|
||||
do_output_title (void)
|
||||
{
|
||||
@@ -438,22 +427,21 @@ do_output (void)
|
||||
static void
|
||||
do_output_filesystems (void)
|
||||
{
|
||||
char **fses;
|
||||
size_t i;
|
||||
|
||||
fses = guestfs_list_filesystems (g);
|
||||
CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g);
|
||||
if (fses == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; fses[i] != NULL; i += 2) {
|
||||
char *dev, *vfs_label = NULL, *vfs_uuid = NULL;
|
||||
char **parents;
|
||||
CLEANUP_FREE char *dev = NULL, *vfs_label = NULL, *vfs_uuid = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **parents = NULL;
|
||||
int64_t size = -1;
|
||||
|
||||
/* Skip swap and unknown, unless --extra flag was given. */
|
||||
if (!(output & OUTPUT_FILESYSTEMS_EXTRA) &&
|
||||
(STREQ (fses[i+1], "swap") || STREQ (fses[i+1], "unknown")))
|
||||
goto next;
|
||||
continue;
|
||||
|
||||
dev = guestfs_canonical_device_name (g, fses[i]);
|
||||
if (dev == NULL)
|
||||
@@ -499,32 +487,20 @@ do_output_filesystems (void)
|
||||
|
||||
write_row (dev, "filesystem",
|
||||
fses[i+1], vfs_label, -1, size, parents, vfs_uuid);
|
||||
|
||||
free_strings (parents);
|
||||
free (dev);
|
||||
free (vfs_label);
|
||||
free (vfs_uuid);
|
||||
|
||||
next:
|
||||
free (fses[i]);
|
||||
free (fses[i+1]);
|
||||
}
|
||||
|
||||
free (fses);
|
||||
}
|
||||
|
||||
static void
|
||||
do_output_lvs (void)
|
||||
{
|
||||
char **lvs;
|
||||
size_t i;
|
||||
|
||||
lvs = guestfs_lvs (g);
|
||||
CLEANUP_FREE_STRING_LIST char **lvs = guestfs_lvs (g);
|
||||
if (lvs == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; lvs[i] != NULL; ++i) {
|
||||
char *uuid = NULL, *parent_name = NULL;
|
||||
CLEANUP_FREE char *uuid = NULL, *parent_name = NULL;
|
||||
const char *parents[2];
|
||||
int64_t size = -1;
|
||||
|
||||
@@ -553,29 +529,23 @@ do_output_lvs (void)
|
||||
|
||||
write_row (lvs[i], "lv",
|
||||
NULL, NULL, -1, size, (char **) parents, uuid);
|
||||
|
||||
free (uuid);
|
||||
free (parent_name);
|
||||
free (lvs[i]);
|
||||
}
|
||||
|
||||
free (lvs);
|
||||
}
|
||||
|
||||
static void
|
||||
do_output_vgs (void)
|
||||
{
|
||||
struct guestfs_lvm_vg_list *vgs;
|
||||
size_t i;
|
||||
|
||||
vgs = guestfs_vgs_full (g);
|
||||
CLEANUP_FREE_LVM_VG_LIST struct guestfs_lvm_vg_list *vgs =
|
||||
guestfs_vgs_full (g);
|
||||
if (vgs == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; i < vgs->len; ++i) {
|
||||
char *name;
|
||||
CLEANUP_FREE char *name = NULL;
|
||||
char uuid[33];
|
||||
char **parents;
|
||||
CLEANUP_FREE_STRING_LIST char **parents = NULL;
|
||||
|
||||
if (asprintf (&name, "/dev/%s", vgs->val[i].vg_name) == -1) {
|
||||
perror ("asprintf");
|
||||
@@ -589,12 +559,7 @@ do_output_vgs (void)
|
||||
|
||||
write_row (name, "vg",
|
||||
NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, parents, uuid);
|
||||
|
||||
free (name);
|
||||
free_strings (parents);
|
||||
}
|
||||
|
||||
guestfs_free_lvm_vg_list (vgs);
|
||||
}
|
||||
|
||||
/* Cache the output of guestfs_pvs_full, since we use it in a few places. */
|
||||
@@ -629,11 +594,11 @@ do_output_pvs (void)
|
||||
struct guestfs_lvm_pv_list *pvs = get_pvs ();
|
||||
|
||||
for (i = 0; i < pvs->len; ++i) {
|
||||
char *dev;
|
||||
char uuid[33];
|
||||
const char *parents[1] = { NULL };
|
||||
|
||||
dev = guestfs_canonical_device_name (g, pvs->val[i].pv_name);
|
||||
CLEANUP_FREE char *dev =
|
||||
guestfs_canonical_device_name (g, pvs->val[i].pv_name);
|
||||
if (!dev)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
@@ -642,15 +607,13 @@ do_output_pvs (void)
|
||||
write_row (dev, "pv",
|
||||
NULL, NULL, -1, (int64_t) pvs->val[i].pv_size,
|
||||
(char **) parents, uuid);
|
||||
|
||||
free (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
get_mbr_id (const char *dev, const char *parent_name)
|
||||
{
|
||||
char *parttype = NULL;
|
||||
CLEANUP_FREE char *parttype = NULL;
|
||||
int mbr_id = -1, partnum;
|
||||
|
||||
guestfs_push_error_handler (g, NULL, NULL);
|
||||
@@ -663,8 +626,6 @@ get_mbr_id (const char *dev, const char *parent_name)
|
||||
mbr_id = guestfs_part_get_mbr_id (g, parent_name, partnum);
|
||||
}
|
||||
|
||||
free (parttype);
|
||||
|
||||
guestfs_pop_error_handler (g);
|
||||
|
||||
return mbr_id;
|
||||
@@ -673,15 +634,14 @@ get_mbr_id (const char *dev, const char *parent_name)
|
||||
static void
|
||||
do_output_partitions (void)
|
||||
{
|
||||
char **parts;
|
||||
size_t i;
|
||||
|
||||
parts = guestfs_list_partitions (g);
|
||||
CLEANUP_FREE_STRING_LIST char **parts = guestfs_list_partitions (g);
|
||||
if (parts == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; parts[i] != NULL; ++i) {
|
||||
char *dev, *parent_name = NULL;
|
||||
CLEANUP_FREE char *dev = NULL, *parent_name = NULL, *canonical_name = NULL;
|
||||
const char *parents[2];
|
||||
int64_t size = -1;
|
||||
int mbr_id = -1;
|
||||
@@ -703,41 +663,32 @@ do_output_partitions (void)
|
||||
if ((columns & COLUMN_MBR))
|
||||
mbr_id = get_mbr_id (parts[i], parent_name);
|
||||
|
||||
char *p = guestfs_canonical_device_name (g, parent_name);
|
||||
if (!p)
|
||||
canonical_name = guestfs_canonical_device_name (g, parent_name);
|
||||
if (!canonical_name)
|
||||
exit (EXIT_FAILURE);
|
||||
free (parent_name);
|
||||
parent_name = p;
|
||||
|
||||
parents[0] = parent_name;
|
||||
parents[0] = canonical_name;
|
||||
parents[1] = NULL;
|
||||
}
|
||||
|
||||
write_row (dev, "partition",
|
||||
NULL, NULL, mbr_id, size, (char **) parents, NULL);
|
||||
|
||||
free (dev);
|
||||
free (parent_name);
|
||||
free (parts[i]);
|
||||
}
|
||||
|
||||
free (parts);
|
||||
}
|
||||
|
||||
static void
|
||||
do_output_blockdevs (void)
|
||||
{
|
||||
char **devices;
|
||||
size_t i;
|
||||
|
||||
devices = guestfs_list_devices (g);
|
||||
CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g);
|
||||
if (devices == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
int64_t size = -1;
|
||||
char *dev;
|
||||
char **parents;
|
||||
CLEANUP_FREE_STRING_LIST char **parents = NULL;
|
||||
CLEANUP_FREE char *dev;
|
||||
|
||||
dev = guestfs_canonical_device_name (g, devices[i]);
|
||||
if (!dev)
|
||||
@@ -756,18 +707,10 @@ do_output_blockdevs (void)
|
||||
|
||||
write_row (dev, "device",
|
||||
NULL, NULL, -1, size, parents, NULL);
|
||||
|
||||
free (dev);
|
||||
free (devices[i]);
|
||||
free_strings (parents);
|
||||
}
|
||||
|
||||
free (devices);
|
||||
}
|
||||
|
||||
/* Returns an empty list of parents. Note this must be freed using
|
||||
* free_strings.
|
||||
*/
|
||||
/* Returns an empty list of parents. Note this must be freed. */
|
||||
static char **
|
||||
no_parents (void)
|
||||
{
|
||||
@@ -806,11 +749,11 @@ is_md (char *device)
|
||||
static char **
|
||||
parents_of_md (char *device)
|
||||
{
|
||||
struct guestfs_mdstat_list *stats;
|
||||
char **ret;
|
||||
size_t i;
|
||||
|
||||
stats = guestfs_md_stat (g, device);
|
||||
CLEANUP_FREE_MDSTAT_LIST struct guestfs_mdstat_list *stats =
|
||||
guestfs_md_stat (g, device);
|
||||
if (!stats)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
@@ -828,8 +771,6 @@ parents_of_md (char *device)
|
||||
|
||||
ret[stats->len] = NULL;
|
||||
|
||||
guestfs_free_mdstat_list (stats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -861,15 +802,14 @@ static char **
|
||||
parents_of_vg (char *vg)
|
||||
{
|
||||
struct guestfs_lvm_pv_list *pvs = get_pvs ();
|
||||
char **pvuuids;
|
||||
char **ret;
|
||||
size_t n, i, j;
|
||||
|
||||
pvuuids = guestfs_vgpvuuids (g, vg);
|
||||
CLEANUP_FREE_STRING_LIST char **pvuuids = guestfs_vgpvuuids (g, vg);
|
||||
if (!pvuuids)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
n = count_strings (pvuuids);
|
||||
n = guestfs___count_strings (pvuuids);
|
||||
|
||||
ret = malloc ((n + 1) * sizeof (char *));
|
||||
if (!ret) {
|
||||
@@ -901,8 +841,6 @@ parents_of_vg (char *vg)
|
||||
|
||||
ret[i] = NULL;
|
||||
|
||||
free_strings (pvuuids);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -941,7 +879,7 @@ write_row (const char *name, const char *type,
|
||||
int64_t size, char **parents, const char *uuid)
|
||||
{
|
||||
const char *strings[NR_COLUMNS];
|
||||
char *parents_str = NULL;
|
||||
CLEANUP_FREE char *parents_str = NULL;
|
||||
size_t len = 0;
|
||||
char hum[LONGEST_HUMAN_READABLE];
|
||||
char num[256];
|
||||
@@ -989,8 +927,6 @@ write_row (const char *name, const char *type,
|
||||
assert (len <= NR_COLUMNS);
|
||||
|
||||
write_row_strings ((char **) strings, len);
|
||||
|
||||
free (parents_str);
|
||||
}
|
||||
|
||||
static void add_row (char **strings, size_t len);
|
||||
@@ -1159,23 +1095,3 @@ do_output_end (void)
|
||||
}
|
||||
free (rows);
|
||||
}
|
||||
|
||||
static void
|
||||
free_strings (char **strings)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; strings[i] != NULL; ++i)
|
||||
free (strings[i]);
|
||||
free (strings);
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_strings (char **strings)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; strings[i] != NULL; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,12 @@ them with separate I<-a> options.
|
||||
The format of the disk image is auto-detected. To override this and
|
||||
force a particular format use the I<--format=..> option.
|
||||
|
||||
=item B<-a URI>
|
||||
|
||||
=item B<--add URI>
|
||||
|
||||
Add a remote disk. See L<guestfish(1)/ADDING REMOTE STORAGE>.
|
||||
|
||||
=item B<--all>
|
||||
|
||||
Display everything. This is currently the same as specifying these
|
||||
|
||||
106
cat/virt-ls.c
106
cat/virt-ls.c
@@ -25,13 +25,13 @@
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "human.h"
|
||||
#include "progname.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
@@ -82,14 +82,6 @@ static int is_fifo (int64_t mode);
|
||||
static int is_lnk (int64_t mode);
|
||||
static int is_sock (int64_t mode);
|
||||
|
||||
static void free_strings (char **);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
usage (int status)
|
||||
{
|
||||
@@ -138,9 +130,6 @@ main (int argc, char *argv[])
|
||||
/* Current time for --time-days, --time-relative output. */
|
||||
time (&now);
|
||||
|
||||
/* Set global program name that is not polluted with libtool artifacts. */
|
||||
set_program_name (argv[0]);
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
||||
textdomain (PACKAGE);
|
||||
@@ -163,6 +152,7 @@ main (int argc, char *argv[])
|
||||
{ "human-readable", 0, 0, 'h' },
|
||||
{ "keys-from-stdin", 0, 0, 0 },
|
||||
{ "long", 0, 0, 'l' },
|
||||
{ "long-options", 0, 0, 0 },
|
||||
{ "recursive", 0, 0, 'R' },
|
||||
{ "time", 0, 0, 0 },
|
||||
{ "times", 0, 0, 0 },
|
||||
@@ -191,15 +181,15 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argv[0] = bad_cast (program_name);
|
||||
|
||||
for (;;) {
|
||||
c = getopt_long (argc, argv, options, long_options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 0: /* options which are long only */
|
||||
if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
if (STREQ (long_options[option_index].name, "long-options"))
|
||||
display_long_options (long_options);
|
||||
else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
|
||||
keys_from_stdin = 1;
|
||||
} else if (STREQ (long_options[option_index].name, "echo-keys")) {
|
||||
echo_keys = 1;
|
||||
@@ -408,18 +398,14 @@ main (int argc, char *argv[])
|
||||
static int
|
||||
do_ls (const char *dir)
|
||||
{
|
||||
char **lines;
|
||||
size_t i;
|
||||
CLEANUP_FREE_STRING_LIST char **lines = guestfs_ls (g, dir);
|
||||
|
||||
if ((lines = guestfs_ls (g, dir)) == NULL) {
|
||||
if (lines == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; lines[i] != NULL; ++i) {
|
||||
for (i = 0; lines[i] != NULL; ++i)
|
||||
printf ("%s\n", lines[i]);
|
||||
free (lines[i]);
|
||||
}
|
||||
free (lines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -427,13 +413,12 @@ do_ls (const char *dir)
|
||||
static int
|
||||
do_ls_l (const char *dir)
|
||||
{
|
||||
char *out;
|
||||
CLEANUP_FREE char *out = guestfs_ll (g, dir);
|
||||
|
||||
if ((out = guestfs_ll (g, dir)) == NULL)
|
||||
if (out == NULL)
|
||||
return -1;
|
||||
|
||||
printf ("%s", out);
|
||||
free (out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -441,18 +426,14 @@ do_ls_l (const char *dir)
|
||||
static int
|
||||
do_ls_R (const char *dir)
|
||||
{
|
||||
char **dirs;
|
||||
size_t i;
|
||||
CLEANUP_FREE_STRING_LIST char **dirs = guestfs_find (g, dir);
|
||||
|
||||
dirs = guestfs_find (g, dir);
|
||||
if (dirs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; dirs[i] != NULL; ++i) {
|
||||
for (i = 0; dirs[i] != NULL; ++i)
|
||||
puts (dirs[i]);
|
||||
free (dirs[i]);
|
||||
}
|
||||
free (dirs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -473,8 +454,8 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
* case.
|
||||
*/
|
||||
if (depth == 0) {
|
||||
struct guestfs_stat *stat;
|
||||
struct guestfs_xattr_list *xattrs;
|
||||
CLEANUP_FREE_STAT struct guestfs_stat *stat = NULL;
|
||||
CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL;
|
||||
int r;
|
||||
|
||||
stat = guestfs_lstat (g, dir);
|
||||
@@ -482,40 +463,35 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
return -1;
|
||||
|
||||
xattrs = guestfs_lgetxattrs (g, dir);
|
||||
if (xattrs == NULL) {
|
||||
guestfs_free_stat (stat);
|
||||
if (xattrs == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = f (dir, NULL, stat, xattrs);
|
||||
guestfs_free_stat (stat);
|
||||
guestfs_free_xattr_list (xattrs);
|
||||
|
||||
if (r == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
char **names = NULL;
|
||||
char *path = NULL;
|
||||
size_t i, xattrp;
|
||||
struct guestfs_stat_list *stats = NULL;
|
||||
struct guestfs_xattr_list *xattrs = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **names = NULL;
|
||||
CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *stats = NULL;
|
||||
CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL;
|
||||
|
||||
names = guestfs_ls (g, dir);
|
||||
if (names == NULL)
|
||||
goto out;
|
||||
return -1;
|
||||
|
||||
stats = guestfs_lstatlist (g, dir, names);
|
||||
if (stats == NULL)
|
||||
goto out;
|
||||
return -1;
|
||||
|
||||
xattrs = guestfs_lxattrlist (g, dir, names);
|
||||
if (xattrs == NULL)
|
||||
goto out;
|
||||
return -1;
|
||||
|
||||
/* Call function on everything in this directory. */
|
||||
for (i = 0, xattrp = 0; names[i] != NULL; ++i, ++xattrp) {
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
struct guestfs_xattr_list file_xattrs;
|
||||
size_t nr_xattrs;
|
||||
|
||||
@@ -528,7 +504,7 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
if (xattrs->val[xattrp].attrval_len == 0) {
|
||||
fprintf (stderr, _("%s: error getting extended attrs for %s %s\n"),
|
||||
program_name, dir, names[i]);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
/* attrval is not \0-terminated. */
|
||||
char attrval[xattrs->val[xattrp].attrval_len+1];
|
||||
@@ -538,7 +514,7 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
if (sscanf (attrval, "%zu", &nr_xattrs) != 1) {
|
||||
fprintf (stderr, _("%s: error: cannot parse xattr count for %s %s\n"),
|
||||
program_name, dir, names[i]);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_xattrs.len = nr_xattrs;
|
||||
@@ -547,28 +523,17 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
|
||||
/* Call the function. */
|
||||
if (f (dir, names[i], &stats->val[i], &file_xattrs) == -1)
|
||||
goto out;
|
||||
return -1;
|
||||
|
||||
/* Recursively call visit, but only on directories. */
|
||||
if (is_dir (stats->val[i].mode)) {
|
||||
path = full_path (dir, names[i]);
|
||||
if (visit (depth + 1, path, f) == -1)
|
||||
goto out;
|
||||
free (path); path = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
free (path);
|
||||
if (names)
|
||||
free_strings (names);
|
||||
if (stats)
|
||||
guestfs_free_stat_list (stats);
|
||||
if (xattrs)
|
||||
guestfs_free_xattr_list (xattrs);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
@@ -611,7 +576,7 @@ show_file (const char *dir, const char *name,
|
||||
const struct guestfs_xattr_list *xattrs)
|
||||
{
|
||||
char filetype[2];
|
||||
char *path, *csum = NULL, *link = NULL;
|
||||
CLEANUP_FREE char *path = NULL, *csum = NULL, *link = NULL;
|
||||
|
||||
/* Display the basic fields. */
|
||||
output_start_line ();
|
||||
@@ -683,10 +648,6 @@ show_file (const char *dir, const char *name,
|
||||
|
||||
output_end_line ();
|
||||
|
||||
free (path);
|
||||
free (csum);
|
||||
free (link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -966,14 +927,3 @@ is_sock (int64_t mode)
|
||||
{
|
||||
return (mode & 0170000) == 0140000;
|
||||
}
|
||||
|
||||
/* String functions. */
|
||||
static void
|
||||
free_strings (char **names)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; names[i] != NULL; ++i)
|
||||
free (names[i]);
|
||||
free (names);
|
||||
}
|
||||
|
||||
@@ -277,6 +277,12 @@ them with separate I<-a> options.
|
||||
The format of the disk image is auto-detected. To override this and
|
||||
force a particular format use the I<--format=..> option.
|
||||
|
||||
=item B<-a URI>
|
||||
|
||||
=item B<--add URI>
|
||||
|
||||
Add a remote disk. See L<guestfish(1)/ADDING REMOTE STORAGE>.
|
||||
|
||||
=item B<--checksum>
|
||||
|
||||
=item B<--checksum=crc|md5|sha1|sha224|sha256|sha384|sha512>
|
||||
@@ -499,9 +505,6 @@ L<guestfish(1)>,
|
||||
L<virt-cat(1)>,
|
||||
L<virt-copy-out(1)>,
|
||||
L<virt-tar-out(1)>,
|
||||
L<Sys::Guestfs(3)>,
|
||||
L<Sys::Guestfs::Lib(3)>,
|
||||
L<Sys::Virt(3)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHOR
|
||||
@@ -510,4 +513,4 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
Copyright (C) 2009-2013 Red Hat Inc.
|
||||
|
||||
1109
configure.ac
1109
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs autobuild script
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl -w
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-2012 Red Hat Inc.
|
||||
# Copyright (C) 2009-2013 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/ocamlrun /usr/bin/ocaml
|
||||
|
||||
(* Convert *.qtr (qemu block device trace) to Postscript.
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
* By Richard W.M. Jones <rjones@redhat.com>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
36
daemon/9p.c
36
daemon/9p.c
@@ -48,8 +48,10 @@ do_list_9p (void)
|
||||
dir = opendir (BUS_PATH);
|
||||
if (!dir) {
|
||||
perror ("opendir: " BUS_PATH);
|
||||
if (errno != ENOENT)
|
||||
if (errno != ENOENT) {
|
||||
reply_with_perror ("opendir: " BUS_PATH);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If this directory doesn't exist, it probably means that
|
||||
* the virtio driver isn't loaded. Don't return an error
|
||||
@@ -75,17 +77,14 @@ do_list_9p (void)
|
||||
* the mount tag length to be unlimited (or up to 65536 bytes).
|
||||
* See: linux/include/linux/virtio_9p.h
|
||||
*/
|
||||
char *mount_tag = read_whole_file (mount_tag_path);
|
||||
CLEANUP_FREE char *mount_tag = read_whole_file (mount_tag_path);
|
||||
if (mount_tag == 0)
|
||||
continue;
|
||||
|
||||
if (add_string (&r, mount_tag) == -1) {
|
||||
free (mount_tag);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (mount_tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +147,7 @@ read_whole_file (const char *filename)
|
||||
*/
|
||||
ssize_t n = read (fd, r + size, alloc - size - 1);
|
||||
if (n == -1) {
|
||||
perror (filename);
|
||||
fprintf (stderr, "read: %s: %m\n", filename);
|
||||
free (r);
|
||||
close (fd);
|
||||
return NULL;
|
||||
@@ -159,7 +158,7 @@ read_whole_file (const char *filename)
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror (filename);
|
||||
fprintf (stderr, "close: %s: %m\n", filename);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
@@ -173,26 +172,26 @@ read_whole_file (const char *filename)
|
||||
int
|
||||
do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options)
|
||||
{
|
||||
char *mp = NULL, *opts = NULL, *err = NULL;
|
||||
CLEANUP_FREE char *mp = NULL, *opts = NULL, *err = NULL;
|
||||
struct stat statbuf;
|
||||
int r = -1;
|
||||
int r;
|
||||
|
||||
ABS_PATH (mountpoint, , return -1);
|
||||
|
||||
mp = sysroot_path (mountpoint);
|
||||
if (!mp) {
|
||||
reply_with_perror ("malloc");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check the mountpoint exists and is a directory. */
|
||||
if (stat (mp, &statbuf) == -1) {
|
||||
reply_with_perror ("%s", mountpoint);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_perror ("%s: mount point is not a directory", mountpoint);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add trans=virtio to the options. */
|
||||
@@ -200,14 +199,14 @@ do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options)
|
||||
STRNEQ (options, "")) {
|
||||
if (asprintf (&opts, "trans=virtio,%s", options) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
opts = strdup ("trans=virtio");
|
||||
if (opts == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,13 +214,8 @@ do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options)
|
||||
str_mount, "-o", opts, "-t", "9p", mount_tag, mp, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s on %s: %s", mount_tag, mountpoint, err);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
free (err);
|
||||
free (opts);
|
||||
free (mp);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,26 +19,31 @@ include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
CLEANFILES = stamp-guestfsd.pod
|
||||
|
||||
libsrcdir = $(top_builddir)/src
|
||||
|
||||
generator_built = \
|
||||
actions.h \
|
||||
stubs.c \
|
||||
names.c
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(generator_built) \
|
||||
shared_with_library = \
|
||||
guestfs_protocol.c \
|
||||
guestfs_protocol.h \
|
||||
errnostring-gperf.c \
|
||||
errnostring-gperf.gperf \
|
||||
errnostring.c \
|
||||
errnostring.h
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(generator_built) \
|
||||
$(shared_with_library) \
|
||||
errnostring-gperf.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(BUILT_SOURCES) \
|
||||
guestfsd.pod
|
||||
|
||||
$(shared_with_library): %: $(top_srcdir)/src/%
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
|
||||
noinst_LIBRARIES = libprotocol.a
|
||||
|
||||
# This convenience library is solely to compile its generated sources with
|
||||
@@ -46,16 +51,10 @@ noinst_LIBRARIES = libprotocol.a
|
||||
libprotocol_a_SOURCES = guestfs_protocol.c guestfs_protocol.h
|
||||
libprotocol_a_CFLAGS = -Wall -Wno-unused -fno-strict-aliasing
|
||||
|
||||
guestfs_protocol.c: $(libsrcdir)/guestfs_protocol.c
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
guestfs_protocol.h: $(libsrcdir)/guestfs_protocol.h
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
$(libsrcdir)/guestfs_protocol.c: force
|
||||
$(MAKE) -C $(libsrcdir) guestfs_protocol.c
|
||||
$(libsrcdir)/guestfs_protocol.h: force
|
||||
$(MAKE) -C $(libsrcdir) guestfs_protocol.h
|
||||
$(top_builddir)/src/guestfs_protocol.c: force
|
||||
$(MAKE) -C $(top_builddir)/src guestfs_protocol.c
|
||||
$(top_builddir)/src/guestfs_protocol.h: force
|
||||
$(MAKE) -C $(top_builddir)/src guestfs_protocol.h
|
||||
|
||||
# Build the errnostring perfect hash code. The generated code has lots
|
||||
# of warnings so we must compile it in a separate mini-library.
|
||||
@@ -70,15 +69,6 @@ errnostring-gperf.c: errnostring-gperf.gperf
|
||||
rm -f $@
|
||||
$(GPERF) -t $< > $@-t
|
||||
mv $@-t $@
|
||||
errnostring-gperf.gperf: $(libsrcdir)/errnostring-gperf.gperf
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
errnostring.c: $(libsrcdir)/errnostring.c
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
errnostring.h: $(libsrcdir)/errnostring.h
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
|
||||
if INSTALL_DAEMON
|
||||
sbin_PROGRAMS = guestfsd
|
||||
@@ -148,6 +138,7 @@ guestfsd_SOURCES = \
|
||||
mktemp.c \
|
||||
modprobe.c \
|
||||
mount.c \
|
||||
mountable.c \
|
||||
names.c \
|
||||
ntfs.c \
|
||||
ntfsclone.c \
|
||||
@@ -158,6 +149,7 @@ guestfsd_SOURCES = \
|
||||
proto.c \
|
||||
readdir.c \
|
||||
realpath.c \
|
||||
rename.c \
|
||||
rsync.c \
|
||||
scrub.c \
|
||||
selinux.c \
|
||||
@@ -169,6 +161,7 @@ guestfsd_SOURCES = \
|
||||
stubs.c \
|
||||
swap.c \
|
||||
sync.c \
|
||||
syslinux.c \
|
||||
tar.c \
|
||||
truncate.c \
|
||||
umask.c \
|
||||
@@ -197,14 +190,20 @@ guestfsd_LDADD = \
|
||||
$(LIBSOCKET) \
|
||||
$(LIB_CLOCK_GETTIME) \
|
||||
$(LIBINTL) \
|
||||
$(SERVENT_LIB)
|
||||
$(SERVENT_LIB) \
|
||||
$(PCRE_LIBS)
|
||||
|
||||
guestfsd_CPPFLAGS = -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
|
||||
guestfsd_CPPFLAGS = \
|
||||
-I$(top_srcdir)/gnulib/lib \
|
||||
-I$(top_builddir)/gnulib/lib \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src
|
||||
guestfsd_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(AUGEAS_CFLAGS) \
|
||||
$(HIVEX_CFLAGS) \
|
||||
$(YAJL_CFLAGS)
|
||||
$(YAJL_CFLAGS) \
|
||||
$(PCRE_CFLAGS)
|
||||
|
||||
# Manual pages and HTML files for the website.
|
||||
man_MANS = guestfsd.8
|
||||
|
||||
@@ -68,7 +68,7 @@ optgroup_augeas_available (void)
|
||||
int
|
||||
do_aug_init (const char *root, int flags)
|
||||
{
|
||||
char *buf;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
|
||||
if (aug) {
|
||||
aug_close (aug);
|
||||
@@ -82,7 +82,6 @@ do_aug_init (const char *root, int flags)
|
||||
}
|
||||
|
||||
aug = aug_init (buf, NULL, flags);
|
||||
free (buf);
|
||||
|
||||
if (!aug) {
|
||||
reply_with_error ("Augeas initialization failed");
|
||||
@@ -338,7 +337,6 @@ char **
|
||||
do_aug_ls (const char *path)
|
||||
{
|
||||
char **matches;
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
NEED_AUG (NULL);
|
||||
@@ -358,6 +356,8 @@ do_aug_ls (const char *path)
|
||||
if (STREQ (path, "/"))
|
||||
matches = do_aug_match ("/*");
|
||||
else {
|
||||
CLEANUP_FREE char *buf;
|
||||
|
||||
len += 3; /* / * + terminating \0 */
|
||||
buf = malloc (len);
|
||||
if (buf == NULL) {
|
||||
@@ -367,7 +367,6 @@ do_aug_ls (const char *path)
|
||||
|
||||
snprintf (buf, len, "%s/*", path);
|
||||
matches = do_aug_match (buf);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
if (matches == NULL)
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
GUESTFSD_EXT_CMD(str_grep, grep);
|
||||
GUESTFSD_EXT_CMD(str_modprobe, modprobe);
|
||||
|
||||
int
|
||||
do_available (char *const *groups)
|
||||
static int
|
||||
available (char *const *groups, int error_on_unavailable)
|
||||
{
|
||||
int av;
|
||||
size_t i, j;
|
||||
@@ -44,8 +44,12 @@ do_available (char *const *groups)
|
||||
if (STREQ (groups[i], optgroups[j].group)) {
|
||||
av = optgroups[j].available ();
|
||||
if (!av) {
|
||||
reply_with_error ("%s: group not available", optgroups[j].group);
|
||||
return -1;
|
||||
if (error_on_unavailable) {
|
||||
reply_with_error ("%s: group not available", optgroups[j].group);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
break; /* out of for (j) loop */
|
||||
}
|
||||
@@ -58,6 +62,23 @@ do_available (char *const *groups)
|
||||
}
|
||||
}
|
||||
|
||||
/* All specified groups available. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
do_feature_available (char *const *groups)
|
||||
{
|
||||
return available (groups, 0);
|
||||
}
|
||||
|
||||
int
|
||||
do_available (char *const *groups)
|
||||
{
|
||||
if (available (groups, 1) == -1)
|
||||
return -1;
|
||||
|
||||
/* No error, so all groups available, just returns no error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -84,7 +105,7 @@ test_proc_filesystems (const char *filesystem)
|
||||
{
|
||||
size_t len = strlen (filesystem) + 32;
|
||||
char regex[len];
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
snprintf (regex, len, "^[[:space:]]*%s$", filesystem);
|
||||
@@ -92,10 +113,8 @@ test_proc_filesystems (const char *filesystem)
|
||||
r = commandr (NULL, &err, str_grep, regex, "/proc/filesystems", NULL);
|
||||
if (r == -1 || r >= 2) {
|
||||
fprintf (stderr, "grep /proc/filesystems: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
@@ -42,7 +45,7 @@ do_base64_in (const char *file)
|
||||
{
|
||||
int err, r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
|
||||
if (asprintf_nowarn (&cmd, "%s -d -i > %R", str_base64, file) == -1) {
|
||||
err = errno;
|
||||
@@ -61,10 +64,8 @@ do_base64_in (const char *file)
|
||||
cancel_receive ();
|
||||
errno = err;
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* The semantics of fwrite are too undefined, so write to the
|
||||
* file descriptor directly instead.
|
||||
@@ -99,12 +100,32 @@ do_base64_in (const char *file)
|
||||
int
|
||||
do_base64_out (const char *file)
|
||||
{
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
struct stat statbuf;
|
||||
int r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char buf[GUESTFS_MAX_CHUNK_SIZE];
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
char buffer[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
if (asprintf_nowarn (&cmd, "%s %R", str_base64, file) == -1) {
|
||||
/* Check the filename exists and is not a directory (RHBZ#908322). */
|
||||
buf = sysroot_path (file);
|
||||
if (buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stat (buf, &statbuf) == -1) {
|
||||
reply_with_perror ("stat: %s", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_error ("%s: is a directory", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Construct the command. */
|
||||
if (asprintf_nowarn (&cmd, "%s %s", str_base64, buf) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
@@ -115,10 +136,8 @@ do_base64_out (const char *file)
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* Now we must send the reply message, before the file contents. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
@@ -126,22 +145,22 @@ do_base64_out (const char *file)
|
||||
*/
|
||||
reply (NULL, NULL);
|
||||
|
||||
while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
|
||||
if (send_file_write (buf, r) < 0) {
|
||||
while ((r = fread (buffer, 1, sizeof buffer, fp)) > 0) {
|
||||
if (send_file_write (buffer, r) < 0) {
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (file);
|
||||
fprintf (stderr, "fread: %s: %m\n", file);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (file);
|
||||
fprintf (stderr, "pclose: %s: %m\n", file);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ GUESTFSD_EXT_CMD(str_blkid, blkid);
|
||||
static char *
|
||||
get_blkid_tag (const char *device, const char *tag)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = commandr (&out, &err,
|
||||
@@ -46,12 +47,9 @@ get_blkid_tag (const char *device, const char *tag)
|
||||
else
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
if (r == 2) { /* means UUID etc not found */
|
||||
free (out);
|
||||
out = strdup ("");
|
||||
@@ -69,21 +67,21 @@ get_blkid_tag (const char *device, const char *tag)
|
||||
}
|
||||
|
||||
char *
|
||||
do_vfs_type (const char *device)
|
||||
do_vfs_type (const mountable_t *mountable)
|
||||
{
|
||||
return get_blkid_tag (device, "TYPE");
|
||||
return get_blkid_tag (mountable->device, "TYPE");
|
||||
}
|
||||
|
||||
char *
|
||||
do_vfs_label (const char *device)
|
||||
do_vfs_label (const mountable_t *mountable)
|
||||
{
|
||||
return get_blkid_tag (device, "LABEL");
|
||||
return get_blkid_tag (mountable->device, "LABEL");
|
||||
}
|
||||
|
||||
char *
|
||||
do_vfs_uuid (const char *device)
|
||||
do_vfs_uuid (const mountable_t *mountable)
|
||||
{
|
||||
return get_blkid_tag (device, "UUID");
|
||||
return get_blkid_tag (mountable->device, "UUID");
|
||||
}
|
||||
|
||||
/* RHEL5 blkid doesn't have the -p (low-level probing) option and the
|
||||
@@ -96,32 +94,27 @@ static int
|
||||
test_blkid_p_i_opt (void)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL, *err2 = NULL;
|
||||
|
||||
r = commandr (NULL, &err, str_blkid, "-p", "/dev/null", NULL);
|
||||
if (r == -1) {
|
||||
/* This means we couldn't run the blkid command at all. */
|
||||
command_failed:
|
||||
reply_with_error ("could not run 'blkid' command: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr (err, "invalid option --")) {
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
free (err);
|
||||
|
||||
r = commandr (NULL, &err, str_blkid, "-i", NULL);
|
||||
r = commandr (NULL, &err2, str_blkid, "-i", NULL);
|
||||
if (r == -1)
|
||||
goto command_failed;
|
||||
|
||||
if (strstr (err, "invalid option --")) {
|
||||
free (err);
|
||||
if (strstr (err2, "invalid option --")) {
|
||||
return 0;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* We have both options. */
|
||||
return 1;
|
||||
@@ -132,8 +125,8 @@ blkid_with_p_i_opt (const char *device)
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **lines = NULL;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
r = command (&out, &err, str_blkid, "-c", "/dev/null",
|
||||
@@ -184,17 +177,9 @@ blkid_with_p_i_opt (const char *device)
|
||||
|
||||
if (end_stringsbuf (&ret) == -1) goto error;
|
||||
|
||||
free (out);
|
||||
free (err);
|
||||
free_strings (lines);
|
||||
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
if (ret.argv)
|
||||
free_strings (ret.argv);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
|
||||
{
|
||||
int r;
|
||||
int64_t rv;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
const char *argv[] = {
|
||||
str_blockdev,
|
||||
switc,
|
||||
@@ -73,8 +73,6 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", argv[0], err);
|
||||
free (err);
|
||||
free (out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -83,15 +81,10 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
|
||||
if (prints) {
|
||||
if (sscanf (out, "%" SCNi64, &rv) != 1) {
|
||||
reply_with_error ("%s: expected output, but got nothing", argv[0]);
|
||||
free (out);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free (out);
|
||||
free (err);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
288
daemon/btrfs.c
288
daemon/btrfs.c
@@ -21,17 +21,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <pcre.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
#include "xstrtol.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_btrfs, btrfs);
|
||||
GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
|
||||
GUESTFSD_EXT_CMD(str_btrfsck, btrfsck);
|
||||
GUESTFSD_EXT_CMD(str_mkfs_btrfs, mkfs.btrfs);
|
||||
GUESTFSD_EXT_CMD(str_umount, umount);
|
||||
|
||||
int
|
||||
optgroup_btrfs_available (void)
|
||||
@@ -44,8 +47,7 @@ int
|
||||
do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
{
|
||||
const size_t MAX_ARGS = 64;
|
||||
char *buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *buf = NULL, *err = NULL;
|
||||
int r;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
@@ -77,15 +79,12 @@ do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", filesystem, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -107,7 +106,7 @@ do_mkfs_btrfs (char *const *devices,
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0, j;
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
char allocstart_s[64];
|
||||
char bytecount_s[64];
|
||||
char leafsize_s[64];
|
||||
@@ -197,14 +196,15 @@ do_mkfs_btrfs (char *const *devices,
|
||||
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
for (j = 0; j < nr_devices; ++j)
|
||||
wipe_device_before_mkfs (devices[j]);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", devices[0], err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ do_btrfs_subvolume_snapshot (const char *source, const char *dest)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *source_buf, *dest_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *source_buf = NULL, *dest_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
source_buf = sysroot_path (source);
|
||||
@@ -226,7 +226,6 @@ do_btrfs_subvolume_snapshot (const char *source, const char *dest)
|
||||
dest_buf = sysroot_path (dest);
|
||||
if (dest_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (source_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -238,14 +237,10 @@ do_btrfs_subvolume_snapshot (const char *source, const char *dest)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (source_buf);
|
||||
free (dest_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", source, dest, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -256,8 +251,8 @@ do_btrfs_subvolume_delete (const char *subvolume)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *subvolume_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *subvolume_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
subvolume_buf = sysroot_path (subvolume);
|
||||
@@ -273,13 +268,10 @@ do_btrfs_subvolume_delete (const char *subvolume)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (subvolume_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", subvolume, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -290,8 +282,8 @@ do_btrfs_subvolume_create (const char *dest)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *dest_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *dest_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
dest_buf = sysroot_path (dest);
|
||||
@@ -307,111 +299,196 @@ do_btrfs_subvolume_create (const char *dest)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (dest_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", dest, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
guestfs_int_btrfssubvolume_list *
|
||||
do_btrfs_subvolume_list (const char *fs)
|
||||
do_btrfs_subvolume_list (const mountable_t *fs)
|
||||
{
|
||||
const size_t MAX_ARGS = 64;
|
||||
guestfs_int_btrfssubvolume_list *ret;
|
||||
char *fs_buf;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *out, *err, **lines, *pos;
|
||||
size_t nr_subvolumes;
|
||||
int r;
|
||||
char **lines;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
/* Execute 'btrfs subvolume list <fs>', and split the output into lines */
|
||||
{
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
|
||||
if (fs->type == MOUNTABLE_PATH) {
|
||||
fs_buf = sysroot_path (fs->device);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
|
||||
cmderror:
|
||||
if (fs->type != MOUNTABLE_PATH && fs_buf) {
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
if (command (NULL, &err, str_umount, fs_buf, NULL) == -1)
|
||||
fprintf (stderr, "%s\n", err);
|
||||
|
||||
if (rmdir (fs_buf) == -1 && errno != ENOENT)
|
||||
fprintf (stderr, "rmdir: %m\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
fs_buf = strdup ("/tmp/btrfs.XXXXXX");
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
goto cmderror;
|
||||
}
|
||||
|
||||
if (mkdtemp (fs_buf) == NULL) {
|
||||
reply_with_perror ("mkdtemp");
|
||||
goto cmderror;
|
||||
}
|
||||
|
||||
if (mount_vfs_nochroot ("", NULL, fs, fs_buf, "<internal>") == -1) {
|
||||
goto cmderror;
|
||||
}
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
ADD_ARG (argv, i, str_btrfs);
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "list");
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
CLEANUP_FREE char *out = NULL, *errout = NULL;
|
||||
int r = commandv (&out, &errout, argv);
|
||||
|
||||
if (fs->type != MOUNTABLE_PATH) {
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
if (command (NULL, &err, str_umount, fs_buf, NULL) == -1) {
|
||||
reply_with_error ("%s", err ? err : "malloc");
|
||||
goto cmderror;
|
||||
}
|
||||
|
||||
if (rmdir (fs_buf) == -1 && errno != ENOENT) {
|
||||
reply_with_error ("rmdir: %m\n");
|
||||
goto cmderror;
|
||||
}
|
||||
}
|
||||
|
||||
if (r == -1) {
|
||||
CLEANUP_FREE char *fs_desc = mountable_to_string (fs);
|
||||
if (fs_desc == NULL) {
|
||||
fprintf (stderr, "malloc: %m");
|
||||
}
|
||||
reply_with_error ("%s: %s", fs_desc ? fs_desc : "malloc", errout);
|
||||
goto cmderror;
|
||||
}
|
||||
|
||||
lines = split_lines (out);
|
||||
if (!lines) return NULL;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, str_btrfs);
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "list");
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (&out, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
lines = split_lines (out);
|
||||
free (out);
|
||||
if (!lines)
|
||||
return NULL;
|
||||
|
||||
/* Output is:
|
||||
*
|
||||
* ID 256 top level 5 path test1
|
||||
* ID 257 top level 5 path dir/test2
|
||||
* ID 258 top level 5 path test3
|
||||
* ID 256 gen 30 top level 5 path test1
|
||||
* ID 257 gen 30 top level 5 path dir/test2
|
||||
* ID 258 gen 30 top level 5 path test3
|
||||
*
|
||||
* "ID <n>" is the subvolume ID. "top level <n>" is the top level
|
||||
* subvolume ID. "path <str>" is the subvolume path, relative to
|
||||
* the top of the filesystem.
|
||||
* "ID <n>" is the subvolume ID.
|
||||
* "gen <n>" is the generation when the root was created or last
|
||||
* updated.
|
||||
* "top level <n>" is the top level subvolume ID.
|
||||
* "path <str>" is the subvolume path, relative to the top of the
|
||||
* filesystem.
|
||||
*
|
||||
* Note that the order that each of the above is fixed, but
|
||||
* different versions of btrfs may display different sets of data.
|
||||
* Specifically, older versions of btrfs do not display gen.
|
||||
*/
|
||||
nr_subvolumes = count_strings (lines);
|
||||
|
||||
guestfs_int_btrfssubvolume_list *ret = NULL;
|
||||
pcre *re = NULL;
|
||||
|
||||
size_t nr_subvolumes = count_strings (lines);
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free_stringslen (lines, nr_subvolumes);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret->guestfs_int_btrfssubvolume_list_len = nr_subvolumes;
|
||||
ret->guestfs_int_btrfssubvolume_list_val =
|
||||
calloc (nr_subvolumes, sizeof (struct guestfs_int_btrfssubvolume));
|
||||
if (ret->guestfs_int_btrfssubvolume_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
free_stringslen (lines, nr_subvolumes);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_subvolumes; ++i) {
|
||||
const char *errptr;
|
||||
int erroffset;
|
||||
re = pcre_compile ("ID\\s+(\\d+).*\\s"
|
||||
"top level\\s+(\\d+).*\\s"
|
||||
"path\\s(.*)",
|
||||
0, &errptr, &erroffset, NULL);
|
||||
if (re == NULL) {
|
||||
reply_with_error ("pcre_compile (%i): %s", erroffset, errptr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nr_subvolumes; ++i) {
|
||||
/* To avoid allocations, reuse the 'line' buffer to store the
|
||||
* path. Thus we don't need to free 'line', since it will be
|
||||
* freed by the calling (XDR) code.
|
||||
*/
|
||||
char *line = lines[i];
|
||||
#define N_MATCHES 4
|
||||
int ovector[N_MATCHES * 3];
|
||||
|
||||
if (sscanf (line, "ID %" SCNu64 " top level %" SCNu64 " path ",
|
||||
&ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_id,
|
||||
&ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_top_level_id) != 2) {
|
||||
if (pcre_exec (re, NULL, line, strlen (line), 0, 0,
|
||||
ovector, N_MATCHES * 3) < 0)
|
||||
#undef N_MATCHES
|
||||
{
|
||||
unexpected_output:
|
||||
reply_with_error ("unexpected output from 'btrfs subvolume list' command: %s", line);
|
||||
free_stringslen (lines, nr_subvolumes);
|
||||
free (ret->guestfs_int_btrfssubvolume_list_val);
|
||||
free (ret);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pos = strstr (line, " path ");
|
||||
if (pos == NULL)
|
||||
goto unexpected_output;
|
||||
pos += 6;
|
||||
struct guestfs_int_btrfssubvolume *this =
|
||||
&ret->guestfs_int_btrfssubvolume_list_val[i];
|
||||
|
||||
memmove (line, pos, strlen (pos) + 1);
|
||||
ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_path = line;
|
||||
#if __WORDSIZE == 64
|
||||
#define XSTRTOU64 xstrtoul
|
||||
#else
|
||||
#define XSTRTOU64 xstrtoull
|
||||
#endif
|
||||
|
||||
if (XSTRTOU64 (line + ovector[2], NULL, 10,
|
||||
&this->btrfssubvolume_id, NULL) != LONGINT_OK)
|
||||
goto unexpected_output;
|
||||
if (XSTRTOU64 (line + ovector[4], NULL, 10,
|
||||
&this->btrfssubvolume_top_level_id, NULL) != LONGINT_OK)
|
||||
goto unexpected_output;
|
||||
|
||||
#undef XSTRTOU64
|
||||
|
||||
memmove (line, line + ovector[6], ovector[7] + 1);
|
||||
this->btrfssubvolume_path = line;
|
||||
}
|
||||
|
||||
free (lines);
|
||||
pcre_free (re);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
free_stringslen (lines, nr_subvolumes);
|
||||
if (ret) free (ret->guestfs_int_btrfssubvolume_list_val);
|
||||
free (ret);
|
||||
if (re) pcre_free (re);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -420,9 +497,9 @@ do_btrfs_subvolume_set_default (int64_t id, const char *fs)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *fs_buf;
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
char buf[64];
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
snprintf (buf, sizeof buf, "%" PRIi64, id);
|
||||
@@ -441,13 +518,10 @@ do_btrfs_subvolume_set_default (int64_t id, const char *fs)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -458,8 +532,8 @@ do_btrfs_filesystem_sync (const char *fs)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
@@ -475,13 +549,10 @@ do_btrfs_filesystem_sync (const char *fs)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -492,8 +563,8 @@ do_btrfs_filesystem_balance (const char *fs)
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
@@ -509,13 +580,10 @@ do_btrfs_filesystem_balance (const char *fs)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -531,8 +599,8 @@ do_btrfs_device_add (char *const *devices, const char *fs)
|
||||
size_t MAX_ARGS = nr_devices + 8;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0, j;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
@@ -552,13 +620,10 @@ do_btrfs_device_add (char *const *devices, const char *fs)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -574,8 +639,8 @@ do_btrfs_device_delete (char *const *devices, const char *fs)
|
||||
size_t MAX_ARGS = nr_devices + 8;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0, j;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *fs_buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
@@ -595,13 +660,10 @@ do_btrfs_device_delete (char *const *devices, const char *fs)
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -609,7 +671,7 @@ do_btrfs_device_delete (char *const *devices, const char *fs)
|
||||
int
|
||||
do_btrfs_set_seeding (const char *device, int svalue)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
const char *s_value = svalue ? "1" : "0";
|
||||
@@ -617,11 +679,9 @@ do_btrfs_set_seeding (const char *device, int svalue)
|
||||
r = commandr (NULL, &err, str_btrfstune, "-S", s_value, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -629,7 +689,7 @@ do_btrfs_set_seeding (const char *device, int svalue)
|
||||
int
|
||||
do_btrfs_fsck (const char *device, int64_t superblock, int repair)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
size_t i = 0;
|
||||
const size_t MAX_ARGS = 64;
|
||||
@@ -661,10 +721,8 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -66,7 +66,8 @@ static char *
|
||||
checksum (const char *csumtype, int fd)
|
||||
{
|
||||
const char *program;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int flags, r;
|
||||
size_t len;
|
||||
|
||||
@@ -84,12 +85,9 @@ checksum (const char *csumtype, int fd)
|
||||
pulse_mode_cancel ();
|
||||
reply_with_error ("%s: %s", program, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
/* Split it at the first whitespace. */
|
||||
len = strcspn (out, " \t\n");
|
||||
out[len] = '\0';
|
||||
@@ -141,7 +139,7 @@ do_checksums_out (const char *csumtype, const char *dir)
|
||||
if (program == NULL)
|
||||
return -1;
|
||||
|
||||
char *sysrootdir = sysroot_path (dir);
|
||||
CLEANUP_FREE char *sysrootdir = sysroot_path (dir);
|
||||
if (!sysrootdir) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
@@ -150,24 +148,19 @@ do_checksums_out (const char *csumtype, const char *dir)
|
||||
r = stat (sysrootdir, &statbuf);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("%s", dir);
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_error ("%s: not a directory", dir);
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
if (asprintf_nowarn (&cmd, "cd %Q && %s -type f -print0 | %s -0 %s",
|
||||
str_find, str_xargs,
|
||||
sysrootdir, program) == -1) {
|
||||
sysrootdir, str_find, str_xargs, program) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
free (sysrootdir);
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
@@ -175,10 +168,8 @@ do_checksums_out (const char *csumtype, const char *dir)
|
||||
FILE *fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* Now we must send the reply message, before the file contents. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
@@ -196,14 +187,14 @@ do_checksums_out (const char *csumtype, const char *dir)
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (dir);
|
||||
fprintf (stderr, "fread: %s: %m\n", dir);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (dir);
|
||||
fprintf (stderr, "pclose: %s: %m\n", dir);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
12
daemon/cmp.c
12
daemon/cmp.c
@@ -32,8 +32,8 @@ GUESTFSD_EXT_CMD(str_cmp, cmp);
|
||||
int
|
||||
do_equal (const char *file1, const char *file2)
|
||||
{
|
||||
char *file1buf, *file2buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *file1buf = NULL, *file2buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
file1buf = sysroot_path (file1);
|
||||
@@ -45,22 +45,14 @@ do_equal (const char *file1, const char *file2)
|
||||
file2buf = sysroot_path (file2);
|
||||
if (file2buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (file1buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = commandr (NULL, &err, str_cmp, "-s", file1buf, file2buf, NULL);
|
||||
|
||||
free (file1buf);
|
||||
free (file2buf);
|
||||
|
||||
if (r == -1 || r > 1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ umount_ignore_fail (const char *path)
|
||||
char *
|
||||
do_command (char *const *argv)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
int r;
|
||||
char *sysroot_dev, *sysroot_dev_pts, *sysroot_proc,
|
||||
*sysroot_selinux, *sysroot_sys;
|
||||
CLEANUP_FREE char *sysroot_dev = NULL, *sysroot_dev_pts = NULL,
|
||||
*sysroot_proc = NULL, *sysroot_selinux = NULL, *sysroot_sys = NULL;
|
||||
int dev_ok, dev_pts_ok, proc_ok, selinux_ok, sys_ok;
|
||||
|
||||
/* We need a root filesystem mounted to do this. */
|
||||
@@ -76,11 +77,6 @@ do_command (char *const *argv)
|
||||
sysroot_proc == NULL || sysroot_selinux == NULL ||
|
||||
sysroot_sys == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (sysroot_dev);
|
||||
free (sysroot_dev_pts);
|
||||
free (sysroot_proc);
|
||||
free (sysroot_selinux);
|
||||
free (sysroot_sys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -105,28 +101,19 @@ do_command (char *const *argv)
|
||||
if (dev_pts_ok) umount_ignore_fail (sysroot_dev_pts);
|
||||
if (dev_ok) umount_ignore_fail (sysroot_dev);
|
||||
|
||||
free (sysroot_dev);
|
||||
free (sysroot_dev_pts);
|
||||
free (sysroot_proc);
|
||||
free (sysroot_selinux);
|
||||
free (sysroot_sys);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out; /* Caller frees. */
|
||||
}
|
||||
|
||||
char **
|
||||
do_command_lines (char *const *argv)
|
||||
{
|
||||
char *out;
|
||||
CLEANUP_FREE char *out = NULL;
|
||||
char **lines;
|
||||
|
||||
out = do_command (argv);
|
||||
@@ -134,7 +121,6 @@ do_command_lines (char *const *argv)
|
||||
return NULL;
|
||||
|
||||
lines = split_lines (out);
|
||||
free (out);
|
||||
|
||||
if (lines == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -39,7 +39,7 @@ do_compressX_out (const char *file, const char *filter, int is_device)
|
||||
{
|
||||
int r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
char buf[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
/* The command will look something like:
|
||||
@@ -71,10 +71,8 @@ do_compressX_out (const char *file, const char *filter, int is_device)
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* Now we must send the reply message, before the file contents. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
@@ -90,14 +88,14 @@ do_compressX_out (const char *file, const char *filter, int is_device)
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (file);
|
||||
fprintf (stderr, "fread: %s: %m\n", file);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (file);
|
||||
fprintf (stderr, "pclose: %s: %m\n", file);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
@@ -111,7 +109,7 @@ do_compressX_out (const char *file, const char *filter, int is_device)
|
||||
#define CHECK_SUPPORTED(prog) \
|
||||
if (!prog_exists (prog)) \
|
||||
/* note: substring "not supported" must appear in this error */ \
|
||||
NOT_SUPPORTED (-1, "compression type %s is not supported", prog);
|
||||
NOT_SUPPORTED (-1, "compression type %s is not supported, because external program '%s' is not available in the appliance", prog, prog);
|
||||
|
||||
static int
|
||||
get_filter (const char *ctype, int level, char *ret, size_t n)
|
||||
|
||||
@@ -42,13 +42,14 @@ static int
|
||||
copy (const char *src, const char *src_display,
|
||||
const char *dest, const char *dest_display,
|
||||
int wrflags, int wrmode,
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size)
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size, int sparse)
|
||||
{
|
||||
int64_t saved_size = size;
|
||||
int src_fd, dest_fd;
|
||||
char buf[BUFSIZ];
|
||||
size_t n;
|
||||
ssize_t r;
|
||||
int err;
|
||||
|
||||
if ((optargs_bitmask & GUESTFS_COPY_DEVICE_TO_DEVICE_SRCOFFSET_BITMASK)) {
|
||||
if (srcoffset < 0) {
|
||||
@@ -77,6 +78,9 @@ copy (const char *src, const char *src_display,
|
||||
else
|
||||
size = -1;
|
||||
|
||||
if (! (optargs_bitmask & GUESTFS_COPY_DEVICE_TO_DEVICE_SPARSE_BITMASK))
|
||||
sparse = 0;
|
||||
|
||||
/* Open source and destination. */
|
||||
src_fd = open (src, O_RDONLY|O_CLOEXEC);
|
||||
if (src_fd == -1) {
|
||||
@@ -116,8 +120,10 @@ copy (const char *src, const char *src_display,
|
||||
|
||||
r = read (src_fd, buf, n);
|
||||
if (r == -1) {
|
||||
err = errno;
|
||||
if (size == -1)
|
||||
pulse_mode_cancel ();
|
||||
errno = err;
|
||||
reply_with_perror ("read: %s", src_display);
|
||||
close (src_fd);
|
||||
close (dest_fd);
|
||||
@@ -133,14 +139,31 @@ copy (const char *src, const char *src_display,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sparse && is_zero (buf, r)) {
|
||||
if (lseek (dest_fd, r, SEEK_CUR) == -1) {
|
||||
err = errno;
|
||||
if (size == -1)
|
||||
pulse_mode_cancel ();
|
||||
errno = err;
|
||||
reply_with_perror ("%s: seek (because of sparse flag)", dest_display);
|
||||
close (src_fd);
|
||||
close (dest_fd);
|
||||
return -1;
|
||||
}
|
||||
goto sparse_skip;
|
||||
}
|
||||
|
||||
if (xwrite (dest_fd, buf, r) == -1) {
|
||||
err = errno;
|
||||
if (size == -1)
|
||||
pulse_mode_cancel ();
|
||||
errno = err;
|
||||
reply_with_perror ("%s: write", dest_display);
|
||||
close (src_fd);
|
||||
close (dest_fd);
|
||||
return -1;
|
||||
}
|
||||
sparse_skip:
|
||||
|
||||
if (size != -1) {
|
||||
size -= r;
|
||||
@@ -167,58 +190,51 @@ copy (const char *src, const char *src_display,
|
||||
|
||||
int
|
||||
do_copy_device_to_device (const char *src, const char *dest,
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size)
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size,
|
||||
int sparse)
|
||||
{
|
||||
return copy (src, src, dest, dest, DEST_DEVICE_FLAGS,
|
||||
srcoffset, destoffset, size);
|
||||
srcoffset, destoffset, size, sparse);
|
||||
}
|
||||
|
||||
int
|
||||
do_copy_device_to_file (const char *src, const char *dest,
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size)
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size,
|
||||
int sparse)
|
||||
{
|
||||
char *dest_buf;
|
||||
int r;
|
||||
CLEANUP_FREE char *dest_buf = sysroot_path (dest);
|
||||
|
||||
dest_buf = sysroot_path (dest);
|
||||
if (!dest_buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = copy (src, src, dest_buf, dest, DEST_FILE_FLAGS,
|
||||
srcoffset, destoffset, size);
|
||||
free (dest_buf);
|
||||
|
||||
return r;
|
||||
return copy (src, src, dest_buf, dest, DEST_FILE_FLAGS,
|
||||
srcoffset, destoffset, size, sparse);
|
||||
}
|
||||
|
||||
int
|
||||
do_copy_file_to_device (const char *src, const char *dest,
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size)
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size,
|
||||
int sparse)
|
||||
{
|
||||
char *src_buf;
|
||||
int r;
|
||||
CLEANUP_FREE char *src_buf = sysroot_path (src);
|
||||
|
||||
src_buf = sysroot_path (src);
|
||||
if (!src_buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = copy (src_buf, src, dest, dest, DEST_DEVICE_FLAGS,
|
||||
srcoffset, destoffset, size);
|
||||
free (src_buf);
|
||||
|
||||
return r;
|
||||
return copy (src_buf, src, dest, dest, DEST_DEVICE_FLAGS,
|
||||
srcoffset, destoffset, size, sparse);
|
||||
}
|
||||
|
||||
int
|
||||
do_copy_file_to_file (const char *src, const char *dest,
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size)
|
||||
int64_t srcoffset, int64_t destoffset, int64_t size,
|
||||
int sparse)
|
||||
{
|
||||
char *src_buf, *dest_buf;
|
||||
int r;
|
||||
CLEANUP_FREE char *src_buf = NULL, *dest_buf = NULL;
|
||||
|
||||
src_buf = sysroot_path (src);
|
||||
if (!src_buf) {
|
||||
@@ -229,14 +245,9 @@ do_copy_file_to_file (const char *src, const char *dest,
|
||||
dest_buf = sysroot_path (dest);
|
||||
if (!dest_buf) {
|
||||
reply_with_perror ("malloc");
|
||||
free (src_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = copy (src_buf, src, dest_buf, dest, DEST_FILE_FLAGS,
|
||||
srcoffset, destoffset, size);
|
||||
free (src_buf);
|
||||
free (dest_buf);
|
||||
|
||||
return r;
|
||||
return copy (src_buf, src, dest_buf, dest, DEST_FILE_FLAGS,
|
||||
srcoffset, destoffset, size, sparse);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -51,8 +51,8 @@ do_mv (const char *src, const char *dest)
|
||||
static int
|
||||
cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest)
|
||||
{
|
||||
char *srcbuf, *destbuf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *srcbuf = NULL, *destbuf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
srcbuf = sysroot_path (src);
|
||||
@@ -64,7 +64,6 @@ cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest)
|
||||
destbuf = sysroot_path (dest);
|
||||
if (destbuf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (srcbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -75,16 +74,11 @@ cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest)
|
||||
else
|
||||
r = command (NULL, &err, cmd, srcbuf, destbuf, NULL);
|
||||
|
||||
free (srcbuf);
|
||||
free (destbuf);
|
||||
|
||||
if (r == -1) {
|
||||
pulse_mode_cancel ();
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
pulse_mode_end ();
|
||||
|
||||
|
||||
121
daemon/daemon.h
121
daemon/daemon.h
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,16 @@
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
|
||||
#include "guestfs-internal-all.h"
|
||||
|
||||
/* Mountables */
|
||||
|
||||
typedef struct {
|
||||
mountable_type_t type;
|
||||
const char *device;
|
||||
const char *volume;
|
||||
} mountable_t;
|
||||
|
||||
/*-- in guestfsd.c --*/
|
||||
extern int verbose;
|
||||
|
||||
@@ -47,6 +57,14 @@ extern int xwrite (int sock, const void *buf, size_t len)
|
||||
extern int xread (int sock, void *buf, size_t len)
|
||||
__attribute__((__warn_unused_result__));
|
||||
|
||||
extern char *mountable_to_string (const mountable_t *mountable);
|
||||
|
||||
/*-- in mount.c --*/
|
||||
|
||||
extern int mount_vfs_nochroot (const char *options, const char *vfstype,
|
||||
const mountable_t *mountable,
|
||||
const char *mp, const char *user_mp);
|
||||
|
||||
/* Growable strings buffer. */
|
||||
struct stringsbuf {
|
||||
char **argv;
|
||||
@@ -100,9 +118,9 @@ extern char **split_lines (char *str);
|
||||
#define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
|
||||
|
||||
extern int commandf (char **stdoutput, char **stderror, int flags,
|
||||
const char *name, ...);
|
||||
const char *name, ...) __attribute__((sentinel));
|
||||
extern int commandrf (char **stdoutput, char **stderror, int flags,
|
||||
const char *name, ...);
|
||||
const char *name, ...) __attribute__((sentinel));
|
||||
extern int commandvf (char **stdoutput, char **stderror, int flags,
|
||||
char const *const *argv);
|
||||
extern int commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
@@ -114,6 +132,8 @@ extern void trim (char *str);
|
||||
|
||||
extern int device_name_translation (char *device);
|
||||
|
||||
extern int parse_btrfsvol (char *desc, mountable_t *mountable);
|
||||
|
||||
extern int prog_exists (const char *prog);
|
||||
|
||||
extern void udev_settle (void);
|
||||
@@ -122,8 +142,13 @@ extern int random_name (char *template);
|
||||
|
||||
/* This just stops gcc from giving a warning about our custom printf
|
||||
* formatters %Q and %R. See guestfs(3)/EXTENDING LIBGUESTFS for more
|
||||
* info about these.
|
||||
* info about these. In GCC 4.8.0 the warning is even harder to
|
||||
* 'trick', hence the need for the #pragma directives.
|
||||
*/
|
||||
#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 40800 /* gcc >= 4.8.0 */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
|
||||
#endif
|
||||
static inline int
|
||||
asprintf_nowarn (char **strp, const char *fmt, ...)
|
||||
{
|
||||
@@ -135,6 +160,14 @@ asprintf_nowarn (char **strp, const char *fmt, ...)
|
||||
va_end (args);
|
||||
return r;
|
||||
}
|
||||
#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 40800 /* gcc >= 4.8.0 */
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/* Use by the CLEANUP_* macros. */
|
||||
extern void cleanup_free (void *ptr);
|
||||
extern void cleanup_free_string_list (void *ptr);
|
||||
extern void cleanup_unlink_free (void *ptr);
|
||||
|
||||
/*-- in names.c (auto-generated) --*/
|
||||
extern const char *function_names[];
|
||||
@@ -179,6 +212,9 @@ extern int lv_canonical (const char *device, char **ret);
|
||||
/*-- in lvm-filter.c --*/
|
||||
extern void copy_lvm (void);
|
||||
|
||||
/*-- in zero.c --*/
|
||||
extern void wipe_device_before_mkfs (const char *device);
|
||||
|
||||
/*-- in proto.c --*/
|
||||
extern void main_loop (int sock) __attribute__((noreturn));
|
||||
|
||||
@@ -237,6 +273,11 @@ extern void pulse_mode_start (void);
|
||||
extern void pulse_mode_end (void);
|
||||
extern void pulse_mode_cancel (void);
|
||||
|
||||
/* Send a progress message without rate-limiting. This is just
|
||||
* for debugging - DON'T use it in regular code!
|
||||
*/
|
||||
extern void notify_progress_no_ratelimit (uint64_t position, uint64_t total, const struct timeval *now);
|
||||
|
||||
/* Return true iff the buffer is all zero bytes.
|
||||
*
|
||||
* Note that gcc is smart enough to optimize this properly:
|
||||
@@ -320,6 +361,33 @@ is_zero (const char *buffer, size_t size)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* All functions that take a mountable argument must call this macro.
|
||||
* It parses the mountable into a mountable_t, ensures any
|
||||
* underlying device exists, and does device name translation
|
||||
* (described in the guestfs(3) manpage).
|
||||
*
|
||||
* Note that the "string" argument may be modified.
|
||||
*/
|
||||
#define RESOLVE_MOUNTABLE(string,mountable,cancel_stmt,fail_stmt) \
|
||||
do { \
|
||||
if (STRPREFIX ((string), "btrfsvol:")) { \
|
||||
if (parse_btrfsvol ((string) + strlen ("btrfsvol:"), &(mountable)) == -1)\
|
||||
{ \
|
||||
cancel_stmt; \
|
||||
reply_with_error ("%s: %s: expecting a btrfs volume", \
|
||||
__func__, (string)); \
|
||||
fail_stmt; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
else { \
|
||||
(mountable).type = MOUNTABLE_DEVICE; \
|
||||
(mountable).device = (string); \
|
||||
(mountable).volume = NULL; \
|
||||
RESOLVE_DEVICE((string), cancel_stmt, fail_stmt); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Helper for functions which need either an absolute path in the
|
||||
* mounted filesystem, OR a /dev/ device which exists.
|
||||
*
|
||||
@@ -340,6 +408,24 @@ is_zero (const char *buffer, size_t size)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Helper for functions which need either an absolute path in the
|
||||
* mounted filesystem, OR a valid mountable description.
|
||||
*/
|
||||
#define REQUIRE_ROOT_OR_RESOLVE_MOUNTABLE(string, mountable, \
|
||||
cancel_stmt, fail_stmt) \
|
||||
do { \
|
||||
if (STREQLEN ((string), "/dev/", strlen ("/dev/")) || (string)[0] != '/') {\
|
||||
RESOLVE_MOUNTABLE (string, mountable, cancel_stmt, fail_stmt); \
|
||||
} \
|
||||
\
|
||||
else { \
|
||||
NEED_ROOT (cancel_stmt, fail_stmt); \
|
||||
(mountable).type = MOUNTABLE_PATH; \
|
||||
(mountable).device = (string); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
|
||||
/* NB:
|
||||
* (1) You must match CHROOT_IN and CHROOT_OUT even along error paths.
|
||||
* (2) You must not change directory! cwd must always be "/", otherwise
|
||||
@@ -384,24 +470,15 @@ is_zero (const char *buffer, size_t size)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#ifndef __attribute__
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
|
||||
# define __attribute__(x) /* empty */
|
||||
# endif
|
||||
#ifdef HAVE_ATTRIBUTE_CLEANUP
|
||||
#define CLEANUP_FREE __attribute__((cleanup(cleanup_free)))
|
||||
#define CLEANUP_FREE_STRING_LIST \
|
||||
__attribute__((cleanup(cleanup_free_string_list)))
|
||||
#define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
|
||||
#else
|
||||
#define CLEANUP_FREE
|
||||
#define CLEANUP_FREE_STRING_LIST
|
||||
#define CLEANUP_UNLINK_FREE
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#define STREQ(a,b) (strcmp((a),(b)) == 0)
|
||||
#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
|
||||
#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
|
||||
#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
|
||||
#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
|
||||
#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
|
||||
#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
|
||||
#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
|
||||
#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
|
||||
|
||||
#endif /* GUESTFSD_DAEMON_H */
|
||||
|
||||
17
daemon/dd.c
17
daemon/dd.c
@@ -33,8 +33,8 @@ int
|
||||
do_dd (const char *src, const char *dest)
|
||||
{
|
||||
int src_is_dev, dest_is_dev;
|
||||
char *if_arg, *of_arg;
|
||||
char *err;
|
||||
CLEANUP_FREE char *if_arg = NULL, *of_arg = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
src_is_dev = STRPREFIX (src, "/dev/");
|
||||
@@ -56,20 +56,14 @@ do_dd (const char *src, const char *dest)
|
||||
r = asprintf (&of_arg, "of=%s%s", sysroot, dest);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free (if_arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &err, str_dd, "bs=1024K", if_arg, of_arg, NULL);
|
||||
free (if_arg);
|
||||
free (of_arg);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", src, dest, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -77,19 +71,17 @@ do_dd (const char *src, const char *dest)
|
||||
int
|
||||
do_copy_size (const char *src, const char *dest, int64_t ssize)
|
||||
{
|
||||
char *buf;
|
||||
int src_fd, dest_fd;
|
||||
|
||||
if (STRPREFIX (src, "/dev/"))
|
||||
src_fd = open (src, O_RDONLY | O_CLOEXEC);
|
||||
else {
|
||||
buf = sysroot_path (src);
|
||||
CLEANUP_FREE char *buf = sysroot_path (src);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
src_fd = open (buf, O_RDONLY | O_CLOEXEC);
|
||||
free (buf);
|
||||
}
|
||||
if (src_fd == -1) {
|
||||
reply_with_perror ("%s", src);
|
||||
@@ -99,14 +91,13 @@ do_copy_size (const char *src, const char *dest, int64_t ssize)
|
||||
if (STRPREFIX (dest, "/dev/"))
|
||||
dest_fd = open (dest, O_WRONLY | O_CLOEXEC);
|
||||
else {
|
||||
buf = sysroot_path (dest);
|
||||
CLEANUP_FREE char *buf = sysroot_path (dest);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
close (src_fd);
|
||||
return -1;
|
||||
}
|
||||
dest_fd = open (buf, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
free (buf);
|
||||
}
|
||||
if (dest_fd == -1) {
|
||||
reply_with_perror ("%s", dest);
|
||||
|
||||
202
daemon/debug.c
202
daemon/debug.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -72,6 +73,8 @@ static char *debug_qtrace (const char *subcmd, size_t argc, char *const *const a
|
||||
static char *debug_segv (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_setenv (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_sh (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_spew (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static void deliberately_cause_a_segfault (void);
|
||||
|
||||
static struct cmd cmds[] = {
|
||||
{ "help", debug_help },
|
||||
@@ -87,6 +90,7 @@ static struct cmd cmds[] = {
|
||||
{ "segv", debug_segv },
|
||||
{ "setenv", debug_setenv },
|
||||
{ "sh", debug_sh },
|
||||
{ "spew", debug_spew },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -209,13 +213,7 @@ debug_fds (const char *subcmd, size_t argc, char *const *const argv)
|
||||
static char *
|
||||
debug_segv (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
/* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
|
||||
* "Dereferencing a NULL Pointer: contrary to popular belief,
|
||||
* dereferencing a null pointer in C is undefined. It is not defined
|
||||
* to trap [...]"
|
||||
*/
|
||||
volatile int *ptr = NULL;
|
||||
*ptr = 1;
|
||||
deliberately_cause_a_segfault ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -227,7 +225,7 @@ debug_segv (const char *subcmd, size_t argc, char *const *const argv)
|
||||
static char *
|
||||
debug_sh (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
size_t len, i, j;
|
||||
|
||||
if (argc < 1) {
|
||||
@@ -266,8 +264,6 @@ debug_sh (const char *subcmd, size_t argc, char *const *const argv)
|
||||
char *err;
|
||||
int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
|
||||
"/bin/sh", "-c", cmd, NULL);
|
||||
free (cmd);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -282,18 +278,16 @@ static char *
|
||||
debug_env (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
r = command (&out, &err, str_printenv, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("printenv: %s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -326,7 +320,8 @@ static char *
|
||||
debug_binaries (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
char cmd[256];
|
||||
|
||||
snprintf (cmd, sizeof (cmd),
|
||||
@@ -340,12 +335,9 @@ debug_binaries (const char *subcmd, size_t argc, char *const *const argv)
|
||||
if (r == -1) {
|
||||
reply_with_error ("find: %s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -356,7 +348,8 @@ static char *
|
||||
debug_ldd (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err, *ret;
|
||||
char *out, *ret;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
if (argc != 1) {
|
||||
reply_with_error ("ldd: no file argument");
|
||||
@@ -373,7 +366,6 @@ debug_ldd (const char *subcmd, size_t argc, char *const *const argv)
|
||||
if (r == -1) {
|
||||
reply_with_error ("ldd: %s: %s", argv[0], err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -382,12 +374,10 @@ debug_ldd (const char *subcmd, size_t argc, char *const *const argv)
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("realloc");
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcat (ret, err);
|
||||
free (err);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -399,6 +389,9 @@ debug_ls (const char *subcmd, size_t argc, char *const *const argv)
|
||||
size_t len = count_strings (argv);
|
||||
const char *cargv[len+3];
|
||||
size_t i;
|
||||
int r;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
|
||||
cargv[0] = str_ls;
|
||||
cargv[1] = "-a";
|
||||
@@ -406,19 +399,13 @@ debug_ls (const char *subcmd, size_t argc, char *const *const argv)
|
||||
cargv[2+i] = argv[i];
|
||||
cargv[2+len] = NULL;
|
||||
|
||||
int r;
|
||||
char *out, *err;
|
||||
|
||||
r = commandv (&out, &err, (void *) cargv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("ls: %s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -429,6 +416,9 @@ debug_ll (const char *subcmd, size_t argc, char *const *const argv)
|
||||
size_t len = count_strings (argv);
|
||||
const char *cargv[len+3];
|
||||
size_t i;
|
||||
int r;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
|
||||
cargv[0] = str_ls;
|
||||
cargv[1] = "-la";
|
||||
@@ -436,19 +426,13 @@ debug_ll (const char *subcmd, size_t argc, char *const *const argv)
|
||||
cargv[2+i] = argv[i];
|
||||
cargv[2+len] = NULL;
|
||||
|
||||
int r;
|
||||
char *out, *err;
|
||||
|
||||
r = commandv (&out, &err, (void *) cargv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("ll: %s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -456,29 +440,56 @@ debug_ll (const char *subcmd, size_t argc, char *const *const argv)
|
||||
static char *
|
||||
debug_progress (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
uint64_t secs, rate = 0;
|
||||
char *ret;
|
||||
|
||||
if (argc < 1) {
|
||||
error:
|
||||
reply_with_error ("progress: expecting arg (time in seconds as string)");
|
||||
reply_with_error ("progress: expecting one or more args: time in seconds [, rate in microseconds]");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *secs_str = argv[0];
|
||||
unsigned secs;
|
||||
if (sscanf (secs_str, "%u", &secs) != 1)
|
||||
if (sscanf (argv[0], "%" SCNu64, &secs) != 1)
|
||||
goto error;
|
||||
if (secs == 0 || secs > 1000000) { /* RHBZ#816839 */
|
||||
reply_with_error ("progress: argument is 0, less than 0, or too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
unsigned tsecs = secs * 10; /* 1/10ths of seconds */
|
||||
for (i = 1; i <= tsecs; ++i) {
|
||||
usleep (100000);
|
||||
notify_progress ((uint64_t) i, (uint64_t) tsecs);
|
||||
if (argc >= 2) {
|
||||
if (sscanf (argv[1], "%" SCNu64, &rate) != 1)
|
||||
goto error;
|
||||
if (rate == 0 || rate > 1000000) {
|
||||
reply_with_error ("progress: rate is 0 or too large");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *ret = strdup ("ok");
|
||||
/* Note the inner loops go to '<= limit' because we want to ensure
|
||||
* that the final 100% completed message is set.
|
||||
*/
|
||||
if (rate == 0) { /* Ordinary rate-limited progress messages. */
|
||||
uint64_t tsecs = secs * 10; /* 1/10ths of seconds */
|
||||
uint64_t i;
|
||||
|
||||
for (i = 1; i <= tsecs; ++i) {
|
||||
usleep (100000);
|
||||
notify_progress (i, tsecs);
|
||||
}
|
||||
}
|
||||
else { /* Send messages at a given rate. */
|
||||
uint64_t usecs = secs * 1000000; /* microseconds */
|
||||
uint64_t i;
|
||||
struct timeval now;
|
||||
|
||||
for (i = rate; i <= usecs; i += rate) {
|
||||
usleep (rate);
|
||||
gettimeofday (&now, NULL);
|
||||
notify_progress_no_ratelimit (i, usecs, &now);
|
||||
}
|
||||
}
|
||||
|
||||
ret = strdup ("ok");
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
@@ -538,6 +549,42 @@ debug_core_pattern (const char *subcmd, size_t argc, char *const *const argv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Generate lots of debug messages. Each line of output is 72
|
||||
* characters long (plus '\n'), so the total size of the output in
|
||||
* bytes is n*73.
|
||||
*/
|
||||
static char *
|
||||
debug_spew (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
size_t i, n;
|
||||
char *ret;
|
||||
|
||||
if (argc != 1) {
|
||||
reply_with_error ("spew: expecting number of lines <n>");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sscanf (argv[0], "%zu", &n) != 1) {
|
||||
reply_with_error ("spew: could not parse number of lines '%s'", argv[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
fprintf (stderr,
|
||||
"abcdefghijklmnopqrstuvwxyz" /* 26 */
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 52 */
|
||||
"01234567890123456789" /* 72 */
|
||||
"\n");
|
||||
|
||||
ret = strdup ("ok");
|
||||
if (!ret) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
write_cb (void *fd_ptr, const void *buf, size_t len)
|
||||
{
|
||||
@@ -589,12 +636,13 @@ debug_qtrace (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{ 2, 15, 21, 2, -1 }, /* disable trace */
|
||||
{ 2, 21, 15, 2, -1 } /* enable trace */
|
||||
};
|
||||
void *buf;
|
||||
CLEANUP_FREE void *buf = NULL;
|
||||
size_t i;
|
||||
|
||||
/* For O_DIRECT, buffer must be aligned too (thanks Matt).
|
||||
* Note posix_memalign has this strange errno behaviour.
|
||||
*/
|
||||
/* coverity[resource_leak] */
|
||||
errno = posix_memalign (&buf, QTRACE_SIZE, QTRACE_SIZE);
|
||||
if (errno != 0) {
|
||||
reply_with_perror ("posix_memalign");
|
||||
@@ -606,20 +654,17 @@ debug_qtrace (const char *subcmd, size_t argc, char *const *const argv)
|
||||
if (lseek (fd, patterns[enable][i]*QTRACE_SIZE, SEEK_SET) == -1) {
|
||||
reply_with_perror ("qtrace: %s: lseek", argv[0]);
|
||||
close (fd);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (read (fd, buf, QTRACE_SIZE) == -1) {
|
||||
reply_with_perror ("qtrace: %s: read", argv[0]);
|
||||
close (fd);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
close (fd);
|
||||
free (buf);
|
||||
|
||||
/* This does a sync and flushes all caches. */
|
||||
if (do_drop_caches (3) == -1)
|
||||
@@ -676,3 +721,64 @@ do_debug_upload (const char *filename, int mode)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Internal function used only when testing
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=914931
|
||||
*/
|
||||
|
||||
static int
|
||||
crash_cb (void *countv, const void *buf, size_t len)
|
||||
{
|
||||
int *countp = countv;
|
||||
|
||||
(*countp)--;
|
||||
sleep (1);
|
||||
|
||||
if (*countp == 0)
|
||||
deliberately_cause_a_segfault ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Has one FileIn parameter. */
|
||||
int
|
||||
do_internal_rhbz914931 (int count)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (count <= 0 || count > 1000) {
|
||||
reply_with_error ("count out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = receive_file (crash_cb, &count);
|
||||
if (r == -1) { /* write error */
|
||||
int err = errno;
|
||||
cancel_receive ();
|
||||
errno = err;
|
||||
reply_with_error ("write error");
|
||||
return -1;
|
||||
}
|
||||
if (r == -2) { /* cancellation from library */
|
||||
/* This error is ignored by the library since it initiated the
|
||||
* cancel. Nevertheless we must send an error reply here.
|
||||
*/
|
||||
reply_with_error ("file upload cancelled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
deliberately_cause_a_segfault (void)
|
||||
{
|
||||
/* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
|
||||
* "Dereferencing a NULL Pointer: contrary to popular belief,
|
||||
* dereferencing a null pointer in C is undefined. It is not defined
|
||||
* to trap [...]"
|
||||
*/
|
||||
volatile int *ptr = NULL;
|
||||
/* coverity[var_deref_op] */
|
||||
*ptr = 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -244,42 +244,62 @@ do_part_to_partnum (const char *part)
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_is_whole_device (const char *device)
|
||||
{
|
||||
/* A 'whole' block device will have a symlink to the device in its
|
||||
* /sys/block directory */
|
||||
CLEANUP_FREE char *devpath = NULL;
|
||||
if (asprintf (&devpath, "/sys/block/%s/device",
|
||||
device + strlen ("/dev/")) == -1)
|
||||
{
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct stat statbuf;
|
||||
if (stat (devpath, &statbuf) == -1) {
|
||||
if (errno == ENOENT || errno == ENOTDIR) return 0;
|
||||
|
||||
reply_with_perror ("stat");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
do_device_index (const char *device)
|
||||
{
|
||||
char **devices;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
CLEANUP_FREE_STRING_LIST char **devices = do_list_devices ();
|
||||
|
||||
devices = do_list_devices ();
|
||||
if (devices == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
if (STREQ (device, devices[i]))
|
||||
ret = (int) i;
|
||||
free (devices[i]);
|
||||
}
|
||||
free (devices);
|
||||
|
||||
if (ret == -1)
|
||||
reply_with_error ("device not found");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
do_nr_devices (void)
|
||||
{
|
||||
char **devices;
|
||||
size_t i;
|
||||
CLEANUP_FREE_STRING_LIST char **devices = do_list_devices ();
|
||||
|
||||
devices = do_list_devices ();
|
||||
if (devices == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i)
|
||||
free (devices[i]);
|
||||
free (devices);
|
||||
;
|
||||
|
||||
return (int) i;
|
||||
}
|
||||
@@ -291,7 +311,7 @@ do_list_disk_labels (void)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
struct dirent *d;
|
||||
char *path = NULL, *rawdev = NULL;
|
||||
char *rawdev = NULL;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
dir = opendir (GUESTFSDIR);
|
||||
@@ -302,6 +322,8 @@ do_list_disk_labels (void)
|
||||
|
||||
errno = 0;
|
||||
while ((d = readdir (dir)) != NULL) {
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
|
||||
if (d->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
@@ -318,9 +340,6 @@ do_list_disk_labels (void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
free (path);
|
||||
path = NULL;
|
||||
|
||||
if (add_string (&ret, d->d_name) == -1)
|
||||
goto error;
|
||||
|
||||
@@ -354,7 +373,6 @@ do_list_disk_labels (void)
|
||||
error:
|
||||
if (dir)
|
||||
closedir (dir);
|
||||
free (path);
|
||||
free (rawdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
12
daemon/df.c
12
daemon/df.c
@@ -33,7 +33,8 @@ char *
|
||||
do_df (void)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
NEED_ROOT (, return NULL);
|
||||
|
||||
@@ -41,12 +42,9 @@ do_df (void)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out; /* Caller frees. */
|
||||
}
|
||||
|
||||
@@ -54,7 +52,8 @@ char *
|
||||
do_df_h (void)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
NEED_ROOT (, return NULL);
|
||||
|
||||
@@ -62,11 +61,8 @@ do_df_h (void)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out; /* Caller frees. */
|
||||
}
|
||||
|
||||
12
daemon/dir.c
12
daemon/dir.c
@@ -56,7 +56,7 @@ int
|
||||
do_rm_rf (const char *path)
|
||||
{
|
||||
int r;
|
||||
char *buf, *err;
|
||||
CLEANUP_FREE char *buf = NULL, *err = NULL;
|
||||
|
||||
if (STREQ (path, "/")) {
|
||||
reply_with_error ("cannot remove root directory");
|
||||
@@ -70,17 +70,12 @@ do_rm_rf (const char *path)
|
||||
}
|
||||
|
||||
r = command (NULL, &err, str_rm, "-rf", buf, NULL);
|
||||
free (buf);
|
||||
|
||||
/* rm -rf is never supposed to fail. I/O errors perhaps? */
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", path, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -133,7 +128,7 @@ recursive_mkdir (const char *path)
|
||||
{
|
||||
int loop = 0;
|
||||
int r;
|
||||
char *ppath, *p;
|
||||
char *p;
|
||||
struct stat buf;
|
||||
|
||||
again:
|
||||
@@ -153,14 +148,13 @@ recursive_mkdir (const char *path)
|
||||
if (path[0] == '/' && path[1] == '\0') return -1;
|
||||
|
||||
/* Try to make the parent directory first. */
|
||||
ppath = strdup (path);
|
||||
CLEANUP_FREE char *ppath = strdup (path);
|
||||
if (ppath == NULL) return -1;
|
||||
|
||||
p = strrchr (ppath, '/');
|
||||
if (p) *p = '\0';
|
||||
|
||||
r = recursive_mkdir (ppath);
|
||||
free (ppath);
|
||||
|
||||
if (r != 0) return r;
|
||||
|
||||
|
||||
@@ -32,17 +32,16 @@ GUESTFSD_EXT_CMD(str_dmesg, dmesg);
|
||||
char *
|
||||
do_dmesg (void)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (&out, &err, str_dmesg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
13
daemon/du.c
13
daemon/du.c
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,8 +35,7 @@ do_du (const char *path)
|
||||
{
|
||||
int r;
|
||||
int64_t rv;
|
||||
char *out, *err;
|
||||
char *buf;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL, *buf = NULL;
|
||||
|
||||
/* Make the path relative to /sysroot. */
|
||||
buf = sysroot_path (path);
|
||||
@@ -48,26 +47,18 @@ do_du (const char *path)
|
||||
pulse_mode_start ();
|
||||
|
||||
r = command (&out, &err, str_du, "-s", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
pulse_mode_cancel ();
|
||||
reply_with_error ("%s: %s", path, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
if (sscanf (out, "%"SCNi64, &rv) != 1) {
|
||||
pulse_mode_cancel ();
|
||||
reply_with_error ("%s: could not read output: %s", path, out);
|
||||
free (out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (out);
|
||||
|
||||
pulse_mode_end ();
|
||||
|
||||
return rv;
|
||||
|
||||
@@ -50,7 +50,7 @@ do_echo_daemon (char *const *argv)
|
||||
char *out_new = realloc (out, out_len + 1);
|
||||
if (NULL == out_new) {
|
||||
reply_with_perror ("realloc");
|
||||
free(out);
|
||||
free (out);
|
||||
return 0;
|
||||
}
|
||||
out = out_new;
|
||||
|
||||
184
daemon/ext2.c
184
daemon/ext2.c
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -42,18 +42,15 @@ char **
|
||||
do_tune2fs_l (const char *device)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
char *p, *pend, *colon;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
r = command (&out, &err, str_tune2fs, "-l", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
p = out;
|
||||
|
||||
@@ -63,7 +60,6 @@ do_tune2fs_l (const char *device)
|
||||
if (p) p++;
|
||||
else {
|
||||
reply_with_error ("truncated output");
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -85,30 +81,25 @@ do_tune2fs_l (const char *device)
|
||||
do { colon++; } while (*colon && c_isspace (*colon));
|
||||
|
||||
if (add_string (&ret, p) == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
if (STREQ (colon, "<none>") ||
|
||||
STREQ (colon, "<not available>") ||
|
||||
STREQ (colon, "(none)")) {
|
||||
if (add_string (&ret, "") == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (add_string (&ret, colon) == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (add_string (&ret, p) == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
if (add_string (&ret, "") == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -116,8 +107,6 @@ do_tune2fs_l (const char *device)
|
||||
p = pend;
|
||||
}
|
||||
|
||||
free (out);
|
||||
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
@@ -127,43 +116,50 @@ do_tune2fs_l (const char *device)
|
||||
int
|
||||
do_set_e2label (const char *device, const char *label)
|
||||
{
|
||||
return do_set_label (device, label);
|
||||
mountable_t mountable;
|
||||
mountable.type = MOUNTABLE_DEVICE;
|
||||
mountable.device = device;
|
||||
return do_set_label (&mountable, label);
|
||||
}
|
||||
|
||||
char *
|
||||
do_get_e2label (const char *device)
|
||||
{
|
||||
return do_vfs_label (device);
|
||||
mountable_t mountable;
|
||||
mountable.type = MOUNTABLE_DEVICE;
|
||||
mountable.device = device;
|
||||
return do_vfs_label (&mountable);
|
||||
}
|
||||
|
||||
int
|
||||
do_set_e2uuid (const char *device, const char *uuid)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
r = command (NULL, &err, str_tune2fs, "-U", uuid, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
do_get_e2uuid (const char *device)
|
||||
{
|
||||
return do_vfs_uuid (device);
|
||||
mountable_t mountable;
|
||||
mountable.type = MOUNTABLE_DEVICE;
|
||||
mountable.device = device;
|
||||
return do_vfs_uuid (&mountable);
|
||||
}
|
||||
|
||||
/* If the filesystem is not mounted, run e2fsck -f on it unconditionally. */
|
||||
static int
|
||||
if_not_mounted_run_e2fsck (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r, mounted;
|
||||
|
||||
mounted = is_device_mounted (device);
|
||||
@@ -171,13 +167,13 @@ if_not_mounted_run_e2fsck (const char *device)
|
||||
return -1;
|
||||
|
||||
if (!mounted) {
|
||||
r = command (NULL, &err, str_e2fsck, "-fy", device, NULL);
|
||||
r = commandf (NULL, &err,
|
||||
COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
|
||||
str_e2fsck, "-fy", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -186,7 +182,7 @@ if_not_mounted_run_e2fsck (const char *device)
|
||||
int
|
||||
do_resize2fs (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (if_not_mounted_run_e2fsck (device) == -1)
|
||||
@@ -195,18 +191,16 @@ do_resize2fs (const char *device)
|
||||
r = command (NULL, &err, str_resize2fs, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_resize2fs_size (const char *device, int64_t size)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
/* resize2fs itself may impose additional limits. Since we are
|
||||
@@ -229,18 +223,16 @@ do_resize2fs_size (const char *device, int64_t size)
|
||||
r = command (NULL, &err, str_resize2fs, device, buf, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_resize2fs_M (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (if_not_mounted_run_e2fsck (device) == -1)
|
||||
@@ -249,11 +241,9 @@ do_resize2fs_M (const char *device)
|
||||
r = command (NULL, &err, str_resize2fs, "-M", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -264,7 +254,7 @@ do_e2fsck (const char *device,
|
||||
int forceall)
|
||||
{
|
||||
const char *argv[MAX_ARGS];
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
size_t i = 0;
|
||||
int r;
|
||||
|
||||
@@ -291,7 +281,9 @@ do_e2fsck (const char *device,
|
||||
ADD_ARG (argv, i, device);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
r = commandvf (NULL, &err,
|
||||
COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
|
||||
argv);
|
||||
/* 0 = no errors, 1 = errors corrected.
|
||||
*
|
||||
* >= 4 means uncorrected or other errors.
|
||||
@@ -301,11 +293,9 @@ do_e2fsck (const char *device,
|
||||
*/
|
||||
if (r == -1 || r >= 2) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -319,29 +309,29 @@ do_e2fsck_f (const char *device)
|
||||
int
|
||||
do_mke2journal (int blocksize, const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
char blocksize_s[32];
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_mke2journal_L (int blocksize, const char *label, const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (strlen (label) > EXT2_LABEL_MAX) {
|
||||
@@ -353,40 +343,40 @@ do_mke2journal_L (int blocksize, const char *label, const char *device)
|
||||
char blocksize_s[32];
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
"-L", label,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_mke2journal_U (int blocksize, const char *uuid, const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
char blocksize_s[32];
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
"-U", uuid,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -394,7 +384,7 @@ int
|
||||
do_mke2fs_J (const char *fstype, int blocksize, const char *device,
|
||||
const char *journal)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
char blocksize_s[32];
|
||||
@@ -404,16 +394,16 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device,
|
||||
char jdev[len+32];
|
||||
snprintf (jdev, len+32, "device=%s", journal);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -421,7 +411,7 @@ int
|
||||
do_mke2fs_JL (const char *fstype, int blocksize, const char *device,
|
||||
const char *label)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (strlen (label) > EXT2_LABEL_MAX) {
|
||||
@@ -437,16 +427,16 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device,
|
||||
char jdev[len+32];
|
||||
snprintf (jdev, len+32, "device=LABEL=%s", label);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -454,7 +444,7 @@ int
|
||||
do_mke2fs_JU (const char *fstype, int blocksize, const char *device,
|
||||
const char *uuid)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
char blocksize_s[32];
|
||||
@@ -464,16 +454,16 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device,
|
||||
char jdev[len+32];
|
||||
snprintf (jdev, len+32, "device=UUID=%s", uuid);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -494,7 +484,7 @@ do_tune2fs (const char *device, /* only required parameter */
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
char maxmountcount_s[64];
|
||||
char mountcount_s[64];
|
||||
char group_s[64];
|
||||
@@ -612,11 +602,9 @@ do_tune2fs (const char *device, /* only required parameter */
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -632,8 +620,9 @@ char *
|
||||
do_get_e2attrs (const char *filename)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *buf;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
size_t i, j;
|
||||
|
||||
buf = sysroot_path (filename);
|
||||
@@ -643,14 +632,11 @@ do_get_e2attrs (const char *filename)
|
||||
}
|
||||
|
||||
r = command (&out, &err, str_lsattr, "-d", "--", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", "lsattr", filename, err);
|
||||
free (err);
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* Output looks like:
|
||||
* -------------e- filename
|
||||
@@ -674,8 +660,8 @@ int
|
||||
do_set_e2attrs (const char *filename, const char *attrs, int clear)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
size_t i, j;
|
||||
int lowers[26], uppers[26];
|
||||
char attr_arg[26*2+1+1]; /* '+'/'-' + attrs + trailing '\0' */
|
||||
@@ -737,13 +723,10 @@ do_set_e2attrs (const char *filename, const char *attrs, int clear)
|
||||
}
|
||||
|
||||
r = command (NULL, &err, str_chattr, attr_arg, "--", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", "chattr", filename, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -752,8 +735,7 @@ int64_t
|
||||
do_get_e2generation (const char *filename)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *buf = NULL, *out = NULL, *err = NULL;
|
||||
int64_t ret;
|
||||
|
||||
buf = sysroot_path (filename);
|
||||
@@ -763,22 +745,16 @@ do_get_e2generation (const char *filename)
|
||||
}
|
||||
|
||||
r = command (&out, &err, str_lsattr, "-dv", "--", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", "lsattr", filename, err);
|
||||
free (err);
|
||||
free (out);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
if (sscanf (out, "%" SCNu64, &ret) != 1) {
|
||||
reply_with_error ("cannot parse output from '%s' command: %s",
|
||||
"lsattr", out);
|
||||
free (out);
|
||||
return -1;
|
||||
}
|
||||
free (out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -787,8 +763,7 @@ int
|
||||
do_set_e2generation (const char *filename, int64_t generation)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *err;
|
||||
CLEANUP_FREE char *buf = NULL, *err = NULL;
|
||||
char generation_str[64];
|
||||
|
||||
buf = sysroot_path (filename);
|
||||
@@ -801,13 +776,10 @@ do_set_e2generation (const char *filename, int64_t generation)
|
||||
"%" PRIu64, (uint64_t) generation);
|
||||
|
||||
r = command (NULL, &err, str_chattr, "-v", generation_str, "--", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", "chattr", filename, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -854,7 +826,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
int uninitbg)
|
||||
{
|
||||
int r;
|
||||
char *err = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
const char *argv[MAX_ARGS];
|
||||
char blockscount_s[64];
|
||||
char blocksize_s[64];
|
||||
@@ -864,7 +836,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
char bytesperinode_s[64];
|
||||
char inodesize_s[64];
|
||||
char journalsize_s[64];
|
||||
char *journaldevice_s = NULL;
|
||||
CLEANUP_FREE char *journaldevice_s = NULL;
|
||||
char reservedblockspercentage_s[64];
|
||||
char numberofinodes_s[64];
|
||||
char mmpupdateinterval_s[84];
|
||||
@@ -878,7 +850,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_BLOCKSIZE_BITMASK) {
|
||||
if (blocksize < 0) {
|
||||
reply_with_error ("blocksize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%" PRIi64, blocksize);
|
||||
ADD_ARG (argv, i, "-b");
|
||||
@@ -887,7 +859,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_FRAGSIZE_BITMASK) {
|
||||
if (fragsize < 0) {
|
||||
reply_with_error ("fragsize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (fragsize_s, sizeof fragsize_s, "%" PRIi64, fragsize);
|
||||
ADD_ARG (argv, i, "-f");
|
||||
@@ -900,7 +872,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_BLOCKSPERGROUP_BITMASK) {
|
||||
if (blockspergroup < 0) {
|
||||
reply_with_error ("blockspergroup must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (blockspergroup_s, sizeof blockspergroup_s,
|
||||
"%" PRIi64, blockspergroup);
|
||||
@@ -910,7 +882,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_NUMBEROFGROUPS_BITMASK) {
|
||||
if (numberofgroups < 0) {
|
||||
reply_with_error ("numberofgroups must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (numberofgroups_s, sizeof numberofgroups_s,
|
||||
"%" PRIi64, numberofgroups);
|
||||
@@ -920,7 +892,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_BYTESPERINODE_BITMASK) {
|
||||
if (bytesperinode < 0) {
|
||||
reply_with_error ("bytesperinode must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (bytesperinode_s, sizeof bytesperinode_s, "%" PRIi64, bytesperinode);
|
||||
ADD_ARG (argv, i, "-i");
|
||||
@@ -929,7 +901,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_INODESIZE_BITMASK) {
|
||||
if (inodesize < 0) {
|
||||
reply_with_error ("inodesize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (inodesize_s, sizeof inodesize_s, "%" PRIi64, inodesize);
|
||||
ADD_ARG (argv, i, "-I");
|
||||
@@ -938,7 +910,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_JOURNALSIZE_BITMASK) {
|
||||
if (journalsize < 0) {
|
||||
reply_with_error ("journalsize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (journalsize_s, sizeof journalsize_s,
|
||||
"size=" "%" PRIi64, journalsize);
|
||||
@@ -954,12 +926,12 @@ do_mke2fs (const char *device, /* 0 */
|
||||
journaldevice_s = malloc (strlen (journaldevice) + 8);
|
||||
if (!journaldevice_s) {
|
||||
reply_with_perror ("malloc");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf (journaldevice_s, "device=%s", journaldevice);
|
||||
if (STRPREFIX (&journaldevice_s[7], "/dev/"))
|
||||
RESOLVE_DEVICE (&journaldevice_s[7], , goto error);
|
||||
RESOLVE_DEVICE (&journaldevice_s[7], , return -1);
|
||||
|
||||
ADD_ARG (argv, i, "-J");
|
||||
ADD_ARG (argv, i, journaldevice_s);
|
||||
@@ -974,7 +946,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_RESERVEDBLOCKSPERCENTAGE_BITMASK) {
|
||||
if (reservedblockspercentage < 0) {
|
||||
reply_with_error ("reservedblockspercentage must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (reservedblockspercentage_s, sizeof reservedblockspercentage_s,
|
||||
"%" PRIi32, reservedblockspercentage);
|
||||
@@ -990,7 +962,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_NUMBEROFINODES_BITMASK) {
|
||||
if (numberofinodes < 0) {
|
||||
reply_with_error ("numberofinodes must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (numberofinodes_s, sizeof numberofinodes_s,
|
||||
"%" PRIi64, numberofinodes);
|
||||
@@ -1028,7 +1000,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_MMPUPDATEINTERVAL_BITMASK) {
|
||||
if (mmpupdateinterval < 0) {
|
||||
reply_with_error ("mmpupdateinterval must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (mmpupdateinterval_s, sizeof mmpupdateinterval_s,
|
||||
"mmp_update_interval=" "%" PRIi32, mmpupdateinterval);
|
||||
@@ -1038,7 +1010,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_STRIDESIZE_BITMASK) {
|
||||
if (stridesize < 0) {
|
||||
reply_with_error ("stridesize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (stridesize_s, sizeof stridesize_s,
|
||||
"stride=" "%" PRIi64, stridesize);
|
||||
@@ -1048,7 +1020,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_STRIPEWIDTH_BITMASK) {
|
||||
if (stripewidth< 0) {
|
||||
reply_with_error ("stripewidth must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (stripewidth_s, sizeof stripewidth_s,
|
||||
"stripe_width=" "%" PRIi64, stripewidth);
|
||||
@@ -1058,7 +1030,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_MAXONLINERESIZE_BITMASK) {
|
||||
if (maxonlineresize < 0) {
|
||||
reply_with_error ("maxonlineresize must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (maxonlineresize_s, sizeof maxonlineresize_s,
|
||||
"resize=" "%" PRIi64, maxonlineresize);
|
||||
@@ -1169,7 +1141,7 @@ do_mke2fs (const char *device, /* 0 */
|
||||
if (optargs_bitmask & GUESTFS_MKE2FS_BLOCKSCOUNT_BITMASK) {
|
||||
if (blockscount < 0) {
|
||||
reply_with_error ("blockscount must be >= 0");
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
snprintf (blockscount_s, sizeof blockscount_s, "%" PRIi64, blockscount);
|
||||
ADD_ARG (argv, i, blockscount_s);
|
||||
@@ -1177,26 +1149,21 @@ do_mke2fs (const char *device, /* 0 */
|
||||
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (journaldevice_s);
|
||||
free (err);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free (journaldevice_s);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
do_mklost_and_found (const char *mountpoint)
|
||||
{
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
int r;
|
||||
|
||||
if (asprintf_nowarn (&cmd, "cd %R && mklost+found", mountpoint) == -1) {
|
||||
@@ -1207,15 +1174,12 @@ do_mklost_and_found (const char *mountpoint)
|
||||
r = system (cmd);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("system");
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
|
||||
reply_with_error ("%s: command failed", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -440,7 +440,7 @@ do_pwrite_device (const char *device, const char *content, size_t size,
|
||||
char *
|
||||
do_file (const char *path)
|
||||
{
|
||||
char *buf = NULL;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
const char *display_path = path;
|
||||
|
||||
int is_dev = STRPREFIX (path, "/dev/");
|
||||
@@ -459,15 +459,12 @@ do_file (const char *path)
|
||||
struct stat statbuf;
|
||||
if (lstat (path, &statbuf) == -1) {
|
||||
reply_with_perror ("lstat: %s", display_path);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! S_ISREG (statbuf.st_mode)) {
|
||||
char *ret;
|
||||
|
||||
free (buf);
|
||||
|
||||
if (S_ISDIR (statbuf.st_mode))
|
||||
ret = strdup ("directory");
|
||||
else if (S_ISCHR (statbuf.st_mode))
|
||||
@@ -494,22 +491,27 @@ do_file (const char *path)
|
||||
*/
|
||||
const char *flags = is_dev ? "-zbsL" : "-zb";
|
||||
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err;
|
||||
int r = command (&out, &err, str_file, flags, path, NULL);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
free (out);
|
||||
reply_with_error ("%s: %s", display_path, err);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* We need to remove the trailing \n from output of file(1). */
|
||||
size_t len = strlen (out);
|
||||
if (len > 0 && out[len-1] == '\n')
|
||||
out[len-1] = '\0';
|
||||
out[--len] = '\0';
|
||||
|
||||
/* Some upstream versions of file add a space at the end of the
|
||||
* output. This is fixed in the Fedora version, but we might as
|
||||
* well fix it here too. (RHBZ#928995).
|
||||
*/
|
||||
if (len > 0 && out[len-1] == ' ')
|
||||
out[--len] = '\0';
|
||||
|
||||
return out; /* caller frees */
|
||||
}
|
||||
@@ -520,7 +522,7 @@ do_zfile (const char *method, const char *path)
|
||||
{
|
||||
size_t len;
|
||||
const char *zcat;
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
FILE *fp;
|
||||
char line[256];
|
||||
|
||||
@@ -544,12 +546,9 @@ do_zfile (const char *method, const char *path)
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (cmd);
|
||||
|
||||
if (fgets (line, sizeof line, fp) == NULL) {
|
||||
reply_with_perror ("fgets");
|
||||
fclose (fp);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -51,14 +51,6 @@ input_to_nul (FILE *fp, char *buf, size_t maxlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The code below assumes each path returned can fit into a protocol
|
||||
* chunk. If this turns out not to be true at some point in the
|
||||
* future then we'll need to modify the code a bit to handle it.
|
||||
*/
|
||||
#if PATH_MAX > GUESTFS_MAX_CHUNK_SIZE
|
||||
#error "PATH_MAX > GUESTFS_MAX_CHUNK_SIZE"
|
||||
#endif
|
||||
|
||||
/* Has one FileOut parameter. */
|
||||
int
|
||||
do_find0 (const char *dir)
|
||||
@@ -66,9 +58,9 @@ do_find0 (const char *dir)
|
||||
struct stat statbuf;
|
||||
int r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char *sysrootdir;
|
||||
size_t sysrootdirlen, len;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
CLEANUP_FREE char *sysrootdir = NULL;
|
||||
size_t sysrootdirlen;
|
||||
char str[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
sysrootdir = sysroot_path (dir);
|
||||
@@ -80,12 +72,10 @@ do_find0 (const char *dir)
|
||||
r = stat (sysrootdir, &statbuf);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("%s", dir);
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_error ("%s: not a directory", dir);
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -93,10 +83,8 @@ do_find0 (const char *dir)
|
||||
|
||||
if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
}
|
||||
free (sysrootdir);
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
@@ -104,10 +92,8 @@ do_find0 (const char *dir)
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* Now we must send the reply message, before the file contents. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
@@ -115,8 +101,13 @@ do_find0 (const char *dir)
|
||||
*/
|
||||
reply (NULL, NULL);
|
||||
|
||||
/* The code below assumes each path returned can fit into a protocol
|
||||
* chunk (if not you'll get a runtime protocol error). If this
|
||||
* turns out not to be a problem at some point in the future then
|
||||
* we'll need to modify the code to handle it. XXX
|
||||
*/
|
||||
while ((r = input_to_nul (fp, str, GUESTFS_MAX_CHUNK_SIZE)) > 0) {
|
||||
len = strlen (str);
|
||||
size_t len = strlen (str);
|
||||
if (len <= sysrootdirlen)
|
||||
continue;
|
||||
|
||||
@@ -128,14 +119,14 @@ do_find0 (const char *dir)
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (dir);
|
||||
fprintf (stderr, "fgetc: %s: %m\n", dir);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (dir);
|
||||
fprintf (stderr, "pclose: %s: %m\n", dir);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ GUESTFSD_EXT_CMD(str_findfs, findfs);
|
||||
static char *
|
||||
findfs (const char *tag, const char *label_or_uuid)
|
||||
{
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
/* Kill the cache file, forcing blkid to reread values from the
|
||||
* original filesystems. In blkid there is a '-p' option which is
|
||||
* supposed to do this, but (a) it doesn't work and (b) that option
|
||||
@@ -43,17 +47,13 @@ findfs (const char *tag, const char *label_or_uuid)
|
||||
char arg[len];
|
||||
snprintf (arg, len, "%s=%s", tag, label_or_uuid);
|
||||
|
||||
char *out, *err;
|
||||
int r = command (&out, &err, str_findfs, arg, NULL);
|
||||
r = command (&out, &err, str_findfs, arg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
/* Trim trailing \n if present. */
|
||||
len = strlen (out);
|
||||
if (len > 0 && out[len-1] == '\n')
|
||||
|
||||
@@ -31,16 +31,14 @@ GUESTFSD_EXT_CMD(str_fsck, fsck);
|
||||
int
|
||||
do_fsck (const char *fstype, const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = commandr (NULL, &err, str_fsck, "-a", "-t", fstype, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ do_fstrim (const char *path,
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char offset_s[64], length_s[64], mfe_s[64];
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
ADD_ARG (argv, i, str_fstrim);
|
||||
@@ -90,10 +90,8 @@ do_fstrim (const char *path,
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ grep (const char *regex, const char *path,
|
||||
{
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
int fd, flags, r;
|
||||
char **lines;
|
||||
|
||||
@@ -78,15 +78,10 @@ grep (const char *regex, const char *path,
|
||||
r = commandrvf (&out, &err, flags, argv);
|
||||
if (r == -1 || r > 1) {
|
||||
reply_with_error ("%s: %s", regex, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
lines = split_lines (out);
|
||||
free (out);
|
||||
if (lines == NULL) return NULL;
|
||||
|
||||
return lines;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,8 +38,7 @@ int
|
||||
do_grub_install (const char *root, const char *device)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
char *buf;
|
||||
CLEANUP_FREE char *err = NULL, *buf = NULL;
|
||||
|
||||
if (asprintf_nowarn (&buf, "--root-directory=%R", root) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
@@ -47,14 +46,11 @@ do_grub_install (const char *root, const char *device)
|
||||
}
|
||||
|
||||
r = command (NULL, &err, str_grub_install, buf, device, NULL);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -66,6 +66,10 @@ static char *read_cmdline (void);
|
||||
# define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
/* For improved readability dealing with pipe arrays */
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
|
||||
/* If root device is an ext2 filesystem, this is the major and minor.
|
||||
* This is so we can ignore this device from the point of view of the
|
||||
* user, eg. in guestfs_list_devices and many other places.
|
||||
@@ -354,6 +358,13 @@ read_cmdline (void)
|
||||
/* Return true iff device is the root device (and therefore should be
|
||||
* ignored from the point of view of user calls).
|
||||
*/
|
||||
static int
|
||||
is_root_device_stat (struct stat *statbuf)
|
||||
{
|
||||
if (statbuf->st_rdev == root_device) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
is_root_device (const char *device)
|
||||
{
|
||||
@@ -362,9 +373,8 @@ is_root_device (const char *device)
|
||||
perror (device);
|
||||
return 0;
|
||||
}
|
||||
if (statbuf.st_rdev == root_device)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
return is_root_device_stat (&statbuf);
|
||||
}
|
||||
|
||||
/* Turn "/path" into "/sysroot/path".
|
||||
@@ -513,6 +523,9 @@ free_strings (char **argv)
|
||||
{
|
||||
size_t argc;
|
||||
|
||||
if (!argv)
|
||||
return;
|
||||
|
||||
for (argc = 0; argv[argc] != NULL; ++argc)
|
||||
free (argv[argc]);
|
||||
free (argv);
|
||||
@@ -523,6 +536,9 @@ free_stringslen (char **argv, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!argv)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
free (argv[i]);
|
||||
free (argv);
|
||||
@@ -647,7 +663,8 @@ int
|
||||
commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char **argv;
|
||||
/* NB: Mustn't free the strings which are on the stack. */
|
||||
CLEANUP_FREE const char **argv;
|
||||
char *s;
|
||||
size_t i;
|
||||
int r;
|
||||
@@ -668,7 +685,6 @@ commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
const char **p = realloc (argv, sizeof (char *) * (++i));
|
||||
if (p == NULL) {
|
||||
perror ("realloc");
|
||||
free (argv);
|
||||
va_end (args);
|
||||
return -1;
|
||||
}
|
||||
@@ -681,9 +697,6 @@ commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
|
||||
r = commandvf (stdoutput, stderror, flags, (const char * const*) argv);
|
||||
|
||||
/* NB: Mustn't free the strings which are on the stack. */
|
||||
free (argv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -695,7 +708,7 @@ int
|
||||
commandrf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char **argv;
|
||||
CLEANUP_FREE const char **argv;
|
||||
char *s;
|
||||
int i, r;
|
||||
|
||||
@@ -715,7 +728,6 @@ commandrf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
const char **p = realloc (argv, sizeof (char *) * (++i));
|
||||
if (p == NULL) {
|
||||
perror ("realloc");
|
||||
free (argv);
|
||||
va_end (args);
|
||||
return -1;
|
||||
}
|
||||
@@ -728,9 +740,6 @@ commandrf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
|
||||
r = commandrvf (stdoutput, stderror, flags, argv);
|
||||
|
||||
/* NB: Mustn't free the strings which are on the stack. */
|
||||
free (argv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -785,8 +794,8 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
size_t so_size = 0, se_size = 0;
|
||||
int so_fd[2], se_fd[2];
|
||||
int flag_copy_stdin = flags & COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN;
|
||||
int stdin_fd[2] = { -1, -1 };
|
||||
pid_t pid, stdin_pid = -1;
|
||||
int flag_copy_fd = flags & COMMAND_FLAG_FD_MASK;
|
||||
pid_t pid;
|
||||
int r, quit, i;
|
||||
fd_set rset, rset2;
|
||||
char buf[256];
|
||||
@@ -816,13 +825,6 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (flag_copy_stdin) {
|
||||
if (pipe (stdin_fd) == -1) {
|
||||
error (0, errno, "pipe");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork ();
|
||||
if (pid == -1) {
|
||||
error (0, errno, "fork");
|
||||
@@ -834,95 +836,42 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
close (0);
|
||||
if (flag_copy_stdin) {
|
||||
dup2 (stdin_fd[0], 0);
|
||||
close (stdin_fd[0]);
|
||||
close (stdin_fd[1]);
|
||||
dup2 (flag_copy_fd, STDIN_FILENO);
|
||||
} else {
|
||||
/* Set stdin to /dev/null (ignore failure) */
|
||||
ignore_value (open ("/dev/null", O_RDONLY|O_CLOEXEC));
|
||||
}
|
||||
close (so_fd[0]);
|
||||
close (se_fd[0]);
|
||||
close (so_fd[PIPE_READ]);
|
||||
close (se_fd[PIPE_READ]);
|
||||
if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR))
|
||||
dup2 (so_fd[1], 1);
|
||||
dup2 (so_fd[PIPE_WRITE], STDOUT_FILENO);
|
||||
else
|
||||
dup2 (se_fd[1], 1);
|
||||
dup2 (se_fd[1], 2);
|
||||
close (so_fd[1]);
|
||||
close (se_fd[1]);
|
||||
dup2 (se_fd[PIPE_WRITE], STDOUT_FILENO);
|
||||
dup2 (se_fd[PIPE_WRITE], STDERR_FILENO);
|
||||
close (so_fd[PIPE_WRITE]);
|
||||
close (se_fd[PIPE_WRITE]);
|
||||
|
||||
ignore_value (chdir ("/"));
|
||||
|
||||
execvp (argv[0], (void *) argv);
|
||||
perror (argv[0]);
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (flag_copy_stdin) {
|
||||
int fd = flags & COMMAND_FLAG_FD_MASK;
|
||||
|
||||
stdin_pid = fork ();
|
||||
if (stdin_pid == -1) {
|
||||
error (0, errno, "fork");
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (stdin_pid == 0) { /* Child process copying stdin. */
|
||||
close (so_fd[0]);
|
||||
close (so_fd[1]);
|
||||
close (se_fd[0]);
|
||||
close (se_fd[1]);
|
||||
|
||||
close (1);
|
||||
dup2 (stdin_fd[1], 1);
|
||||
close (stdin_fd[0]);
|
||||
close (stdin_fd[1]);
|
||||
|
||||
if (chroot (sysroot) == -1) {
|
||||
perror ("chroot");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ssize_t n;
|
||||
char buffer[BUFSIZ];
|
||||
while ((n = read (fd, buffer, sizeof buffer)) > 0) {
|
||||
if (xwrite (1, buffer, n) == -1)
|
||||
/* EPIPE error indicates the command process has exited
|
||||
* early. If the command process fails that will be caught
|
||||
* by the daemon, and if not, then it's not an error.
|
||||
*/
|
||||
_exit (errno == EPIPE ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (n == -1) {
|
||||
perror ("read");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror ("close");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
close (stdin_fd[0]);
|
||||
close (stdin_fd[1]);
|
||||
}
|
||||
|
||||
/* Parent process. */
|
||||
close (so_fd[1]);
|
||||
close (se_fd[1]);
|
||||
close (so_fd[PIPE_WRITE]);
|
||||
close (se_fd[PIPE_WRITE]);
|
||||
|
||||
FD_ZERO (&rset);
|
||||
FD_SET (so_fd[0], &rset);
|
||||
FD_SET (se_fd[0], &rset);
|
||||
FD_SET (so_fd[PIPE_READ], &rset);
|
||||
FD_SET (se_fd[PIPE_READ], &rset);
|
||||
|
||||
quit = 0;
|
||||
while (quit < 2) {
|
||||
again:
|
||||
rset2 = rset;
|
||||
r = select (MAX (so_fd[0], se_fd[0]) + 1, &rset2, NULL, NULL, NULL);
|
||||
r = select (MAX (so_fd[PIPE_READ], se_fd[PIPE_READ]) + 1, &rset2,
|
||||
NULL, NULL, NULL);
|
||||
if (r == -1) {
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
@@ -943,20 +892,20 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
*stderror = strdup ("error running external command, "
|
||||
"see debug output for details");
|
||||
}
|
||||
close (so_fd[0]);
|
||||
close (se_fd[0]);
|
||||
close (so_fd[PIPE_READ]);
|
||||
close (se_fd[PIPE_READ]);
|
||||
if (flag_copy_stdin) close (flag_copy_fd);
|
||||
waitpid (pid, NULL, 0);
|
||||
if (stdin_pid >= 0) waitpid (stdin_pid, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET (so_fd[0], &rset2)) { /* something on stdout */
|
||||
r = read (so_fd[0], buf, sizeof buf);
|
||||
if (FD_ISSET (so_fd[PIPE_READ], &rset2)) { /* something on stdout */
|
||||
r = read (so_fd[PIPE_READ], buf, sizeof buf);
|
||||
if (r == -1) {
|
||||
perror ("read");
|
||||
goto quit;
|
||||
}
|
||||
if (r == 0) { FD_CLR (so_fd[0], &rset); quit++; }
|
||||
if (r == 0) { FD_CLR (so_fd[PIPE_READ], &rset); quit++; }
|
||||
|
||||
if (r > 0 && stdoutput) {
|
||||
so_size += r;
|
||||
@@ -970,17 +919,17 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET (se_fd[0], &rset2)) { /* something on stderr */
|
||||
r = read (se_fd[0], buf, sizeof buf);
|
||||
if (FD_ISSET (se_fd[PIPE_READ], &rset2)) { /* something on stderr */
|
||||
r = read (se_fd[PIPE_READ], buf, sizeof buf);
|
||||
if (r == -1) {
|
||||
perror ("read");
|
||||
goto quit;
|
||||
}
|
||||
if (r == 0) { FD_CLR (se_fd[0], &rset); quit++; }
|
||||
if (r == 0) { FD_CLR (se_fd[PIPE_READ], &rset); quit++; }
|
||||
|
||||
if (r > 0) {
|
||||
if (verbose)
|
||||
ignore_value (write (2, buf, r));
|
||||
ignore_value (write (STDERR_FILENO, buf, r));
|
||||
|
||||
if (stderror) {
|
||||
se_size += r;
|
||||
@@ -996,8 +945,8 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
close (so_fd[0]);
|
||||
close (se_fd[0]);
|
||||
close (so_fd[PIPE_READ]);
|
||||
close (se_fd[PIPE_READ]);
|
||||
|
||||
/* Make sure the output buffers are \0-terminated. Also remove any
|
||||
* trailing \n characters from the error buffer (not from stdout).
|
||||
@@ -1028,21 +977,9 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (flag_copy_stdin) {
|
||||
/* Check copy process didn't fail. */
|
||||
if (waitpid (stdin_pid, &r, 0) != stdin_pid) {
|
||||
perror ("waitpid");
|
||||
kill (pid, 9);
|
||||
waitpid (pid, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
|
||||
fprintf (stderr, "failed copying from input file, see earlier messages (r = %d)\n", r);
|
||||
kill (pid, 9);
|
||||
waitpid (pid, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
if (flag_copy_stdin && close (flag_copy_fd) == -1) {
|
||||
perror ("close");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the exit status of the command. */
|
||||
@@ -1233,6 +1170,88 @@ device_name_translation (char *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse the mountable descriptor for a btrfs subvolume. Don't call this
|
||||
* directly - use the RESOLVE_MOUNTABLE macro.
|
||||
*
|
||||
* A btrfs subvolume is given as:
|
||||
*
|
||||
* btrfsvol:/dev/sda3/root
|
||||
*
|
||||
* where /dev/sda3 is a block device containing a btrfs filesystem, and root is
|
||||
* the name of a subvolume on it. This function is passed the string following
|
||||
* 'btrfsvol:'.
|
||||
*/
|
||||
int
|
||||
parse_btrfsvol (char *desc, mountable_t *mountable)
|
||||
{
|
||||
char *device, *volume = NULL, *slash;
|
||||
struct stat statbuf;
|
||||
|
||||
mountable->type = MOUNTABLE_BTRFSVOL;
|
||||
|
||||
device = desc;
|
||||
|
||||
if (! STRPREFIX (device, "/dev/"))
|
||||
return -1;
|
||||
|
||||
slash = device + strlen ("/dev/") - 1;
|
||||
while ((slash = strchr (slash + 1, '/'))) {
|
||||
*slash = '\0';
|
||||
|
||||
if (device_name_translation (device) == -1) {
|
||||
perror (device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat (device, &statbuf) == -1) {
|
||||
perror (device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISDIR (statbuf.st_mode) &&
|
||||
!is_root_device_stat (&statbuf))
|
||||
{
|
||||
volume = slash + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
if (!volume) return -1;
|
||||
|
||||
mountable->device = device;
|
||||
mountable->volume = volume;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert a mountable_t back to its string representation
|
||||
*
|
||||
* This function can be used in an error path, and must not call
|
||||
* reply_with_error().
|
||||
*/
|
||||
char *
|
||||
mountable_to_string (const mountable_t *mountable)
|
||||
{
|
||||
char *desc;
|
||||
|
||||
switch (mountable->type) {
|
||||
case MOUNTABLE_DEVICE:
|
||||
case MOUNTABLE_PATH:
|
||||
return strdup (mountable->device);
|
||||
|
||||
case MOUNTABLE_BTRFSVOL:
|
||||
if (asprintf(&desc, "btrfsvol:%s/%s",
|
||||
mountable->device, mountable->volume) == -1)
|
||||
return NULL;
|
||||
return desc;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check program exists and is executable on $PATH. Actually, we
|
||||
* just assume PATH contains the default entries (see main() above).
|
||||
*/
|
||||
@@ -1311,3 +1330,27 @@ udev_settle (void)
|
||||
{
|
||||
(void) command (NULL, NULL, str_udevadm, "settle", NULL);
|
||||
}
|
||||
|
||||
/* Use by the CLEANUP_* macros. Do not call these directly. */
|
||||
void
|
||||
cleanup_free (void *ptr)
|
||||
{
|
||||
free (* (void **) ptr);
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_free_string_list (void *ptr)
|
||||
{
|
||||
free_strings (* (char ***) ptr);
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_unlink_free (void *ptr)
|
||||
{
|
||||
char *filename = * (char **) ptr;
|
||||
|
||||
if (filename) {
|
||||
unlink (filename);
|
||||
free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,4 +100,4 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
Copyright (C) 2009-2013 Red Hat Inc.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
static char **
|
||||
headtail (const char *prog, const char *flag, const char *n, const char *path)
|
||||
{
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
int fd, flags, r;
|
||||
char **lines;
|
||||
|
||||
@@ -48,13 +48,9 @@ headtail (const char *prog, const char *flag, const char *n, const char *path)
|
||||
r = commandf (&out, &err, flags, prog, flag, n, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s %s %s: %s", prog, flag, n, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
#if 0
|
||||
/* Split it at the first whitespace. */
|
||||
len = strcspn (out, " \t\n");
|
||||
@@ -62,7 +58,6 @@ headtail (const char *prog, const char *flag, const char *n, const char *path)
|
||||
#endif
|
||||
|
||||
lines = split_lines (out);
|
||||
free (out);
|
||||
if (lines == NULL) return NULL;
|
||||
|
||||
return lines;
|
||||
|
||||
@@ -31,7 +31,8 @@ char *
|
||||
do_hexdump (const char *path)
|
||||
{
|
||||
int fd, flags, r;
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
@@ -46,12 +47,9 @@ do_hexdump (const char *path)
|
||||
r = commandf (&out, &err, flags, "hexdump", "-C", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", path, err);
|
||||
free (err);
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ hivex_finalize (void)
|
||||
int
|
||||
do_hivex_open (const char *filename, int verbose, int debug, int write)
|
||||
{
|
||||
char *buf;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
int flags = 0;
|
||||
|
||||
if (h) {
|
||||
@@ -100,11 +100,9 @@ do_hivex_open (const char *filename, int verbose, int debug, int write)
|
||||
h = hivex_open (buf, flags);
|
||||
if (!h) {
|
||||
reply_with_perror ("hivex failed to open %s", filename);
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,7 +153,7 @@ guestfs_int_hivex_node_list *
|
||||
do_hivex_node_children (int64_t nodeh)
|
||||
{
|
||||
guestfs_int_hivex_node_list *ret;
|
||||
hive_node_h *r;
|
||||
CLEANUP_FREE hive_node_h *r = NULL;
|
||||
size_t i, len;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
@@ -173,7 +171,6 @@ do_hivex_node_children (int64_t nodeh)
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -183,15 +180,12 @@ do_hivex_node_children (int64_t nodeh)
|
||||
if (ret->guestfs_int_hivex_node_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
ret->guestfs_int_hivex_node_list_val[i].hivex_node_h = r[i];
|
||||
|
||||
free (r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -232,7 +226,7 @@ guestfs_int_hivex_value_list *
|
||||
do_hivex_node_values (int64_t nodeh)
|
||||
{
|
||||
guestfs_int_hivex_value_list *ret;
|
||||
hive_value_h *r;
|
||||
CLEANUP_FREE hive_value_h *r = NULL;
|
||||
size_t i, len;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
@@ -250,7 +244,6 @@ do_hivex_node_values (int64_t nodeh)
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -260,15 +253,12 @@ do_hivex_node_values (int64_t nodeh)
|
||||
if (ret->guestfs_int_hivex_value_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
ret->guestfs_int_hivex_value_list_val[i].hivex_value_h = (int64_t) r[i];
|
||||
|
||||
free (r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -341,11 +331,30 @@ do_hivex_value_value (int64_t valueh, size_t *size_r)
|
||||
int
|
||||
do_hivex_commit (const char *filename)
|
||||
{
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
if (hivex_commit (h, filename, 0) == -1) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
/* The 'filename' parameter is an optional string, and in most
|
||||
* cases will be NULL.
|
||||
*/
|
||||
if (filename) {
|
||||
buf = sysroot_path (filename);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hivex_commit (h, buf, 0) == -1) {
|
||||
reply_with_perror ("%s: commit failed", filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hivex_commit (h, NULL, 0) == -1) {
|
||||
reply_with_perror ("commit failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -83,7 +83,7 @@ do_internal_hot_remove_drive_precheck (const char *label)
|
||||
size_t len = strlen (label);
|
||||
char path[len+64];
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
/* Ensure there are no requests in flight (thanks Paolo Bonzini). */
|
||||
udev_settle ();
|
||||
@@ -94,11 +94,8 @@ do_internal_hot_remove_drive_precheck (const char *label)
|
||||
r = commandr (&out, &err, str_fuser, "-v", "-m", path, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("fuser: %s: %s", path, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* "fuser returns a non-zero return code if none of the specified
|
||||
* files is accessed or in case of a fatal error. If at least one
|
||||
@@ -112,13 +109,9 @@ do_internal_hot_remove_drive_precheck (const char *label)
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", out);
|
||||
|
||||
free (out);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,11 @@ char **
|
||||
do_initrd_list (const char *path)
|
||||
{
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char filename[PATH_MAX];
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
DECLARE_STRINGSBUF (filenames);
|
||||
size_t len;
|
||||
CLEANUP_FREE char *filename = NULL;
|
||||
size_t allocsize;
|
||||
ssize_t len;
|
||||
|
||||
/* "zcat /sysroot/<path> | cpio --quiet -it", but path must be quoted. */
|
||||
if (asprintf_nowarn (&cmd, "%s %R | %s --quiet -it", str_zcat, path, str_cpio) == -1) {
|
||||
@@ -54,16 +55,13 @@ do_initrd_list (const char *path)
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("popen: %s", cmd);
|
||||
free (cmd);
|
||||
return NULL;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
while (fgets (filename, sizeof filename, fp) != NULL) {
|
||||
len = strlen (filename);
|
||||
allocsize = 0;
|
||||
while ((len = getline (&filename, &allocsize, fp)) != -1) {
|
||||
if (len > 0 && filename[len-1] == '\n')
|
||||
filename[len-1] = '\0';
|
||||
|
||||
if (add_string (&filenames, filename) == -1) {
|
||||
pclose (fp);
|
||||
return NULL;
|
||||
@@ -88,33 +86,36 @@ char *
|
||||
do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
{
|
||||
char tmpdir[] = "/tmp/initrd-cat-XXXXXX";
|
||||
CLEANUP_FREE char *cmd;
|
||||
struct stat statbuf;
|
||||
int fd, r;
|
||||
char *ret = NULL;
|
||||
CLEANUP_FREE char *fullpath = NULL;
|
||||
|
||||
if (mkdtemp (tmpdir) == NULL) {
|
||||
reply_with_perror ("mkdtemp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* "zcat /sysroot/<path> | cpio --quiet -id file", but paths must be quoted */
|
||||
char *cmd;
|
||||
if (asprintf_nowarn (&cmd, "cd %Q && zcat %R | cpio --quiet -id %Q",
|
||||
tmpdir, path, filename) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
rmdir (tmpdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extract file into temporary directory. This may create subdirs.
|
||||
* It's also possible that this doesn't create anything at all
|
||||
* (eg. if the named file does not exist in the cpio archive) --
|
||||
* cpio is silent in this case.
|
||||
*/
|
||||
int r = system (cmd);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("command failed: %s", cmd);
|
||||
free (cmd);
|
||||
/* "zcat /sysroot/<path> | cpio --quiet -id file", but paths must be quoted */
|
||||
if (asprintf_nowarn (&cmd, "cd %Q && zcat %R | cpio --quiet -id %Q",
|
||||
tmpdir, path, filename) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
rmdir (tmpdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = system (cmd);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("command failed: %s", cmd);
|
||||
rmdir (tmpdir);
|
||||
return NULL;
|
||||
}
|
||||
free (cmd);
|
||||
if (WEXITSTATUS (r) != 0) {
|
||||
reply_with_perror ("command failed with return code %d",
|
||||
WEXITSTATUS (r));
|
||||
@@ -122,13 +123,14 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Construct the expected name of the extracted file. */
|
||||
if (asprintf (&fullpath, "%s/%s", tmpdir, filename) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
rmdir (tmpdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* See if we got a file. */
|
||||
char fullpath[PATH_MAX];
|
||||
snprintf (fullpath, sizeof fullpath, "%s/%s", tmpdir, filename);
|
||||
|
||||
struct stat statbuf;
|
||||
int fd;
|
||||
|
||||
fd = open (fullpath, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s:%s", path, filename);
|
||||
@@ -139,8 +141,6 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
/* From this point, we know the file exists, so we require full
|
||||
* cleanup.
|
||||
*/
|
||||
char *ret = NULL;
|
||||
|
||||
if (fstat (fd, &statbuf) == -1) {
|
||||
reply_with_perror ("fstat: %s:%s", path, filename);
|
||||
goto cleanup;
|
||||
@@ -189,8 +189,7 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
|
||||
/* Remove the file. */
|
||||
if (unlink (fullpath) == -1) {
|
||||
fprintf (stderr, "unlink: ");
|
||||
perror (fullpath);
|
||||
fprintf (stderr, "unlink: %s: %m\n", fullpath);
|
||||
/* non-fatal */
|
||||
}
|
||||
|
||||
@@ -200,8 +199,7 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
if (!p) break;
|
||||
*p = '\0';
|
||||
if (rmdir (fullpath) == -1) {
|
||||
fprintf (stderr, "rmdir: ");
|
||||
perror (fullpath);
|
||||
fprintf (stderr, "rmdir: %s: %m\n", fullpath);
|
||||
/* non-fatal */
|
||||
}
|
||||
} while (STRNEQ (fullpath, tmpdir));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,6 +43,9 @@ static int inotify_fd = -1;
|
||||
static char inotify_buf[64*1024*1024]; /* Event buffer, [0..posn-1] is valid */
|
||||
static size_t inotify_posn = 0;
|
||||
|
||||
/* Because of use of arbitrary offsets within inotify_buf. */
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
/* Clean up the inotify handle on daemon exit. */
|
||||
static void inotify_finalize (void) __attribute__((destructor));
|
||||
static void
|
||||
@@ -151,7 +154,7 @@ int64_t
|
||||
do_inotify_add_watch (const char *path, int mask)
|
||||
{
|
||||
int64_t r;
|
||||
char *buf;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
|
||||
NEED_INOTIFY (-1);
|
||||
|
||||
@@ -162,7 +165,6 @@ do_inotify_add_watch (const char *path, int mask)
|
||||
}
|
||||
|
||||
r = inotify_add_watch (inotify_fd, buf, mask);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("%s", path);
|
||||
return -1;
|
||||
|
||||
@@ -239,10 +239,9 @@ parse_isoinfo (char **lines)
|
||||
static guestfs_int_isoinfo *
|
||||
isoinfo (const char *path)
|
||||
{
|
||||
char *out = NULL, *err = NULL;
|
||||
int r;
|
||||
char **lines = NULL;
|
||||
guestfs_int_isoinfo *ret = NULL;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **lines = NULL;
|
||||
|
||||
/* --debug is necessary to get additional fields, in particular
|
||||
* the date & time fields.
|
||||
@@ -250,24 +249,14 @@ isoinfo (const char *path)
|
||||
r = command (&out, &err, str_isoinfo, "--debug", "-d", "-i", path, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
goto done;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lines = split_lines (out);
|
||||
if (lines == NULL)
|
||||
goto done;
|
||||
return NULL;
|
||||
|
||||
ret = parse_isoinfo (lines);
|
||||
if (ret == NULL)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
|
||||
return ret;
|
||||
return parse_isoinfo (lines);
|
||||
}
|
||||
|
||||
guestfs_int_isoinfo *
|
||||
@@ -279,17 +268,14 @@ do_isoinfo_device (const char *device)
|
||||
guestfs_int_isoinfo *
|
||||
do_isoinfo (const char *path)
|
||||
{
|
||||
char *buf;
|
||||
guestfs_int_isoinfo *ret;
|
||||
|
||||
buf = sysroot_path (path);
|
||||
CLEANUP_FREE char *buf = sysroot_path (path);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = isoinfo (buf);
|
||||
free (buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ static int
|
||||
e2label (const char *device, const char *label)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
if (strlen (label) > EXT2_LABEL_MAX) {
|
||||
reply_with_error ("%s: ext2 labels are limited to %d bytes",
|
||||
@@ -45,11 +45,9 @@ e2label (const char *device, const char *label)
|
||||
r = command (NULL, &err, str_e2label, device, label, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -57,7 +55,7 @@ static int
|
||||
ntfslabel (const char *device, const char *label)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
/* XXX We should check if the label is longer than 128 unicode
|
||||
* characters and return an error. This is not so easy since we
|
||||
@@ -66,31 +64,28 @@ ntfslabel (const char *device, const char *label)
|
||||
r = command (NULL, &err, str_ntfslabel, device, label, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_set_label (const char *device, const char *label)
|
||||
do_set_label (const mountable_t *mountable, const char *label)
|
||||
{
|
||||
char *vfs_type;
|
||||
int r;
|
||||
|
||||
/* How we set the label depends on the filesystem type. */
|
||||
vfs_type = do_vfs_type (device);
|
||||
CLEANUP_FREE char *vfs_type = do_vfs_type (mountable);
|
||||
if (vfs_type == NULL)
|
||||
return -1;
|
||||
|
||||
if (STREQ (vfs_type, "ext2") || STREQ (vfs_type, "ext3")
|
||||
|| STREQ (vfs_type, "ext4"))
|
||||
r = e2label (device, label);
|
||||
r = e2label (mountable->device, label);
|
||||
|
||||
else if (STREQ (vfs_type, "ntfs"))
|
||||
r = ntfslabel (device, label);
|
||||
r = ntfslabel (mountable->device, label);
|
||||
|
||||
else {
|
||||
reply_with_error ("don't know how to set the label for '%s' filesystems",
|
||||
@@ -98,6 +93,5 @@ do_set_label (const char *device, const char *label)
|
||||
r = -1;
|
||||
}
|
||||
|
||||
free (vfs_type);
|
||||
return r;
|
||||
}
|
||||
|
||||
88
daemon/ldm.c
88
daemon/ldm.c
@@ -105,15 +105,13 @@ int
|
||||
do_ldmtool_create_all (void)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
r = command (NULL, &err, "ldmtool", "create", "all", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,15 +119,13 @@ int
|
||||
do_ldmtool_remove_all (void)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
r = command (NULL, &err, "ldmtool", "remove", "all", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,9 +289,9 @@ do_ldmtool_scan_devices (char * const * devices)
|
||||
{
|
||||
char **ret;
|
||||
size_t i, nr_devices;
|
||||
const char **argv;
|
||||
CLEANUP_FREE_STRING_LIST const char **argv = NULL;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
nr_devices = count_strings (devices);
|
||||
argv = malloc ((3 + nr_devices) * sizeof (char *));
|
||||
@@ -311,153 +307,113 @@ do_ldmtool_scan_devices (char * const * devices)
|
||||
argv[2+i] = NULL;
|
||||
|
||||
r = commandv (&out, &err, argv);
|
||||
free (argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_string_list (out, __func__, "ldmtool scan");
|
||||
free (out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
do_ldmtool_diskgroup_name (const char *diskgroup)
|
||||
{
|
||||
char *ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err, str_ldmtool, "show", "diskgroup", diskgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string (out, "name", 0,
|
||||
__func__, "ldmtool show diskgroup");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string (out, "name", 0,
|
||||
__func__, "ldmtool show diskgroup");
|
||||
}
|
||||
|
||||
char **
|
||||
do_ldmtool_diskgroup_volumes (const char *diskgroup)
|
||||
{
|
||||
char **ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err, str_ldmtool, "show", "diskgroup", diskgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string_list (out, "volumes",
|
||||
__func__, "ldmtool show diskgroup");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string_list (out, "volumes",
|
||||
__func__, "ldmtool show diskgroup");
|
||||
}
|
||||
|
||||
char **
|
||||
do_ldmtool_diskgroup_disks (const char *diskgroup)
|
||||
{
|
||||
char **ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err, str_ldmtool, "show", "diskgroup", diskgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string_list (out, "disks",
|
||||
__func__, "ldmtool show diskgroup");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string_list (out, "disks",
|
||||
__func__, "ldmtool show diskgroup");
|
||||
}
|
||||
|
||||
char *
|
||||
do_ldmtool_volume_type (const char *diskgroup, const char *volume)
|
||||
{
|
||||
char *ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err,
|
||||
str_ldmtool, "show", "volume", diskgroup, volume, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string (out, "type", 0,
|
||||
__func__, "ldmtool show volume");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string (out, "type", 0,
|
||||
__func__, "ldmtool show volume");
|
||||
}
|
||||
|
||||
char *
|
||||
do_ldmtool_volume_hint (const char *diskgroup, const char *volume)
|
||||
{
|
||||
char *ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err,
|
||||
str_ldmtool, "show", "volume", diskgroup, volume, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string (out, "hint", GET_STRING_NULL_TO_EMPTY,
|
||||
__func__, "ldmtool show volume");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string (out, "hint", GET_STRING_NULL_TO_EMPTY,
|
||||
__func__, "ldmtool show volume");
|
||||
}
|
||||
|
||||
char **
|
||||
do_ldmtool_volume_partitions (const char *diskgroup, const char *volume)
|
||||
{
|
||||
char **ret;
|
||||
int r;
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
r = command (&out, &err,
|
||||
str_ldmtool, "show", "volume", diskgroup, volume, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
ret = parse_json_get_object_string_list (out, "partitions",
|
||||
__func__, "ldmtool show volume");
|
||||
free (out);
|
||||
return ret;
|
||||
return parse_json_get_object_string_list (out, "partitions",
|
||||
__func__, "ldmtool show volume");
|
||||
}
|
||||
|
||||
#else /* !HAVE_YAJL */
|
||||
|
||||
143
daemon/link.c
143
daemon/link.c
@@ -25,6 +25,8 @@
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "areadlink.h"
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
@@ -33,25 +35,17 @@ GUESTFSD_EXT_CMD(str_ln, ln);
|
||||
char *
|
||||
do_readlink (const char *path)
|
||||
{
|
||||
ssize_t r;
|
||||
char *ret;
|
||||
char link[PATH_MAX];
|
||||
char *link;
|
||||
|
||||
CHROOT_IN;
|
||||
r = readlink (path, link, sizeof link);
|
||||
link = areadlink (path);
|
||||
CHROOT_OUT;
|
||||
if (r == -1) {
|
||||
if (link == NULL) {
|
||||
reply_with_perror ("readlink");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = strndup (link, r);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("strndup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret; /* caller frees */
|
||||
return link; /* caller frees */
|
||||
}
|
||||
|
||||
char **
|
||||
@@ -59,9 +53,6 @@ do_internal_readlinklist (const char *path, char *const *names)
|
||||
{
|
||||
int fd_cwd;
|
||||
size_t i;
|
||||
ssize_t r;
|
||||
char link[PATH_MAX];
|
||||
const char *str;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
CHROOT_IN;
|
||||
@@ -74,23 +65,20 @@ do_internal_readlinklist (const char *path, char *const *names)
|
||||
}
|
||||
|
||||
for (i = 0; names[i] != NULL; ++i) {
|
||||
r = readlinkat (fd_cwd, names[i], link, sizeof link);
|
||||
if (r >= PATH_MAX) {
|
||||
reply_with_perror ("readlinkat: returned link is too long");
|
||||
close (fd_cwd);
|
||||
return NULL;
|
||||
}
|
||||
/* Because of the way this function is intended to be used,
|
||||
* we actually expect to see errors here, and they are not fatal.
|
||||
*/
|
||||
if (r >= 0) {
|
||||
link[r] = '\0';
|
||||
str = link;
|
||||
} else
|
||||
str = "";
|
||||
if (add_string (&ret, str) == -1) {
|
||||
close (fd_cwd);
|
||||
return NULL;
|
||||
CLEANUP_FREE char *link = areadlinkat (fd_cwd, names[i]);
|
||||
|
||||
if (link != NULL) {
|
||||
if (add_string (&ret, link) == -1) {
|
||||
add_string_failed:
|
||||
close (fd_cwd);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (add_string (&ret, "") == -1)
|
||||
goto add_string_failed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,13 +90,47 @@ do_internal_readlinklist (const char *path, char *const *names)
|
||||
return ret.argv;
|
||||
}
|
||||
|
||||
static int
|
||||
_link (const char *flag, int symbolic, const char *target, const char *linkname)
|
||||
int
|
||||
do_ln (const char *target, const char *linkname)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
char *buf_linkname;
|
||||
char *buf_target;
|
||||
|
||||
CHROOT_IN;
|
||||
r = link (target, linkname);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("link: %s: %s", target, linkname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_ln_f (const char *target, const char *linkname)
|
||||
{
|
||||
int r;
|
||||
|
||||
CHROOT_IN;
|
||||
unlink (linkname);
|
||||
r = link (target, linkname);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("link: %s: %s", target, linkname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_symlink (const char *flag, const char *target, const char *linkname)
|
||||
{
|
||||
int r;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE char *buf_linkname = NULL;
|
||||
|
||||
/* Prefix linkname with sysroot. */
|
||||
buf_linkname = sysroot_path (linkname);
|
||||
@@ -117,65 +139,26 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only prefix target if it's _not_ a symbolic link, and if
|
||||
* the target is absolute. Note that the resulting link will
|
||||
* always be "broken" from the p.o.v. of the appliance, ie:
|
||||
* /a -> /b but the path as seen here is /sysroot/b
|
||||
*/
|
||||
buf_target = NULL;
|
||||
if (!symbolic && target[0] == '/') {
|
||||
buf_target = sysroot_path (target);
|
||||
if (!buf_target) {
|
||||
reply_with_perror ("malloc");
|
||||
free (buf_linkname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
r = command (NULL, &err,
|
||||
str_ln, flag, "--", /* target could begin with '-' */
|
||||
buf_target ? : target, buf_linkname, NULL);
|
||||
else
|
||||
r = command (NULL, &err,
|
||||
str_ln, "--",
|
||||
buf_target ? : target, buf_linkname, NULL);
|
||||
free (buf_linkname);
|
||||
free (buf_target);
|
||||
r = command (NULL, &err,
|
||||
str_ln, flag, "--", /* target could begin with '-' */
|
||||
target, buf_linkname, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("ln%s%s: %s: %s: %s",
|
||||
flag ? " " : "",
|
||||
flag ? : "",
|
||||
target, linkname, err);
|
||||
free (err);
|
||||
reply_with_error ("ln %s: %s: %s: %s",
|
||||
flag, target, linkname, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_ln (const char *target, const char *linkname)
|
||||
{
|
||||
return _link (NULL, 0, target, linkname);
|
||||
}
|
||||
|
||||
int
|
||||
do_ln_f (const char *target, const char *linkname)
|
||||
{
|
||||
return _link ("-f", 0, target, linkname);
|
||||
}
|
||||
|
||||
int
|
||||
do_ln_s (const char *target, const char *linkname)
|
||||
{
|
||||
return _link ("-s", 1, target, linkname);
|
||||
return _symlink ("-s", target, linkname);
|
||||
}
|
||||
|
||||
int
|
||||
do_ln_sf (const char *target, const char *linkname)
|
||||
{
|
||||
return _link ("-sf", 1, target, linkname);
|
||||
return _symlink ("-sf", target, linkname);
|
||||
}
|
||||
|
||||
20
daemon/ls.c
20
daemon/ls.c
@@ -77,14 +77,14 @@ do_ls0 (const char *path)
|
||||
}
|
||||
|
||||
if (errno != 0) {
|
||||
perror (path);
|
||||
fprintf (stderr, "readdir: %s: %m\n", path);
|
||||
send_file_end (1); /* Cancel. */
|
||||
closedir (dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (closedir (dir) == -1) {
|
||||
perror (path);
|
||||
fprintf (stderr, "closedir: %s: %m\n", path);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
@@ -105,8 +105,9 @@ char *
|
||||
do_ll (const char *path)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *spath;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE char *spath = NULL;
|
||||
|
||||
spath = sysroot_path (path);
|
||||
if (!spath) {
|
||||
@@ -115,15 +116,12 @@ do_ll (const char *path)
|
||||
}
|
||||
|
||||
r = command (&out, &err, str_ls, "-la", spath, NULL);
|
||||
free (spath);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
@@ -131,8 +129,9 @@ char *
|
||||
do_llz (const char *path)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *spath;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE char *spath;
|
||||
|
||||
spath = sysroot_path (path);
|
||||
if (!spath) {
|
||||
@@ -141,14 +140,11 @@ do_llz (const char *path)
|
||||
}
|
||||
|
||||
r = command (&out, &err, str_ls, "-laZ", spath, NULL);
|
||||
free (spath);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
@@ -115,18 +115,15 @@ luks_open (const char *device, const char *key, const char *mapname,
|
||||
ADD_ARG (argv, i, mapname);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -155,16 +152,13 @@ do_luks_close (const char *device)
|
||||
|
||||
const char *mapname = &device[12];
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (NULL, &err, str_cryptsetup, "luksClose", mapname, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -196,18 +190,15 @@ luks_format (const char *device, const char *key, int keyslot,
|
||||
ADD_ARG (argv, i, tempfile);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -256,19 +247,16 @@ do_luks_add_key (const char *device, const char *key, const char *newkey,
|
||||
ADD_ARG (argv, i, newkeyfile);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (keyfile);
|
||||
remove_temp (newkeyfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,17 +281,14 @@ do_luks_kill_slot (const char *device, const char *key, int keyslot)
|
||||
ADD_ARG (argv, i, keyslot_s);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,13 @@ GUESTFSD_EXT_CMD(str_rm, rm);
|
||||
|
||||
/* This runs during daemon start up and creates a complete copy of
|
||||
* /etc/lvm so that we can modify it as we desire. We set
|
||||
* LVM_SYSTEM_DIR to point to the copy.
|
||||
* LVM_SYSTEM_DIR to point to the copy. Note that the final directory
|
||||
* layout is:
|
||||
* /tmp/lvmXXXXXX (lvm_system_dir set to this)
|
||||
* /tmp/lvmXXXXXX/lvm ($LVM_SYSTEM_DIR set to this)
|
||||
* /tmp/lvmXXXXXX/lvm/lvm.conf (configuration file)
|
||||
* /tmp/lvmXXXXXX/lvm/cache
|
||||
* etc.
|
||||
*/
|
||||
static char lvm_system_dir[] = "/tmp/lvmXXXXXX";
|
||||
|
||||
@@ -47,7 +53,7 @@ void
|
||||
copy_lvm (void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char cmd[64];
|
||||
char cmd[64], env[64];
|
||||
int r;
|
||||
|
||||
/* If /etc/lvm directory doesn't exist (or isn't a directory) assume
|
||||
@@ -64,12 +70,12 @@ copy_lvm (void)
|
||||
}
|
||||
|
||||
if (mkdtemp (lvm_system_dir) == NULL) {
|
||||
perror (lvm_system_dir);
|
||||
fprintf (stderr, "mkdtemp: %s: %m\n", lvm_system_dir);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Hopefully no dotfiles in there ... XXX */
|
||||
snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/* %s", str_cp, lvm_system_dir);
|
||||
/* Copy the entire directory */
|
||||
snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/ %s", str_cp, lvm_system_dir);
|
||||
r = system (cmd);
|
||||
if (r == -1) {
|
||||
perror (cmd);
|
||||
@@ -85,7 +91,8 @@ copy_lvm (void)
|
||||
}
|
||||
|
||||
/* Set environment variable so we use the copy. */
|
||||
setenv ("LVM_SYSTEM_DIR", lvm_system_dir, 1);
|
||||
snprintf (env, sizeof env, "%s/lvm", lvm_system_dir);
|
||||
setenv ("LVM_SYSTEM_DIR", env, 1);
|
||||
|
||||
/* Set a handler to remove the temporary directory at exit. */
|
||||
atexit (rm_lvm_system_dir);
|
||||
@@ -129,10 +136,11 @@ static int
|
||||
set_filter (const char *filter)
|
||||
{
|
||||
char lvm_conf[64];
|
||||
snprintf (lvm_conf, sizeof lvm_conf, "%s/lvm.conf", lvm_system_dir);
|
||||
snprintf (lvm_conf, sizeof lvm_conf, "%s/lvm/lvm.conf", lvm_system_dir);
|
||||
|
||||
char lvm_conf_new[64];
|
||||
snprintf (lvm_conf_new, sizeof lvm_conf, "%s/lvm.conf.new", lvm_system_dir);
|
||||
snprintf (lvm_conf_new, sizeof lvm_conf, "%s/lvm/lvm.conf.new",
|
||||
lvm_system_dir);
|
||||
|
||||
FILE *ifp = fopen (lvm_conf, "r");
|
||||
if (ifp == NULL) {
|
||||
@@ -146,9 +154,9 @@ set_filter (const char *filter)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline (&line, &len, ifp) != -1) {
|
||||
CLEANUP_FREE char *line = NULL;
|
||||
size_t allocsize = 0;
|
||||
while (getline (&line, &allocsize, ifp) != -1) {
|
||||
int r;
|
||||
if (is_filter_line (line)) {
|
||||
r = fprintf (ofp, " filter = [ %s ]\n", filter);
|
||||
@@ -160,14 +168,11 @@ set_filter (const char *filter)
|
||||
reply_with_error ("%s: write failed", lvm_conf_new);
|
||||
fclose (ifp);
|
||||
fclose (ofp);
|
||||
free (line);
|
||||
unlink (lvm_conf_new);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free (line);
|
||||
|
||||
if (fclose (ifp) == EOF) {
|
||||
reply_with_perror ("close: %s", lvm_conf);
|
||||
unlink (lvm_conf_new);
|
||||
@@ -192,15 +197,13 @@ set_filter (const char *filter)
|
||||
static int
|
||||
vgchange (const char *vgchange_flag)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (NULL, &err, str_lvm, "vgchange", vgchange_flag, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgchange: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -223,19 +226,17 @@ static int
|
||||
rescan (void)
|
||||
{
|
||||
char lvm_cache[64];
|
||||
snprintf (lvm_cache, sizeof lvm_cache, "%s/cache/.cache", lvm_system_dir);
|
||||
snprintf (lvm_cache, sizeof lvm_cache, "%s/lvm/cache/.cache", lvm_system_dir);
|
||||
|
||||
unlink (lvm_cache);
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (NULL, &err, str_lvm, "vgscan", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgscan: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -287,17 +288,14 @@ make_filter_string (char *const *devices)
|
||||
int
|
||||
do_lvm_set_filter (char *const *devices)
|
||||
{
|
||||
char *filter = make_filter_string (devices);
|
||||
CLEANUP_FREE char *filter = make_filter_string (devices);
|
||||
if (filter == NULL)
|
||||
return -1;
|
||||
|
||||
if (deactivate () == -1) {
|
||||
free (filter);
|
||||
if (deactivate () == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = set_filter (filter);
|
||||
free (filter);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
|
||||
|
||||
243
daemon/lvm.c
243
daemon/lvm.c
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -103,7 +103,8 @@ convert_lvm_output (char *out, const char *prefix)
|
||||
char **
|
||||
do_pvs (void)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
@@ -111,19 +112,17 @@ do_pvs (void)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return convert_lvm_output (out, NULL);
|
||||
}
|
||||
|
||||
char **
|
||||
do_vgs (void)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
@@ -131,19 +130,17 @@ do_vgs (void)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return convert_lvm_output (out, NULL);
|
||||
}
|
||||
|
||||
char **
|
||||
do_lvs (void)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
@@ -153,12 +150,9 @@ do_lvs (void)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return convert_lvm_output (out, "/dev/");
|
||||
}
|
||||
|
||||
@@ -187,19 +181,16 @@ do_lvs_full (void)
|
||||
int
|
||||
do_pvcreate (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvcreate", device, NULL);
|
||||
str_lvm, "pvcreate", "--force", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -208,9 +199,9 @@ do_pvcreate (const char *device)
|
||||
int
|
||||
do_vgcreate (const char *volgroup, char *const *physvols)
|
||||
{
|
||||
char *err;
|
||||
int r, argc, i;
|
||||
const char **argv;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE const char **argv = NULL;
|
||||
|
||||
argc = count_strings (physvols) + 3;
|
||||
argv = malloc (sizeof (char *) * (argc + 1));
|
||||
@@ -227,14 +218,9 @@ do_vgcreate (const char *volgroup, char *const *physvols)
|
||||
r = commandv (NULL, &err, (const char * const*) argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
free (argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
free (argv);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -243,7 +229,7 @@ do_vgcreate (const char *volgroup, char *const *physvols)
|
||||
int
|
||||
do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
char size[64];
|
||||
|
||||
@@ -254,12 +240,9 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
|
||||
"-L", size, "-n", logvol, volgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -268,7 +251,7 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
|
||||
int
|
||||
do_lvcreate_free (const char *logvol, const char *volgroup, int percent)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (percent < 0 || percent > 100) {
|
||||
@@ -284,12 +267,9 @@ do_lvcreate_free (const char *logvol, const char *volgroup, int percent)
|
||||
"-l", size, "-n", logvol, volgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -309,7 +289,7 @@ ignore_same_size_error (const char *err)
|
||||
int
|
||||
do_lvresize (const char *logvol, int mbytes)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
char size[64];
|
||||
|
||||
@@ -321,19 +301,17 @@ do_lvresize (const char *logvol, int mbytes)
|
||||
if (r == -1) {
|
||||
if (!ignore_same_size_error (err)) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_lvresize_free (const char *logvol, int percent)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (percent < 0 || percent > 100) {
|
||||
@@ -349,12 +327,10 @@ do_lvresize_free (const char *logvol, int percent)
|
||||
if (r == -1) {
|
||||
if (!ignore_same_size_error (err)) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -364,71 +340,66 @@ do_lvresize_free (const char *logvol, int percent)
|
||||
int
|
||||
do_lvm_remove_all (void)
|
||||
{
|
||||
char **xs;
|
||||
size_t i;
|
||||
int r;
|
||||
char *err;
|
||||
|
||||
/* Remove LVs. */
|
||||
xs = do_lvs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
/* Deactivate the LV first. On Ubuntu, lvremove '-f' option
|
||||
* does not remove active LVs reliably.
|
||||
*/
|
||||
(void) command (NULL, NULL, str_lvm, "lvchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, str_lvm, "lvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("lvremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
free_strings (xs);
|
||||
{
|
||||
/* Remove LVs. */
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **xs = do_lvs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
/* Deactivate the LV first. On Ubuntu, lvremove '-f' option
|
||||
* does not remove active LVs reliably.
|
||||
*/
|
||||
(void) command (NULL, NULL, str_lvm, "lvchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, str_lvm, "lvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("lvremove: %s: %s", xs[i], err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free (err);
|
||||
}
|
||||
free_strings (xs);
|
||||
|
||||
/* Remove VGs. */
|
||||
xs = do_vgs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
/* Deactivate the VG first, see note above. */
|
||||
(void) command (NULL, NULL, str_lvm, "vgchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, str_lvm, "vgremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
free_strings (xs);
|
||||
{
|
||||
/* Remove VGs. */
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **xs = do_vgs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
}
|
||||
free_strings (xs);
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
/* Deactivate the VG first, see note above. */
|
||||
(void) command (NULL, NULL, str_lvm, "vgchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, str_lvm, "vgremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgremove: %s: %s", xs[i], err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Remove PVs. */
|
||||
xs = do_pvs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
r = command (NULL, &err, str_lvm, "pvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("pvremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
free_strings (xs);
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **xs = do_pvs ();
|
||||
if (xs == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
r = command (NULL, &err, str_lvm, "pvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("pvremove: %s: %s", xs[i], err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free (err);
|
||||
}
|
||||
free_strings (xs);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -439,19 +410,16 @@ do_lvm_remove_all (void)
|
||||
int
|
||||
do_lvremove (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "lvremove", "-f", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -460,19 +428,16 @@ do_lvremove (const char *device)
|
||||
int
|
||||
do_vgremove (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgremove", "-f", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -481,19 +446,16 @@ do_vgremove (const char *device)
|
||||
int
|
||||
do_pvremove (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvremove", "-ff", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -502,25 +464,23 @@ do_pvremove (const char *device)
|
||||
int
|
||||
do_pvresize (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvresize", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_pvresize_size (const char *device, int64_t size)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
char buf[32];
|
||||
@@ -532,20 +492,18 @@ do_pvresize_size (const char *device, int64_t size)
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_vg_activate (int activate, char *const *volgroups)
|
||||
{
|
||||
char *err;
|
||||
int r, i, argc;
|
||||
const char **argv;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE const char **argv = NULL;
|
||||
|
||||
argc = count_strings (volgroups) + 4;
|
||||
argv = malloc (sizeof (char *) * (argc+1));
|
||||
@@ -564,14 +522,9 @@ do_vg_activate (int activate, char *const *volgroups)
|
||||
r = commandv (NULL, &err, (const char * const*) argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgchange: %s", err);
|
||||
free (err);
|
||||
free (argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
free (argv);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -587,7 +540,7 @@ do_vg_activate_all (int activate)
|
||||
int
|
||||
do_lvrename (const char *logvol, const char *newlogvol)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
@@ -595,12 +548,9 @@ do_lvrename (const char *logvol, const char *newlogvol)
|
||||
logvol, newlogvol, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s -> %s: %s", logvol, newlogvol, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -609,7 +559,7 @@ do_lvrename (const char *logvol, const char *newlogvol)
|
||||
int
|
||||
do_vgrename (const char *volgroup, const char *newvolgroup)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
@@ -617,12 +567,9 @@ do_vgrename (const char *volgroup, const char *newvolgroup)
|
||||
volgroup, newvolgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s -> %s: %s", volgroup, newvolgroup, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -632,7 +579,7 @@ static char *
|
||||
get_lvm_field (const char *cmd, const char *field, const char *device)
|
||||
{
|
||||
char *out;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (&out, &err,
|
||||
str_lvm, cmd,
|
||||
"--unbuffered", "--noheadings", "-o", field,
|
||||
@@ -640,12 +587,9 @@ get_lvm_field (const char *cmd, const char *field, const char *device)
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
trim (out);
|
||||
return out; /* Caller frees. */
|
||||
}
|
||||
@@ -671,23 +615,18 @@ do_lvuuid (const char *device)
|
||||
static char **
|
||||
get_lvm_fields (const char *cmd, const char *field, const char *device)
|
||||
{
|
||||
char *out;
|
||||
char *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
|
||||
int r = command (&out, &err,
|
||||
str_lvm, cmd,
|
||||
"--unbuffered", "--noheadings", "-o", field,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
char **ret = split_lines (out);
|
||||
free (out);
|
||||
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
@@ -714,18 +653,16 @@ do_vglvuuids (const char *vgname)
|
||||
int
|
||||
do_vgscan (void)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgscan", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -760,7 +697,7 @@ lv_canonical (const char *device, char **ret)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char **lvs = do_lvs ();
|
||||
CLEANUP_FREE_STRING_LIST char **lvs = do_lvs ();
|
||||
if (lvs == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -769,7 +706,6 @@ lv_canonical (const char *device, char **ret)
|
||||
r = stat (lvs[i], &stat2);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("stat: %s", lvs[i]);
|
||||
free_strings (lvs);
|
||||
return -1;
|
||||
}
|
||||
if (stat1.st_rdev == stat2.st_rdev) { /* found it */
|
||||
@@ -777,17 +713,14 @@ lv_canonical (const char *device, char **ret)
|
||||
*ret = strdup (lvs[i]);
|
||||
if (*ret == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
free_strings (lvs);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free_strings (lvs);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
free_strings (lvs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -894,7 +827,7 @@ do_list_dm_devices (void)
|
||||
char *
|
||||
do_vgmeta (const char *vg, size_t *size_r)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int fd, r;
|
||||
char tmp[] = "/tmp/vgmetaXXXXXX";
|
||||
size_t alloc, size, max;
|
||||
@@ -913,10 +846,8 @@ do_vgmeta (const char *vg, size_t *size_r)
|
||||
r = command (NULL, &err, str_lvm, "vgcfgbackup", "-f", tmp, vg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgcfgbackup: %s", err);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* Now read back the temporary file. */
|
||||
fd = open (tmp, O_RDONLY|O_CLOEXEC);
|
||||
@@ -981,19 +912,16 @@ do_vgmeta (const char *vg, size_t *size_r)
|
||||
int
|
||||
do_pvchange_uuid (const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvchange", "-u", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -1002,19 +930,16 @@ do_pvchange_uuid (const char *device)
|
||||
int
|
||||
do_pvchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvchange", "-u", "-a", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -1023,19 +948,16 @@ do_pvchange_uuid_all (void)
|
||||
int
|
||||
do_vgchange_uuid (const char *vg)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgchange", "-u", vg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", vg, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -1044,19 +966,16 @@ do_vgchange_uuid (const char *vg)
|
||||
int
|
||||
do_vgchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgchange", "-u", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
|
||||
30
daemon/md.c
30
daemon/md.c
@@ -61,7 +61,7 @@ do_md_create (const char *name, char *const *devices,
|
||||
char chunk_s[32];
|
||||
size_t j;
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
uint64_t umissingbitmap = (uint64_t) missingbitmap;
|
||||
|
||||
/* Check the optional parameters and set defaults where appropriate. */
|
||||
@@ -161,12 +161,9 @@ do_md_create (const char *name, char *const *devices,
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("mdadm: %s: %s", name, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
@@ -241,8 +238,8 @@ do_md_detail(const char *md)
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
CLEANUP_FREE_STRING_LIST char **lines = NULL;
|
||||
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
@@ -295,20 +292,12 @@ do_md_detail(const char *md)
|
||||
}
|
||||
}
|
||||
|
||||
free (out);
|
||||
free (err);
|
||||
free_strings (lines);
|
||||
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
if (ret.argv != NULL)
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
|
||||
@@ -319,16 +308,14 @@ int
|
||||
do_md_stop(const char *md)
|
||||
{
|
||||
int r;
|
||||
char *err = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
const char *mdadm[] = { str_mdadm, "--stop", md, NULL};
|
||||
r = commandv(NULL, &err, mdadm);
|
||||
if (r == -1) {
|
||||
reply_with_error("%s", err);
|
||||
free(err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -454,8 +441,8 @@ do_md_stat (const char *md)
|
||||
{
|
||||
size_t mdlen;
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
CLEANUP_FREE char *line = NULL;
|
||||
size_t allocsize = 0;
|
||||
ssize_t n;
|
||||
guestfs_int_mdstat_list *ret = NULL;
|
||||
|
||||
@@ -470,13 +457,12 @@ do_md_stat (const char *md)
|
||||
}
|
||||
|
||||
/* Search for a line which begins with "<md> : ". */
|
||||
while ((n = getline (&line, &len, fp)) != -1) {
|
||||
while ((n = getline (&line, &allocsize, fp)) != -1) {
|
||||
if (STRPREFIX (line, md) &&
|
||||
line[mdlen] == ' ' && line[mdlen+1] == ':' && line[mdlen+2] == ' ') {
|
||||
/* Found it. */
|
||||
ret = parse_md_stat_line (&line[mdlen+3]);
|
||||
if (!ret) {
|
||||
free (line);
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
@@ -488,8 +474,6 @@ do_md_stat (const char *md)
|
||||
}
|
||||
}
|
||||
|
||||
free (line);
|
||||
|
||||
if (fclose (fp) == EOF) {
|
||||
reply_with_perror ("fclose: %s", "/proc/mdstat");
|
||||
xdr_free ((xdrproc_t) xdr_guestfs_int_mdstat_list, (char *) ret);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,7 +44,7 @@ do_mkfs (const char *fstype, const char *device, int blocksize,
|
||||
char inode_str[32];
|
||||
char sectorsize_str[32];
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int extfs = 0;
|
||||
|
||||
if (STREQ (fstype, "ext2") || STREQ (fstype, "ext3") ||
|
||||
@@ -184,14 +184,14 @@ do_mkfs (const char *fstype, const char *device, int blocksize,
|
||||
ADD_ARG (argv, i, device);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
wipe_device_before_mkfs (device);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s: %s", fstype, device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,14 +36,13 @@ optgroup_linuxmodules_available (void)
|
||||
int
|
||||
do_modprobe (const char *module)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (NULL, &err, str_modprobe, module, NULL);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ is_root_mounted (void)
|
||||
*/
|
||||
fp = setmntent ("/proc/mounts", "r");
|
||||
if (fp == NULL) {
|
||||
perror ("/proc/mounts");
|
||||
fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ is_device_mounted (const char *device)
|
||||
*/
|
||||
fp = setmntent ("/proc/mounts", "r");
|
||||
if (fp == NULL) {
|
||||
perror ("/proc/mounts");
|
||||
fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -124,11 +124,9 @@ is_device_mounted (const char *device)
|
||||
|
||||
int
|
||||
do_mount_vfs (const char *options, const char *vfstype,
|
||||
const char *device, const char *mountpoint)
|
||||
const mountable_t *mountable, const char *mountpoint)
|
||||
{
|
||||
int r;
|
||||
char *mp;
|
||||
char *error;
|
||||
CLEANUP_FREE char *mp = NULL;
|
||||
struct stat statbuf;
|
||||
|
||||
ABS_PATH (mountpoint, , return -1);
|
||||
@@ -142,50 +140,77 @@ do_mount_vfs (const char *options, const char *vfstype,
|
||||
/* Check the mountpoint exists and is a directory. */
|
||||
if (stat (mp, &statbuf) == -1) {
|
||||
reply_with_perror ("mount: %s", mountpoint);
|
||||
free (mp);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_perror ("mount: %s: mount point is not a directory", mountpoint);
|
||||
free (mp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mount_vfs_nochroot (options, vfstype, mountable, mp, mountpoint);
|
||||
}
|
||||
|
||||
int
|
||||
mount_vfs_nochroot (const char *options, const char *vfstype,
|
||||
const mountable_t *mountable,
|
||||
const char *mp, const char *user_mp)
|
||||
{
|
||||
CLEANUP_FREE char *options_plus = NULL;
|
||||
const char *device = mountable->device;
|
||||
if (mountable->type == MOUNTABLE_BTRFSVOL) {
|
||||
if (options && strlen (options) > 0) {
|
||||
if (asprintf (&options_plus, "subvol=%s,%s",
|
||||
mountable->volume, options) == -1)
|
||||
{
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (asprintf (&options_plus, "subvol=%s", mountable->volume) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLEANUP_FREE char *error = NULL;
|
||||
int r;
|
||||
if (vfstype)
|
||||
r = command (NULL, &error,
|
||||
str_mount, "-o", options, "-t", vfstype, device, mp, NULL);
|
||||
str_mount, "-o", options_plus ? options_plus : options,
|
||||
"-t", vfstype, device, mp, NULL);
|
||||
else
|
||||
r = command (NULL, &error,
|
||||
str_mount, "-o", options, device, mp, NULL);
|
||||
free (mp);
|
||||
str_mount, "-o", options_plus ? options_plus : options,
|
||||
device, mp, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s on %s (options: '%s'): %s",
|
||||
device, mountpoint, options, error);
|
||||
free (error);
|
||||
device, user_mp, options, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_mount (const char *device, const char *mountpoint)
|
||||
do_mount (const mountable_t *mountable, const char *mountpoint)
|
||||
{
|
||||
return do_mount_vfs ("", NULL, device, mountpoint);
|
||||
return do_mount_vfs ("", NULL, mountable, mountpoint);
|
||||
}
|
||||
|
||||
int
|
||||
do_mount_ro (const char *device, const char *mountpoint)
|
||||
do_mount_ro (const mountable_t *mountable, const char *mountpoint)
|
||||
{
|
||||
return do_mount_vfs ("ro", NULL, device, mountpoint);
|
||||
return do_mount_vfs ("ro", NULL, mountable, mountpoint);
|
||||
}
|
||||
|
||||
int
|
||||
do_mount_options (const char *options, const char *device,
|
||||
do_mount_options (const char *options, const mountable_t *mountable,
|
||||
const char *mountpoint)
|
||||
{
|
||||
return do_mount_vfs (options, NULL, device, mountpoint);
|
||||
return do_mount_vfs (options, NULL, mountable, mountpoint);
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
@@ -194,8 +219,8 @@ do_umount (const char *pathordevice,
|
||||
int force, int lazyunmount)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
char *buf;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
int is_dev;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
@@ -227,16 +252,12 @@ do_umount (const char *pathordevice,
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", pathordevice, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -255,7 +276,7 @@ mounts_or_mountpoints (int mp)
|
||||
*/
|
||||
fp = setmntent ("/proc/mounts", "r");
|
||||
if (fp == NULL) {
|
||||
perror ("/proc/mounts");
|
||||
fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -348,7 +369,7 @@ do_umount_all (void)
|
||||
FILE *fp;
|
||||
struct mntent *m;
|
||||
DECLARE_STRINGSBUF (mounts);
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
@@ -357,7 +378,7 @@ do_umount_all (void)
|
||||
*/
|
||||
fp = setmntent ("/proc/mounts", "r");
|
||||
if (fp == NULL) {
|
||||
perror ("/proc/mounts");
|
||||
fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -388,11 +409,9 @@ do_umount_all (void)
|
||||
r = command (NULL, &err, str_umount, mounts.argv[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("umount: %s: %s", mounts.argv[i], err);
|
||||
free (err);
|
||||
free_stringslen (mounts.argv, mounts.size);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
}
|
||||
|
||||
free_stringslen (mounts.argv, mounts.size);
|
||||
@@ -408,8 +427,7 @@ int
|
||||
do_mount_loop (const char *file, const char *mountpoint)
|
||||
{
|
||||
int r;
|
||||
char *buf, *mp;
|
||||
char *error;
|
||||
CLEANUP_FREE char *buf = NULL, *mp = NULL, *error = NULL;
|
||||
|
||||
/* We have to prefix /sysroot on both the filename and the mountpoint. */
|
||||
mp = sysroot_path (mountpoint);
|
||||
@@ -421,20 +439,15 @@ do_mount_loop (const char *file, const char *mountpoint)
|
||||
buf = sysroot_path (file);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
free (mp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &error, str_mount, "-o", "loop", buf, mp, NULL);
|
||||
free (mp);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s on %s: %s", file, mountpoint, error);
|
||||
free (error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
64
daemon/mountable.c
Normal file
64
daemon/mountable.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "guestfs_protocol.h"
|
||||
|
||||
guestfs_int_internal_mountable *
|
||||
do_internal_parse_mountable (const mountable_t *mountable)
|
||||
{
|
||||
guestfs_int_internal_mountable *ret = calloc (1, sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("calloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->im_type = mountable->type;
|
||||
|
||||
if (mountable->device)
|
||||
ret->im_device = strdup (mountable->device);
|
||||
else
|
||||
ret->im_device = strdup ("");
|
||||
|
||||
if (!ret->im_device) {
|
||||
reply_with_perror ("strdup");
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mountable->volume)
|
||||
ret->im_volume = strdup (mountable->volume);
|
||||
else
|
||||
ret->im_volume = strdup ("");
|
||||
|
||||
if (!ret->im_volume) {
|
||||
reply_with_perror ("strdup");
|
||||
free (ret->im_device);
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,7 +49,7 @@ optgroup_ntfsprogs_available (void)
|
||||
int
|
||||
do_ntfs_3g_probe (int rw, const char *device)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
const char *rw_flag;
|
||||
|
||||
@@ -58,11 +58,9 @@ do_ntfs_3g_probe (int rw, const char *device)
|
||||
r = commandr (NULL, &err, str_ntfs3g_probe, rw_flag, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -70,7 +68,7 @@ do_ntfs_3g_probe (int rw, const char *device)
|
||||
int
|
||||
do_ntfsresize (const char *device, int64_t size, int force)
|
||||
{
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
@@ -99,11 +97,9 @@ do_ntfsresize (const char *device, int64_t size, int force)
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,7 +117,7 @@ do_ntfsfix (const char *device, int clearbadsectors)
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
ADD_ARG (argv, i, str_ntfsfix);
|
||||
|
||||
@@ -135,10 +131,8 @@ do_ntfsfix (const char *device, int clearbadsectors)
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -69,7 +69,7 @@ do_ntfsclone_in (const char *device)
|
||||
{
|
||||
int err, r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
char error_file[] = "/tmp/ntfscloneXXXXXX";
|
||||
int fd;
|
||||
|
||||
@@ -102,10 +102,8 @@ do_ntfsclone_in (const char *device)
|
||||
errno = err;
|
||||
reply_with_perror ("%s", cmd);
|
||||
unlink (error_file);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* The semantics of fwrite are too undefined, so write to the
|
||||
* file descriptor directly instead.
|
||||
@@ -115,9 +113,8 @@ do_ntfsclone_in (const char *device)
|
||||
r = receive_file (write_cb, &fd);
|
||||
if (r == -1) { /* write error */
|
||||
cancel_receive ();
|
||||
char *errstr = read_error_file (error_file);
|
||||
CLEANUP_FREE char *errstr = read_error_file (error_file);
|
||||
reply_with_error ("write error on device: %s: %s", device, errstr);
|
||||
free (errstr);
|
||||
unlink (error_file);
|
||||
pclose (fp);
|
||||
return -1;
|
||||
@@ -133,10 +130,9 @@ do_ntfsclone_in (const char *device)
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
char *errstr = read_error_file (error_file);
|
||||
CLEANUP_FREE char *errstr = read_error_file (error_file);
|
||||
reply_with_error ("ntfsclone subcommand failed on device: %s: %s",
|
||||
device, errstr);
|
||||
free (errstr);
|
||||
unlink (error_file);
|
||||
return -1;
|
||||
}
|
||||
@@ -155,7 +151,7 @@ do_ntfsclone_out (const char *device,
|
||||
{
|
||||
int r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
char buf[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
/* Construct the ntfsclone command. */
|
||||
@@ -177,10 +173,8 @@ do_ntfsclone_out (const char *device,
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* Now we must send the reply message, before the file contents. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
@@ -196,14 +190,14 @@ do_ntfsclone_out (const char *device,
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (device);
|
||||
fprintf (stderr, "fread: %s: %m\n", device);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (device);
|
||||
fprintf (stderr, "pclose: %s: %m\n", device);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
227
daemon/parted.c
227
daemon/parted.c
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,9 +27,11 @@
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_parted, parted);
|
||||
GUESTFSD_EXT_CMD(str_sfdisk, sfdisk);
|
||||
GUESTFSD_EXT_CMD(str_sgdisk, sgdisk);
|
||||
|
||||
/* Notes:
|
||||
*
|
||||
@@ -74,7 +76,7 @@ int
|
||||
do_part_init (const char *device, const char *parttype)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
parttype = check_parttype (parttype);
|
||||
if (!parttype) {
|
||||
@@ -88,10 +90,8 @@ do_part_init (const char *device, const char *parttype)
|
||||
str_parted, "-s", "--", device, "mklabel", parttype, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -103,7 +103,7 @@ do_part_add (const char *device, const char *prlogex,
|
||||
int64_t startsect, int64_t endsect)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
char startstr[32];
|
||||
char endstr[32];
|
||||
|
||||
@@ -144,10 +144,8 @@ do_part_add (const char *device, const char *prlogex,
|
||||
device, "mkpart", prlogex, startstr, endstr, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -158,7 +156,7 @@ int
|
||||
do_part_del (const char *device, int partnum)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
if (partnum <= 0) {
|
||||
reply_with_error ("partition number must be >= 1");
|
||||
@@ -174,10 +172,8 @@ do_part_del (const char *device, int partnum)
|
||||
str_parted, "-s", "--", device, "rm", partnum_str, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -188,7 +184,7 @@ int
|
||||
do_part_disk (const char *device, const char *parttype)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
parttype = check_parttype (parttype);
|
||||
if (!parttype) {
|
||||
@@ -220,10 +216,8 @@ do_part_disk (const char *device, const char *parttype)
|
||||
startstr, endstr, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -234,7 +228,7 @@ int
|
||||
do_part_set_bootable (const char *device, int partnum, int bootable)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
if (partnum <= 0) {
|
||||
reply_with_error ("partition number must be >= 1");
|
||||
@@ -252,10 +246,8 @@ do_part_set_bootable (const char *device, int partnum, int bootable)
|
||||
device, "set", partstr, "boot", bootable ? "on" : "off", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -266,7 +258,7 @@ int
|
||||
do_part_set_name (const char *device, int partnum, const char *name)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
if (partnum <= 0) {
|
||||
reply_with_error ("partition number must be >= 1");
|
||||
@@ -283,10 +275,8 @@ do_part_set_name (const char *device, int partnum, const char *name)
|
||||
str_parted, "-s", "--", device, "name", partstr, name, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("parted: %s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -335,12 +325,11 @@ test_parted_m_opt (void)
|
||||
if (result >= 0)
|
||||
return result;
|
||||
|
||||
char *err = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandr (NULL, &err, str_parted, "-s", "-m", "/dev/null", NULL);
|
||||
if (r == -1) {
|
||||
/* Test failed, eg. missing or completely unusable parted binary. */
|
||||
reply_with_error ("could not run 'parted' command");
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -348,14 +337,14 @@ test_parted_m_opt (void)
|
||||
result = 0;
|
||||
else
|
||||
result = 1;
|
||||
free (err);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *
|
||||
print_partition_table (const char *device, int parted_has_m_opt)
|
||||
{
|
||||
char *out, *err;
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
if (parted_has_m_opt)
|
||||
@@ -371,10 +360,8 @@ print_partition_table (const char *device, int parted_has_m_opt)
|
||||
/* Hack for parted 1.x which sends errors to stdout. */
|
||||
*err ? err : out);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -386,7 +373,7 @@ do_part_get_parttype (const char *device)
|
||||
if (parted_has_m_opt == -1)
|
||||
return NULL;
|
||||
|
||||
char *out = print_partition_table (device, parted_has_m_opt);
|
||||
CLEANUP_FREE char *out = print_partition_table (device, parted_has_m_opt);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
@@ -394,8 +381,7 @@ do_part_get_parttype (const char *device)
|
||||
/* New-style parsing using the "machine-readable" format from
|
||||
* 'parted -m'.
|
||||
*/
|
||||
char **lines = split_lines (out);
|
||||
free (out);
|
||||
CLEANUP_FREE_STRING_LIST char **lines = split_lines (out);
|
||||
|
||||
if (!lines)
|
||||
return NULL;
|
||||
@@ -403,13 +389,11 @@ do_part_get_parttype (const char *device)
|
||||
if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) {
|
||||
reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s",
|
||||
lines[0] ? lines[0] : "(signature was null)");
|
||||
free_strings (lines);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lines[1] == NULL) {
|
||||
reply_with_error ("parted didn't return a line describing the device");
|
||||
free_strings (lines);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -418,12 +402,9 @@ do_part_get_parttype (const char *device)
|
||||
*/
|
||||
char *r = get_table_field (lines[1], 5);
|
||||
if (r == NULL) {
|
||||
free_strings (lines);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free_strings (lines);
|
||||
|
||||
/* If "loop" return an error (RHBZ#634246). */
|
||||
if (STREQ (r, "loop")) {
|
||||
free (r);
|
||||
@@ -438,7 +419,6 @@ do_part_get_parttype (const char *device)
|
||||
char *p = strstr (out, "\nPartition Table: ");
|
||||
if (!p) {
|
||||
reply_with_error ("parted didn't return Partition Table line");
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -446,14 +426,12 @@ do_part_get_parttype (const char *device)
|
||||
char *q = strchr (p, '\n');
|
||||
if (!q) {
|
||||
reply_with_error ("parted Partition Table has no end of line char");
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*q = '\0';
|
||||
|
||||
p = strdup (p);
|
||||
free (out);
|
||||
if (!p) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
@@ -477,12 +455,11 @@ do_part_list (const char *device)
|
||||
if (parted_has_m_opt == -1)
|
||||
return NULL;
|
||||
|
||||
char *out = print_partition_table (device, parted_has_m_opt);
|
||||
CLEANUP_FREE char *out = print_partition_table (device, parted_has_m_opt);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
char **lines = split_lines (out);
|
||||
free (out);
|
||||
CLEANUP_FREE_STRING_LIST char **lines = split_lines (out);
|
||||
|
||||
if (!lines)
|
||||
return NULL;
|
||||
@@ -503,7 +480,7 @@ do_part_list (const char *device)
|
||||
r = malloc (sizeof *r);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
goto error1;
|
||||
return NULL;
|
||||
}
|
||||
r->guestfs_int_partition_list_len = nr_rows;
|
||||
r->guestfs_int_partition_list_val =
|
||||
@@ -540,7 +517,7 @@ do_part_list (const char *device)
|
||||
|
||||
if (start == 0) {
|
||||
reply_with_error ("parted output has no \"Number\" line");
|
||||
goto error1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (row = start; lines[row] != NULL; ++row)
|
||||
@@ -551,7 +528,7 @@ do_part_list (const char *device)
|
||||
|
||||
if (end == 0) {
|
||||
reply_with_error ("parted output has no blank after end of table");
|
||||
goto error1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t nr_rows = end - start;
|
||||
@@ -559,7 +536,7 @@ do_part_list (const char *device)
|
||||
r = malloc (sizeof *r);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
goto error1;
|
||||
return NULL;
|
||||
}
|
||||
r->guestfs_int_partition_list_len = nr_rows;
|
||||
r->guestfs_int_partition_list_val =
|
||||
@@ -583,15 +560,12 @@ do_part_list (const char *device)
|
||||
}
|
||||
}
|
||||
|
||||
free_strings (lines);
|
||||
return r;
|
||||
|
||||
error3:
|
||||
free (r->guestfs_int_partition_list_val);
|
||||
error2:
|
||||
free (r);
|
||||
error1:
|
||||
free_strings (lines);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -607,12 +581,11 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
if (parted_has_m_opt == -1)
|
||||
return -1;
|
||||
|
||||
char *out = print_partition_table (device, parted_has_m_opt);
|
||||
CLEANUP_FREE char *out = print_partition_table (device, parted_has_m_opt);
|
||||
if (!out)
|
||||
return -1;
|
||||
|
||||
char **lines = split_lines (out);
|
||||
free (out);
|
||||
CLEANUP_FREE_STRING_LIST char **lines = split_lines (out);
|
||||
|
||||
if (!lines)
|
||||
return -1;
|
||||
@@ -627,13 +600,11 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) {
|
||||
reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s",
|
||||
lines[0] ? lines[0] : "(signature was null)");
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lines[1] == NULL) {
|
||||
reply_with_error ("parted didn't return a line describing the device");
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -642,7 +613,6 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
for (row = 2; lines[row] != NULL; ++row) {
|
||||
if (sscanf (lines[row], "%d:", &pnum) != 1) {
|
||||
reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
if (pnum == partnum)
|
||||
@@ -651,22 +621,14 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
|
||||
if (lines[row] == NULL) {
|
||||
reply_with_error ("partition number %d not found", partnum);
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *boot = get_table_field (lines[row], 6);
|
||||
if (boot == NULL) {
|
||||
free_strings (lines);
|
||||
CLEANUP_FREE char *boot = get_table_field (lines[row], 6);
|
||||
if (boot == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = STREQ (boot, "boot");
|
||||
|
||||
free (boot);
|
||||
free_strings (lines);
|
||||
|
||||
return r;
|
||||
return STREQ (boot, "boot");
|
||||
}
|
||||
else {
|
||||
/* Old-style: First look for the line matching "^Number". */
|
||||
@@ -681,7 +643,6 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
|
||||
if (start == 0) {
|
||||
reply_with_error ("parted output has no \"Number\" line");
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -694,7 +655,6 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
char *p = strstr (lines[header], "Flags");
|
||||
if (!p) {
|
||||
reply_with_error ("parted output has no \"Flags\" field");
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
size_t col = p - lines[header];
|
||||
@@ -706,7 +666,6 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
for (row = start; lines[row] != NULL; ++row) {
|
||||
if (sscanf (lines[row], " %d", &pnum) != 1) {
|
||||
reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
if (pnum == partnum)
|
||||
@@ -715,13 +674,10 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
|
||||
if (lines[row] == NULL) {
|
||||
reply_with_error ("partition number %d not found", partnum);
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = STRPREFIX (&lines[row][col], "boot");
|
||||
free_strings (lines);
|
||||
return r;
|
||||
return STRPREFIX (&lines[row][col], "boot");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +698,7 @@ do_part_get_mbr_id (const char *device, int partnum)
|
||||
char partnum_str[16];
|
||||
snprintf (partnum_str, sizeof partnum_str, "%d", partnum);
|
||||
|
||||
char *out, *err;
|
||||
CLEANUP_FREE char *out = NULL, *err = NULL;
|
||||
int r;
|
||||
|
||||
udev_settle ();
|
||||
@@ -750,11 +706,8 @@ do_part_get_mbr_id (const char *device, int partnum)
|
||||
r = command (&out, &err, str_sfdisk, "--print-id", device, partnum_str, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("sfdisk --print-id: %s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
@@ -762,11 +715,9 @@ do_part_get_mbr_id (const char *device, int partnum)
|
||||
int id;
|
||||
if (sscanf (out, "%x", &id) != 1) {
|
||||
reply_with_error ("sfdisk --print-id: cannot parse output: %s", out);
|
||||
free (out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (out);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -784,7 +735,7 @@ do_part_set_mbr_id (const char *device, int partnum, int idbyte)
|
||||
char idbyte_str[16];
|
||||
snprintf (idbyte_str, sizeof partnum_str, "%x", idbyte); /* NB: hex */
|
||||
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
|
||||
udev_settle ();
|
||||
@@ -793,12 +744,130 @@ do_part_set_mbr_id (const char *device, int partnum, int idbyte)
|
||||
"--change-id", device, partnum_str, idbyte_str, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("sfdisk --change-id: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
optgroup_gdisk_available (void)
|
||||
{
|
||||
return prog_exists (str_sgdisk);
|
||||
}
|
||||
|
||||
int
|
||||
do_part_set_gpt_type(const char *device, int partnum, const char *guid)
|
||||
{
|
||||
if (partnum <= 0) {
|
||||
reply_with_error ("partition number must be >= 1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CLEANUP_FREE char *typecode = NULL;
|
||||
if (asprintf (&typecode, "%i:%s", partnum, guid) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
|
||||
str_sgdisk, device, "-t", typecode, NULL);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s %s -t %s: %s", str_sgdisk, device, typecode, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
do_part_get_gpt_type(const char *device, int partnum)
|
||||
{
|
||||
if (partnum <= 0) {
|
||||
reply_with_error ("partition number must be >= 1");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLEANUP_FREE char *partnum_str = NULL;
|
||||
if (asprintf (&partnum_str, "%i", partnum) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
|
||||
str_sgdisk, device, "-i", partnum_str, NULL);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s %s -i %s: %s", str_sgdisk, device, partnum_str, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **lines = split_lines (err);
|
||||
if (lines == NULL) {
|
||||
reply_with_error ("'%s %s -i %i' returned no output",
|
||||
str_sgdisk, device, partnum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse the output of sgdisk -i:
|
||||
* Partition GUID code: 21686148-6449-6E6F-744E-656564454649 (BIOS boot partition)
|
||||
* Partition unique GUID: 19AEC5FE-D63A-4A15-9D37-6FCBFB873DC0
|
||||
* First sector: 2048 (at 1024.0 KiB)
|
||||
* Last sector: 411647 (at 201.0 MiB)
|
||||
* Partition size: 409600 sectors (200.0 MiB)
|
||||
* Attribute flags: 0000000000000000
|
||||
* Partition name: 'EFI System Partition'
|
||||
*/
|
||||
for (char **i = lines; *i != NULL; i++) {
|
||||
char *line = *i;
|
||||
|
||||
/* Skip blank lines */
|
||||
if (line[0] == '\0') continue;
|
||||
|
||||
/* Split the line in 2 at the colon */
|
||||
char *colon = strchr (line, ':');
|
||||
if (colon) {
|
||||
#define SEARCH "Partition GUID code"
|
||||
if (colon - line == strlen(SEARCH) &&
|
||||
memcmp (line, SEARCH, strlen(SEARCH)) == 0)
|
||||
{
|
||||
#undef SEARCH
|
||||
/* The value starts after the colon */
|
||||
char *value = colon + 1;
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
value += strspn (value, " \t");
|
||||
|
||||
/* The value contains only valid GUID characters */
|
||||
size_t value_len = strspn (value, "-0123456789ABCDEF");
|
||||
|
||||
char *ret = malloc (value_len + 1);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy (ret, value, value_len);
|
||||
ret[value_len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* Ignore lines with no colon. Log to stderr so it will show up in
|
||||
* LIBGUESTFS_DEBUG. */
|
||||
if (verbose) {
|
||||
fprintf (stderr, "get-gpt-type: unexpected sgdisk output ignored: %s\n",
|
||||
line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got here it means we didn't find the Partition GUID code */
|
||||
reply_with_error ("sgdisk output did not contain Partition GUID code. "
|
||||
"See LIBGUESTFS_DEBUG output for more details");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -363,12 +363,13 @@ receive_file (receive_cb cb, void *opaque)
|
||||
{
|
||||
guestfs_chunk chunk;
|
||||
char lenbuf[4];
|
||||
char *buf;
|
||||
XDR xdr;
|
||||
int r;
|
||||
uint32_t len;
|
||||
|
||||
for (;;) {
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "guestfsd: receive_file: reading length word\n");
|
||||
|
||||
@@ -402,11 +403,9 @@ receive_file (receive_cb cb, void *opaque)
|
||||
memset (&chunk, 0, sizeof chunk);
|
||||
if (!xdr_guestfs_chunk (&xdr, &chunk)) {
|
||||
xdr_destroy (&xdr);
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
xdr_destroy (&xdr);
|
||||
free (buf);
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr,
|
||||
@@ -600,19 +599,22 @@ void
|
||||
notify_progress (uint64_t position, uint64_t total)
|
||||
{
|
||||
struct timeval now_t;
|
||||
int64_t last_us, now_us, elapsed_us;
|
||||
|
||||
gettimeofday (&now_t, NULL);
|
||||
|
||||
/* Always send a notification at 100%. This simplifies callers by
|
||||
* allowing them to 'finish' the progress bar at 100% without
|
||||
* needing special code.
|
||||
*/
|
||||
if (count_progress > 0 && position == total)
|
||||
goto send;
|
||||
if (count_progress > 0 && position == total) {
|
||||
notify_progress_no_ratelimit (position, total, &now_t);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate time in microseconds since the last progress message
|
||||
* was sent out (or since the start of the call).
|
||||
*/
|
||||
int64_t last_us, now_us, elapsed_us;
|
||||
last_us =
|
||||
(int64_t) last_progress_t.tv_sec * 1000000 + last_progress_t.tv_usec;
|
||||
now_us = (int64_t) now_t.tv_sec * 1000000 + now_t.tv_usec;
|
||||
@@ -623,16 +625,24 @@ notify_progress (uint64_t position, uint64_t total)
|
||||
(count_progress > 0 && elapsed_us < NOTIFICATION_PERIOD))
|
||||
return;
|
||||
|
||||
send:
|
||||
/* We're going to send a message now ... */
|
||||
count_progress++;
|
||||
last_progress_t = now_t;
|
||||
notify_progress_no_ratelimit (position, total, &now_t);
|
||||
}
|
||||
|
||||
/* Send the header word. */
|
||||
void
|
||||
notify_progress_no_ratelimit (uint64_t position, uint64_t total,
|
||||
const struct timeval *now_t)
|
||||
{
|
||||
XDR xdr;
|
||||
char buf[128];
|
||||
uint32_t i = GUESTFS_PROGRESS_FLAG;
|
||||
uint32_t i;
|
||||
size_t len;
|
||||
guestfs_progress message;
|
||||
|
||||
count_progress++;
|
||||
last_progress_t = *now_t;
|
||||
|
||||
/* Send the header word. */
|
||||
i = GUESTFS_PROGRESS_FLAG;
|
||||
xdrmem_create (&xdr, buf, 4, XDR_ENCODE);
|
||||
xdr_u_int (&xdr, &i);
|
||||
xdr_destroy (&xdr);
|
||||
@@ -642,12 +652,10 @@ notify_progress (uint64_t position, uint64_t total)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
guestfs_progress message = {
|
||||
.proc = proc_nr,
|
||||
.serial = serial,
|
||||
.position = position,
|
||||
.total = total,
|
||||
};
|
||||
message.proc = proc_nr;
|
||||
message.serial = serial;
|
||||
message.position = position;
|
||||
message.total = total;
|
||||
|
||||
xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
|
||||
if (!xdr_guestfs_progress (&xdr, &message)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -33,11 +33,6 @@
|
||||
#include "optgroups.h"
|
||||
#include "actions.h"
|
||||
|
||||
/* On Windows, NAME_MAX is not defined. */
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX FILENAME_MAX
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REALPATH
|
||||
|
||||
int
|
||||
@@ -68,17 +63,21 @@ OPTGROUP_REALPATH_NOT_AVAILABLE
|
||||
|
||||
#endif /* !HAVE_REALPATH */
|
||||
|
||||
static int find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret);
|
||||
static int find_path_element (int fd_cwd, int is_end, const char *name, char **name_ret);
|
||||
|
||||
char *
|
||||
do_case_sensitive_path (const char *path)
|
||||
{
|
||||
char ret[PATH_MAX+1] = "/";
|
||||
char name[NAME_MAX+1];
|
||||
size_t next = 1;
|
||||
size_t next;
|
||||
int fd_cwd, fd2, err, is_end;
|
||||
size_t i;
|
||||
char *retp;
|
||||
char *ret;
|
||||
|
||||
ret = strdup ("/");
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
next = 1; /* next position in 'ret' buffer */
|
||||
|
||||
/* 'fd_cwd' here is a surrogate for the current working directory, so
|
||||
* that we don't have to actually call chdir(2).
|
||||
@@ -86,13 +85,17 @@ do_case_sensitive_path (const char *path)
|
||||
fd_cwd = open (sysroot, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd_cwd == -1) {
|
||||
reply_with_perror ("%s", sysroot);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* First character is a '/'. Take each subsequent path element
|
||||
* and follow it.
|
||||
*/
|
||||
while (*path) {
|
||||
char *t;
|
||||
size_t i, len;
|
||||
CLEANUP_FREE char *name_in = NULL, *name_out = NULL;
|
||||
|
||||
i = strcspn (path, "/");
|
||||
if (i == 0) {
|
||||
path++;
|
||||
@@ -104,14 +107,13 @@ do_case_sensitive_path (const char *path)
|
||||
reply_with_error ("path contained . or .. elements");
|
||||
goto error;
|
||||
}
|
||||
if (i > NAME_MAX) {
|
||||
reply_with_error ("path element too long");
|
||||
|
||||
name_in = strndup (path, i);
|
||||
if (name_in == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy (name, path, i);
|
||||
name[i] = '\0';
|
||||
|
||||
/* Skip to next element in path (for the next loop iteration). */
|
||||
path += i;
|
||||
is_end = *path == 0;
|
||||
@@ -120,23 +122,26 @@ do_case_sensitive_path (const char *path)
|
||||
* this element of the path. This replaces 'name' with the
|
||||
* correct case version.
|
||||
*/
|
||||
if (find_path_element (fd_cwd, is_end, name, &i) == -1)
|
||||
if (find_path_element (fd_cwd, is_end, name_in, &name_out) == -1)
|
||||
goto error;
|
||||
len = strlen (name_out);
|
||||
|
||||
/* Add the real name of this path element to the return value. */
|
||||
if (next > 1)
|
||||
ret[next++] = '/';
|
||||
|
||||
if (next + i >= PATH_MAX) {
|
||||
reply_with_error ("final path too long");
|
||||
t = realloc (ret, next+len+1);
|
||||
if (t == NULL) {
|
||||
reply_with_perror ("realloc");
|
||||
goto error;
|
||||
}
|
||||
ret = t;
|
||||
|
||||
strcpy (&ret[next], name);
|
||||
next += i;
|
||||
strcpy (&ret[next], name_out);
|
||||
next += len;
|
||||
|
||||
/* Is it a directory? Try going into it. */
|
||||
fd2 = openat (fd_cwd, name, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
fd2 = openat (fd_cwd, name_out, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
err = errno;
|
||||
close (fd_cwd);
|
||||
fd_cwd = fd2;
|
||||
@@ -146,7 +151,7 @@ do_case_sensitive_path (const char *path)
|
||||
if (is_end && (errno == ENOTDIR || errno == ENOENT))
|
||||
break;
|
||||
|
||||
reply_with_perror ("openat: %s", name);
|
||||
reply_with_perror ("openat: %s", name_out);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@@ -154,34 +159,28 @@ do_case_sensitive_path (const char *path)
|
||||
if (fd_cwd >= 0)
|
||||
close (fd_cwd);
|
||||
|
||||
ret[next] = '\0';
|
||||
retp = strdup (ret);
|
||||
if (retp == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
return retp; /* caller frees */
|
||||
return ret; /* caller frees */
|
||||
|
||||
error:
|
||||
if (fd_cwd >= 0)
|
||||
close (fd_cwd);
|
||||
free (ret);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 'fd_cwd' is a file descriptor pointing to an open directory.
|
||||
* 'name' is a buffer of NAME_MAX+1 characters in size which initially
|
||||
* contains the path element to search for. 'is_end' is a flag
|
||||
* 'name' is the path element to search for. 'is_end' is a flag
|
||||
* indicating if this is the last path element.
|
||||
*
|
||||
* We search the directory looking for a path element that case
|
||||
* insensitively matches 'name' and update the 'name' buffer.
|
||||
* insensitively matches 'name', returning the actual name in '*name_ret'.
|
||||
*
|
||||
* If this is successful, return 0. If it fails, reply with an error
|
||||
* and return -1.
|
||||
*/
|
||||
static int
|
||||
find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret)
|
||||
find_path_element (int fd_cwd, int is_end, const char *name, char **name_ret)
|
||||
{
|
||||
int fd2;
|
||||
DIR *dir;
|
||||
@@ -219,6 +218,11 @@ find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret)
|
||||
* create a new file or directory (RHBZ#840115).
|
||||
*/
|
||||
closedir (dir);
|
||||
*name_ret = strdup (name);
|
||||
if (*name_ret == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -228,17 +232,13 @@ find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*name_len_ret = strlen (d->d_name);
|
||||
if (*name_len_ret > NAME_MAX) {
|
||||
/* Should never happen? */
|
||||
reply_with_error ("path element longer than NAME_MAX");
|
||||
*name_ret = strdup (d->d_name);
|
||||
if (*name_ret == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
closedir (dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Safe because name is a buffer of NAME_MAX+1 characters. */
|
||||
strcpy (name, d->d_name);
|
||||
|
||||
/* NB: closedir frees the structure associated with 'd', so we must
|
||||
* do this last.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* virt-alignment-scan
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -16,15 +16,26 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUESTFS_VIRT_ALIGNMENT_SCAN_H_
|
||||
#define GUESTFS_VIRT_ALIGNMENT_SCAN_H_
|
||||
#include <config.h>
|
||||
|
||||
/* domains.c */
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
extern void get_domains_from_libvirt (int uuid, size_t *worst_alignment);
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
/* scan.c */
|
||||
extern void scan (size_t *worst_alignment, const char *prefix);
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
#endif /* GUESTFS_VIRT_ALIGNMENT_SCAN_H_ */
|
||||
int
|
||||
do_rename (const char *oldpath, const char *newpath)
|
||||
{
|
||||
int r;
|
||||
|
||||
CHROOT_IN;
|
||||
r = rename (oldpath, newpath);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("rename: %s: %s", oldpath, newpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ rsync (const char *src, const char *src_orig,
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
int r;
|
||||
char *err;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
ADD_ARG (argv, i, str_rsync);
|
||||
|
||||
@@ -63,12 +63,9 @@ rsync (const char *src, const char *src_orig,
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("'%s' to '%s': %s", src_orig, dest_orig, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,14 +74,13 @@ int
|
||||
do_rsync (const char *src_orig, const char *dest_orig,
|
||||
int archive, int deletedest)
|
||||
{
|
||||
char *src = NULL, *dest = NULL;
|
||||
int r = -1;
|
||||
CLEANUP_FREE char *src = NULL, *dest = NULL;
|
||||
|
||||
src = sysroot_path (src_orig);
|
||||
dest = sysroot_path (dest_orig);
|
||||
if (!src || !dest) {
|
||||
reply_with_perror ("malloc");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_ARCHIVE_BITMASK))
|
||||
@@ -92,12 +88,7 @@ do_rsync (const char *src_orig, const char *dest_orig,
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_DELETEDEST_BITMASK))
|
||||
deletedest = 0;
|
||||
|
||||
r = rsync (src, src_orig, dest, dest_orig, archive, deletedest);
|
||||
|
||||
out:
|
||||
free (src);
|
||||
free (dest);
|
||||
return r;
|
||||
return rsync (src, src_orig, dest, dest_orig, archive, deletedest);
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
@@ -105,13 +96,12 @@ int
|
||||
do_rsync_in (const char *remote, const char *dest_orig,
|
||||
int archive, int deletedest)
|
||||
{
|
||||
char *dest = NULL;
|
||||
int r = -1;
|
||||
CLEANUP_FREE char *dest = NULL;
|
||||
|
||||
dest = sysroot_path (dest_orig);
|
||||
if (!dest) {
|
||||
reply_with_perror ("malloc");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_IN_ARCHIVE_BITMASK))
|
||||
@@ -119,11 +109,7 @@ do_rsync_in (const char *remote, const char *dest_orig,
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_IN_DELETEDEST_BITMASK))
|
||||
deletedest = 0;
|
||||
|
||||
r = rsync (remote, remote, dest, dest_orig, archive, deletedest);
|
||||
|
||||
out:
|
||||
free (dest);
|
||||
return r;
|
||||
return rsync (remote, remote, dest, dest_orig, archive, deletedest);
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
@@ -131,13 +117,12 @@ int
|
||||
do_rsync_out (const char *src_orig, const char *remote,
|
||||
int archive, int deletedest)
|
||||
{
|
||||
char *src = NULL;
|
||||
int r = -1;
|
||||
CLEANUP_FREE char *src = NULL;
|
||||
|
||||
src = sysroot_path (src_orig);
|
||||
if (!src) {
|
||||
reply_with_perror ("malloc");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_OUT_ARCHIVE_BITMASK))
|
||||
@@ -145,9 +130,5 @@ do_rsync_out (const char *src_orig, const char *remote,
|
||||
if (!(optargs_bitmask & GUESTFS_RSYNC_OUT_DELETEDEST_BITMASK))
|
||||
deletedest = 0;
|
||||
|
||||
r = rsync (src, src_orig, remote, remote, archive, deletedest);
|
||||
|
||||
out:
|
||||
free (src);
|
||||
return r;
|
||||
return rsync (src, src_orig, remote, remote, archive, deletedest);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user