mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 16:26:17 +00:00
Compare commits
429 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1394d4a69b | ||
|
|
863168467f | ||
|
|
b3d0cc0588 | ||
|
|
d40b502876 | ||
|
|
9b9c372114 | ||
|
|
981c7b7310 | ||
|
|
4efa0f8f38 | ||
|
|
f21b866f31 | ||
|
|
06780a92b3 | ||
|
|
499497fab0 | ||
|
|
77326fa4ad | ||
|
|
54db02b60a | ||
|
|
7b2f6bd665 | ||
|
|
b075b4d1fe | ||
|
|
b61a8a50bc | ||
|
|
dcc0ebc8e0 | ||
|
|
590774ed9e | ||
|
|
96d34d883f | ||
|
|
fe2253088f | ||
|
|
0f837ec068 | ||
|
|
5f30912d74 | ||
|
|
7b84b49603 | ||
|
|
208d1c1a09 | ||
|
|
0b3b5f984c | ||
|
|
42bf3274e4 | ||
|
|
e64bf3fb29 | ||
|
|
2b59b5f1d2 | ||
|
|
1fb95e6566 | ||
|
|
b7ff02354d | ||
|
|
4fa51f11da | ||
|
|
e68336d72a | ||
|
|
a121f1d654 | ||
|
|
d74e7fad28 | ||
|
|
61c9ea496e | ||
|
|
7d3f190d90 | ||
|
|
a887dd5109 | ||
|
|
399887defd | ||
|
|
9519c60ce5 | ||
|
|
7dab208765 | ||
|
|
6e3f8d2511 | ||
|
|
a47fa7a65e | ||
|
|
d6ef91d7c4 | ||
|
|
ef1a8446a6 | ||
|
|
8f3a839aa8 | ||
|
|
ebe826f23f | ||
|
|
67e1c90605 | ||
|
|
493e80ab4e | ||
|
|
97aeaa86d0 | ||
|
|
5d0ef09963 | ||
|
|
507aa9ac35 | ||
|
|
d8b2c1afee | ||
|
|
c03cdcc25c | ||
|
|
40e5317cfb | ||
|
|
f4094b91d2 | ||
|
|
bda974e64c | ||
|
|
6bdc4b30ea | ||
|
|
2b059535b1 | ||
|
|
941ec968b8 | ||
|
|
bf00be0e17 | ||
|
|
3614d76b37 | ||
|
|
a6366f5dae | ||
|
|
bc917a0efc | ||
|
|
b6afb98a79 | ||
|
|
c65ee25a75 | ||
|
|
0a1b2f85e6 | ||
|
|
f9e484ca45 | ||
|
|
793a482015 | ||
|
|
5fb0f4e07e | ||
|
|
20a5b4de7d | ||
|
|
7a691e6665 | ||
|
|
7f519bdc06 | ||
|
|
99f108b840 | ||
|
|
68836022d2 | ||
|
|
890a4fbc87 | ||
|
|
67f7a30cc9 | ||
|
|
f2d7305091 | ||
|
|
ef75c4c568 | ||
|
|
524bb29526 | ||
|
|
abcd6f0c15 | ||
|
|
aa0efa9eb4 | ||
|
|
42ba262003 | ||
|
|
f32b93416a | ||
|
|
fa3b204f4a | ||
|
|
a58368b3db | ||
|
|
ec8e3b6cad | ||
|
|
08cad54349 | ||
|
|
52fa23d74f | ||
|
|
4df6beee54 | ||
|
|
54fd9a10a6 | ||
|
|
709e28e6d5 | ||
|
|
a6e0e0d6bf | ||
|
|
184b9d7c11 | ||
|
|
9d314c7c3f | ||
|
|
4c261da5ba | ||
|
|
80d102c49d | ||
|
|
eca544d87d | ||
|
|
2e4089f300 | ||
|
|
6054051a9d | ||
|
|
d1d29ab488 | ||
|
|
d88f4ca634 | ||
|
|
a8b4ea1f0c | ||
|
|
f514d462cd | ||
|
|
805d642565 | ||
|
|
719297a220 | ||
|
|
6e1b5f0fea | ||
|
|
fc86db3b3b | ||
|
|
1b94ea204d | ||
|
|
a0a517869c | ||
|
|
eef11f33f9 | ||
|
|
50780a84f6 | ||
|
|
781857a86b | ||
|
|
9c2b9c2df6 | ||
|
|
b25aea33fa | ||
|
|
87206e4e9e | ||
|
|
2f89f584c0 | ||
|
|
8e75e21b23 | ||
|
|
d76ea07814 | ||
|
|
973581780d | ||
|
|
ac0373bdec | ||
|
|
4bc110e2bc | ||
|
|
182b4a6660 | ||
|
|
9967ad3fa1 | ||
|
|
60c42dd2a1 | ||
|
|
f6846d74c9 | ||
|
|
a99ea198b2 | ||
|
|
8d0baf7b85 | ||
|
|
1e17a32060 | ||
|
|
0bf1e5b665 | ||
|
|
3a442e6617 | ||
|
|
f2ea617e22 | ||
|
|
c7d342a94a | ||
|
|
24b7979ea2 | ||
|
|
d69a03e448 | ||
|
|
2bd080fd5a | ||
|
|
98f2d221cf | ||
|
|
95d26f0240 | ||
|
|
e055bf4cab | ||
|
|
7486fc6f43 | ||
|
|
b48ae2eadf | ||
|
|
98757e151a | ||
|
|
9eb6060456 | ||
|
|
0da2dbef26 | ||
|
|
60805c9217 | ||
|
|
9286f556c6 | ||
|
|
e80f368732 | ||
|
|
e452a0b8ca | ||
|
|
7a0478bed0 | ||
|
|
39d1a7dbc9 | ||
|
|
7b619d47f6 | ||
|
|
196742cd46 | ||
|
|
cf0defedb8 | ||
|
|
ec0c7e0a1a | ||
|
|
f883e4d8d3 | ||
|
|
1c8403885c | ||
|
|
33bb7408f6 | ||
|
|
f9a5e3ed86 | ||
|
|
afb30b1b8a | ||
|
|
8df259496a | ||
|
|
5546ea6d68 | ||
|
|
bfbfe6dd78 | ||
|
|
1cde66165a | ||
|
|
b749dc7074 | ||
|
|
bd3e42a8de | ||
|
|
e6dec15948 | ||
|
|
6e5a85bb9b | ||
|
|
1596b6026d | ||
|
|
ac25512175 | ||
|
|
ad7c4498f6 | ||
|
|
52d188e32f | ||
|
|
1b87f89b5c | ||
|
|
a95fc92388 | ||
|
|
7996e08824 | ||
|
|
ffbf1475f7 | ||
|
|
bcc4ffb52b | ||
|
|
fc3c6fff4b | ||
|
|
27ebf517fa | ||
|
|
917550a117 | ||
|
|
c0a3c9ce70 | ||
|
|
cb24ceedd8 | ||
|
|
0437a79056 | ||
|
|
1608ca182b | ||
|
|
906f8e3ae2 | ||
|
|
100271c7bc | ||
|
|
757b089053 | ||
|
|
5489304c8d | ||
|
|
339f3647f8 | ||
|
|
ea8421c5d2 | ||
|
|
7eaa99994e | ||
|
|
47b8225b05 | ||
|
|
152b179a19 | ||
|
|
cba4916909 | ||
|
|
b07d096882 | ||
|
|
b9f858e5ee | ||
|
|
a176f508cb | ||
|
|
27efd99ddb | ||
|
|
2f1a602c4b | ||
|
|
04a533ca8c | ||
|
|
e7d2d3cb89 | ||
|
|
8439e97f76 | ||
|
|
1b56aedc2b | ||
|
|
2d56e5af90 | ||
|
|
927ef14c58 | ||
|
|
b3df3ba5c8 | ||
|
|
cadfab1a20 | ||
|
|
1d17a6e9d8 | ||
|
|
6777425636 | ||
|
|
6afb7336e3 | ||
|
|
b3a5403cda | ||
|
|
2eacd4a191 | ||
|
|
05d4e07918 | ||
|
|
bbb7d75c91 | ||
|
|
0977c8408a | ||
|
|
8d88b06277 | ||
|
|
eb8eb3b9d5 | ||
|
|
c87956837e | ||
|
|
9e221e55b6 | ||
|
|
11317b5d12 | ||
|
|
ef5c02c6ee | ||
|
|
90d0beb3c5 | ||
|
|
8fc2127975 | ||
|
|
f27770e141 | ||
|
|
2afa0eeb90 | ||
|
|
030e318049 | ||
|
|
729bb9c6b5 | ||
|
|
78a515ec4a | ||
|
|
a0a86484be | ||
|
|
461455ca7c | ||
|
|
9e7644346d | ||
|
|
35882ba977 | ||
|
|
ef1514aa1e | ||
|
|
4d3ec25b47 | ||
|
|
8098d062b4 | ||
|
|
823ba05ebd | ||
|
|
6cb74d46ba | ||
|
|
145f35badf | ||
|
|
6352953ea9 | ||
|
|
489da3ccdf | ||
|
|
bc7f1a5ef1 | ||
|
|
baee3f52ef | ||
|
|
d7c9c6a0d9 | ||
|
|
39df80dcc0 | ||
|
|
4846b84476 | ||
|
|
50aa9533e4 | ||
|
|
dd216fedbd | ||
|
|
87de366701 | ||
|
|
60a2f8706b | ||
|
|
7b1cd65c44 | ||
|
|
cd6005128d | ||
|
|
81ee155b9d | ||
|
|
abbace6888 | ||
|
|
d43e3d63de | ||
|
|
199cc2853c | ||
|
|
8b15fb3e22 | ||
|
|
4c828dc568 | ||
|
|
8735e92a1d | ||
|
|
a9d7d044f5 | ||
|
|
46ed232dc2 | ||
|
|
998ebc333d | ||
|
|
c0a087b823 | ||
|
|
4165e28b53 | ||
|
|
919b7e3f6c | ||
|
|
cef979b289 | ||
|
|
dbd489f95d | ||
|
|
69e2616b6c | ||
|
|
6e981fe586 | ||
|
|
320adf4778 | ||
|
|
9a5c0d3908 | ||
|
|
7509cdf18e | ||
|
|
62c5b6db58 | ||
|
|
0c0a7d0d86 | ||
|
|
e0b5ecc801 | ||
|
|
295d6af48d | ||
|
|
7652b5aece | ||
|
|
7590924022 | ||
|
|
668a0cebdf | ||
|
|
251b131e0a | ||
|
|
42475dd21f | ||
|
|
20137c8731 | ||
|
|
ac2f9a42fb | ||
|
|
011666ae77 | ||
|
|
4ba6aa3eae | ||
|
|
4f671c829e | ||
|
|
6cf15e8841 | ||
|
|
52af9a88b8 | ||
|
|
f90c01a5dc | ||
|
|
4e5d3b06fb | ||
|
|
1bdfc88eba | ||
|
|
450493cf6b | ||
|
|
bbb21f923a | ||
|
|
3893dc0b94 | ||
|
|
148e806826 | ||
|
|
bcbb6bb760 | ||
|
|
a7868dd3c9 | ||
|
|
a7e4a6c692 | ||
|
|
a81165eb00 | ||
|
|
42dd5fa5b9 | ||
|
|
fe68cd77cb | ||
|
|
8e8a576429 | ||
|
|
6445bc5952 | ||
|
|
73071b3163 | ||
|
|
fba81add94 | ||
|
|
3936412e33 | ||
|
|
f00066d22b | ||
|
|
cffb7fefc8 | ||
|
|
ee9ab52bc3 | ||
|
|
216a6d16ab | ||
|
|
d5d9ceee8b | ||
|
|
975a41db20 | ||
|
|
f904fa8223 | ||
|
|
b8b5ed65c2 | ||
|
|
144d7cd988 | ||
|
|
c7d3aa9cd6 | ||
|
|
0e05e9f6ce | ||
|
|
54028b9b66 | ||
|
|
87d604f88c | ||
|
|
f774f8fd8d | ||
|
|
1f3b8b395b | ||
|
|
91f3456244 | ||
|
|
d51631034a | ||
|
|
695b3c9633 | ||
|
|
27b9c1c755 | ||
|
|
d1f6325e10 | ||
|
|
a119e057d1 | ||
|
|
f5e0c0e3ee | ||
|
|
b6d4c29212 | ||
|
|
020e7aa505 | ||
|
|
88a854cf7f | ||
|
|
32765e440c | ||
|
|
b9331a2d73 | ||
|
|
a84d02e8d8 | ||
|
|
e9f6ce2492 | ||
|
|
7fffaf204e | ||
|
|
2040a15ac7 | ||
|
|
2fd2c85f6a | ||
|
|
e8ec521dc6 | ||
|
|
18451abdf5 | ||
|
|
a75020a066 | ||
|
|
b42dcb05dc | ||
|
|
2c50a5da46 | ||
|
|
a219fede92 | ||
|
|
9cf19466f0 | ||
|
|
034733e981 | ||
|
|
46b6766156 | ||
|
|
7201a48d18 | ||
|
|
157f6fb18b | ||
|
|
eb29a9424c | ||
|
|
30ecbf3ec2 | ||
|
|
10725acf96 | ||
|
|
5c59790845 | ||
|
|
a3718c6b8b | ||
|
|
77afc92fcd | ||
|
|
0e960614ab | ||
|
|
e275786cb2 | ||
|
|
a50db3be60 | ||
|
|
a1680f03b7 | ||
|
|
042a0b063b | ||
|
|
1581dbe79f | ||
|
|
5647567826 | ||
|
|
7b72c12428 | ||
|
|
5764ac12cf | ||
|
|
d0ec0b4c8c | ||
|
|
af1439bc9f | ||
|
|
a79b22a613 | ||
|
|
dd23234f73 | ||
|
|
3ea36903f2 | ||
|
|
eaa05ff012 | ||
|
|
e0f36898cb | ||
|
|
bd91bd76d1 | ||
|
|
9e2cdd309b | ||
|
|
a2cc317c03 | ||
|
|
c53ea071c6 | ||
|
|
0cc3525142 | ||
|
|
93734c78d8 | ||
|
|
e60556d927 | ||
|
|
00202b9c29 | ||
|
|
f072a21f3a | ||
|
|
66a525ce5a | ||
|
|
620ad8eb1a | ||
|
|
79bf966cea | ||
|
|
29c5e052e4 | ||
|
|
1304236c6c | ||
|
|
95a67b1e6a | ||
|
|
500cc67f29 | ||
|
|
e6bfb55f65 | ||
|
|
922052c70f | ||
|
|
51f43402f6 | ||
|
|
027fefd517 | ||
|
|
75514ab57a | ||
|
|
6aa95e87c1 | ||
|
|
ea74856d95 | ||
|
|
79822d46e3 | ||
|
|
bb73cf0941 | ||
|
|
a23e84ee02 | ||
|
|
cc79854037 | ||
|
|
d448ae0c2b | ||
|
|
1f0964536b | ||
|
|
23f8cab1e8 | ||
|
|
ac75e46c5a | ||
|
|
e493884a76 | ||
|
|
819cba54e6 | ||
|
|
a505423e58 | ||
|
|
eafefab937 | ||
|
|
d58cb029a3 | ||
|
|
317ba894b3 | ||
|
|
8fb67ee66a | ||
|
|
6c88c3758b | ||
|
|
a2dc83cf03 | ||
|
|
8cb30dc805 | ||
|
|
39d79e677b | ||
|
|
2cc4314ecc | ||
|
|
beaa528855 | ||
|
|
2d414112f7 | ||
|
|
12c5394d4c | ||
|
|
e188eb8268 | ||
|
|
87ea7a0409 | ||
|
|
3cc9703f90 | ||
|
|
bd1a699c15 | ||
|
|
046d6c20e7 | ||
|
|
303b159134 | ||
|
|
580ae3297a | ||
|
|
a98d9f4840 | ||
|
|
0e49186814 | ||
|
|
5fab4db8de | ||
|
|
d16868b938 | ||
|
|
37a3cdbc13 | ||
|
|
a2d30626cb | ||
|
|
7fc7c3aa5b | ||
|
|
95515c4576 | ||
|
|
148b51fe0b |
48
.gitignore
vendored
48
.gitignore
vendored
@@ -22,10 +22,10 @@
|
||||
bindtests.tmp
|
||||
cscope.out
|
||||
.deps
|
||||
.gdb_history
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
pod2htm?.tmp
|
||||
|
||||
/ABOUT-NLS
|
||||
/aclocal.m4
|
||||
@@ -61,8 +61,8 @@ pod2htm?.tmp
|
||||
/csharp/Libguestfs.cs
|
||||
/daemon/actions.h
|
||||
/daemon/errnostring.c
|
||||
/daemon/errnostring_gperf.c
|
||||
/daemon/errnostring_gperf.gperf
|
||||
/daemon/errnostring-gperf.c
|
||||
/daemon/errnostring-gperf.gperf
|
||||
/daemon/errnostring.h
|
||||
/daemon/guestfsd
|
||||
/daemon/guestfsd.exe
|
||||
@@ -91,18 +91,21 @@ pod2htm?.tmp
|
||||
/examples/create_disk
|
||||
/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/mount_local
|
||||
/examples/stamp-guestfs-examples.pod
|
||||
/examples/stamp-guestfs-faq.pod
|
||||
/examples/stamp-guestfs-performance.pod
|
||||
/examples/stamp-guestfs-recipes.pod
|
||||
/examples/stamp-guestfs-testing.pod
|
||||
/examples/virt-dhcp-address
|
||||
/fish/cmds.c
|
||||
/fish/cmds_gperf.c
|
||||
/fish/cmds_gperf.gperf
|
||||
/fish/cmds-gperf.c
|
||||
/fish/cmds-gperf.gperf
|
||||
/fish/completion.c
|
||||
/fish/event-names.c
|
||||
/fish/fish-cmds.h
|
||||
@@ -155,6 +158,7 @@ pod2htm?.tmp
|
||||
/html/guestfs.3.html
|
||||
/html/guestfs-erlang.3.html
|
||||
/html/guestfs-examples.3.html
|
||||
/html/guestfs-faq.1.html
|
||||
/html/guestfs-java.3.html
|
||||
/html/guestfs-ocaml.3.html
|
||||
/html/guestfs-performance.1.html
|
||||
@@ -199,7 +203,6 @@ pod2htm?.tmp
|
||||
/java/doc-stamp
|
||||
/java/examples/guestfs-java.3
|
||||
/java/examples/stamp-guestfs-java.pod
|
||||
/libguestfs.pc
|
||||
/libguestfs.spec
|
||||
/libguestfs-*.tar.gz
|
||||
/libtool
|
||||
@@ -224,9 +227,7 @@ pod2htm?.tmp
|
||||
/ocaml/examples/guestfs-ocaml.3
|
||||
/ocaml/examples/inspect_vm
|
||||
/ocaml/examples/stamp-guestfs-ocaml.pod
|
||||
/ocaml/guestfs_c_actions.c
|
||||
/ocaml/guestfs_inspector.ml
|
||||
/ocaml/guestfs_inspector.mli
|
||||
/ocaml/guestfs-c-actions.c
|
||||
/ocaml/guestfs.ml
|
||||
/ocaml/guestfs.mli
|
||||
/ocamlinit-stamp
|
||||
@@ -243,8 +244,8 @@ pod2htm?.tmp
|
||||
/ocaml/t/guestfs_400_events.opt
|
||||
/ocaml/t/guestfs_400_progress.bc
|
||||
/ocaml/t/guestfs_400_progress.opt
|
||||
/ocaml/t/guestfs_500_parallel_mount_local.bc
|
||||
/ocaml/t/guestfs_500_parallel_mount_local.opt
|
||||
/ocaml/t/guestfs_500_mount_local.bc
|
||||
/ocaml/t/guestfs_500_mount_local.opt
|
||||
/perl/bindtests.pl
|
||||
/perl/blib
|
||||
/perl/examples/guestfs-perl.3
|
||||
@@ -291,27 +292,14 @@ pod2htm?.tmp
|
||||
/php/extension/php_guestfs_php.h
|
||||
/php/extension/run-tests.php
|
||||
/php/extension/tmp-php.ini
|
||||
/po/boldquot.sed
|
||||
/po/ChangeLog
|
||||
/po-docs/*/*.1
|
||||
/po-docs/*/*.3
|
||||
/po-docs/*/*.pl
|
||||
/po-docs/po4a.conf
|
||||
/po-docs/*/*.pod
|
||||
/po-docs/*/stamp-update-po
|
||||
/podwrapper.sh
|
||||
/po/en@boldquot.header
|
||||
/po/en@quot.header
|
||||
/podwrapper.pl
|
||||
/po/*.gmo
|
||||
/po/insert-header.sin
|
||||
/po/LINGUAS
|
||||
/po/Makevars.template
|
||||
/po/POTFILES
|
||||
/po/quot.sed
|
||||
/po/remove-potcdate.sed
|
||||
/po/Rules-quot
|
||||
/po/stamp-it
|
||||
/po/stamp-po
|
||||
/python/bindtests.py
|
||||
/python/examples/guestfs-python.3
|
||||
/python/examples/stamp-guestfs-python.pod
|
||||
@@ -324,6 +312,7 @@ pod2htm?.tmp
|
||||
/rescue/virt-rescue
|
||||
/rescue/virt-rescue.1
|
||||
/resize/.depend
|
||||
/resize/resize_gettext.ml
|
||||
/resize/stamp-virt-resize.pod
|
||||
/resize/utils_tests
|
||||
/resize/virt-resize
|
||||
@@ -340,14 +329,15 @@ pod2htm?.tmp
|
||||
/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/bindtests.c
|
||||
/src/errnostring.c
|
||||
/src/errnostring_gperf.c
|
||||
/src/errnostring_gperf.gperf
|
||||
/src/errnostring-gperf.c
|
||||
/src/errnostring-gperf.gperf
|
||||
/src/errnostring.h
|
||||
/src/guestfs.3
|
||||
/src/guestfs-actions.pod
|
||||
@@ -358,6 +348,7 @@ pod2htm?.tmp
|
||||
/src/guestfs_protocol.h
|
||||
/src/guestfs_protocol.x
|
||||
/src/guestfs-structs.pod
|
||||
/src/libguestfs.pc
|
||||
/src/libguestfs.syms
|
||||
/src/.libs/libguestfs.so
|
||||
/src/stamp-guestfs.pod
|
||||
@@ -367,6 +358,7 @@ pod2htm?.tmp
|
||||
/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
|
||||
@@ -390,6 +382,7 @@ pod2htm?.tmp
|
||||
/tests/c-api/tests.c
|
||||
/tests/c-api/test*.tmp
|
||||
/tests/c-api/test-user-cancel
|
||||
/tests/charsets/test-charset-fidelity
|
||||
/tests/data/100kallnewlines
|
||||
/tests/data/100kallspaces
|
||||
/tests/data/100kallzeroes
|
||||
@@ -412,6 +405,7 @@ pod2htm?.tmp
|
||||
/tests/guests/stamp-fedora-md.img
|
||||
/tests/guests/ubuntu.img
|
||||
/tests/guests/windows.img
|
||||
/tests/mount-local/test-parallel-mount-local
|
||||
/tests/regressions/rhbz501893
|
||||
/tests/regressions/rhbz790721
|
||||
/test-tool/libguestfs-test-tool
|
||||
|
||||
2
.gnulib
2
.gnulib
Submodule .gnulib updated: b64318247b...e630af09e1
2
AUTHORS
2
AUTHORS
@@ -4,6 +4,7 @@ Charles Duffy <cduffy@messageone.com>
|
||||
Daniel Berrange <berrange@redhat.com>
|
||||
Daniel Cabrera <logan@fedoraproject.org>
|
||||
Douglas Schilling Landgraf <dougsland@redhat.com>
|
||||
Eric Blake <eblake@redhat.com>
|
||||
Erik Nolte <erik_nolte@acm.org>
|
||||
Geert Warrink <geert.warrink@onsnet.nu>
|
||||
Guido Günther <agx@sigxcpu.org>
|
||||
@@ -13,6 +14,7 @@ Jim Meyering <jim@meyering.net>
|
||||
Jiri Popelka <jpopelka@redhat.com>
|
||||
Karel Klíč <kklic@redhat.com>
|
||||
Marcin Gibula <m.gibula@e24cloud.com>
|
||||
Masami HIRATA <msmhrt@gmail.com>
|
||||
Matthew Booth <mbooth@redhat.com>
|
||||
Maxim Koltsov <kolmax94@gmail.com>
|
||||
Michael Scherer <misc@zarb.org>
|
||||
|
||||
361
BUGS
361
BUGS
@@ -1,5 +1,5 @@
|
||||
NOTE: This file is automatically generated from "update-bugs.sh".
|
||||
Last updated: 2012-04-22
|
||||
Last updated: 2012-08-02
|
||||
|
||||
This contains a local list of the bugs that are open against
|
||||
libguestfs. Bugs are tracked in the Red Hat Bugzilla database
|
||||
@@ -20,42 +20,84 @@ When reporting a new bug, please check:
|
||||
--------------------------------------------------
|
||||
Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
|
||||
507278 NEW https://bugzilla.redhat.com/show_bug.cgi?id=507278
|
||||
libguestfs fails to build on Fedora sparc64
|
||||
|
||||
547488 NEW https://bugzilla.redhat.com/show_bug.cgi?id=547488
|
||||
guestfish cannot tab complete filenames that contain spaces
|
||||
|
||||
554829 NEW https://bugzilla.redhat.com/show_bug.cgi?id=554829
|
||||
SELinux handling could be done better.
|
||||
|
||||
555803 NEW https://bugzilla.redhat.com/show_bug.cgi?id=555803
|
||||
guestfs_tgz_out does not detect failure of tar command
|
||||
|
||||
563450 NEW https://bugzilla.redhat.com/show_bug.cgi?id=563450
|
||||
list-devices returns devices of different types out of order
|
||||
|
||||
572337 NEW https://bugzilla.redhat.com/show_bug.cgi?id=572337
|
||||
libguestfs should support gptsync
|
||||
|
||||
578103 NEW https://bugzilla.redhat.com/show_bug.cgi?id=578103
|
||||
[RFE] Tool to Compare Windows Registry Entries
|
||||
|
||||
593511 NEW https://bugzilla.redhat.com/show_bug.cgi?id=593511
|
||||
[RFE] function to get partition name
|
||||
|
||||
596354 NEW https://bugzilla.redhat.com/show_bug.cgi?id=596354
|
||||
guestfish.1.html and guestfs.3.html declared "XHTML 1.0 Strict" but are not in fact well-formed XML
|
||||
|
||||
604041 NEW https://bugzilla.redhat.com/show_bug.cgi?id=604041
|
||||
guestmount absolute symlinks don't work
|
||||
|
||||
624334 NEW https://bugzilla.redhat.com/show_bug.cgi?id=624334
|
||||
blockdev-setbsz succeeds, but does not affect blockdev-getbsz
|
||||
|
||||
624335 NEW https://bugzilla.redhat.com/show_bug.cgi?id=624335
|
||||
blockdev-setbsz succeeds, but does not affect blockdev-getbsz
|
||||
|
||||
637251 NEW https://bugzilla.redhat.com/show_bug.cgi?id=637251
|
||||
virt-inspector fails to recognize data-only NTFS disk image
|
||||
|
||||
660687 NEW https://bugzilla.redhat.com/show_bug.cgi?id=660687
|
||||
guestmount: "touch" command fails: touch: setting times of `timestamp': Invalid argument
|
||||
|
||||
672485 NEW https://bugzilla.redhat.com/show_bug.cgi?id=672485
|
||||
[RFE] virt-edit/tar/inspector do not support encrypted system
|
||||
|
||||
676020 NEW https://bugzilla.redhat.com/show_bug.cgi?id=676020
|
||||
After using virt-resize with an ntfs partition windows is not booting
|
||||
|
||||
684486 NEW https://bugzilla.redhat.com/show_bug.cgi?id=684486
|
||||
Guest fails to boot after virt-resize
|
||||
|
||||
691659 NEW https://bugzilla.redhat.com/show_bug.cgi?id=691659
|
||||
libguestfs fails to run under JRuby 1.6.0
|
||||
|
||||
693064 NEW https://bugzilla.redhat.com/show_bug.cgi?id=693064
|
||||
Symbolic links on ntfs-3g are not followed correctly by some commands
|
||||
|
||||
701814 NEW https://bugzilla.redhat.com/show_bug.cgi?id=701814
|
||||
virt-win-reg fails on a libvirt guest that has no defined disk format: "format parameter is empty or contains disallowed characters"
|
||||
696445 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696445
|
||||
Backport virt-inspector for virt-v2v
|
||||
|
||||
696451 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696451
|
||||
libguestfs: unknown filesystem label SWAP-sda2
|
||||
|
||||
696484 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696484
|
||||
[RFE] virt-v2v show the warning info after convert rhel4u8 guest if comment a line of swap in the fstab
|
||||
|
||||
700342 NEW https://bugzilla.redhat.com/show_bug.cgi?id=700342
|
||||
virt-inspector resports unknown filesystem UUID
|
||||
|
||||
709326 NEW https://bugzilla.redhat.com/show_bug.cgi?id=709326
|
||||
virt-inspector cannot detect ReactOS
|
||||
|
||||
728224 NEW https://bugzilla.redhat.com/show_bug.cgi?id=728224
|
||||
configure can't find qemu on PPC
|
||||
|
||||
737261 NEW https://bugzilla.redhat.com/show_bug.cgi?id=737261
|
||||
libguestfs grub-install API needs grub1
|
||||
|
||||
745282 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745282
|
||||
[RFE] Support to use virt-filesystems with remote libvirt systems
|
||||
|
||||
745576 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745576
|
||||
libguestfs (or qemu?) hangs if sparse file runs out of disk space
|
||||
|
||||
745606 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745606
|
||||
libguestfs: error: part_list: could not parse row from output of parted print command
|
||||
|
||||
761565 NEW https://bugzilla.redhat.com/show_bug.cgi?id=761565
|
||||
Missing deps on netpbm-progs and icoutils
|
||||
|
||||
767852 NEW https://bugzilla.redhat.com/show_bug.cgi?id=767852
|
||||
dependency on fuse suggested
|
||||
|
||||
770075 NEW https://bugzilla.redhat.com/show_bug.cgi?id=770075
|
||||
FEBOOTSTRAP_MODULES fails if modules directory is not under /lib
|
||||
|
||||
@@ -68,12 +110,6 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
785603 NEW https://bugzilla.redhat.com/show_bug.cgi?id=785603
|
||||
copy-out can't find root directory
|
||||
|
||||
786187 NEW https://bugzilla.redhat.com/show_bug.cgi?id=786187
|
||||
list-filesystems error mentions "list-devices"
|
||||
|
||||
789504 NEW https://bugzilla.redhat.com/show_bug.cgi?id=789504
|
||||
virt-df (other tools?) should not give up if a guest disk is missing
|
||||
|
||||
790837 NEW https://bugzilla.redhat.com/show_bug.cgi?id=790837
|
||||
Use of atexit to clean up handles is wrong in multithreaded programs
|
||||
|
||||
@@ -83,8 +119,29 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
801117 NEW https://bugzilla.redhat.com/show_bug.cgi?id=801117
|
||||
libguestfs cannot get icon for Windows 8 preview
|
||||
|
||||
803533 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803533
|
||||
guestfish: write error
|
||||
801640 NEW https://bugzilla.redhat.com/show_bug.cgi?id=801640
|
||||
[RFE] the error reported by resize2fs-M need to be more clear
|
||||
|
||||
802389 NEW https://bugzilla.redhat.com/show_bug.cgi?id=802389
|
||||
event handlers for 'close' event doesn't work in remote mode
|
||||
|
||||
803643 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803643
|
||||
inspect-is-multipart return false when inspection results should be true
|
||||
|
||||
803650 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803650
|
||||
inspect-is-live return false when inspection results should be true
|
||||
|
||||
803657 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803657
|
||||
[RFE] inspect-is-netinst : support more distributions
|
||||
|
||||
805417 NEW https://bugzilla.redhat.com/show_bug.cgi?id=805417
|
||||
RFE: support inspection of installation ISOs of WinVista, Win7, Win2008 & Win2008r2
|
||||
|
||||
806176 NEW https://bugzilla.redhat.com/show_bug.cgi?id=806176
|
||||
libguestfs doesn't use the external tools (wrestool ...) to get icon even these tools are installed
|
||||
|
||||
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
|
||||
@@ -110,239 +167,87 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
815149 NEW https://bugzilla.redhat.com/show_bug.cgi?id=815149
|
||||
virt-alignment-scan gives error "part_list: could not parse row from output of parted print command: /dev/vda:4194304B:virtblk:512:512:msdos:Virtio Block Device"
|
||||
|
||||
563450 NEW https://bugzilla.redhat.com/show_bug.cgi?id=563450
|
||||
list-devices returns devices of different types out of order
|
||||
816839 NEW https://bugzilla.redhat.com/show_bug.cgi?id=816839
|
||||
data overflow error when debug progress -1
|
||||
|
||||
696445 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696445
|
||||
Backport virt-inspector for virt-v2v
|
||||
819086 NEW https://bugzilla.redhat.com/show_bug.cgi?id=819086
|
||||
look for qemu-kvm on /usr/libexec
|
||||
|
||||
806176 NEW https://bugzilla.redhat.com/show_bug.cgi?id=806176
|
||||
libguestfs doesn't use the external tools (wrestool ...) to get icon even these tools are installed
|
||||
822538 NEW https://bugzilla.redhat.com/show_bug.cgi?id=822538
|
||||
libguestfs tools hang on qcow2 encrypted disks
|
||||
|
||||
813329 NEW https://bugzilla.redhat.com/show_bug.cgi?id=813329
|
||||
virt-p2v can not convert physical host on MD device
|
||||
822626 NEW https://bugzilla.redhat.com/show_bug.cgi?id=822626
|
||||
virt-ls error: "libguestfs: error: checksum: path: parameter cannot be NULL"
|
||||
|
||||
547488 NEW https://bugzilla.redhat.com/show_bug.cgi?id=547488
|
||||
guestfish cannot tab complete filenames that contain spaces
|
||||
824021 NEW https://bugzilla.redhat.com/show_bug.cgi?id=824021
|
||||
inspection cannot recognize guest which uses btrfs subvolumes for root
|
||||
|
||||
672485 NEW https://bugzilla.redhat.com/show_bug.cgi?id=672485
|
||||
[RFE] virt-edit/tar/inspector do not support encrypted system
|
||||
824782 NEW https://bugzilla.redhat.com/show_bug.cgi?id=824782
|
||||
virt-resize cannot resize PowerPC guests
|
||||
|
||||
745282 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745282
|
||||
[RFE] Support to use virt-filesystems with remote libvirt systems
|
||||
830135 NEW https://bugzilla.redhat.com/show_bug.cgi?id=830135
|
||||
libguestfs should support mount-local APIs in RHEL 6 (for OpenStack)
|
||||
|
||||
801640 NEW https://bugzilla.redhat.com/show_bug.cgi?id=801640
|
||||
[RFE] the error reported by resize2fs-M need to be more clear
|
||||
832602 NEW https://bugzilla.redhat.com/show_bug.cgi?id=832602
|
||||
"error in chunked encoding" when trying to extract (tar-out) a truncated ISO image
|
||||
|
||||
803643 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803643
|
||||
inspect-is-multipart return false when inspection results should be true
|
||||
833362 NEW https://bugzilla.redhat.com/show_bug.cgi?id=833362
|
||||
virt-make-fs test fails on ppc64 because filesystem block size is 64k
|
||||
|
||||
803650 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803650
|
||||
inspect-is-live return false when inspection results should be true
|
||||
834712 NEW https://bugzilla.redhat.com/show_bug.cgi?id=834712
|
||||
virt-resize test failed once: lvresize_free: New size (91 extents) matches existing size (91 extents)
|
||||
|
||||
803657 NEW https://bugzilla.redhat.com/show_bug.cgi?id=803657
|
||||
[RFE] inspect-is-netinst : support more distributions
|
||||
835622 NEW https://bugzilla.redhat.com/show_bug.cgi?id=835622
|
||||
virt-sparsify to LVM thin raw volume isn't sparse
|
||||
|
||||
805417 NEW https://bugzilla.redhat.com/show_bug.cgi?id=805417
|
||||
RFE: support inspection of installation ISOs of WinVista, Win7, Win2008 & Win2008r2
|
||||
836501 NEW https://bugzilla.redhat.com/show_bug.cgi?id=836501
|
||||
dependency on fuse suggested
|
||||
|
||||
806179 NEW https://bugzilla.redhat.com/show_bug.cgi?id=806179
|
||||
RFE: support inspection of icon for more Windows guests
|
||||
837691 NEW https://bugzilla.redhat.com/show_bug.cgi?id=837691
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
507278 NEW https://bugzilla.redhat.com/show_bug.cgi?id=507278
|
||||
libguestfs fails to build on Fedora sparc64
|
||||
837941 NEW https://bugzilla.redhat.com/show_bug.cgi?id=837941
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
554829 NEW https://bugzilla.redhat.com/show_bug.cgi?id=554829
|
||||
SELinux handling could be done better.
|
||||
838081 NEW https://bugzilla.redhat.com/show_bug.cgi?id=838081
|
||||
ocaml/t/guestfs_500_parallel_mount_local crashes in caml_thread_reinitialize
|
||||
|
||||
555803 NEW https://bugzilla.redhat.com/show_bug.cgi?id=555803
|
||||
guestfs_tgz_out does not detect failure of tar command
|
||||
838609 NEW https://bugzilla.redhat.com/show_bug.cgi?id=838609
|
||||
guestmount + fusermount allows a race condition when unmounting and immediately using the disk image
|
||||
|
||||
572337 NEW https://bugzilla.redhat.com/show_bug.cgi?id=572337
|
||||
libguestfs should support gptsync
|
||||
838904 NEW https://bugzilla.redhat.com/show_bug.cgi?id=838904
|
||||
make-debian-img.sh failed: /dev/debian/root: not found: device not cleared. Aborting. Failed to wipe start of new LV.
|
||||
|
||||
578103 NEW https://bugzilla.redhat.com/show_bug.cgi?id=578103
|
||||
[RFE] Tool to Compare Windows Registry Entries
|
||||
840474 NEW https://bugzilla.redhat.com/show_bug.cgi?id=840474
|
||||
cannot install libguestfs due to missing dependency
|
||||
|
||||
592910 NEW https://bugzilla.redhat.com/show_bug.cgi?id=592910
|
||||
'guestfish --remote run' hangs in a shell command substitution context
|
||||
843188 NEW https://bugzilla.redhat.com/show_bug.cgi?id=843188
|
||||
Ruby bindings segfault in event callbacks when the Ruby GC is invoked.
|
||||
|
||||
593511 NEW https://bugzilla.redhat.com/show_bug.cgi?id=593511
|
||||
[RFE] function to get partition name
|
||||
843199 NEW https://bugzilla.redhat.com/show_bug.cgi?id=843199
|
||||
Ruby bindings segfault in event callbacks when the Ruby GC is invoked.
|
||||
|
||||
596354 NEW https://bugzilla.redhat.com/show_bug.cgi?id=596354
|
||||
guestfish.1.html and guestfs.3.html declared "XHTML 1.0 Strict" but are not in fact well-formed XML
|
||||
|
||||
604041 NEW https://bugzilla.redhat.com/show_bug.cgi?id=604041
|
||||
guestmount absolute symlinks don't work
|
||||
|
||||
624334 NEW https://bugzilla.redhat.com/show_bug.cgi?id=624334
|
||||
blockdev-setbsz succeeds, but does not affect blockdev-getbsz
|
||||
|
||||
624335 NEW https://bugzilla.redhat.com/show_bug.cgi?id=624335
|
||||
blockdev-setbsz succeeds, but does not affect blockdev-getbsz
|
||||
|
||||
627675 NEW https://bugzilla.redhat.com/show_bug.cgi?id=627675
|
||||
libguestfs inspector code cannot handle /dev/disk/by-id/* paths
|
||||
|
||||
635971 NEW https://bugzilla.redhat.com/show_bug.cgi?id=635971
|
||||
glob mkfs ext2 /dev/vd[b-t]1 does not expand
|
||||
|
||||
637251 NEW https://bugzilla.redhat.com/show_bug.cgi?id=637251
|
||||
virt-inspector fails to recognize data-only NTFS disk image
|
||||
|
||||
646036 NEW https://bugzilla.redhat.com/show_bug.cgi?id=646036
|
||||
libguestfs fails to launch
|
||||
|
||||
660687 NEW https://bugzilla.redhat.com/show_bug.cgi?id=660687
|
||||
guestmount: "touch" command fails: touch: setting times of `timestamp': Invalid argument
|
||||
|
||||
696451 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696451
|
||||
libguestfs: unknown filesystem label SWAP-sda2
|
||||
|
||||
696484 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696484
|
||||
[RFE] virt-v2v show the warning info after convert rhel4u8 guest if comment a line of swap in the fstab
|
||||
|
||||
700342 NEW https://bugzilla.redhat.com/show_bug.cgi?id=700342
|
||||
virt-inspector resports unknown filesystem UUID
|
||||
|
||||
802389 NEW https://bugzilla.redhat.com/show_bug.cgi?id=802389
|
||||
event handlers for 'close' event doesn't work in remote mode
|
||||
|
||||
691389 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=691389
|
||||
Extended attributes don't work over guestmount (FUSE)
|
||||
|
||||
713678 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=713678
|
||||
Not all febootstrap messages are redirected to log callbacks
|
||||
|
||||
721160 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=721160
|
||||
Missing btrfs support
|
||||
|
||||
755729 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=755729
|
||||
Error message for resize2fs-M needs tweaking
|
||||
|
||||
583974 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=583974
|
||||
mount hangs there when you lack proper permission to guest image
|
||||
|
||||
539746 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=539746
|
||||
launch fails when run inside a Xen guest, when no non-PV kernels are installed
|
||||
845234 NEW https://bugzilla.redhat.com/show_bug.cgi?id=845234
|
||||
RFE: virt-ls on Windows guest doesn't support drive letters
|
||||
|
||||
503134 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=503134
|
||||
guestfish's list splitting does not recognize internal quoting
|
||||
|
||||
539746 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=539746
|
||||
launch fails when run inside a Xen guest, when no non-PV kernels are installed
|
||||
|
||||
541618 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=541618
|
||||
guestfish not able to mount freebsd ufs2 partitions automatically
|
||||
|
||||
619334 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=619334
|
||||
RFE: Enable coredump capture in the appliance
|
||||
|
||||
--------------------------------------------------
|
||||
Bugs in MODIFIED, POST or ON_QA state are fixed.
|
||||
You can help by testing the fixes.
|
||||
691389 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=691389
|
||||
Extended attributes don't work over guestmount (FUSE)
|
||||
|
||||
750889 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=750889
|
||||
Python code incompatible with Python v3.
|
||||
713678 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=713678
|
||||
Not all febootstrap messages are redirected to log callbacks
|
||||
|
||||
784647 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=784647
|
||||
Libguestfs uses deprecated net-tools
|
||||
|
||||
657499 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=657499
|
||||
checksum: wrong check sum type causes umount to fail
|
||||
|
||||
719879 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=719879
|
||||
Rebase libguestfs in RHEL 6.3
|
||||
|
||||
729076 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=729076
|
||||
libguestfs confuses Hp_recovery partition with Windows root filesystem
|
||||
|
||||
749828 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=749828
|
||||
p2v does not support raid devices
|
||||
|
||||
741183 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=741183
|
||||
[RFE] Write a tool to align the partition(s) in a Windows XP image to a multiple of 8 sectors
|
||||
|
||||
--------------------------------------------------
|
||||
These bugs are in the VERIFIED state.
|
||||
|
||||
731742 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=731742
|
||||
libguestfs should escape special/non-printing characters in debug output
|
||||
|
||||
760221 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=760221
|
||||
RFE: Support inspection of cciss devices
|
||||
|
||||
769359 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=769359
|
||||
virt-resize on RHEL 6 kernel fails to re-read the partition table
|
||||
|
||||
785305 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=785305
|
||||
ocaml (bytecode) bindings segfault in 'add_drive_opts'
|
||||
|
||||
788642 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=788642
|
||||
virt-edit doesn't preserve file permissions
|
||||
|
||||
790958 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=790958
|
||||
multiprovider build error: RuntimeError: link: /tmp/.guestfs-0/kernel /tmp/.guestfs-0/kernel.10139: File exists
|
||||
|
||||
797760 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=797760
|
||||
virt-resize on Windows XP in sysprep state causes "UNMOUNTABLE_BOOT_VOLUME" BSOD
|
||||
|
||||
798197 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=798197
|
||||
virt-resize confuses format and output_format variables; using --output-format sets the input format
|
||||
|
||||
798980 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=798980
|
||||
Libguestfs live support should be disabled in RHEL 6 packages
|
||||
|
||||
799695 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=799695
|
||||
guestfs.h fails to compile with c++ compiler
|
||||
|
||||
801788 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=801788
|
||||
libguestfs holds open file descriptors when handle is launched
|
||||
|
||||
803699 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=803699
|
||||
libguestfs inspection fails on Windows XP: libguestfs: error: hivex: could not locate HKLMSYSTEMMountedDevices
|
||||
|
||||
809401 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=809401
|
||||
inspection doesn't recognize Fedora 17+ (because of grub2 and UsrMove)
|
||||
|
||||
811673 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=811673
|
||||
guestfs_last_error not set when qemu fails early during launch
|
||||
|
||||
812092 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=812092
|
||||
libguestfs cannot open disk images which are symlinks to files that contain ':' (colon) character
|
||||
|
||||
647174 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=647174
|
||||
RHEL6: virt-clone should remove old udev rules when changing MAC address
|
||||
|
||||
789960 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=789960
|
||||
guestfsd crash when try to mount non-exist disk
|
||||
|
||||
799798 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=799798
|
||||
set_autosync: this function can only be called in the config state at /usr/share/perl5/vendor_perl/Sys/VirtConvert/GuestfsHandle.pm line 107
|
||||
|
||||
807557 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=807557
|
||||
virt-sysprep: wrong params are passed to virt-inspector
|
||||
|
||||
807905 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=807905
|
||||
mkfs blocksize option breaks when creating btrfs
|
||||
|
||||
811112 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=811112
|
||||
[RFE][virt-sysprep] hostname can not be changed on rhel system
|
||||
|
||||
811117 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=811117
|
||||
[RFE][virt-sysprep] net-hwaddr not removed from "ifcfg-*" files on rhel
|
||||
|
||||
679737 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=679737
|
||||
libguestfs: improve error message when zerofree is not available in the appliance
|
||||
|
||||
785668 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=785668
|
||||
aug-defnode: daemon crash
|
||||
|
||||
795322 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=795322
|
||||
add_ro should return error if not running in a config state
|
||||
|
||||
796520 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=796520
|
||||
[RFE] Prevent user from running some appliance configure commands after appliance boot up
|
||||
|
||||
801273 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=801273
|
||||
Document for set-pgroup need to be updated
|
||||
(76 bugs)
|
||||
|
||||
End of BUGS file.
|
||||
|
||||
14
COPYING
14
COPYING
@@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
|
||||
206
COPYING.LIB
206
COPYING.LIB
@@ -1,112 +1,125 @@
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
@@ -255,7 +268,7 @@ distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
@@ -282,23 +295,31 @@ of these things:
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
@@ -347,7 +368,7 @@ Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
@@ -390,7 +411,7 @@ excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
@@ -411,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
@@ -434,9 +455,9 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
@@ -453,19 +474,18 @@ convey the exclusion of warranty; and each file should have at least the
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
|
||||
26
Makefile.am
26
Makefile.am
@@ -38,10 +38,17 @@ SUBDIRS += tests/qemu
|
||||
SUBDIRS += tests/guests
|
||||
SUBDIRS += tests/c-api
|
||||
SUBDIRS += tests/protocol
|
||||
SUBDIRS += tests/disks
|
||||
SUBDIRS += tests/lvm
|
||||
SUBDIRS += tests/luks
|
||||
SUBDIRS += tests/md
|
||||
SUBDIRS += tests/selinux
|
||||
SUBDIRS += tests/ntfsclone
|
||||
SUBDIRS += tests/btrfs
|
||||
SUBDIRS += tests/charsets
|
||||
SUBDIRS += tests/xml
|
||||
SUBDIRS += tests/mount-local
|
||||
SUBDIRS += tests/9p
|
||||
SUBDIRS += tests/regressions
|
||||
endif
|
||||
|
||||
@@ -135,11 +142,9 @@ EXTRA_DIST = \
|
||||
contrib/visualize-alignment/README \
|
||||
contrib/visualize-alignment/tracetops.ml \
|
||||
html/pod.css \
|
||||
libguestfs.pc libguestfs.pc.in \
|
||||
libtool-kill-dependency_libs.sh \
|
||||
logo/fish.svg logo/fish.png \
|
||||
m4/.gitignore \
|
||||
po/remove-potcdate.sin \
|
||||
update-bugs.sh
|
||||
|
||||
# The website.
|
||||
@@ -147,6 +152,7 @@ HTMLFILES = \
|
||||
html/guestfs.3.html \
|
||||
html/guestfs-examples.3.html \
|
||||
html/guestfs-erlang.3.html \
|
||||
html/guestfs-faq.1.html \
|
||||
html/guestfs-java.3.html \
|
||||
html/guestfs-ocaml.3.html \
|
||||
html/guestfs-performance.1.html \
|
||||
@@ -212,7 +218,9 @@ dist-hook:
|
||||
mv AUTHORS-t AUTHORS
|
||||
cp AUTHORS $(distdir)/AUTHORS
|
||||
|
||||
# Update the list of translatable files in po/POTFILES.in.
|
||||
# Update the list of translatable files (po/POTFILES po/POTFILES-ml).
|
||||
# This has to be in the top-level Makefile.am so that we have access
|
||||
# to DIST_SUBDIRS.
|
||||
all-local:
|
||||
cd $(srcdir); \
|
||||
find $(DIST_SUBDIRS) \
|
||||
@@ -229,12 +237,10 @@ all-local:
|
||||
grep -v '^po-docs/' | \
|
||||
grep -v '^images/' | \
|
||||
LC_ALL=C sort | \
|
||||
sed 's,^\./,,' > po/POTFILES.in
|
||||
|
||||
# Pkgconfig.
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libguestfs.pc
|
||||
sed 's,^\./,,' > po/POTFILES
|
||||
cd $(srcdir); \
|
||||
find resize sparsify sysprep -name '*.ml' | \
|
||||
LC_ALL=C sort > po/POTFILES-ml
|
||||
|
||||
# Make clean.
|
||||
|
||||
@@ -247,7 +253,7 @@ CLEANFILES = \
|
||||
# is NOT a substitute for proper testing!
|
||||
|
||||
quickcheck:
|
||||
./run test-tool/libguestfs-test-tool $(QUICKCHECK_TEST_TOOL_ARGS)
|
||||
$(top_builddir)/run test-tool/libguestfs-test-tool $(QUICKCHECK_TEST_TOOL_ARGS)
|
||||
|
||||
# Run extra-tests in tests/extra/ subdirectory.
|
||||
|
||||
|
||||
59
README
59
README
@@ -46,7 +46,7 @@ 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
|
||||
|
||||
- recent QEMU >= 0.13 (0.14 or later is better) with virtio-serial support
|
||||
- QEMU >= 1.1.0.
|
||||
|
||||
- kernel >= 2.6.34 with virtio-serial support enabled.
|
||||
|
||||
@@ -55,11 +55,12 @@ For basic functionality and the C tools:
|
||||
to make complex changes to the ./configure command line to get it
|
||||
to work if you don't have virtio)
|
||||
|
||||
- febootstrap >= 3.3 (it is best to use the latest version)
|
||||
- febootstrap >= 3.17
|
||||
|
||||
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)
|
||||
|
||||
@@ -89,8 +90,9 @@ For basic functionality and the C tools:
|
||||
- systemtap/DTrace userspace probes (optional)
|
||||
http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
|
||||
|
||||
- perldoc (pod2man, pod2text, pod2html) to generate the manual pages
|
||||
and other documentation.
|
||||
- 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)
|
||||
|
||||
@@ -100,6 +102,8 @@ For basic functionality and the C tools:
|
||||
- OCaml if you want to rebuild the generated files, and
|
||||
also to build the OCaml bindings (optional)
|
||||
|
||||
- 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.
|
||||
@@ -270,6 +274,53 @@ appliance. You will need to port the febootstrap first
|
||||
(http://people.redhat.com/~rjones/febootstrap/).
|
||||
|
||||
|
||||
Note on using clang (from LLVM) instead of GCC
|
||||
----------------------------------------------------------------------
|
||||
|
||||
export CC=clang
|
||||
./configure --disable-probes
|
||||
make
|
||||
|
||||
SystemTap/DTrace-style userspace probe points don't work under the
|
||||
clang compiler, which is why you may need to disable them.
|
||||
|
||||
Don't enable GCC warnings (ie. *don't* use
|
||||
'./configure --enable-gcc-warnings').
|
||||
|
||||
|
||||
Note on using non-x86 architectures
|
||||
----------------------------------------------------------------------
|
||||
|
||||
In theory libguestfs should work on non-x86 architectures. Usually if
|
||||
it doesn't it's because qemu isn't available or cannot boot the
|
||||
kernel.
|
||||
|
||||
For ARM you will need to specify the exact machine type and CPU
|
||||
variant that is required to boot the Linux kernel (there's no way to
|
||||
know this except by looking at how the Linux kernel was configured).
|
||||
For example:
|
||||
|
||||
./configure \
|
||||
--with-qemu="qemu-system-arm" \
|
||||
--with-qemu-options="-M versatilepb -cpu arm926"
|
||||
./configure \
|
||||
--with-qemu="qemu-system-arm" \
|
||||
--with-qemu-options="-M vexpress-a9 -cpu cortex-a9"
|
||||
|
||||
Note that since virtio is required by libguestfs, and virtio is a
|
||||
PCI-based architecture, whatever architecture qemu emulates must
|
||||
support PCI also.
|
||||
|
||||
For PPC64 you will need to specify the IBM pSeries machine type:
|
||||
|
||||
./configure \
|
||||
--with-qemu="qemu-system-ppc64" \
|
||||
--with-qemu-options="-M pseries"
|
||||
|
||||
After building libguestfs, run 'make quickcheck' and pay close
|
||||
attention to the qemu command line and kernel output.
|
||||
|
||||
|
||||
Copyright and license information
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Release notes for libguestfs 1.18.0
|
||||
-----------------------------------
|
||||
|
||||
UPDATED TO COMMIT 36f1eb922530b254631781bd6475ff6348f511af
|
||||
|
||||
These release notes only cover the differences from the previous
|
||||
stable/dev branch split (1.16.0). For detailed changelogs, please see
|
||||
the git repository, or the ChangeLog file distributed in the tarball.
|
||||
@@ -12,9 +10,7 @@ New features
|
||||
virt tools:
|
||||
|
||||
- virt-sysprep has been rewritten and expanded (thanks Wanlong Gao)
|
||||
|
||||
- virt-edit preserves permissions, UID, GID and SELinux context
|
||||
when editing files
|
||||
http://libguestfs.org/virt-sysprep.1.html
|
||||
|
||||
- virt-sparsify --zero is a new option that zeroes the named
|
||||
partition or filesystem
|
||||
@@ -22,10 +18,12 @@ New features
|
||||
- virt-sparsify can now safely sparsify Linux swap partitions
|
||||
|
||||
- virt-sparsify fixed so it cleans up after ^C
|
||||
http://libguestfs.org/virt-sparsify.1.html
|
||||
|
||||
- a new tool 'libguestfs-make-fixed-appliance' is provided to build
|
||||
fixed appliances that can be copied to other machines that don't
|
||||
have febootstrap support
|
||||
http://libguestfs.org/libguestfs-make-fixed-appliance.1.html
|
||||
|
||||
- virt-filesystems now displays the parents (containers) of MD
|
||||
devices and volume groups
|
||||
@@ -33,11 +31,27 @@ New features
|
||||
- virt-alignment-scan, run with no args, displays alignment information
|
||||
for all libvirt domains
|
||||
|
||||
- comma and colon characters in filenames now handled correctly by
|
||||
all virt tools
|
||||
- virt-df and virt-alignment-scan will display information from all
|
||||
guests even when a disk is inaccessible
|
||||
|
||||
- virt-rescue new --scratch option to make scratch disks
|
||||
https://rwmj.wordpress.com/2012/04/26/virt-rescue-scratch/#content
|
||||
|
||||
- virt-make-fs can now be used to create btrfs
|
||||
|
||||
- virt-edit preserves permissions, UID, GID and SELinux context
|
||||
when editing files
|
||||
|
||||
- guestfish passes the close event over stdout and remote correctly
|
||||
|
||||
- guestfish new '--pipe-error' option lets you detect errors in pipe
|
||||
commands
|
||||
|
||||
- guestfish globs now expand device names
|
||||
|
||||
- comma and colon characters in filenames now handled correctly by
|
||||
all virt tools
|
||||
|
||||
inspection:
|
||||
|
||||
- added support for Fedora 17+
|
||||
@@ -51,8 +65,19 @@ New features
|
||||
|
||||
API:
|
||||
|
||||
- broad support for btrfs added, including adding multiple devices,
|
||||
fsck, snapshots (thanks Wanlong Gao)
|
||||
|
||||
- the new 'mount-local' API brings FUSE support directly into the
|
||||
core libguestfs API
|
||||
https://rwmj.wordpress.com/2012/05/14/tip-using-mount-local-api-from-c/#content
|
||||
|
||||
- new man page: guestfs-performance(1), which contains performance
|
||||
tuning tips.
|
||||
tuning tips
|
||||
http://libguestfs.org/guestfs-performance.1.html
|
||||
|
||||
- new man page: guestfs-faq(1), Frequently Asked Questions
|
||||
http://libguestfs.org/guestfs-faq.1.html
|
||||
|
||||
- ENOTSUP (from guestfs_last_errno) is now returned for APIs that
|
||||
are not supported
|
||||
@@ -63,12 +88,25 @@ New features
|
||||
|
||||
- 'display_icon' program displays the icon associated with a guest
|
||||
|
||||
- 'mount_local.c' example shows how to use the mount-local API
|
||||
|
||||
Security
|
||||
|
||||
(no security problems were found or fixed in this release)
|
||||
|
||||
New APIs
|
||||
|
||||
btrfs-device-add: Add devices to a btrfs filesystem.
|
||||
btrfs-device-delete: Remove devices from a btrfs filesystem.
|
||||
btrfs-filesystem-sync: Sync a btrfs filesystem.
|
||||
btrfs-filesystem-balance: Balance a btrfs filesystem.
|
||||
btrfs-fsck: Check btrfs filesystem.
|
||||
btrfs-set-seeding: Enable or disable seeding.
|
||||
btrfs-subvolume-create: Create a btrfs snapshot.
|
||||
btrfs-subvolume-delete: Delete a btrfs snapshot.
|
||||
btrfs-subvolume-list: List btrfs snapshots and subvolumes.
|
||||
btrfs-subvolume-set-default: Set default btrfs subvolume.
|
||||
btrfs-subvolume-snapshot: Create a writable btrfs snapshot.
|
||||
get-e2attrs: List ext2 file attributes of a file.
|
||||
get-e2generation: Get ext2 file generation of a file.
|
||||
isoinfo, isoinfo-device: Get information from the header of ISO files.
|
||||
@@ -90,6 +128,8 @@ Internals
|
||||
|
||||
- The debian/ subdirectory has been removed. We recommend you use
|
||||
the official Debian packages made by Hilko Bengen.
|
||||
http://people.debian.org/~bengen/libguestfs/
|
||||
http://packages.debian.org/search?keywords=libguestfs
|
||||
|
||||
- O_CLOEXEC / SOCK_CLOEXEC is now used for almost all file
|
||||
descriptors that the library opens.
|
||||
@@ -106,6 +146,8 @@ Internals
|
||||
- use ./configure --enable-valgrind-daemon to use valgrind on the
|
||||
daemon; many errors have been fixed
|
||||
|
||||
- use ./configure --with-qemu-options to pass extra options to qemu
|
||||
|
||||
- the daemon now has a growable strings buffer type (DECLARE_STRINGSBUF)
|
||||
|
||||
- the <guestfs.h> header file works with C++ and we have a regression
|
||||
@@ -116,10 +158,13 @@ Internals
|
||||
|
||||
- .gitignore fixed to use absolute paths
|
||||
|
||||
- gobject bindings have been expanded (thanks Matt Booth)
|
||||
- gobject bindings have been expanded, including mapping libguestfs
|
||||
events to gobject signals (thanks Matt Booth)
|
||||
|
||||
- gobject documentation is generated properly (thanks Matt Booth)
|
||||
|
||||
- gobject header files now live in a subdirectory
|
||||
|
||||
- CompareWithString test in the generator now works
|
||||
|
||||
- FUInt32, FUInt64 struct field types now use the correct XDR type
|
||||
@@ -144,10 +189,19 @@ Internals
|
||||
|
||||
- guestfish --listen now cleans up properly
|
||||
|
||||
- the BUSY state has been removed
|
||||
|
||||
- gettextize has been removed, replaced by a simple Makefile.am
|
||||
|
||||
- gettext support now covers virt-resize, virt-sparsify and virt-sysprep
|
||||
|
||||
- better support for the arm architecture
|
||||
|
||||
Bugs fixed
|
||||
|
||||
[./bugs-in-changelog.sh 1.16.0..]
|
||||
|
||||
- 822490 virt-ls error: "libguestfs: error: checksum: path: parameter cannot be NULL"
|
||||
- 816839 data overflow error when debug progress -1
|
||||
- 816098 virt-make-fs fails to make a btrfs filesystem because it doesn't allocate enough space
|
||||
- 811872 inspection fails on ubuntu 10.04 guest with encrypted swap
|
||||
- 811650 guestfs_last_error not set when qemu fails early during launch
|
||||
- 811649 libguestfs cannot open disk images which are symlinks to files that contain ':' (colon) character
|
||||
@@ -158,20 +212,29 @@ Bugs fixed
|
||||
- 805070 virt-filesystems should show 'parents' of LV and RAID devices
|
||||
- 804464 libguestfs cannot be built when LINGUAS is different then ja or uk
|
||||
- 803664 libguestfs inspection fails on Windows XP: libguestfs: error: hivex: could not locate HKLM\SYSTEM\MountedDevices
|
||||
- 803533 guestfish: write error
|
||||
- 802389 event handlers for 'close' event doesn't work in remote mode
|
||||
- 802109 libguestfs uses putc on stderr, results in many individual 1 byte writes of debug messages
|
||||
- 801640 [RFE] the error reported by resize2fs-M need to be more clear
|
||||
- 801298 Possible null dereference and resource leaks
|
||||
- 801273 Document for set-pgroup need to be updated
|
||||
- 798196 virt-resize confuses format and output_format variables; using --output-format sets the input format
|
||||
- 797986 virt-resize on Windows XP in sysprep state causes "UNMOUNTABLE_BOOT_VOLUME" BSOD
|
||||
- 796520 [RFE] Prevent user from running some appliance configure commands after appliance boot up
|
||||
- 790721 multiprovider build error: RuntimeError: link: /tmp/.guestfs-0/kernel /tmp/.guestfs-0/kernel.10139: File exists
|
||||
- 789960 guestfsd crash when try to mount non-exist disk
|
||||
- 789504 virt-df (other tools?) should not give up if a guest disk is missing
|
||||
- 788641 virt-edit doesn't preserve file permissions
|
||||
- 786215 libguestfs inspection does not recognize FreeDOS operating system
|
||||
- 786188 libguestfs inspection does not recognize FreeDOS install CD
|
||||
- 785668 aug-defnode: daemon crash
|
||||
- 784647 Libguestfs uses deprecated net-tools
|
||||
- 769304 virt-resize on RHEL 6 kernel fails to re-read the partition table
|
||||
- 755729 Error message for resize2fs-M needs tweaking
|
||||
- 701814 virt-win-reg fails on a libvirt guest that has no defined disk format: "format parameter is empty or contains disallowed characters"
|
||||
- 679737 libguestfs: improve error message when zerofree is not available in the appliance
|
||||
- 635971 glob mkfs ext2 /dev/vd[b-t]1 does not expand
|
||||
|
||||
|
||||
Release notes for libguestfs 1.16.0
|
||||
-----------------------------------
|
||||
|
||||
8
ROADMAP
8
ROADMAP
@@ -12,19 +12,19 @@ Before you read this:
|
||||
|
||||
(4) For general "might be good to have" items, see 'TODO'.
|
||||
|
||||
For next major stable release (1.18)
|
||||
For next major stable release (1.20)
|
||||
------------------------------------
|
||||
|
||||
* Allow remote libvirt volumes to be accessed. This requires some
|
||||
enhancements to libvirt which have been agreed but not yet
|
||||
implemented.
|
||||
|
||||
Bugs assigned to 1.18 (put "1.18" in the Devel Whiteboard field in
|
||||
Bugs assigned to 1.20 (put "1.20" in the Devel Whiteboard field in
|
||||
Bugzilla):
|
||||
|
||||
https://bugzilla.redhat.com/buglist.cgi?query_format=advanced&field0-0-0=cf_devel_whiteboard&bug_status=NEW&bug_status=ASSIGNED&bug_status=MODIFIED&bug_status=ON_DEV&bug_status=ON_QA&bug_status=VERIFIED&bug_status=FAILS_QA&bug_status=RELEASE_PENDING&bug_status=POST&bug_status=PASSES_QA&type0-0-0=anywords&value0-0-0=1.18&component=libguestfs&product=Virtualization%20Tools
|
||||
https://bugzilla.redhat.com/buglist.cgi?query_format=advanced&field0-0-0=cf_devel_whiteboard&bug_status=NEW&bug_status=ASSIGNED&bug_status=MODIFIED&bug_status=ON_DEV&bug_status=ON_QA&bug_status=VERIFIED&bug_status=FAILS_QA&bug_status=RELEASE_PENDING&bug_status=POST&bug_status=PASSES_QA&type0-0-0=anywords&value0-0-0=1.20&component=libguestfs&product=Virtualization%20Tools
|
||||
|
||||
Beyond 1.18
|
||||
Beyond 1.20
|
||||
-----------
|
||||
|
||||
* Make 'guestfish --ro' be the default, and get users to use
|
||||
|
||||
110
TODO
110
TODO
@@ -192,6 +192,9 @@ would make more sense to just use libblkid for this.
|
||||
There are some places where we call out to the 'blkid' program. This
|
||||
might be replaced by direct use of the library (if this is easier).
|
||||
|
||||
But it is very hard to be compatible between RHEL6 and RHEL5 when
|
||||
using direct library.
|
||||
|
||||
Visualization
|
||||
-------------
|
||||
|
||||
@@ -373,20 +376,12 @@ Return libosinfo mappings from inspection API.
|
||||
virt-sysprep ideas
|
||||
------------------
|
||||
|
||||
- touch /.unconfigured ?
|
||||
- other Spacewalk / RHN IDs (?)
|
||||
- Kerberos keys
|
||||
- Puppet registration
|
||||
- user accounts
|
||||
- Windows sysprep
|
||||
(see: https://github.com/clalancette/oz/blob/e74ce83283d468fd987583d6837b441608e5f8f0/oz/Windows.py )
|
||||
- blue skies: change the background image
|
||||
- (librarian suggests ...)
|
||||
. install a firstboot script virt-sysprep --script=/tmp/foo.sh
|
||||
. run an external shell script
|
||||
. run external guestfish script virt-sysprep --fish=/tmp/foo.fish
|
||||
. rm /var/cache/apt/archives/*
|
||||
- /var/run/* and pam_faillock's data files
|
||||
- if drives are encrypted, then dm-crypt key should be changed
|
||||
and drives all re-encrypted
|
||||
- /etc/pki
|
||||
@@ -398,13 +393,34 @@ virt-sysprep ideas
|
||||
- secure erase of inodes etc using scrub (Steve Grubb)
|
||||
- other directories that could require cleaning include:
|
||||
/var/run/*
|
||||
/var/lib/sss/db/*
|
||||
/var/lib/samba/*
|
||||
/var/lib/samba/*/*
|
||||
(thanks Marko Myllynen, James Antill)
|
||||
- remove or modify UUIDs in /etc/fstab (eg. on Ubuntu)
|
||||
(thanks Joshua Daniel Franklin)
|
||||
|
||||
Kazuo Moriwaka adds:
|
||||
|
||||
- "yum clean all" (or the equivalent) to remove yum caches
|
||||
- swap devices (both of block device and file) should be wiped. This may
|
||||
good for security purpose, and size. I found virt-sparsify can clear
|
||||
swap partition.
|
||||
- --script is nice. Defining default sysprep script directory
|
||||
like /usr/lib/guestfs/sysprep-scripts.d/ may be useful to integrate
|
||||
other package maintainer(or ISV)'s effort.
|
||||
- To achieve better (or crazy) coverage, a simple examination will be
|
||||
help:
|
||||
Install the same kickstart into VM twice, and diff the trees.
|
||||
Many autogenerated IDs and configs can be found :)
|
||||
|
||||
As well as 'virt-sysprep' there is a case for a 'virt-customize' tool
|
||||
which can customize templated guests. This would be useful within
|
||||
companies/organizations that want to offer multiple guests, but all
|
||||
customized with the organization logo etc. Some ideas:
|
||||
|
||||
- change the background image to some custom desktop
|
||||
- change the sign-on messages (/etc/issue.net etc)
|
||||
- firstboot script (as suggested by librarian above)
|
||||
- Windows login script/service
|
||||
|
||||
Launch remote sessions over ssh
|
||||
-------------------------------
|
||||
|
||||
@@ -460,7 +476,79 @@ during the conversion, since current behaviour is very bad when this
|
||||
happens (it usually causes virt-sparsify to hang). This requires
|
||||
writing a small C binding to statvfs for OCaml.
|
||||
|
||||
'virt-sparsify --whitelist' option to generate skeletons (for
|
||||
debugging, bug forensics, diagnosis). The whilelist option would
|
||||
specify a list of files to be *preserved*. All other files in the
|
||||
image would be replaced by equivalent files of zeroes, thus minimizing
|
||||
the size of the debug image that needs to be shipped to us by the
|
||||
customer.
|
||||
|
||||
Optimize the appliance
|
||||
----------------------
|
||||
|
||||
Pass -cpu host. Anything else?
|
||||
|
||||
[The libvirt attach-method uses 'host-model' which is basically
|
||||
the same as this]
|
||||
|
||||
Sort out partitioning
|
||||
---------------------
|
||||
|
||||
Ignoring some legacy APIs, we currently have a mixed selection of
|
||||
'part-*' APIs, implemented using parted. We don't like parted or
|
||||
libparted very much, and would love to replace it with something else.
|
||||
The part-* APIs are quirky, but not too bad and we should maintain and
|
||||
extend them instead of making another set of APIs.
|
||||
|
||||
One option is to write "libmbr" and "libgpt" libraries that would just
|
||||
do MBR and GPT respectively, and do it directly and do it well. They
|
||||
wouldn't try to abstract anything (so, unlike libparted). We could
|
||||
then reimplement the part-* APIs on top of these hopefully sensible
|
||||
libraries. This is a lot of work.
|
||||
|
||||
Another option is to look for tools or libraries to replace parted.
|
||||
For GPT there is a fairly obvious candidate: Rod Smith's GPT fdisk
|
||||
(http://www.rodsbooks.com/gdisk/). Rod has spent a lot of time
|
||||
studying GPT, and seems to know more about it than any sane man
|
||||
should. There is a command line tool designed for scripts called
|
||||
'sgdisk'. The tools are packaged for many Linux distros. Even if
|
||||
this approach works, it doesn't solve the MBR problem, so likely we'd
|
||||
have to write a library for that (or perhaps go back to sfdisk but
|
||||
using a very abstracted interface over sfdisk).
|
||||
|
||||
qemu caching
|
||||
------------
|
||||
|
||||
(Suggested by Paolo Bonzini and Kevin Wolf)
|
||||
|
||||
Measure the effect of cache=none, cache=directsync,
|
||||
cache=writethrough, cache=writeback.
|
||||
|
||||
It's doubtful that using cache=none is useful, since it disables the
|
||||
host cache making read-heavy workloads slower (they rely entirely on
|
||||
the smaller appliance kernel's cache). And in libguestfs we don't
|
||||
necessarily care about ongoing data integrity while writing, as long
|
||||
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
|
||||
---------------------
|
||||
|
||||
Since libguestfs 1.19.24 this mostly works. Here are some suggested
|
||||
items to work on:
|
||||
|
||||
- SELinux labelling of guestfsd.sock, console.sock
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=842307
|
||||
Once this is fixed, remove <seclabel type=none> from libvirt XML
|
||||
|
||||
- Check feature parity between src/launch-appliance.c and
|
||||
src/launch-libvirt.c.
|
||||
|
||||
- Remote support. (This requires work on libvirt)
|
||||
|
||||
virt-sparsify should use discard
|
||||
--------------------------------
|
||||
|
||||
This requires some changes to qemu to make discard work properly
|
||||
throughout the entire stack.
|
||||
@@ -26,11 +26,11 @@ bin_PROGRAMS = virt-alignment-scan
|
||||
|
||||
SHARED_SOURCE_FILES = \
|
||||
../fish/config.c \
|
||||
../fish/domain.c \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c \
|
||||
../fish/virt.c
|
||||
../fish/options.c
|
||||
|
||||
virt_alignment_scan_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
@@ -62,7 +62,7 @@ noinst_DATA = $(top_builddir)/html/virt-alignment-scan.1.html
|
||||
virt-alignment-scan.1 $(top_builddir)/html/virt-alignment-scan.1.html: stamp-virt-alignment-scan.pod
|
||||
|
||||
stamp-virt-alignment-scan.pod: virt-alignment-scan.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-alignment-scan.1 \
|
||||
--html $(top_builddir)/html/virt-alignment-scan.1.html \
|
||||
$<
|
||||
@@ -70,10 +70,6 @@ stamp-virt-alignment-scan.pod: virt-alignment-scan.pod
|
||||
|
||||
# Tests.
|
||||
|
||||
# random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
# TESTS_ENVIRONMENT = \
|
||||
# MALLOC_PERTURB_=$(random_val) \
|
||||
# $(top_builddir)/run
|
||||
# TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
# TESTS = test-virt-alignment-scan.sh
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
@@ -88,7 +89,7 @@ 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 void add_disks_to_handle_reverse (struct disk *disk);
|
||||
static size_t add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r);
|
||||
static void reset_guestfs_handle (void);
|
||||
|
||||
void
|
||||
@@ -97,7 +98,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
virErrorPtr err;
|
||||
virConnectPtr conn;
|
||||
int n;
|
||||
size_t i;
|
||||
size_t i, count, errors;
|
||||
const char *prefix;
|
||||
|
||||
nr_domains = 0;
|
||||
@@ -108,7 +109,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
if (!conn) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s"),
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -117,7 +118,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of running domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
}
|
||||
@@ -127,7 +128,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list running domains (code %d, domain %d): %s"),
|
||||
_("%s: could not list running domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -138,7 +139,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of inactive domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
}
|
||||
@@ -148,7 +149,7 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list inactive domains (code %d, domain %d): %s"),
|
||||
_("%s: could not list inactive domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -170,8 +171,14 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
/* 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) {
|
||||
add_disks_to_handle_reverse (domains[i].disks);
|
||||
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);
|
||||
@@ -189,6 +196,12 @@ get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
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
|
||||
@@ -296,13 +309,15 @@ add_disk (guestfs_h *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_disks_to_handle_reverse (struct disk *disk)
|
||||
static size_t
|
||||
add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r)
|
||||
{
|
||||
if (disk == NULL)
|
||||
return;
|
||||
size_t nr_disks_added;
|
||||
|
||||
add_disks_to_handle_reverse (disk->next);
|
||||
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 };
|
||||
|
||||
@@ -314,8 +329,12 @@ add_disks_to_handle_reverse (struct disk *disk)
|
||||
optargs.format = disk->format;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive_opts_argv (g, disk->filename, &optargs) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
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. */
|
||||
|
||||
12
align/scan.c
12
align/scan.c
@@ -246,7 +246,7 @@ main (int argc, char *argv[])
|
||||
void
|
||||
scan (size_t *worst_alignment, const char *prefix)
|
||||
{
|
||||
char **devices;
|
||||
char **devices, *p;
|
||||
size_t i, j;
|
||||
size_t alignment;
|
||||
uint64_t start;
|
||||
@@ -262,11 +262,11 @@ scan (size_t *worst_alignment, const char *prefix)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Canonicalize the name of the device for printing. */
|
||||
if (STRPREFIX (devices[i], "/dev/") &&
|
||||
(devices[i][5] == 'h' || devices[i][5] == 'v') &&
|
||||
devices[i][6] == 'd' &&
|
||||
c_isalpha (devices[i][7]))
|
||||
devices[i][5] = 's';
|
||||
p = guestfs_canonical_device_name (g, devices[i]);
|
||||
if (p == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
free (devices[i]);
|
||||
devices[i] = p;
|
||||
|
||||
for (j = 0; j < parts->len; ++j) {
|
||||
/* Start offset of the partition in bytes. */
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# Old RHEL 5 autoconf doesn't have builddir.
|
||||
builddir ?= .
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
@@ -39,26 +42,29 @@ superminfs_DATA = \
|
||||
# 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.
|
||||
make.sh: make.sh.in
|
||||
make.sh: make.sh.in $(top_builddir)/config.log $(top_builddir)/config.status
|
||||
cd $(top_builddir) && \
|
||||
./config.status --file=appliance/$@-t:appliance/$<
|
||||
chmod +x $@-t
|
||||
mv $@-t $@
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
PACKAGELIST_CPP_FLAGS = -D$(DISTRO)=1
|
||||
if VALGRIND_DAEMON
|
||||
PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1
|
||||
endif
|
||||
|
||||
packagelist: packagelist.in
|
||||
packagelist: packagelist.in Makefile
|
||||
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \
|
||||
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
|
||||
mv $@-t $@
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
excludelist: excludelist.in
|
||||
excludelist: excludelist.in Makefile
|
||||
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \
|
||||
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
|
||||
mv $@-t $@
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
supermin.d/base.img supermin.d/hostfiles: stamp-supermin
|
||||
stamp-supermin: make.sh packagelist excludelist
|
||||
@@ -94,7 +100,7 @@ man_MANS = libguestfs-make-fixed-appliance.1
|
||||
libguestfs-make-fixed-appliance.1 $(top_builddir)/html/libguestfs-make-fixed-appliance.1.html: stamp-libguestfs-make-fixed-appliance.pod
|
||||
|
||||
stamp-libguestfs-make-fixed-appliance.pod: libguestfs-make-fixed-appliance.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man libguestfs-make-fixed-appliance.1 \
|
||||
--html $(top_builddir)/html/libguestfs-make-fixed-appliance.1.html \
|
||||
$<
|
||||
|
||||
@@ -32,19 +32,24 @@
|
||||
/* Plymouth is a graphical boot thing - not needed. */
|
||||
^plymouth
|
||||
|
||||
/* Linux firmware. Note that febootstrap itself excludes the kernel
|
||||
* which is also not needed since we get the kernel, modules etc
|
||||
* from the host at appliance boot.
|
||||
*/
|
||||
/* Linux firmware. */
|
||||
^linux-firmware
|
||||
|
||||
/* Keyboard maps - appliance is not interactive. */
|
||||
^kbd-misc
|
||||
|
||||
#ifdef REDHAT
|
||||
|
||||
/* Linux kernel. febootstrap <= 3.18 used to exclude the kernel
|
||||
* package (only) by default, but since 3.19 it doesn't do this any
|
||||
* longer.
|
||||
*/
|
||||
^kernel
|
||||
|
||||
^fedora-logos
|
||||
^redhat-logos
|
||||
^dracut
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBIAN
|
||||
|
||||
@@ -12,9 +12,11 @@ export RUNLEVEL PREVLEVEL
|
||||
|
||||
mkdir -p /sysroot
|
||||
|
||||
rm -f /proc; mkdir /proc
|
||||
if [ ! -d /proc ]; then rm -f /proc; fi
|
||||
mkdir -p /proc
|
||||
mount -t proc /proc /proc
|
||||
rm -f /sys; mkdir /sys
|
||||
if [ ! -d /sys ]; then rm -f /sys; fi
|
||||
mkdir -p /sys
|
||||
mount -t sysfs /sys /sys
|
||||
mkdir -p /run/lock
|
||||
|
||||
@@ -29,36 +31,39 @@ if [ ! -L /etc/init.d/udev -a -x /etc/init.d/udev ]; then
|
||||
fi
|
||||
elif [ -x /sbin/start_udev ] && /sbin/start_udev; then
|
||||
:
|
||||
elif [ -x /sbin/udevd ]; then
|
||||
echo -e '\000\000\000\000' > /proc/sys/kernel/hotplug
|
||||
/sbin/udevd --daemon
|
||||
udevadm trigger
|
||||
udevadm settle
|
||||
elif [ -x /lib/udev/udevd ]; then
|
||||
echo -e '\000\000\000\000' > /proc/sys/kernel/hotplug
|
||||
/lib/udev/udevd --daemon
|
||||
udevadm trigger
|
||||
udevadm settle
|
||||
else
|
||||
echo No udev, creating /dev manually
|
||||
mount -t tmpfs none /dev
|
||||
mkdir /dev/pts /dev/shm /dev/mapper
|
||||
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
|
||||
# Must do each MAKEDEV individually, because if one device fails,
|
||||
# MAKEDEV will quit without creating the rest (RHBZ#507374).
|
||||
for dev in mem null port zero core full ram tty console fd \
|
||||
hda hdb hdc hdd sda sdb sdc sdd loop sd; do
|
||||
MAKEDEV $dev ||:
|
||||
# Find udevd and run it directly.
|
||||
for f in /sbin/udevd /lib/udev/udevd \
|
||||
/lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd \
|
||||
/usr/lib/udev/udevd; do
|
||||
if [ -x "$f" ]; then UDEVD="$f"; fi
|
||||
done
|
||||
mknod /dev/ptmx c 5 2; chmod 0666 /dev/ptmx
|
||||
mknod /dev/random c 1 8; chmod 0666 /dev/random
|
||||
mknod /dev/urandom c 1 9; chmod 0444 /dev/urandom
|
||||
ln -sf /proc/self/fd/0 /dev/stdin
|
||||
ln -sf /proc/self/fd/1 /dev/stdout
|
||||
ln -sf /proc/self/fd/2 /dev/stderr
|
||||
if [ -n "$UDEVD" ]; then
|
||||
echo -e '\000\000\000\000' > /proc/sys/kernel/hotplug
|
||||
$UDEVD --daemon
|
||||
udevadm trigger
|
||||
udevadm settle --timeout=600
|
||||
else
|
||||
echo No udevd, creating /dev manually.
|
||||
mount -t tmpfs none /dev
|
||||
mkdir /dev/pts /dev/shm /dev/mapper
|
||||
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
|
||||
# Must do each MAKEDEV individually, because if one device fails,
|
||||
# MAKEDEV will quit without creating the rest (RHBZ#507374).
|
||||
for dev in mem null port zero core full ram tty console fd \
|
||||
hda hdb hdc hdd sda sdb sdc sdd loop sd; do
|
||||
MAKEDEV $dev ||:
|
||||
done
|
||||
mknod /dev/ptmx c 5 2; chmod 0666 /dev/ptmx
|
||||
mknod /dev/random c 1 8; chmod 0666 /dev/random
|
||||
mknod /dev/urandom c 1 9; chmod 0444 /dev/urandom
|
||||
ln -sf /proc/self/fd/0 /dev/stdin
|
||||
ln -sf /proc/self/fd/1 /dev/stdout
|
||||
ln -sf /proc/self/fd/2 /dev/stderr
|
||||
|
||||
modprobe virtio_pci
|
||||
modprobe virtio_net
|
||||
modprobe virtio_pci
|
||||
modprobe virtio_net
|
||||
fi
|
||||
fi
|
||||
|
||||
if grep -sq selinux=1 /proc/cmdline; then
|
||||
|
||||
@@ -130,7 +130,7 @@ Then copy all four files:
|
||||
|
||||
into a directory somewhere, eg. /usr/local/lib/guestfs/appliance/
|
||||
|
||||
Then build libguestfs (>= 1.16.7 or >= 1.17.10) from source, disabling
|
||||
Then build libguestfs (>= 1.16.7 or >= 1.18) from source, disabling
|
||||
the normal appliance and daemon:
|
||||
|
||||
./configure --disable-appliance --disable-daemon
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
ntfs-3g
|
||||
reiserfs-utils
|
||||
libselinux
|
||||
systemd /* for /sbin/reboot */
|
||||
udev
|
||||
systemd /* for /sbin/reboot and udevd */
|
||||
util-linux-ng
|
||||
vim-minimal
|
||||
xz
|
||||
@@ -64,7 +63,6 @@
|
||||
ntfs-3g
|
||||
ntfsprogs
|
||||
reiserfsprogs
|
||||
udev
|
||||
ufsutils
|
||||
util-linux
|
||||
vim-tiny
|
||||
@@ -87,7 +85,6 @@
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
reiserfsprogs
|
||||
udev
|
||||
util-linux-ng
|
||||
xz
|
||||
#endif /* ARCHLINUX */
|
||||
@@ -96,6 +93,7 @@ acl
|
||||
attr
|
||||
bash
|
||||
binutils
|
||||
bzip2
|
||||
coreutils
|
||||
cpio
|
||||
dosfstools
|
||||
@@ -109,6 +107,7 @@ iproute
|
||||
jfsutils
|
||||
libxml2
|
||||
lsof
|
||||
lsscsi
|
||||
lvm2
|
||||
lzop
|
||||
mdadm
|
||||
@@ -124,6 +123,7 @@ psmisc
|
||||
scrub
|
||||
strace
|
||||
tar
|
||||
udev
|
||||
#ifndef UBUNTU
|
||||
/* on Ubuntu contains a file in /lib64 which conflicts with libc6 that has
|
||||
* /lib64 as a symbolic link
|
||||
|
||||
17
bootstrap
17
bootstrap
@@ -26,13 +26,6 @@ git submodule init || exit $?
|
||||
git submodule update || exit $?
|
||||
GNULIB_SRCDIR=.gnulib
|
||||
|
||||
ls po/*.po 2>/dev/null | sed 's|.*/||; s|\.po$||' > po/LINGUAS
|
||||
|
||||
# Run autopoint, to get po/Makevars.template:
|
||||
# Also, released autopoint has the tendency to install macros that have
|
||||
# been obsoleted in current gnulib, so run this before gnulib-tool.
|
||||
autopoint --force
|
||||
|
||||
# Autoreconf runs aclocal before libtoolize, which causes spurious
|
||||
# warnings if the initial aclocal is confused by the libtoolized
|
||||
# (or worse out-of-date) macro directory.
|
||||
@@ -54,6 +47,7 @@ connect
|
||||
dup3
|
||||
error
|
||||
filevercmp
|
||||
fstatat
|
||||
fsusage
|
||||
fts
|
||||
full-read
|
||||
@@ -72,11 +66,13 @@ ignore-value
|
||||
lock
|
||||
maintainer-makefile
|
||||
manywarnings
|
||||
memmem
|
||||
mkdtemp
|
||||
netdb
|
||||
netinet_in
|
||||
openat
|
||||
perror
|
||||
pipe2
|
||||
pread
|
||||
progname
|
||||
read-file
|
||||
@@ -85,6 +81,7 @@ select
|
||||
setenv
|
||||
sleep
|
||||
socket
|
||||
stat-time
|
||||
strchrnul
|
||||
strerror
|
||||
strndup
|
||||
@@ -101,8 +98,12 @@ xstrtoll
|
||||
xvasprintf
|
||||
'
|
||||
|
||||
# If any tests fail, avoid including them by adding them to
|
||||
# this list.
|
||||
avoid="--avoid=dummy --avoid=getlogin_r-tests"
|
||||
|
||||
$gnulib_tool \
|
||||
--avoid=dummy \
|
||||
$avoid \
|
||||
--with-tests \
|
||||
--m4-base=m4 \
|
||||
--source-base=gnulib/lib \
|
||||
|
||||
@@ -31,11 +31,11 @@ bin_PROGRAMS = virt-cat virt-filesystems virt-ls
|
||||
|
||||
SHARED_SOURCE_FILES = \
|
||||
../fish/config.c \
|
||||
../fish/domain.c \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c \
|
||||
../fish/virt.c
|
||||
../fish/options.c
|
||||
|
||||
virt_cat_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
@@ -102,7 +102,7 @@ noinst_DATA = \
|
||||
virt-cat.1 $(top_builddir)/html/virt-cat.1.html: stamp-virt-cat.pod
|
||||
|
||||
stamp-virt-cat.pod: virt-cat.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-cat.1 \
|
||||
--html $(top_builddir)/html/virt-cat.1.html \
|
||||
$<
|
||||
@@ -111,7 +111,7 @@ stamp-virt-cat.pod: virt-cat.pod
|
||||
virt-ls.1 $(top_builddir)/html/virt-ls.1.html: stamp-virt-ls.pod
|
||||
|
||||
stamp-virt-ls.pod: virt-ls.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-ls.1 \
|
||||
--html $(top_builddir)/html/virt-ls.1.html \
|
||||
$<
|
||||
@@ -120,7 +120,7 @@ stamp-virt-ls.pod: virt-ls.pod
|
||||
virt-filesystems.1 $(top_builddir)/html/virt-filesystems.1.html: stamp-virt-filesystems.pod
|
||||
|
||||
stamp-virt-filesystems.pod: virt-filesystems.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-filesystems.1 \
|
||||
--html $(top_builddir)/html/virt-filesystems.1.html \
|
||||
$<
|
||||
@@ -128,11 +128,7 @@ stamp-virt-filesystems.pod: virt-filesystems.pod
|
||||
|
||||
# Tests.
|
||||
|
||||
random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
MALLOC_PERTURB_=$(random_val) \
|
||||
$(top_builddir)/run
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS = test-virt-cat.sh test-virt-filesystems.sh test-virt-ls.sh
|
||||
|
||||
@@ -82,8 +82,6 @@ static int output = 0;
|
||||
#define NR_COLUMNS 8
|
||||
static int columns;
|
||||
|
||||
static char *canonical_device (const char *dev);
|
||||
|
||||
static void do_output_title (void);
|
||||
static void do_output (void);
|
||||
static void do_output_end (void);
|
||||
@@ -466,7 +464,9 @@ do_output_filesystems (void)
|
||||
(STREQ (fses[i+1], "swap") || STREQ (fses[i+1], "unknown")))
|
||||
goto next;
|
||||
|
||||
dev = canonical_device (fses[i]);
|
||||
dev = guestfs_canonical_device_name (g, fses[i]);
|
||||
if (dev == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Only bother to look these up if we will be displaying them,
|
||||
* otherwise pass them as NULL.
|
||||
@@ -639,7 +639,9 @@ do_output_pvs (void)
|
||||
char uuid[33];
|
||||
const char *parents[1] = { NULL };
|
||||
|
||||
dev = canonical_device (pvs->val[i].pv_name);
|
||||
dev = guestfs_canonical_device_name (g, pvs->val[i].pv_name);
|
||||
if (!dev)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
memcpy (uuid, pvs->val[i].pv_uuid, 32);
|
||||
uuid[32] = '\0';
|
||||
@@ -693,7 +695,9 @@ do_output_partitions (void)
|
||||
int64_t size = -1;
|
||||
int mbr_id = -1;
|
||||
|
||||
dev = canonical_device (parts[i]);
|
||||
dev = guestfs_canonical_device_name (g, parts[i]);
|
||||
if (!dev)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if ((columns & COLUMN_SIZE)) {
|
||||
size = guestfs_blockdev_getsize64 (g, parts[i]);
|
||||
@@ -708,7 +712,9 @@ do_output_partitions (void)
|
||||
if ((columns & COLUMN_MBR))
|
||||
mbr_id = get_mbr_id (parts[i], parent_name);
|
||||
|
||||
char *p = canonical_device (parent_name);
|
||||
char *p = guestfs_canonical_device_name (g, parent_name);
|
||||
if (!p)
|
||||
exit (EXIT_FAILURE);
|
||||
free (parent_name);
|
||||
parent_name = p;
|
||||
|
||||
@@ -742,7 +748,9 @@ do_output_blockdevs (void)
|
||||
char *dev;
|
||||
char **parents;
|
||||
|
||||
dev = canonical_device (devices[i]);
|
||||
dev = guestfs_canonical_device_name (g, devices[i]);
|
||||
if (!dev)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if ((columns & COLUMN_SIZE)) {
|
||||
size = guestfs_blockdev_getsize64 (g, devices[i]);
|
||||
@@ -766,26 +774,6 @@ do_output_blockdevs (void)
|
||||
free (devices);
|
||||
}
|
||||
|
||||
/* /dev/vda1 -> /dev/sda. Returns a string which the caller must free. */
|
||||
static char *
|
||||
canonical_device (const char *dev)
|
||||
{
|
||||
char *ret = strdup (dev);
|
||||
if (ret == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (STRPREFIX (ret, "/dev/") &&
|
||||
(ret[5] == 'h' || ret[5] == 'v') &&
|
||||
ret[6] == 'd' &&
|
||||
c_isalpha (ret[7]) &&
|
||||
(c_isdigit (ret[8]) || ret[8] == '\0'))
|
||||
ret[5] = 's';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns an empty list of parents. Note this must be freed using
|
||||
* free_strings.
|
||||
*/
|
||||
@@ -841,8 +829,11 @@ parents_of_md (char *device)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < stats->len; ++i)
|
||||
ret[i] = canonical_device (stats->val[i].mdstat_device);
|
||||
for (i = 0; i < stats->len; ++i) {
|
||||
ret[i] = guestfs_canonical_device_name (g, stats->val[i].mdstat_device);
|
||||
if (!ret[i])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret[stats->len] = NULL;
|
||||
|
||||
@@ -902,8 +893,11 @@ parents_of_vg (char *vg)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < pvs->len)
|
||||
ret[i] = canonical_device (pvs->val[j].pv_name);
|
||||
if (j < pvs->len) {
|
||||
ret[i] = guestfs_canonical_device_name (g, pvs->val[j].pv_name);
|
||||
if (!ret[i])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%s: warning: unknown PV UUID ignored\n", __func__);
|
||||
ret[i] = strndup (pvuuids[i], 32);
|
||||
|
||||
@@ -781,7 +781,7 @@ show_file (const char *dir, const char *name,
|
||||
const struct guestfs_xattr_list *xattrs)
|
||||
{
|
||||
char filetype[2];
|
||||
char *path = NULL, *csum = NULL, *link = NULL;
|
||||
char *path, *csum = NULL, *link = NULL;
|
||||
|
||||
/* Display the basic fields. */
|
||||
output_start_line ();
|
||||
@@ -833,6 +833,8 @@ show_file (const char *dir, const char *name,
|
||||
output_xattrs (xattrs);
|
||||
*/
|
||||
|
||||
path = full_path (dir, name);
|
||||
|
||||
if (checksum && is_reg (stat->mode)) {
|
||||
csum = guestfs_checksum (g, checksum, path);
|
||||
if (!csum)
|
||||
@@ -841,7 +843,6 @@ show_file (const char *dir, const char *name,
|
||||
output_string (csum);
|
||||
}
|
||||
|
||||
path = full_path (dir, name);
|
||||
output_string (path);
|
||||
|
||||
if (is_lnk (stat->mode))
|
||||
|
||||
483
configure.ac
483
configure.ac
@@ -19,8 +19,8 @@
|
||||
# add extra information using --with-extra="..." which may be any
|
||||
# freeform string.
|
||||
m4_define([libguestfs_major], [1])
|
||||
m4_define([libguestfs_minor], [17])
|
||||
m4_define([libguestfs_release], [33])
|
||||
m4_define([libguestfs_minor], [19])
|
||||
m4_define([libguestfs_release], [28])
|
||||
|
||||
AC_INIT([libguestfs],libguestfs_major.libguestfs_minor.libguestfs_release)
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
@@ -63,13 +63,30 @@ AC_DEFINE([PACKAGE_VERSION_MINOR],[libguestfs_minor],[Minor version number])
|
||||
AC_DEFINE([PACKAGE_VERSION_RELEASE],[libguestfs_release],[Release number])
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_EXTRA],["$libguestfs_extra"],[Extra version string])
|
||||
|
||||
dnl Default attach method.
|
||||
AC_MSG_CHECKING([if the user specified a default attach method])
|
||||
AC_ARG_WITH([default-attach-method],
|
||||
[AS_HELP_STRING([--with-default-attach-method="appliance|libvirt|..."],
|
||||
[set default attach method @<:@default=appliance@:>@])],
|
||||
[DEFAULT_ATTACH_METHOD="$withval"],
|
||||
[DEFAULT_ATTACH_METHOD=appliance])
|
||||
AC_MSG_RESULT([$DEFAULT_ATTACH_METHOD])
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_ATTACH_METHOD],["$DEFAULT_ATTACH_METHOD"],
|
||||
[default attach method])
|
||||
|
||||
dnl Early gnulib initialization.
|
||||
gl_EARLY
|
||||
gl_INIT
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
AC_PROG_SED
|
||||
# Define $(SED).
|
||||
m4_ifdef([AC_PROG_SED],[
|
||||
AC_PROG_SED
|
||||
],[
|
||||
dnl ... else hope for the best
|
||||
AC_SUBST([SED], "sed")
|
||||
])
|
||||
|
||||
dnl Check for basic C environment.
|
||||
AC_PROG_CC_STDC
|
||||
@@ -141,9 +158,12 @@ if test "$gl_gcc_warnings" = yes; then
|
||||
AC_SUBST([WARN_CFLAGS])
|
||||
|
||||
AC_DEFINE([lint], [1], [Define to 1 if the compiler is checking for lint.])
|
||||
AC_DEFINE([_FORTIFY_SOURCE], [2],
|
||||
[enable compile-time and run-time bounds-checking, and some warnings])
|
||||
AC_DEFINE([GNULIB_PORTCHECK], [1], [enable some gnulib portability checks])
|
||||
AH_VERBATIM([FORTIFY_SOURCE],
|
||||
[/* Enable compile-time and run-time bounds-checking, and some warnings. */
|
||||
#if __OPTIMIZE__
|
||||
# define _FORTIFY_SOURCE 2
|
||||
#endif])
|
||||
fi
|
||||
|
||||
AC_C_PROTOTYPES
|
||||
@@ -198,6 +218,7 @@ AC_CHECK_HEADERS([\
|
||||
|
||||
dnl Functions.
|
||||
AC_CHECK_FUNCS([\
|
||||
fsync \
|
||||
futimens \
|
||||
getxattr \
|
||||
htonl \
|
||||
@@ -235,21 +256,22 @@ AC_CHECK_LIB([ncurses], [UP], [], [
|
||||
])
|
||||
LIBS="$old_LIBS"
|
||||
|
||||
dnl For modified printf in the daemon, we need glibc either (old-style)
|
||||
dnl register_printf_function or (new-style) register_printf_specifier.
|
||||
AC_CHECK_FUNC([register_printf_specifier],[
|
||||
AC_DEFINE([HAVE_REGISTER_PRINTF_SPECIFIER],[1],
|
||||
[Define to 1 if you have new-style register_printf_specifier])
|
||||
],[
|
||||
AC_CHECK_FUNC([register_printf_function],[
|
||||
AC_DEFINE([HAVE_REGISTER_PRINTF_FUNCTION],[1],
|
||||
[Define to 1 if you have old-style register_printf_function])
|
||||
],[
|
||||
AC_MSG_FAILURE(
|
||||
[No support for glibc-style extended printf formatters.
|
||||
dnl GNU gettext tools (optional).
|
||||
AC_CHECK_PROG([XGETTEXT],[xgettext],[xgettext],[no])
|
||||
AC_CHECK_PROG([MSGCAT],[msgcat],[msgcat],[no])
|
||||
AC_CHECK_PROG([MSGFMT],[msgfmt],[msgfmt],[no])
|
||||
AC_CHECK_PROG([MSGMERGE],[msgmerge],[msgmerge],[no])
|
||||
|
||||
This means you either have a very old glibc (pre-2.0) or you
|
||||
are using some other libc where this is not supported.])])])
|
||||
dnl Check they are the GNU gettext tools.
|
||||
AC_MSG_CHECKING([msgfmt is GNU tool])
|
||||
if $MSGFMT --version >/dev/null 2>&1 && $MSGFMT --version | grep -q 'GNU gettext'; then
|
||||
msgfmt_is_gnu=yes
|
||||
else
|
||||
msgfmt_is_gnu=no
|
||||
fi
|
||||
AC_MSG_RESULT([$msgfmt_is_gnu])
|
||||
AM_CONDITIONAL([HAVE_GNU_GETTEXT],
|
||||
[test "x$XGETTEXT" != "xno" && test "x$MSGCAT" != "xno" && test "x$MSGFMT" != "xno" && test "x$MSGMERGE" != "xno" && test "x$msgfmt_is_gnu" != "xno"])
|
||||
|
||||
dnl Build the daemon?
|
||||
AC_MSG_CHECKING([if we should build the daemon])
|
||||
@@ -306,6 +328,22 @@ if test "x$enable_daemon" = "xyes"; then
|
||||
fi
|
||||
AC_MSG_RESULT([$DAEMON_SUPERMIN_DIR])
|
||||
AC_SUBST([DAEMON_SUPERMIN_DIR])
|
||||
|
||||
dnl For modified printf in the daemon, we need glibc either (old-style)
|
||||
dnl register_printf_function or (new-style) register_printf_specifier.
|
||||
AC_CHECK_FUNC([register_printf_specifier],[
|
||||
AC_DEFINE([HAVE_REGISTER_PRINTF_SPECIFIER],[1],
|
||||
[Define to 1 if you have new-style register_printf_specifier])
|
||||
],[
|
||||
AC_CHECK_FUNC([register_printf_function],[
|
||||
AC_DEFINE([HAVE_REGISTER_PRINTF_FUNCTION],[1],
|
||||
[Define to 1 if you have old-style register_printf_function])
|
||||
],[
|
||||
AC_MSG_FAILURE(
|
||||
[No support for glibc-style extended printf formatters.
|
||||
|
||||
This means you either have a very old glibc (pre-2.0) or you
|
||||
are using some other libc where this is not supported.])])])
|
||||
fi
|
||||
AM_CONDITIONAL([INSTALL_DAEMON],[test "x$enable_install_daemon" = "xyes"])
|
||||
AM_CONDITIONAL([VALGRIND_DAEMON],[test "x$enable_valgrind_daemon" = "xyes"])
|
||||
@@ -368,6 +406,14 @@ AM_CONDITIONAL([HAVE_RPCGEN],[test "x$RPCGEN" != "xno"])
|
||||
AC_CHECK_LIB([portablexdr],[xdrmem_create],[],[
|
||||
AC_SEARCH_LIBS([xdrmem_create],[rpc xdr nsl])
|
||||
])
|
||||
AC_SEARCH_LIBS([xdr_u_int64_t],[portablexdr rpc xdr nsl],[
|
||||
AC_DEFINE([HAVE_XDR_U_INT64_T],[1],[Define to 1 if xdr_u_int64_t() exists])
|
||||
])
|
||||
AC_SEARCH_LIBS([xdr_uint64_t],[portablexdr rpc xdr nsl],[
|
||||
AC_DEFINE([HAVE_XDR_UINT64_T],[1],[Define to 1 if xdr_uint64_t() exists])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_XDR_U_INT64_T],[test "x$ac_cv_search_xdr_u_int64_t" != "xno"])
|
||||
AM_CONDITIONAL([HAVE_XDR_UINT64_T],[test "x$ac_cv_search_xdr_uint64_t" != "xno"])
|
||||
|
||||
dnl Check for Augeas (optional).
|
||||
PKG_CHECK_MODULES([AUGEAS], [augeas],
|
||||
@@ -401,9 +447,19 @@ fi
|
||||
AC_SUBST([SELINUX_LIB])
|
||||
|
||||
dnl Check for systemtap/DTrace userspace probes (optional).
|
||||
dnl http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
|
||||
AC_CHECK_HEADERS([sys/sdt.h])
|
||||
dnl AC_CHECK_PROG([DTRACE],[dtrace],[dtrace],[no])
|
||||
dnl Since the probe points break under clang, allow this to be disabled.
|
||||
AC_ARG_ENABLE([probes],
|
||||
AS_HELP_STRING([--disable-probes], [Disable systemtap/DTrace userspace probes]),
|
||||
[],
|
||||
[enable_probes=yes])
|
||||
AS_IF([test "x$enable_probes" != "xno"],[
|
||||
dnl http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
|
||||
AC_CHECK_HEADERS([sys/sdt.h])
|
||||
dnl AC_CHECK_PROG([DTRACE],[dtrace],[dtrace],[no])
|
||||
AS_IF([test "x$ac_cv_header_sys_sdt_h" = "xyes"],[
|
||||
AC_DEFINE([ENABLE_PROBES],[1],[enable systemtap/DTrace userspace probes])
|
||||
])
|
||||
])
|
||||
|
||||
dnl Check for cpio which isn't in the default Pardus install amazingly.
|
||||
AC_CHECK_PROG([CPIO],[cpio],[cpio],[no])
|
||||
@@ -415,40 +471,31 @@ AC_CHECK_PROG([GPERF],[gperf],[gperf],[no])
|
||||
test "x$GPERF" = "xno" &&
|
||||
AC_MSG_ERROR([gperf must be installed])
|
||||
|
||||
dnl Check for pod2man, pod2text, pod2html.
|
||||
AC_CHECK_PROG([POD2MAN],[pod2man],[pod2man],[no])
|
||||
test "x$POD2MAN" = "xno" &&
|
||||
AC_MSG_ERROR([pod2man must be installed])
|
||||
AC_CHECK_PROG([POD2TEXT],[pod2text],[pod2text],[no])
|
||||
test "x$POD2TEXT" = "xno" &&
|
||||
AC_MSG_ERROR([pod2text must be installed])
|
||||
AC_CHECK_PROG([POD2HTML],[pod2html],[pod2html],[no])
|
||||
test "x$POD2HTML" = "xno" &&
|
||||
AC_MSG_ERROR([pod2html must be installed])
|
||||
dnl Check for perl.
|
||||
AC_CHECK_PROG([PERL],[perl],[perl],[no])
|
||||
test "x$PERL" = "xno" &&
|
||||
AC_MSG_ERROR([perl must be installed])
|
||||
|
||||
dnl Check if pod2man, pod2text take --stderr and -u options (not in RHEL 5).
|
||||
AC_MSG_CHECKING([if pod2man takes --stderr option])
|
||||
if "$POD2MAN" --stderr >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
POD2_STDERR_OPTION="--stderr"
|
||||
dnl Check for Pod::Man, Pod::Simple.
|
||||
AC_MSG_CHECKING([for Pod::Man])
|
||||
if ! $PERL -MPod::Man -e1 >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_ERROR([perl Pod::Man must be installed])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
AC_MSG_CHECKING([for Pod::Simple])
|
||||
if ! $PERL -MPod::Simple -e1 >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_ERROR([perl Pod::Simple must be installed])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
POD2_STDERR_OPTION=""
|
||||
fi
|
||||
AC_SUBST([POD2_STDERR_OPTION])
|
||||
|
||||
AC_MSG_CHECKING([if pod2man takes -u option])
|
||||
if "$POD2MAN" -u >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
POD2_UTF8_OPTION="-u"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
POD2_UTF8_OPTION=""
|
||||
fi
|
||||
AC_SUBST([POD2_UTF8_OPTION])
|
||||
|
||||
dnl Check for genisoimage.
|
||||
AC_PATH_PROGS([GENISOIMAGE],[genisoimage],[no],
|
||||
dnl Define the path to the podwrapper program.
|
||||
PODWRAPPER="$PERL $(pwd)/podwrapper.pl"
|
||||
AC_SUBST([PODWRAPPER])
|
||||
|
||||
dnl Check for genisoimage/mkisofs
|
||||
AC_PATH_PROGS([GENISOIMAGE],[genisoimage mkisofs],[no],
|
||||
[$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
|
||||
test "x$GENISOIMAGE" = "xno" && AC_MSG_ERROR([genisoimage must be installed])
|
||||
|
||||
@@ -498,7 +545,8 @@ fi
|
||||
|
||||
dnl Check for QEMU for running binaries on this $host_cpu, fall
|
||||
dnl back to basic 'qemu'. Allow the user to override it.
|
||||
default_qemu="qemu-kvm kvm qemu-system-$host_cpu qemu"
|
||||
qemu_system="`echo qemu-system-$host_cpu | $SED 's/i@<:@456@:>@86/i386/g'`"
|
||||
default_qemu="qemu-kvm kvm $qemu_system qemu"
|
||||
AC_ARG_WITH([qemu],
|
||||
[AS_HELP_STRING([--with-qemu],
|
||||
[set default QEMU binary @<:@default=[qemu-kvm] qemu-system-<host> qemu@:>@])],
|
||||
@@ -509,7 +557,24 @@ AC_PATH_PROGS([QEMU],[$with_qemu],[no],
|
||||
test "x$QEMU" = "xno" && AC_MSG_ERROR([qemu must be installed])
|
||||
AC_DEFINE_UNQUOTED([QEMU],["$QEMU"],[Location of qemu binary.])
|
||||
|
||||
dnl Does the user wish to specify -M, -cpu or other qemu options?
|
||||
AC_MSG_CHECKING([if the user specified extra options for qemu command line])
|
||||
AC_ARG_WITH([qemu-options],
|
||||
[AS_HELP_STRING([--with-qemu-options="-M ... -cpu ... etc"],
|
||||
[pass extra options for qemu command line @<:@default=no@:>@])],
|
||||
[QEMU_OPTIONS="$withval"],
|
||||
[QEMU_OPTIONS=no])
|
||||
AS_IF([test "x$QEMU_OPTIONS" = "xno"],[
|
||||
AC_MSG_RESULT([no])
|
||||
QEMU_OPTIONS=
|
||||
],[
|
||||
AC_MSG_RESULT([$QEMU_OPTIONS])
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([QEMU_OPTIONS],["$QEMU_OPTIONS"],
|
||||
[extra options for qemu command line])
|
||||
|
||||
dnl Check that the chosen qemu has virtio-serial support.
|
||||
dnl For historical reasons this can be disabled by setting vmchannel_test=no.
|
||||
if test "x$vmchannel_test" != "xno"; then
|
||||
AC_MSG_CHECKING([that $QEMU -help works])
|
||||
if $QEMU -help >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
@@ -524,53 +589,37 @@ working.
|
||||
])
|
||||
fi
|
||||
|
||||
dnl qemu 0.15 was released with broken support for '-machine',
|
||||
dnl requiring you to add the machine type: '-machine pc,[...]'.
|
||||
dnl The problem is that 'pc' is only applicable for PC-like
|
||||
dnl hardware, so we cannot do this as a general solution. Since
|
||||
dnl qemu 0.15, this problem has been fixed so now the default
|
||||
dnl machine type is chosen (qemu commit 2645c6dcaf6ea2a51a).
|
||||
dnl
|
||||
dnl We need to work out if this qemu is the broken version, so we
|
||||
dnl can add 'pc' just for this broken version.
|
||||
dnl
|
||||
dnl Note that old qemu didn't support the '-machine' option at all.
|
||||
dnl
|
||||
dnl We use the -kernel option for testing this, because this option
|
||||
dnl is processed very late, after qemu has set up the machine.
|
||||
AC_MSG_CHECKING([for broken '-machine accel=tcg' option in $QEMU])
|
||||
LC_ALL=C $QEMU -nographic -machine accel=tcg -kernel /NO_SUCH_FILE \
|
||||
> config1.tmp 2>&1
|
||||
LC_ALL=C $QEMU -nographic -machine pc,accel=tcg -kernel /NO_SUCH_FILE \
|
||||
> config2.tmp 2>&1
|
||||
if cmp -s config1.tmp config2.tmp; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_MSG_CHECKING([that $QEMU -version works])
|
||||
if $QEMU -version >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([QEMU_MACHINE_TYPE_IS_BROKEN],[1],[qemu -machine accel=tcg option is broken (in qemu 0.15 only)])
|
||||
fi
|
||||
rm config1.tmp config2.tmp
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE(
|
||||
[$QEMU -version: command failed.
|
||||
|
||||
dnl See if the '-machine [pc,]accel=tcg' option is required in
|
||||
dnl order to run the virtio-serial test below. This happens when
|
||||
dnl we run qemu-kvm inside a VM without forcing TCG:
|
||||
dnl
|
||||
dnl Could not access KVM kernel module: No such file or directory
|
||||
dnl failed to initialize KVM: No such file or directory
|
||||
dnl No accelerator found!
|
||||
AC_MSG_CHECKING([if -machine @<:@pc,@:>@accel=tcg option is required to test virtio-serial feature])
|
||||
if $QEMU -nographic -device \? >/dev/null 2>&1; then
|
||||
:
|
||||
elif $QEMU -machine accel=tcg -nographic -device \? >/dev/null 2>&1; then
|
||||
QEMU_EXTRA_OPTIONS_FOR_TEST="-machine accel=tcg"
|
||||
elif $QEMU -machine pc,accel=tcg -nographic -device \? >/dev/null 2>&1; then
|
||||
QEMU_EXTRA_OPTIONS_FOR_TEST="-machine pc,accel=tcg"
|
||||
# else nothing ... it'll fail below.
|
||||
This could be a very old version of qemu, or qemu might not be
|
||||
working.
|
||||
])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for $QEMU version >= 1])
|
||||
if $QEMU -version | grep -sq 'version @<:@1-@:>@'; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([$QEMU version must be >= 1.0.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([that $QEMU -nographic -machine accel=kvm:tcg -device ? works])
|
||||
if $QEMU -nographic -machine accel=kvm:tcg -device \? >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([$QEMU -nographic -machine accel=kvm:tcg -device ? doesn't work.])
|
||||
fi
|
||||
AC_MSG_RESULT([$QEMU_EXTRA_OPTIONS_FOR_TEST])
|
||||
|
||||
AC_MSG_CHECKING([for virtio-serial support in $QEMU])
|
||||
if $QEMU $QEMU_EXTRA_OPTIONS_FOR_TEST -nographic -device \? 2>&1 | grep -sq virtio-serial; then
|
||||
if $QEMU $QEMU_OPTIONS -nographic -machine accel=kvm:tcg -device \? 2>&1 | grep -sq virtio-serial; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
@@ -586,8 +635,10 @@ and/or KVM. Please read the relevant section in the README file for
|
||||
more information about this.
|
||||
|
||||
You can override this test by setting the environment variable
|
||||
vmchannel_test=no However if you don't have the right support
|
||||
in your qemu, then this just delays the pain.
|
||||
vmchannel_test=no
|
||||
|
||||
However if you don't have the right support in your qemu, then this
|
||||
just delays the pain.
|
||||
|
||||
If I am using the wrong qemu or you want to compile qemu from source
|
||||
and install it in another location, then you should configure with
|
||||
@@ -596,29 +647,6 @@ the --with-qemu option.
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Set default drive interface used by the guestfs_add_drive_opts call
|
||||
dnl ('-drive ...,if=...' option to qemu).
|
||||
dnl
|
||||
dnl If you encounter performance problems with virtio (RHBZ#509383)
|
||||
dnl then try '--with-drive-if=ide'.
|
||||
AC_ARG_WITH([drive-if],
|
||||
[AS_HELP_STRING([--with-drive-if],
|
||||
[set default driver (ide|scsi|virtio) @<:@default=virtio@:>@])],
|
||||
[],
|
||||
[with_drive_if=virtio])
|
||||
AC_DEFINE_UNQUOTED([DRIVE_IF],["$with_drive_if"],[Default drive interface.])
|
||||
|
||||
dnl Set interface used by the network. Normally you should
|
||||
dnl leave this at the default (virtio-net-pci) but you can use the
|
||||
dnl alternative (ne2k_pci) because of bugs in virtio networking
|
||||
dnl eg. https://bugzilla.redhat.com/show_bug.cgi?id=516022
|
||||
AC_ARG_WITH([net-if],
|
||||
[AS_HELP_STRING([--with-net-if],
|
||||
[set default net driver (virtio-net-pci|ne2k_pci) @<:@default=virtio-net-pci@:>@])],
|
||||
[],
|
||||
[with_net_if=virtio-net-pci])
|
||||
AC_DEFINE_UNQUOTED([NET_IF],["$with_net_if"],[Default network interface.])
|
||||
|
||||
dnl Enable packet dumps when in verbose mode. This generates lots
|
||||
dnl of debug info, only useful for people debugging the RPC mechanism.
|
||||
AC_ARG_ENABLE([packet-dump],
|
||||
@@ -652,9 +680,6 @@ AS_IF([test "x$with_readline" != xno],
|
||||
LIBS="$old_LIBS"
|
||||
])
|
||||
|
||||
dnl For i18n.
|
||||
AM_GNU_GETTEXT([external])
|
||||
|
||||
dnl Check for PCRE (required)
|
||||
PKG_CHECK_MODULES([PCRE], [libpcre])
|
||||
|
||||
@@ -681,6 +706,10 @@ PKG_CHECK_MODULES([LIBXML2], [libxml-2.0],
|
||||
[AC_SUBST([LIBXML2_CFLAGS])
|
||||
AC_SUBST([LIBXML2_LIBS])
|
||||
AC_DEFINE([HAVE_LIBXML2],[1],[libxml2 found at compile time.])
|
||||
old_LIBS="$LIBS"
|
||||
LIBS="$LIBS $LIBXML2_LIBS"
|
||||
AC_CHECK_FUNCS([xmlBufferDetach])
|
||||
LIBS="$old_LIBS"
|
||||
],
|
||||
[AC_MSG_WARN([libxml2 not found, some core features will be disabled])])
|
||||
AM_CONDITIONAL([HAVE_LIBXML2],[test "x$LIBXML2_LIBS" != "x"])
|
||||
@@ -714,7 +743,12 @@ AS_IF([test "x$enable_fuse" != "xno"],
|
||||
[PKG_CHECK_MODULES([FUSE],[fuse],
|
||||
[AC_SUBST([FUSE_CFLAGS])
|
||||
AC_SUBST([FUSE_LIBS])
|
||||
AC_DEFINE([HAVE_FUSE],[1],[Define to 1 if you have FUSE])],
|
||||
AC_DEFINE([HAVE_FUSE],[1],[Define to 1 if you have FUSE])
|
||||
old_LIBS="$LIBS"
|
||||
LIBS="$FUSE_LIBS $LIBS"
|
||||
AC_CHECK_FUNCS([fuse_opt_add_opt_escaped])
|
||||
LIBS="$old_LIBS"
|
||||
],
|
||||
[enable_fuse=no
|
||||
AC_MSG_WARN([FUSE library and headers are missing, so optional FUSE module won't be built])
|
||||
])
|
||||
@@ -731,7 +765,7 @@ AM_CONDITIONAL([HAVE_CXX], [$CXX --version])
|
||||
dnl If valgrind is present (it's not required), check whether or not
|
||||
dnl it supports the new 'valgrind --vgdb' option.
|
||||
AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind],[no])
|
||||
AS_IF([test "x$valgrind" != "xno"],[
|
||||
AS_IF([test "x$VALGRIND" != "xno"],[
|
||||
AC_MSG_CHECKING([if $VALGRIND supports the --vgdb option])
|
||||
if $VALGRIND --help | grep -sq -- --vgdb; then
|
||||
AC_MSG_RESULT([yes])
|
||||
@@ -742,7 +776,7 @@ AS_IF([test "x$valgrind" != "xno"],[
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Check for OCaml (optional, for OCaml bindings).
|
||||
dnl Check for OCaml (optional, for OCaml bindings and OCaml tools).
|
||||
OCAMLC=no
|
||||
OCAMLFIND=no
|
||||
AC_ARG_ENABLE([ocaml],
|
||||
@@ -762,23 +796,107 @@ AM_CONDITIONAL([HAVE_OCAML],
|
||||
AM_CONDITIONAL([HAVE_OCAMLDOC],
|
||||
[test "x$OCAMLDOC" != "xno"])
|
||||
|
||||
dnl Check for Perl (optional, for Perl bindings).
|
||||
PERL=no
|
||||
OCAML_PKG_gettext=no
|
||||
AS_IF([test "x$OCAMLC" != "xno"],[
|
||||
dnl Check for ocaml-gettext package to translate OCaml tools.
|
||||
AC_CHECK_OCAML_PKG(gettext)
|
||||
|
||||
dnl Write gettext modules for each OCaml tool. If OCaml gettext
|
||||
dnl is not available then we write dummy functions.
|
||||
for program in resize sparsify sysprep; do
|
||||
output=$program/${program}_gettext.ml
|
||||
AC_MSG_NOTICE([creating $output])
|
||||
rm -f $output
|
||||
|
||||
cat <<EOF > $output
|
||||
(* This file is generated automatically by ./configure. *)
|
||||
|
||||
(** Gettext functions for virt-$program.
|
||||
|
||||
The ${program}_gettext module provides gettext functions for
|
||||
$program, or dummy functions if ocaml-gettext was not available
|
||||
at configure time.
|
||||
|
||||
{b Note}: Don't translate debug strings, or strings which are
|
||||
meant to be read/written only by machine.
|
||||
|
||||
There are two ways to translate constant strings in OCaml programs.
|
||||
|
||||
For ordinary strings, replace [["string"]] with [[s_"string"]]. Since
|
||||
this is a function call to a function called [[s_]], you may have
|
||||
to put parentheses around the expression.
|
||||
|
||||
For format strings, use:
|
||||
|
||||
{v
|
||||
printf (f_"zeroing filesystem %s") filename;
|
||||
v}
|
||||
|
||||
Note for format strings, the parentheses are almost always required,
|
||||
and they just go around the [[(f_"string")]], {i not} around the other
|
||||
arguments of the printf function.
|
||||
|
||||
At build time, a program parses the OCaml code into an abstract
|
||||
syntax tree and statically determines all calls to the special
|
||||
[[s_]] and [[f_]] functions, which means: (a) You can be very loose
|
||||
with syntax, unlike ordinary xgettext, but (b) you cannot rename
|
||||
these functions.
|
||||
*)
|
||||
|
||||
EOF
|
||||
|
||||
if test "x$OCAML_PKG_gettext" != "xno"; then
|
||||
# ocaml-gettext available: real module.
|
||||
cat <<EOF >>$output
|
||||
module Gettext = Gettext.Program (
|
||||
struct
|
||||
let textdomain = "$PACKAGE_NAME"
|
||||
let codeset = None
|
||||
let dir = None
|
||||
let dependencies = [[]]
|
||||
end
|
||||
) (GettextStub.Native)
|
||||
EOF
|
||||
else
|
||||
# No gettext: module containing dummy gettext functions.
|
||||
cat <<EOF >>$output
|
||||
module Gettext = struct
|
||||
external s_ : string -> string = "%identity"
|
||||
external f_ : ('a, 'b, 'c, 'd, 'e, 'f) format6
|
||||
-> ('a, 'b, 'c, 'd, 'e, 'f) format6
|
||||
= "%identity"
|
||||
let sn_ : string -> string -> int -> string
|
||||
= fun s p n -> if n = 1 then s else p
|
||||
let fn_ : ('a, 'b, 'c, 'd, 'e, 'f) format6
|
||||
-> ('a, 'b, 'c, 'd, 'e, 'f) format6
|
||||
-> int -> ('a, 'b, 'c, 'd, 'e, 'f) format6
|
||||
= fun s p n -> if n = 1 then s else p
|
||||
end
|
||||
EOF
|
||||
fi
|
||||
|
||||
chmod -w $output
|
||||
done
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_OCAML_PKG_GETTEXT],
|
||||
[test "x$OCAMLC" != "xno" && test "x$OCAMLFIND" != "xno" && test "x$OCAML_PKG_gettext" != "xno"])
|
||||
|
||||
AC_CHECK_PROG([OCAML_GETTEXT],[ocaml-gettext],[ocaml-gettext],[no])
|
||||
AM_CONDITIONAL([HAVE_OCAML_GETTEXT],
|
||||
[test "x$OCAMLC" != "xno" && test "x$OCAMLFIND" != "xno" && test "x$OCAML_PKG_gettext" != "xno" && test "x$OCAML_GETTEXT" != "xno"])
|
||||
|
||||
dnl Check for Perl (optional, for Perl bindings and Perl tools).
|
||||
AC_ARG_ENABLE([perl],
|
||||
AS_HELP_STRING([--disable-perl], [Disable Perl language bindings]),
|
||||
[],
|
||||
[enable_perl=yes])
|
||||
AS_IF([test "x$enable_perl" != "xno"],
|
||||
[
|
||||
PERL=
|
||||
AC_CHECK_PROG([PERL],[perl],[perl],[no])
|
||||
|
||||
AS_IF([test "x$enable_perl" != "xno"],[
|
||||
dnl Check for Perl modules that must be present to compile and
|
||||
dnl test the Perl bindings.
|
||||
missing_perl_modules=no
|
||||
for pm in Test::More ExtUtils::MakeMaker; do
|
||||
AC_MSG_CHECKING([for $pm])
|
||||
if ! perl -M$pm -e1 >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
if ! $PERL -M$pm -e1 >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
AC_MSG_RESULT([no])
|
||||
missing_perl_modules=yes
|
||||
else
|
||||
@@ -869,18 +987,40 @@ AM_CONDITIONAL([HAVE_PYTHON],
|
||||
|
||||
dnl Check for Ruby and rake (optional, for Ruby bindings).
|
||||
AC_ARG_ENABLE([ruby],
|
||||
AS_HELP_STRING([--disable-ruby], [Disable Ruby language bindings]),
|
||||
[],
|
||||
[enable_ruby=yes])
|
||||
AS_IF([test "x$enable_ruby" != "xno"],
|
||||
[
|
||||
AC_CHECK_PROG([RUBY],[ruby],[ruby],[no])
|
||||
AC_CHECK_PROG([RAKE],[rake],[rake],[no])
|
||||
AC_CHECK_LIB([ruby],[ruby_init],[HAVE_LIBRUBY=1],[HAVE_LIBRUBY=0])
|
||||
AC_SUBST([RAKE])
|
||||
AS_HELP_STRING([--disable-ruby], [Disable Ruby language bindings]),
|
||||
[],
|
||||
[enable_ruby=yes])
|
||||
AS_IF([test "x$enable_ruby" != "xno"],[
|
||||
AC_CHECK_PROG([RUBY],[ruby],[ruby],[no])
|
||||
AC_CHECK_PROG([RAKE],[rake],[rake],[no])
|
||||
|
||||
AS_IF([test -n "$RUBY" && test -n "$RAKE"],[
|
||||
dnl Find the library. Note on Debian it's not -lruby.
|
||||
AC_MSG_CHECKING([for C library for Ruby extensions])
|
||||
ruby_cmd='puts RbConfig::CONFIG@<:@"RUBY_SO_NAME"@:>@'
|
||||
echo running: $RUBY -rrbconfig -e \'$ruby_cmd\' >&AS_MESSAGE_LOG_FD
|
||||
$RUBY -rrbconfig -e "$ruby_cmd" >conftest 2>&AS_MESSAGE_LOG_FD
|
||||
libruby="$(cat conftest)"
|
||||
rm conftest
|
||||
AS_IF([test -n "$libruby"],[
|
||||
AC_MSG_RESULT([-l$libruby])
|
||||
AC_CHECK_LIB([$libruby],[ruby_init],
|
||||
[have_libruby=1],[have_libruby=])
|
||||
|
||||
dnl Symbols that we substitute when missing.
|
||||
AS_IF([test -n "$have_libruby"],[
|
||||
old_LIBS="$LIBS"
|
||||
LIBS="$LIBS -l$libruby"
|
||||
AC_CHECK_FUNCS([rb_hash_lookup])
|
||||
LIBS="$old_LIBS"
|
||||
])
|
||||
],[
|
||||
AC_MSG_RESULT([not found])
|
||||
])
|
||||
])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_RUBY],
|
||||
[test "x$RAKE" != "xno" && test -n "$HAVE_LIBRUBY"])
|
||||
[test -n "$RUBY" && test -n "$RAKE" && test -n "$have_libruby"])
|
||||
|
||||
dnl Check for Java.
|
||||
AC_ARG_WITH(java_home,
|
||||
@@ -987,20 +1127,20 @@ if test "x$with_java_home" != "xno"; then
|
||||
|
||||
dnl Need extra version flag?
|
||||
AC_MSG_CHECKING([extra javac flags])
|
||||
JAVAC_FLAGS=
|
||||
EXTRA_JAVAC_FLAGS=
|
||||
javac_version=`$JAVAC -version 2>&1`
|
||||
case "$javac_version" in
|
||||
*Eclipse*)
|
||||
JAVAC_FLAGS="-source 1.5" ;;
|
||||
EXTRA_JAVAC_FLAGS="-source 1.5" ;;
|
||||
esac
|
||||
AC_MSG_RESULT([$JAVAC_FLAGS])
|
||||
AC_MSG_RESULT([$EXTRA_JAVAC_FLAGS])
|
||||
|
||||
dnl Extra lint flags?
|
||||
AC_MSG_CHECKING([extra javac lint flags])
|
||||
if $JAVAC -X >/dev/null 2>&1 && \
|
||||
$JAVAC -X 2>&1 | grep -q -- '-Xlint:.*all'; then
|
||||
AC_MSG_RESULT([-Xlint:all])
|
||||
JAVAC_FLAGS="$JAVAC_FLAGS -Xlint:all"
|
||||
EXTRA_JAVAC_FLAGS="$EXTRA_JAVAC_FLAGS -Xlint:all"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
@@ -1028,7 +1168,7 @@ AC_SUBST(JAVAH)
|
||||
AC_SUBST(JAVADOC)
|
||||
AC_SUBST(JAR)
|
||||
AC_SUBST(JNI_CFLAGS)
|
||||
AC_SUBST(JAVAC_FLAGS)
|
||||
AC_SUBST(EXTRA_JAVAC_FLAGS)
|
||||
AC_SUBST(JAR_INSTALL_DIR)
|
||||
AC_SUBST(JNI_INSTALL_DIR)
|
||||
AC_SUBST(JNI_VERSION_INFO)
|
||||
@@ -1177,11 +1317,11 @@ dnl Produce output files.
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html
|
||||
AC_CONFIG_FILES([appliance/libguestfs-make-fixed-appliance],
|
||||
[chmod +x appliance/libguestfs-make-fixed-appliance])
|
||||
AC_CONFIG_FILES([podwrapper.sh],
|
||||
[chmod +x podwrapper.sh])
|
||||
[chmod +x,-w appliance/libguestfs-make-fixed-appliance])
|
||||
AC_CONFIG_FILES([podwrapper.pl],
|
||||
[chmod +x,-w podwrapper.pl])
|
||||
AC_CONFIG_FILES([run],
|
||||
[chmod +x run])
|
||||
[chmod +x,-w run])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
align/Makefile
|
||||
appliance/Makefile
|
||||
@@ -1206,7 +1346,6 @@ AC_CONFIG_FILES([Makefile
|
||||
inspector/Makefile
|
||||
java/Makefile
|
||||
java/examples/Makefile
|
||||
libguestfs.pc
|
||||
ocaml/META
|
||||
ocaml/Makefile
|
||||
ocaml/examples/Makefile
|
||||
@@ -1217,7 +1356,7 @@ AC_CONFIG_FILES([Makefile
|
||||
po-docs/Makefile
|
||||
po-docs/ja/Makefile
|
||||
po-docs/uk/Makefile
|
||||
po/Makefile.in
|
||||
po/Makefile
|
||||
python/Makefile
|
||||
python/examples/Makefile
|
||||
rescue/Makefile
|
||||
@@ -1227,19 +1366,27 @@ AC_CONFIG_FILES([Makefile
|
||||
ruby/examples/Makefile
|
||||
sparsify/Makefile
|
||||
src/Makefile
|
||||
src/libguestfs.pc
|
||||
sysprep/Makefile
|
||||
test-tool/Makefile
|
||||
tests/9p/Makefile
|
||||
tests/btrfs/Makefile
|
||||
tests/c-api/Makefile
|
||||
tests/charsets/Makefile
|
||||
tests/data/Makefile
|
||||
tests/disks/Makefile
|
||||
tests/extra/Makefile
|
||||
tests/guests/Makefile
|
||||
tests/luks/Makefile
|
||||
tests/lvm/Makefile
|
||||
tests/md/Makefile
|
||||
tests/mount-local/Makefile
|
||||
tests/ntfsclone/Makefile
|
||||
tests/protocol/Makefile
|
||||
tests/qemu/Makefile
|
||||
tests/regressions/Makefile
|
||||
tests/selinux/Makefile
|
||||
tests/xml/Makefile
|
||||
tools/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1253,33 +1400,35 @@ echo "This is how we have configured the optional components for you today:"
|
||||
echo
|
||||
echo "Daemon .............................. $enable_daemon"
|
||||
echo "Appliance ........................... $enable_appliance"
|
||||
echo "QEMU ................................ $QEMU"
|
||||
echo -n "OCaml bindings ...................... "
|
||||
echo "QEMU ................................ $QEMU $QEMU_OPTIONS"
|
||||
AS_ECHO_N(["OCaml bindings ...................... "])
|
||||
if test "x$HAVE_OCAML_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Perl bindings ....................... "
|
||||
AS_ECHO_N(["Perl bindings ....................... "])
|
||||
if test "x$HAVE_PERL_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Python bindings ..................... "
|
||||
AS_ECHO_N(["Python bindings ..................... "])
|
||||
if test "x$HAVE_PYTHON_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Ruby bindings ....................... "
|
||||
AS_ECHO_N(["Ruby bindings ....................... "])
|
||||
if test "x$HAVE_RUBY_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Java bindings ....................... "
|
||||
AS_ECHO_N(["Java bindings ....................... "])
|
||||
if test "x$HAVE_JAVA_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Haskell bindings .................... "
|
||||
AS_ECHO_N(["Haskell bindings .................... "])
|
||||
if test "x$HAVE_HASKELL_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "PHP bindings ........................ "
|
||||
AS_ECHO_N(["PHP bindings ........................ "])
|
||||
if test "x$HAVE_PHP_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "Erlang bindings ..................... "
|
||||
AS_ECHO_N(["Erlang bindings ..................... "])
|
||||
if test "x$HAVE_ERLANG_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo "guestfish and C virt tools .......... yes"
|
||||
echo -n "Perl virt tools ..................... "
|
||||
AS_ECHO_N(["Perl virt tools ..................... "])
|
||||
if test "x$HAVE_TOOLS_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "virt-resize ......................... "
|
||||
AS_ECHO_N(["OCaml virt tools .................... "])
|
||||
if test "x$HAVE_OCAML_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo "FUSE filesystem ..................... $enable_fuse"
|
||||
echo -n "gobject bindings .................... "
|
||||
AS_ECHO_N(["gobject bindings .................... "])
|
||||
if test "x$HAVE_GOBJECT_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo -n "gobject introspection ............... "
|
||||
AS_ECHO_N(["gobject introspection ............... "])
|
||||
if test "x$HAVE_INTROSPECTION_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
AS_ECHO_N(["GNU gettext for i18n ................ "])
|
||||
if test "x$HAVE_GNU_GETTEXT_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
echo
|
||||
echo "If any optional component is configured 'no' when you expected 'yes'"
|
||||
echo "then you should check the preceding messages."
|
||||
|
||||
@@ -28,8 +28,8 @@ BUILT_SOURCES = \
|
||||
$(generator_built) \
|
||||
guestfs_protocol.c \
|
||||
guestfs_protocol.h \
|
||||
errnostring_gperf.c \
|
||||
errnostring_gperf.gperf \
|
||||
errnostring-gperf.c \
|
||||
errnostring-gperf.gperf \
|
||||
errnostring.c \
|
||||
errnostring.h
|
||||
|
||||
@@ -57,16 +57,16 @@ $(libsrcdir)/guestfs_protocol.h: force
|
||||
# of warnings so we must compile it in a separate mini-library.
|
||||
noinst_LIBRARIES += liberrnostring.a
|
||||
liberrnostring_a_SOURCES = \
|
||||
errnostring_gperf.c \
|
||||
errnostring-gperf.c \
|
||||
errnostring.h \
|
||||
errnostring.c
|
||||
liberrnostring_a_CFLAGS =
|
||||
|
||||
errnostring_gperf.c: errnostring_gperf.gperf
|
||||
errnostring-gperf.c: errnostring-gperf.gperf
|
||||
rm -f $@
|
||||
$(GPERF) -t $< > $@-t
|
||||
mv $@-t $@
|
||||
errnostring_gperf.gperf: $(libsrcdir)/errnostring_gperf.gperf
|
||||
errnostring-gperf.gperf: $(libsrcdir)/errnostring-gperf.gperf
|
||||
rm -f $@
|
||||
ln $< $@
|
||||
errnostring.c: $(libsrcdir)/errnostring.c
|
||||
@@ -106,7 +106,7 @@ guestfsd_SOURCES = \
|
||||
dmesg.c \
|
||||
dropcaches.c \
|
||||
du.c \
|
||||
echo_daemon.c \
|
||||
echo-daemon.c \
|
||||
ext2.c \
|
||||
fallocate.c \
|
||||
file.c \
|
||||
@@ -114,6 +114,7 @@ guestfsd_SOURCES = \
|
||||
fill.c \
|
||||
find.c \
|
||||
fsck.c \
|
||||
fstrim.c \
|
||||
glob.c \
|
||||
grep.c \
|
||||
grub.c \
|
||||
@@ -162,10 +163,13 @@ guestfsd_SOURCES = \
|
||||
umask.c \
|
||||
upload.c \
|
||||
utimens.c \
|
||||
utsname.c \
|
||||
wc.c \
|
||||
xattr.c \
|
||||
xfs.c \
|
||||
zero.c \
|
||||
zerofree.c
|
||||
|
||||
guestfsd_LDADD = \
|
||||
liberrnostring.a \
|
||||
libprotocol.a \
|
||||
|
||||
@@ -389,85 +389,85 @@ optgroup_augeas_available (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_init (const char *root, int flags)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_close (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_defvar (const char *name, const char *expr)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
guestfs_int_int_bool *
|
||||
guestfs_int_int_bool * __attribute__((noreturn))
|
||||
do_aug_defnode (const char *name, const char *expr, const char *val)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char *
|
||||
char * __attribute__((noreturn))
|
||||
do_aug_get (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_set (const char *path, const char *val)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_clear (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_insert (const char *path, const char *label, int before)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_rm (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_mv (const char *src, const char *dest)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char **
|
||||
char ** __attribute__((noreturn))
|
||||
do_aug_match (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_save (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
int __attribute__((noreturn))
|
||||
do_aug_load (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char **
|
||||
char ** __attribute__((noreturn))
|
||||
do_aug_ls (const char *path)
|
||||
{
|
||||
abort ();
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
int
|
||||
do_available (char *const *groups)
|
||||
@@ -70,3 +73,79 @@ do_available_all_groups (void)
|
||||
|
||||
return groups.argv; /* caller frees */
|
||||
}
|
||||
|
||||
/* Search for filesystem in /proc/filesystems, ignoring "nodev". */
|
||||
static int
|
||||
test_proc_filesystems (const char *filesystem)
|
||||
{
|
||||
size_t len = strlen (filesystem) + 32;
|
||||
char regex[len];
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
snprintf (regex, len, "^[[:space:]]*%s$", filesystem);
|
||||
|
||||
r = commandr (NULL, &err, "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;
|
||||
}
|
||||
|
||||
/* Do modprobe, ignore any errors. */
|
||||
static void
|
||||
modprobe (const char *module)
|
||||
{
|
||||
command (NULL, NULL, "modprobe", module, NULL);
|
||||
}
|
||||
|
||||
/* Internal function for testing if a filesystem is available. Note
|
||||
* this must not call reply_with_error functions.
|
||||
*/
|
||||
int
|
||||
filesystem_available (const char *filesystem)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = test_proc_filesystems (filesystem);
|
||||
if (r == -1 || r > 0)
|
||||
return r;
|
||||
|
||||
/* Not found: try to modprobe the module, then test again. */
|
||||
if (optgroup_linuxmodules_available ()) {
|
||||
modprobe (filesystem);
|
||||
|
||||
r = test_proc_filesystems (filesystem);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_filesystem_available (const char *filesystem)
|
||||
{
|
||||
size_t i, len = strlen (filesystem);
|
||||
int r;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (!c_isalnum (filesystem[i]) && filesystem[i] != '_') {
|
||||
reply_with_error ("filesystem name contains non-alphanumeric characters");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
r = filesystem_available (filesystem);
|
||||
if (r == -1) {
|
||||
reply_with_error ("error testing for filesystem availability; "
|
||||
"enable verbose mode and look at preceeding output");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
482
daemon/btrfs.c
482
daemon/btrfs.c
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2011 Red Hat Inc.
|
||||
* Copyright (C) 2011-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
|
||||
@@ -28,18 +28,17 @@
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
int
|
||||
optgroup_btrfs_available (void)
|
||||
{
|
||||
return prog_exists ("btrfs");
|
||||
return prog_exists ("btrfs") && filesystem_available ("btrfs") > 0;
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
{
|
||||
const size_t MAX_ARGS = 64;
|
||||
char *buf;
|
||||
char *err;
|
||||
int r;
|
||||
@@ -87,13 +86,21 @@ do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_mkfs_btrfs (const char *device,
|
||||
do_mkfs_btrfs (char *const *devices,
|
||||
int64_t allocstart, int64_t bytecount, const char *datatype,
|
||||
int leafsize, const char *label, const char *metadata,
|
||||
int nodesize, int sectorsize)
|
||||
{
|
||||
size_t nr_devices = count_strings (devices);
|
||||
|
||||
if (nr_devices == 0) {
|
||||
reply_with_error ("list of devices must be non-empty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t MAX_ARGS = nr_devices + 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
size_t i = 0, j;
|
||||
int r;
|
||||
char *err;
|
||||
char allocstart_s[64];
|
||||
@@ -180,6 +187,469 @@ do_mkfs_btrfs (const char *device,
|
||||
ADD_ARG (argv, i, sectorsize_s);
|
||||
}
|
||||
|
||||
for (j = 0; j < nr_devices; ++j)
|
||||
ADD_ARG (argv, i, devices[j]);
|
||||
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", devices[0], err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
int r;
|
||||
|
||||
source_buf = sysroot_path (source);
|
||||
if (source_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
dest_buf = sysroot_path (dest);
|
||||
if (dest_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (source_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "snapshot");
|
||||
ADD_ARG (argv, i, source_buf);
|
||||
ADD_ARG (argv, i, dest_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
int r;
|
||||
|
||||
subvolume_buf = sysroot_path (subvolume);
|
||||
if (subvolume_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "delete");
|
||||
ADD_ARG (argv, i, subvolume_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
int r;
|
||||
|
||||
dest_buf = sysroot_path (dest);
|
||||
if (dest_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "create");
|
||||
ADD_ARG (argv, i, dest_buf);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "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 <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.
|
||||
*/
|
||||
nr_subvolumes = count_strings (lines);
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free_stringslen (lines, nr_subvolumes);
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
for (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];
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
pos = strstr (line, " path ");
|
||||
if (pos == NULL)
|
||||
goto unexpected_output;
|
||||
pos += 6;
|
||||
|
||||
memmove (line, pos, strlen (pos) + 1);
|
||||
ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_path = line;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
char buf[64];
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
snprintf (buf, sizeof buf, "%" PRIi64, id);
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "set-default");
|
||||
ADD_ARG (argv, i, buf);
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "filesystem");
|
||||
ADD_ARG (argv, i, "sync");
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "filesystem");
|
||||
ADD_ARG (argv, i, "balance");
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
do_btrfs_device_add (char *const *devices, const char *fs)
|
||||
{
|
||||
size_t nr_devices = count_strings (devices);
|
||||
|
||||
if (nr_devices == 0)
|
||||
return 0;
|
||||
|
||||
size_t MAX_ARGS = nr_devices + 8;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0, j;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "device");
|
||||
ADD_ARG (argv, i, "add");
|
||||
|
||||
for (j = 0; j < nr_devices; ++j)
|
||||
ADD_ARG (argv, i, devices[j]);
|
||||
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
do_btrfs_device_delete (char *const *devices, const char *fs)
|
||||
{
|
||||
size_t nr_devices = count_strings (devices);
|
||||
|
||||
if (nr_devices == 0)
|
||||
return 0;
|
||||
|
||||
size_t MAX_ARGS = nr_devices + 8;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0, j;
|
||||
char *fs_buf;
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
fs_buf = sysroot_path (fs);
|
||||
if (fs_buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, "device");
|
||||
ADD_ARG (argv, i, "delete");
|
||||
|
||||
for (j = 0; j < nr_devices; ++j)
|
||||
ADD_ARG (argv, i, devices[j]);
|
||||
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
do_btrfs_set_seeding (const char *device, int svalue)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
const char *s_value = svalue ? "1" : "0";
|
||||
|
||||
r = commandr (NULL, &err, "btrfstune", "-S", s_value, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_btrfs_fsck (const char *device, int64_t superblock, int repair)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
size_t i = 0;
|
||||
const size_t MAX_ARGS = 64;
|
||||
const char *argv[MAX_ARGS];
|
||||
char super_s[64];
|
||||
|
||||
ADD_ARG (argv, i, "btrfsck");
|
||||
|
||||
/* Optional arguments. */
|
||||
if (optargs_bitmask & GUESTFS_BTRFS_FSCK_SUPERBLOCK_BITMASK) {
|
||||
if (superblock < 0) {
|
||||
reply_with_error ("super block offset must be >= 0");
|
||||
return -1;
|
||||
}
|
||||
snprintf (super_s, sizeof super_s, "%" PRIi64, superblock);
|
||||
ADD_ARG (argv, i, "--super");
|
||||
ADD_ARG (argv, i, super_s);
|
||||
}
|
||||
|
||||
if (!(optargs_bitmask & GUESTFS_BTRFS_FSCK_REPAIR_BITMASK))
|
||||
repair = 0;
|
||||
|
||||
if (repair)
|
||||
ADD_ARG (argv, i, "--repair");
|
||||
|
||||
ADD_ARG (argv, i, device);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ extern void sort_strings (char **argv, size_t len);
|
||||
extern void free_strings (char **argv);
|
||||
extern void free_stringslen (char **argv, size_t len);
|
||||
|
||||
extern void sort_device_names (char **argv, size_t len);
|
||||
extern int compare_device_names (const char *a, const char *b);
|
||||
|
||||
extern char **split_lines (char *str);
|
||||
|
||||
#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
|
||||
@@ -109,6 +112,8 @@ extern int prog_exists (const char *prog);
|
||||
|
||||
extern void udev_settle (void);
|
||||
|
||||
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.
|
||||
@@ -151,6 +156,9 @@ struct optgroup {
|
||||
};
|
||||
extern struct optgroup optgroups[];
|
||||
|
||||
/*-- in available.c --*/
|
||||
extern int filesystem_available (const char *filesystem);
|
||||
|
||||
/*-- in sync.c --*/
|
||||
/* Use this as a replacement for sync(2). */
|
||||
extern int sync_disks (void);
|
||||
|
||||
@@ -61,6 +61,7 @@ static char *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);
|
||||
static char *debug_qtrace (const char *subcmd, size_t argc, char *const *const argv);
|
||||
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 struct cmd cmds[] = {
|
||||
@@ -75,6 +76,7 @@ static struct cmd cmds[] = {
|
||||
{ "progress", debug_progress },
|
||||
{ "qtrace", debug_qtrace },
|
||||
{ "segv", debug_segv },
|
||||
{ "setenv", debug_setenv },
|
||||
{ "sh", debug_sh },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@@ -286,6 +288,28 @@ debug_env (const char *subcmd, size_t argc, char *const *const argv)
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Set an environment variable in the daemon and future subprocesses. */
|
||||
static char *
|
||||
debug_setenv (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (argc != 2) {
|
||||
reply_with_error ("setenv: two arguments expected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setenv (argv[0], argv[1], 1);
|
||||
|
||||
ret = strdup ("ok");
|
||||
if (NULL == ret) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return binaries in the appliance.
|
||||
* See tests/regressions/rhbz727178.sh
|
||||
*/
|
||||
@@ -429,8 +453,12 @@ debug_progress (const char *subcmd, size_t argc, char *const *const argv)
|
||||
|
||||
char *secs_str = argv[0];
|
||||
unsigned secs;
|
||||
if (sscanf (secs_str, "%u", &secs) != 1 || secs == 0)
|
||||
if (sscanf (secs_str, "%u", &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 */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009 Red Hat Inc.
|
||||
* Copyright (C) 2009-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
|
||||
@@ -38,9 +38,11 @@ static char **
|
||||
foreach_block_device (block_dev_func_t func)
|
||||
{
|
||||
DECLARE_STRINGSBUF (r);
|
||||
|
||||
DIR *dir;
|
||||
int err = 0;
|
||||
struct dirent *d;
|
||||
char dev_path[256];
|
||||
int fd;
|
||||
|
||||
dir = opendir ("/sys/block");
|
||||
if (!dir) {
|
||||
@@ -48,16 +50,15 @@ foreach_block_device (block_dev_func_t func)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
struct dirent *d = readdir(dir);
|
||||
if(NULL == d) break;
|
||||
d = readdir(dir);
|
||||
if (!d) break;
|
||||
|
||||
if (STREQLEN (d->d_name, "sd", 2) ||
|
||||
STREQLEN (d->d_name, "hd", 2) ||
|
||||
STREQLEN (d->d_name, "vd", 2) ||
|
||||
STREQLEN (d->d_name, "sr", 2)) {
|
||||
char dev_path[256];
|
||||
snprintf (dev_path, sizeof dev_path, "/dev/%s", d->d_name);
|
||||
|
||||
/* Ignore the root device. */
|
||||
@@ -68,7 +69,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
* CD-ROM device even though we didn't request it. Try to
|
||||
* detect this by seeing if the device contains media.
|
||||
*/
|
||||
int fd = open (dev_path, O_RDONLY|O_CLOEXEC);
|
||||
fd = open (dev_path, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
perror (dev_path);
|
||||
continue;
|
||||
@@ -76,7 +77,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
close (fd);
|
||||
|
||||
/* Call the map function for this device */
|
||||
if((*func)(d->d_name, &r) != 0) {
|
||||
if ((*func)(d->d_name, &r) != 0) {
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
@@ -84,7 +85,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
}
|
||||
|
||||
/* Check readdir didn't fail */
|
||||
if(0 != errno) {
|
||||
if (errno != 0) {
|
||||
reply_with_perror ("readdir: /sys/block");
|
||||
free_stringslen (r.argv, r.size);
|
||||
closedir (dir);
|
||||
@@ -106,7 +107,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
|
||||
/* Sort the devices. */
|
||||
if (r.size > 0)
|
||||
sort_strings (r.argv, r.size);
|
||||
sort_device_names (r.argv, r.size);
|
||||
|
||||
/* NULL terminate the list */
|
||||
if (end_stringsbuf (&r) == -1) {
|
||||
@@ -241,3 +242,43 @@ do_part_to_partnum (const char *part)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_device_index (const char *device)
|
||||
{
|
||||
char **devices;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
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;
|
||||
|
||||
devices = do_list_devices ();
|
||||
if (devices == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i)
|
||||
free (devices[i]);
|
||||
free (devices);
|
||||
|
||||
return (int) i;
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ do_mke2journal (int blocksize, const char *device)
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-O", "journal_dev", "-b", blocksize_s,
|
||||
prog, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -409,7 +409,7 @@ do_mke2journal_L (int blocksize, const char *label, const char *device)
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-O", "journal_dev", "-b", blocksize_s,
|
||||
prog, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
"-L", label,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
@@ -436,7 +436,7 @@ do_mke2journal_U (int blocksize, const char *uuid, const char *device)
|
||||
snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-O", "journal_dev", "-b", blocksize_s,
|
||||
prog, "-F", "-O", "journal_dev", "-b", blocksize_s,
|
||||
"-U", uuid,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
@@ -468,7 +468,7 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device,
|
||||
snprintf (jdev, len+32, "device=%s", journal);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -505,7 +505,7 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device,
|
||||
snprintf (jdev, len+32, "device=LABEL=%s", label);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -536,7 +536,7 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device,
|
||||
snprintf (jdev, len+32, "device=UUID=%s", uuid);
|
||||
|
||||
r = command (NULL, &err,
|
||||
prog, "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
|
||||
97
daemon/fstrim.c
Normal file
97
daemon/fstrim.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* 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 <inttypes.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
int
|
||||
optgroup_fstrim_available (void)
|
||||
{
|
||||
return prog_exists ("fstrim");
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_fstrim (const char *path,
|
||||
int64_t offset, int64_t length, int64_t minimumfreeextent)
|
||||
{
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char offset_s[64], length_s[64], mfe_s[64];
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
ADD_ARG (argv, i, "fstrim");
|
||||
|
||||
if ((optargs_bitmask & GUESTFS_FSTRIM_OFFSET_BITMASK)) {
|
||||
if (offset < 0) {
|
||||
reply_with_error ("offset < 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf (offset_s, sizeof offset_s, "%" PRIi64, offset);
|
||||
ADD_ARG (argv, i, "-o");
|
||||
ADD_ARG (argv, i, offset_s);
|
||||
}
|
||||
|
||||
if ((optargs_bitmask & GUESTFS_FSTRIM_LENGTH_BITMASK)) {
|
||||
if (length <= 0) {
|
||||
reply_with_error ("length <= 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf (length_s, sizeof length_s, "%" PRIi64, length);
|
||||
ADD_ARG (argv, i, "-l");
|
||||
ADD_ARG (argv, i, length_s);
|
||||
}
|
||||
|
||||
if ((optargs_bitmask & GUESTFS_FSTRIM_MINIMUMFREEEXTENT_BITMASK)) {
|
||||
if (minimumfreeextent <= 0) {
|
||||
reply_with_error ("minimumfreeextent <= 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf (mfe_s, sizeof mfe_s, "%" PRIi64, minimumfreeextent);
|
||||
ADD_ARG (argv, i, "-m");
|
||||
ADD_ARG (argv, i, mfe_s);
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, path);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -28,13 +28,40 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
static char **
|
||||
grep (const char *prog, const char *flag, const char *regex, const char *path)
|
||||
grep (const char *regex, const char *path,
|
||||
int extended, int fixed, int insensitive, int compressed)
|
||||
{
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
char *out, *err;
|
||||
int fd, flags, r;
|
||||
char **lines;
|
||||
|
||||
if (extended && fixed) {
|
||||
reply_with_error ("can't use 'extended' and 'fixed' flags at the same time");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!compressed)
|
||||
ADD_ARG (argv, i, "grep");
|
||||
else
|
||||
ADD_ARG (argv, i, "zgrep");
|
||||
|
||||
if (extended)
|
||||
ADD_ARG (argv, i, "-E");
|
||||
|
||||
if (fixed)
|
||||
ADD_ARG (argv, i, "-F");
|
||||
|
||||
if (insensitive)
|
||||
ADD_ARG (argv, i, "-i");
|
||||
|
||||
ADD_ARG (argv, i, regex);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
@@ -48,9 +75,9 @@ grep (const char *prog, const char *flag, const char *regex, const char *path)
|
||||
* suppress this error and return an empty list.
|
||||
*/
|
||||
flags = COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN | fd;
|
||||
r = commandrf (&out, &err, flags, prog, flag, regex, NULL);
|
||||
r = commandrvf (&out, &err, flags, argv);
|
||||
if (r == -1 || r > 1) {
|
||||
reply_with_error ("%s %s %s: %s", prog, flag, regex, err);
|
||||
reply_with_error ("%s: %s", regex, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
@@ -65,75 +92,85 @@ grep (const char *prog, const char *flag, const char *regex, const char *path)
|
||||
return lines;
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
char **
|
||||
do_grep (const char *regex, const char *path)
|
||||
do_grep (const char *regex, const char *path,
|
||||
int extended, int fixed, int insensitive, int compressed)
|
||||
{
|
||||
/* The "--" is not really needed, but it helps when we don't need a flag. */
|
||||
return grep ("grep", "--", regex, path);
|
||||
if (!(optargs_bitmask & GUESTFS_GREP_EXTENDED_BITMASK))
|
||||
extended = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_GREP_FIXED_BITMASK))
|
||||
fixed = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_GREP_INSENSITIVE_BITMASK))
|
||||
insensitive = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_GREP_COMPRESSED_BITMASK))
|
||||
compressed = 0;
|
||||
|
||||
return grep (regex, path, extended, fixed, insensitive, compressed);
|
||||
}
|
||||
|
||||
char **
|
||||
do_egrep (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("egrep", "--", regex, path);
|
||||
return grep (regex, path, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
char **
|
||||
do_fgrep (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("fgrep", "--", regex, path);
|
||||
return grep (regex, path, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
char **
|
||||
do_grepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("grep", "-i", regex, path);
|
||||
return grep (regex, path, 0, 0, 1, 0);
|
||||
}
|
||||
|
||||
char **
|
||||
do_egrepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("egrep", "-i", regex, path);
|
||||
return grep (regex, path, 1, 0, 1, 0);
|
||||
}
|
||||
|
||||
char **
|
||||
do_fgrepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("fgrep", "-i", regex, path);
|
||||
return grep (regex, path, 0, 1, 1, 0);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zgrep (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zgrep", "--", regex, path);
|
||||
return grep (regex, path, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zegrep (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zegrep", "--", regex, path);
|
||||
return grep (regex, path, 1, 0, 0, 1);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zfgrep (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zfgrep", "--", regex, path);
|
||||
return grep (regex, path, 0, 1, 0, 1);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zgrepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zgrep", "-i", regex, path);
|
||||
return grep (regex, path, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zegrepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zegrep", "-i", regex, path);
|
||||
return grep (regex, path, 1, 0, 1, 1);
|
||||
}
|
||||
|
||||
char **
|
||||
do_zfgrepi (const char *regex, const char *path)
|
||||
{
|
||||
return grep ("zfgrep", "-i", regex, path);
|
||||
return grep (regex, path, 0, 1, 1, 1);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_PRINTF_H
|
||||
# include <printf.h>
|
||||
@@ -514,6 +515,69 @@ free_stringslen (char **argv, size_t len)
|
||||
free (argv);
|
||||
}
|
||||
|
||||
/* Compare device names (including partition numbers if present).
|
||||
* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/
|
||||
*/
|
||||
int
|
||||
compare_device_names (const char *a, const char *b)
|
||||
{
|
||||
size_t a_devlen, b_devlen;
|
||||
int r;
|
||||
int a_partnum, b_partnum;
|
||||
|
||||
/* Skip /dev/ prefix if present. */
|
||||
if (STRPREFIX (a, "/dev/"))
|
||||
a += 5;
|
||||
if (STRPREFIX (b, "/dev/"))
|
||||
b += 5;
|
||||
|
||||
/* Skip sd/hd/vd. */
|
||||
assert (a[1] == 'd');
|
||||
a += 2;
|
||||
assert (b[1] == 'd');
|
||||
b += 2;
|
||||
|
||||
/* Get device name part, that is, just 'a', 'ab' etc. */
|
||||
a_devlen = strcspn (a, "0123456789");
|
||||
b_devlen = strcspn (b, "0123456789");
|
||||
|
||||
/* If device name part is longer, it is always greater, eg.
|
||||
* "/dev/sdz" < "/dev/sdaa".
|
||||
*/
|
||||
if (a_devlen != b_devlen)
|
||||
return a_devlen - b_devlen;
|
||||
|
||||
/* Device name parts are the same length, so do a regular compare. */
|
||||
r = strncmp (a, b, a_devlen);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Compare partitions numbers. */
|
||||
a += a_devlen;
|
||||
b += a_devlen;
|
||||
|
||||
r = sscanf (a, "%d", &a_partnum);
|
||||
assert (r == 1);
|
||||
r = sscanf (b, "%d", &b_partnum);
|
||||
assert (r == 1);
|
||||
|
||||
return a_partnum - b_partnum;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_device_names_vp (const void *vp1, const void *vp2)
|
||||
{
|
||||
char * const *p1 = (char * const *) vp1;
|
||||
char * const *p2 = (char * const *) vp2;
|
||||
return compare_device_names (*p1, *p2);
|
||||
}
|
||||
|
||||
void
|
||||
sort_device_names (char **argv, size_t len)
|
||||
{
|
||||
qsort (argv, len, sizeof (char *), compare_device_names_vp);
|
||||
}
|
||||
|
||||
/* Easy ways to run external commands. For full documentation, see
|
||||
* 'commandrvf' below.
|
||||
*/
|
||||
@@ -1126,6 +1190,52 @@ prog_exists (const char *prog)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pass a template such as "/sysroot/XXXXXXXX.XXX". This updates the
|
||||
* template to contain a randomly named file. Any 'X' characters
|
||||
* after the final '/' are replaced with random characters.
|
||||
*
|
||||
* Notes: You should probably use an 8.3 path, so it's compatible with
|
||||
* all filesystems including basic FAT. Also this only substitutes
|
||||
* lowercase ASCII letters and numbers, again for compatibility with
|
||||
* lowest common denominator filesystems.
|
||||
*
|
||||
* This doesn't create a file or check whether or not the file exists
|
||||
* (it would be extremely unlikely to exist as long as the RNG is
|
||||
* working).
|
||||
*
|
||||
* If there is an error, -1 is returned.
|
||||
*/
|
||||
int
|
||||
random_name (char *template)
|
||||
{
|
||||
int fd;
|
||||
unsigned char c;
|
||||
char *p;
|
||||
|
||||
fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
p = strrchr (template, '/');
|
||||
if (p == NULL)
|
||||
abort (); /* internal error - bad template */
|
||||
|
||||
while (*p) {
|
||||
if (*p == 'X') {
|
||||
if (read (fd, &c, 1) != 1) {
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
*p = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36];
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LVM and other commands aren't synchronous, especially when udev is
|
||||
* involved. eg. You can create or remove some device, but the /dev
|
||||
* device node won't appear until some time later. This means that
|
||||
|
||||
@@ -245,7 +245,7 @@ make_filter_string (char *const *devices)
|
||||
size_t i;
|
||||
size_t len = 64;
|
||||
for (i = 0; devices[i] != NULL; ++i)
|
||||
len += strlen (devices[i]) + 16;
|
||||
len += 2 * strlen (devices[i]) + 64;
|
||||
|
||||
char *filter = malloc (len);
|
||||
if (filter == NULL) {
|
||||
@@ -255,19 +255,22 @@ make_filter_string (char *const *devices)
|
||||
|
||||
char *p = filter;
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
/* Because of the way matching works in LVM, each match clause
|
||||
* should be either:
|
||||
* "a|^/dev/sda|", for whole block devices, or
|
||||
* "a|^/dev/sda1$|", for single partitions
|
||||
* (the assumption being we have <= 26 block devices XXX).
|
||||
/* Because of the way matching works in LVM (yes, they wrote their
|
||||
* own regular expression engine!), each match clause should be either:
|
||||
*
|
||||
* for single partitions:
|
||||
* "a|^/dev/sda1$|",
|
||||
* for whole block devices:
|
||||
* "a|^/dev/sda$|", "a|^/dev/sda[0-9]|",
|
||||
*/
|
||||
size_t slen = strlen (devices[i]);
|
||||
char str[slen+16];
|
||||
char str[2*slen+64];
|
||||
|
||||
if (c_isdigit (devices[i][slen-1]))
|
||||
snprintf (str, slen+16, "\"a|^%s$|\", ", devices[i]);
|
||||
else
|
||||
snprintf (str, slen+16, "\"a|^%s|\", ", devices[i]);
|
||||
if (c_isdigit (devices[i][slen-1])) /* single partition */
|
||||
snprintf (str, 2*slen+64, "\"a|^%s$|\", ", devices[i]);
|
||||
else /* whole block device */
|
||||
snprintf (str, 2*slen+64, "\"a|^%s$|\", \"a|^%s[0-9]|\", ",
|
||||
devices[i], devices[i]);
|
||||
|
||||
strcpy (p, str);
|
||||
p += strlen (str);
|
||||
|
||||
84
daemon/lvm.c
84
daemon/lvm.c
@@ -960,3 +960,87 @@ do_vgmeta (const char *vg, size_t *size_r)
|
||||
|
||||
return buf; /* caller will free */
|
||||
}
|
||||
|
||||
int
|
||||
do_pvchange_uuid (const char *device)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"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;
|
||||
}
|
||||
|
||||
int
|
||||
do_pvchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "pvchange", "-u", "-a", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_vgchange_uuid (const char *vg)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"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;
|
||||
}
|
||||
|
||||
int
|
||||
do_vgchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "vgchange", "-u", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
const char *features, int inode, int sectorsize)
|
||||
do_mkfs (const char *fstype, const char *device, int blocksize,
|
||||
const char *features, int inode, int sectorsize)
|
||||
{
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
@@ -100,7 +100,7 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
}
|
||||
|
||||
/* Process blocksize parameter if set. */
|
||||
if (optargs_bitmask & GUESTFS_MKFS_OPTS_BLOCKSIZE_BITMASK) {
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BLOCKSIZE_BITMASK) {
|
||||
if (blocksize <= 0 || !is_power_of_2 (blocksize)) {
|
||||
reply_with_error ("block size must be > 0 and a power of 2");
|
||||
return -1;
|
||||
@@ -146,12 +146,12 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
}
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_OPTS_FEATURES_BITMASK) {
|
||||
if (optargs_bitmask & GUESTFS_MKFS_FEATURES_BITMASK) {
|
||||
ADD_ARG (argv, i, "-O");
|
||||
ADD_ARG (argv, i, features);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_OPTS_INODE_BITMASK) {
|
||||
if (optargs_bitmask & GUESTFS_MKFS_INODE_BITMASK) {
|
||||
if (!extfs) {
|
||||
reply_with_error ("inode size (-I) can only be set on ext2/3/4 filesystems");
|
||||
return -1;
|
||||
@@ -167,7 +167,7 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
ADD_ARG (argv, i, inode_str);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_OPTS_SECTORSIZE_BITMASK) {
|
||||
if (optargs_bitmask & GUESTFS_MKFS_SECTORSIZE_BITMASK) {
|
||||
if (!STREQ (fstype, "ufs")) {
|
||||
reply_with_error ("sector size (-S) can only be set on ufs filesystems");
|
||||
return -1;
|
||||
@@ -197,16 +197,9 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_mkfs (const char *fstype, const char *device)
|
||||
{
|
||||
optargs_bitmask = 0;
|
||||
return do_mkfs_opts (fstype, device, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
do_mkfs_b (const char *fstype, int blocksize, const char *device)
|
||||
{
|
||||
optargs_bitmask = GUESTFS_MKFS_OPTS_BLOCKSIZE_BITMASK;
|
||||
return do_mkfs_opts (fstype, device, blocksize, 0, 0, 0);
|
||||
optargs_bitmask = GUESTFS_MKFS_BLOCKSIZE_BITMASK;
|
||||
return do_mkfs (fstype, device, blocksize, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
/* You must mount something on "/" first before many operations.
|
||||
* Hence we have an internal function which can test if something is
|
||||
* mounted on *or under* the sysroot directory. (It has to be *or
|
||||
@@ -154,7 +156,8 @@ do_mount_vfs (const char *options, const char *vfstype,
|
||||
"mount", "-o", options, device, mp, NULL);
|
||||
free (mp);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s on %s: %s", device, mountpoint, error);
|
||||
reply_with_error ("%s on %s (options: '%s'): %s",
|
||||
device, mountpoint, options, error);
|
||||
free (error);
|
||||
return -1;
|
||||
}
|
||||
@@ -182,16 +185,17 @@ do_mount_options (const char *options, const char *device,
|
||||
return do_mount_vfs (options, NULL, device, mountpoint);
|
||||
}
|
||||
|
||||
/* Again, use the external /bin/umount program, so that /etc/mtab
|
||||
* is kept updated.
|
||||
*/
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_umount (const char *pathordevice)
|
||||
do_umount (const char *pathordevice,
|
||||
int force, int lazyunmount)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
char *buf;
|
||||
int is_dev;
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
|
||||
is_dev = STREQLEN (pathordevice, "/dev/", 5);
|
||||
buf = is_dev ? strdup (pathordevice)
|
||||
@@ -201,10 +205,25 @@ do_umount (const char *pathordevice)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_dev)
|
||||
RESOLVE_DEVICE (buf, , { free (buf); return -1; });
|
||||
if (!(optargs_bitmask & GUESTFS_UMOUNT_FORCE_BITMASK))
|
||||
force = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_UMOUNT_LAZYUNMOUNT_BITMASK))
|
||||
lazyunmount = 0;
|
||||
|
||||
r = command (NULL, &err, "umount", buf, NULL);
|
||||
/* Use the external /bin/umount program, so that /etc/mtab is kept
|
||||
* updated.
|
||||
*/
|
||||
ADD_ARG (argv, i, "umount");
|
||||
|
||||
if (force)
|
||||
ADD_ARG (argv, i, "-f");
|
||||
if (lazyunmount)
|
||||
ADD_ARG (argv, i, "-l");
|
||||
|
||||
ADD_ARG (argv, i, buf);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
|
||||
@@ -64,7 +64,7 @@ do_ntfs_3g_probe (int rw, const char *device)
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_ntfsresize_opts (const char *device, int64_t size, int force)
|
||||
do_ntfsresize (const char *device, int64_t size, int force)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
@@ -75,7 +75,7 @@ do_ntfsresize_opts (const char *device, int64_t size, int force)
|
||||
ADD_ARG (argv, i, "ntfsresize");
|
||||
ADD_ARG (argv, i, "-P");
|
||||
|
||||
if (optargs_bitmask & GUESTFS_NTFSRESIZE_OPTS_SIZE_BITMASK) {
|
||||
if (optargs_bitmask & GUESTFS_NTFSRESIZE_SIZE_BITMASK) {
|
||||
if (size <= 0) {
|
||||
reply_with_error ("size is zero or negative");
|
||||
return -1;
|
||||
@@ -86,7 +86,7 @@ do_ntfsresize_opts (const char *device, int64_t size, int force)
|
||||
ADD_ARG (argv, i, size_str);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_NTFSRESIZE_OPTS_FORCE_BITMASK && force)
|
||||
if (optargs_bitmask & GUESTFS_NTFSRESIZE_FORCE_BITMASK && force)
|
||||
ADD_ARG (argv, i, "--force");
|
||||
|
||||
ADD_ARG (argv, i, device);
|
||||
@@ -103,17 +103,11 @@ do_ntfsresize_opts (const char *device, int64_t size, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_ntfsresize (const char *device)
|
||||
{
|
||||
return do_ntfsresize_opts (device, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
do_ntfsresize_size (const char *device, int64_t size)
|
||||
{
|
||||
optargs_bitmask = GUESTFS_NTFSRESIZE_OPTS_SIZE_BITMASK;
|
||||
return do_ntfsresize_opts (device, size, 0);
|
||||
optargs_bitmask = GUESTFS_NTFSRESIZE_SIZE_BITMASK;
|
||||
return do_ntfsresize (device, size, 0);
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
|
||||
@@ -199,7 +199,9 @@ do_part_disk (const char *device, const char *parttype)
|
||||
*
|
||||
* - aligned operations are faster
|
||||
* - absolute minimum recommended alignment is 64K (1M would be better)
|
||||
* - GPT requires at least 34 sectors at the end of the disk.
|
||||
* - GPT requires at least 34 sectors* at the end of the disk.
|
||||
*
|
||||
* *=except for 4k sector disks, where only 6 sectors are required
|
||||
*/
|
||||
const char *startstr = "128s";
|
||||
const char *endstr = "-128s";
|
||||
@@ -694,10 +696,22 @@ do_part_get_bootable (const char *device, int partnum)
|
||||
}
|
||||
size_t col = p - lines[header];
|
||||
|
||||
/* Look for the line corresponding to this partition number. */
|
||||
row = start + partnum - 1;
|
||||
if (row >= count_strings (lines) || !STRPREFIX (lines[row], " ")) {
|
||||
reply_with_error ("partition number out of range: %d", partnum);
|
||||
/* Partitions may not be in any order, so we have to look for
|
||||
* the matching partition number (RHBZ#602997).
|
||||
*/
|
||||
int pnum;
|
||||
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)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lines[row] == NULL) {
|
||||
reply_with_error ("partition number %d not found", partnum);
|
||||
free_strings (lines);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -78,14 +78,17 @@ do_realpath (const char *path)
|
||||
|
||||
#endif /* !HAVE_REALPATH */
|
||||
|
||||
static int find_path_element (int fd_cwd, char *name, size_t *name_len_ret);
|
||||
static int find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret);
|
||||
|
||||
char *
|
||||
do_case_sensitive_path (const char *path)
|
||||
{
|
||||
char ret[PATH_MAX+1] = "/";
|
||||
char name[NAME_MAX+1];
|
||||
size_t next = 1;
|
||||
int fd_cwd;
|
||||
int fd_cwd, fd2, err, is_end;
|
||||
size_t i;
|
||||
char *retp;
|
||||
|
||||
/* 'fd_cwd' here is a surrogate for the current working directory, so
|
||||
* that we don't have to actually call chdir(2).
|
||||
@@ -100,7 +103,7 @@ do_case_sensitive_path (const char *path)
|
||||
* and follow it.
|
||||
*/
|
||||
while (*path) {
|
||||
size_t i = strcspn (path, "/");
|
||||
i = strcspn (path, "/");
|
||||
if (i == 0) {
|
||||
path++;
|
||||
continue;
|
||||
@@ -116,18 +119,18 @@ do_case_sensitive_path (const char *path)
|
||||
goto error;
|
||||
}
|
||||
|
||||
char name[NAME_MAX+1];
|
||||
memcpy (name, path, i);
|
||||
name[i] = '\0';
|
||||
|
||||
/* Skip to next element in path (for the next loop iteration). */
|
||||
path += i;
|
||||
is_end = *path == 0;
|
||||
|
||||
/* Read the current directory looking (case insensitively) for
|
||||
* this element of the path. This replaces 'name' with the
|
||||
* correct case version.
|
||||
*/
|
||||
if (find_path_element (fd_cwd, name, &i) == -1)
|
||||
if (find_path_element (fd_cwd, is_end, name, &i) == -1)
|
||||
goto error;
|
||||
|
||||
/* Add the real name of this path element to the return value. */
|
||||
@@ -143,22 +146,18 @@ do_case_sensitive_path (const char *path)
|
||||
next += i;
|
||||
|
||||
/* Is it a directory? Try going into it. */
|
||||
int fd2 = openat (fd_cwd, name, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
int err = errno;
|
||||
fd2 = openat (fd_cwd, name, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
err = errno;
|
||||
close (fd_cwd);
|
||||
fd_cwd = fd2;
|
||||
errno = err;
|
||||
if (fd_cwd == -1) {
|
||||
/* ENOTDIR is OK provided we've reached the end of the path. */
|
||||
if (errno != ENOTDIR) {
|
||||
reply_with_perror ("openat: %s", name);
|
||||
goto error;
|
||||
}
|
||||
/* Some errors are OK provided we've reached the end of the path. */
|
||||
if (is_end && (errno == ENOTDIR || errno == ENOENT))
|
||||
break;
|
||||
|
||||
if (*path) {
|
||||
reply_with_error ("%s: non-directory element in path", name);
|
||||
goto error;
|
||||
}
|
||||
reply_with_perror ("openat: %s", name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +165,7 @@ do_case_sensitive_path (const char *path)
|
||||
close (fd_cwd);
|
||||
|
||||
ret[next] = '\0';
|
||||
char *retp = strdup (ret);
|
||||
retp = strdup (ret);
|
||||
if (retp == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
@@ -182,7 +181,8 @@ do_case_sensitive_path (const char *path)
|
||||
|
||||
/* '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.
|
||||
* contains 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.
|
||||
@@ -191,7 +191,7 @@ do_case_sensitive_path (const char *path)
|
||||
* and return -1.
|
||||
*/
|
||||
static int
|
||||
find_path_element (int fd_cwd, char *name, size_t *name_len_ret)
|
||||
find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret)
|
||||
{
|
||||
int fd2;
|
||||
DIR *dir;
|
||||
@@ -224,6 +224,14 @@ find_path_element (int fd_cwd, char *name, size_t *name_len_ret)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (d == NULL && is_end) {
|
||||
/* Last path element: return it as-is, assuming that the user will
|
||||
* create a new file or directory (RHBZ#840115).
|
||||
*/
|
||||
closedir (dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d == NULL) {
|
||||
reply_with_error ("%s: no file or directory found with this name", name);
|
||||
closedir (dir);
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
@@ -32,6 +36,10 @@
|
||||
static int sync_win32 (void);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSYNC
|
||||
static void fsync_devices (void);
|
||||
#endif
|
||||
|
||||
int
|
||||
do_sync (void)
|
||||
{
|
||||
@@ -52,6 +60,18 @@ sync_disks (void)
|
||||
{
|
||||
#if defined(HAVE_SYNC)
|
||||
sync ();
|
||||
|
||||
/* On Linux, sync(2) doesn't perform a barrier, so qemu (which may
|
||||
* have a writeback cache, even with cache=none) will still have
|
||||
* some unwritten data. Force the data out of any qemu caches, by
|
||||
* calling fsync on all block devices. Note we still need the
|
||||
* call to sync above in order to schedule the writes.
|
||||
* Thanks to: Avi Kivity, Kevin Wolf.
|
||||
*/
|
||||
#ifdef HAVE_FSYNC
|
||||
fsync_devices ();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#elif defined(WIN32)
|
||||
return sync_win32 ();
|
||||
@@ -60,6 +80,64 @@ sync_disks (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_FSYNC
|
||||
static void
|
||||
fsync_devices (void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char dev_path[256];
|
||||
int fd;
|
||||
|
||||
dir = opendir ("/sys/block");
|
||||
if (!dir) {
|
||||
perror ("opendir: /sys/block");
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
d = readdir(dir);
|
||||
if (!d) break;
|
||||
|
||||
if (STREQLEN (d->d_name, "sd", 2) ||
|
||||
STREQLEN (d->d_name, "hd", 2) ||
|
||||
STREQLEN (d->d_name, "vd", 2) ||
|
||||
STREQLEN (d->d_name, "sr", 2)) {
|
||||
snprintf (dev_path, sizeof dev_path, "/dev/%s", d->d_name);
|
||||
|
||||
/* Ignore the root device. */
|
||||
if (is_root_device (dev_path))
|
||||
continue;
|
||||
|
||||
fd = open (dev_path, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
perror (dev_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* fsync the device. */
|
||||
if (verbose)
|
||||
fprintf (stderr, "fsync %s\n", dev_path);
|
||||
|
||||
if (fsync (fd) == -1)
|
||||
perror ("fsync");
|
||||
|
||||
if (close (fd) == -1)
|
||||
perror ("close");
|
||||
}
|
||||
}
|
||||
|
||||
/* Check readdir didn't fail */
|
||||
if (errno != 0)
|
||||
perror ("readdir: /sys/block");
|
||||
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1)
|
||||
perror ("closedir");
|
||||
}
|
||||
#endif /* HAVE_FSYNC */
|
||||
|
||||
#ifdef WIN32
|
||||
static int
|
||||
sync_win32 (void)
|
||||
|
||||
57
daemon/tar.c
57
daemon/tar.c
@@ -36,6 +36,51 @@ optgroup_xz_available (void)
|
||||
return prog_exists ("xz");
|
||||
}
|
||||
|
||||
/* Detect if chown(2) is supported on the target directory. */
|
||||
static int
|
||||
is_chown_supported (const char *dir)
|
||||
{
|
||||
size_t len = sysroot_len + strlen (dir) + 64;
|
||||
char buf[len];
|
||||
int fd, r, saved_errno;
|
||||
|
||||
/* Create a randomly named file. */
|
||||
snprintf (buf, len, "%s%s/XXXXXXXX.XXX", sysroot, dir);
|
||||
if (random_name (buf) == -1) {
|
||||
reply_with_perror ("random_name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Maybe 'dir' is not a directory or filesystem not writable? */
|
||||
fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("%s", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is the test. */
|
||||
r = fchown (fd, 1000, 1000);
|
||||
saved_errno = errno;
|
||||
|
||||
/* Make sure the test file is removed. */
|
||||
close (fd);
|
||||
unlink (buf);
|
||||
|
||||
if (r == -1 && saved_errno == EPERM) {
|
||||
/* This means chown is not supported by the filesystem. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r == -1) {
|
||||
/* Some other error? */
|
||||
reply_with_perror_errno (saved_errno, "unexpected error in fchown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Else chown is supported. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read the error file. Returns a string that the caller must free. */
|
||||
static char *
|
||||
read_error_file (char *error_file)
|
||||
@@ -75,7 +120,11 @@ do_tXz_in (const char *dir, const char *filter)
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char error_file[] = "/tmp/tarXXXXXX";
|
||||
int fd;
|
||||
int fd, chown_supported;
|
||||
|
||||
chown_supported = is_chown_supported (dir);
|
||||
if (chown_supported == -1)
|
||||
return -1;
|
||||
|
||||
fd = mkstemp (error_file);
|
||||
if (fd == -1) {
|
||||
@@ -86,8 +135,10 @@ do_tXz_in (const char *dir, const char *filter)
|
||||
close (fd);
|
||||
|
||||
/* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
|
||||
if (asprintf_nowarn (&cmd, "tar -C %R -%sxf - 2> %s",
|
||||
dir, filter, error_file) == -1) {
|
||||
if (asprintf_nowarn (&cmd, "tar -C %R -%sxf - %s2> %s",
|
||||
dir, filter,
|
||||
chown_supported ? "" : "--no-same-owner ",
|
||||
error_file) == -1) {
|
||||
err = errno;
|
||||
r = cancel_receive ();
|
||||
errno = err;
|
||||
|
||||
62
daemon/utsname.c
Normal file
62
daemon/utsname.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* 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 <sys/utsname.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
guestfs_int_utsname *
|
||||
do_utsname (void)
|
||||
{
|
||||
struct utsname uts;
|
||||
guestfs_int_utsname *ret;
|
||||
|
||||
if (uname (&uts) == -1) {
|
||||
reply_with_perror ("utsname");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->uts_sysname = strdup (uts.sysname);
|
||||
ret->uts_release = strdup (uts.release);
|
||||
ret->uts_version = strdup (uts.version);
|
||||
ret->uts_machine = strdup (uts.machine);
|
||||
if (!ret->uts_sysname || !ret->uts_release ||
|
||||
!ret->uts_version || !ret->uts_machine) {
|
||||
reply_with_perror ("strdup");
|
||||
free (ret->uts_sysname);
|
||||
free (ret->uts_release);
|
||||
free (ret->uts_version);
|
||||
free (ret->uts_machine);
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
@@ -174,6 +175,12 @@ getxattrs (const char *path,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (vlen > XATTR_SIZE_MAX) {
|
||||
/* The next call to getxattr will fail anyway, so ... */
|
||||
reply_with_error ("extended attribute is too large");
|
||||
goto error;
|
||||
}
|
||||
|
||||
r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
|
||||
r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
|
||||
r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
|
||||
@@ -222,6 +229,11 @@ _setxattr (const char *xattr, const char *val, int vallen, const char *path,
|
||||
{
|
||||
int r;
|
||||
|
||||
if (vallen > XATTR_SIZE_MAX) {
|
||||
reply_with_error ("extended attribute is too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
r = setxattr (path, xattr, val, vallen, 0);
|
||||
CHROOT_OUT;
|
||||
@@ -372,6 +384,11 @@ do_lxattrlist (const char *path, char *const *names)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (vlen > XATTR_SIZE_MAX) {
|
||||
reply_with_error ("extended attribute is too large");
|
||||
goto error;
|
||||
}
|
||||
|
||||
entry[j+1].attrname = strdup (&buf[i]);
|
||||
entry[j+1].attrval.attrval_val = malloc (vlen);
|
||||
entry[j+1].attrval.attrval_len = vlen;
|
||||
@@ -442,6 +459,12 @@ do_getxattr (const char *path, const char *name, size_t *size_r)
|
||||
}
|
||||
|
||||
len = r;
|
||||
|
||||
if (len > XATTR_SIZE_MAX) {
|
||||
reply_with_error ("extended attribute is too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = malloc (len);
|
||||
if (buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
@@ -484,6 +507,12 @@ do_lgetxattr (const char *path, const char *name, size_t *size_r)
|
||||
}
|
||||
|
||||
len = r;
|
||||
|
||||
if (len > XATTR_SIZE_MAX) {
|
||||
reply_with_error ("extended attribute is too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = malloc (len);
|
||||
if (buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
|
||||
461
daemon/xfs.c
Normal file
461
daemon/xfs.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2012 Fujitsu Limited.
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
int
|
||||
optgroup_xfs_available (void)
|
||||
{
|
||||
return prog_exists ("mkfs.xfs");
|
||||
}
|
||||
|
||||
static char *
|
||||
split_strdup (char *string)
|
||||
{
|
||||
char *end = string;
|
||||
while (*end != ' ' && *end != ',' && *end != '\0') end++;
|
||||
size_t len = end - string;
|
||||
char *ret = malloc (len + 1);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
strncpy (ret, string, len);
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_uint32 (uint32_t *ret, const char *str)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
if (sscanf (str, "%" SCNu32, &r) != 1) {
|
||||
reply_with_error ("cannot parse numeric field from isoinfo: %s", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_uint64 (uint64_t *ret, const char *str)
|
||||
{
|
||||
uint64_t r;
|
||||
|
||||
if (sscanf (str, "%" SCNu64, &r) != 1) {
|
||||
reply_with_error ("cannot parse numeric field from isoinfo: %s", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Typical crazy output from the xfs_info command:
|
||||
*
|
||||
* meta-data=/dev/sda1 isize=256 agcount=4, agsize=6392 blks
|
||||
* = sectsz=512 attr=2
|
||||
* data = bsize=4096 blocks=25568, imaxpct=25
|
||||
* = sunit=0 swidth=0 blks
|
||||
* naming =version 2 bsize=4096 ascii-ci=0
|
||||
* log =internal bsize=4096 blocks=1200, version=2
|
||||
* = sectsz=512 sunit=0 blks, lazy-count=1
|
||||
* realtime =none extsz=4096 blocks=0, rtextents=0
|
||||
*
|
||||
* We may need to revisit this parsing code if the output changes
|
||||
* in future.
|
||||
*/
|
||||
static guestfs_int_xfsinfo *
|
||||
parse_xfs_info (char **lines)
|
||||
{
|
||||
guestfs_int_xfsinfo *ret;
|
||||
char *buf = NULL, *p;
|
||||
size_t i;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_error ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize fields to NULL or -1 so the caller can tell which fields
|
||||
* were updated in the code below.
|
||||
*/
|
||||
ret->xfs_mntpoint = NULL;
|
||||
ret->xfs_inodesize = -1;
|
||||
ret->xfs_agcount = -1;
|
||||
ret->xfs_agsize = -1;
|
||||
ret->xfs_sectsize = -1;
|
||||
ret->xfs_attr = -1;
|
||||
ret->xfs_blocksize = -1;
|
||||
ret->xfs_datablocks = -1;
|
||||
ret->xfs_imaxpct = -1;
|
||||
ret->xfs_sunit = -1;
|
||||
ret->xfs_swidth = -1;
|
||||
ret->xfs_dirversion = -1;
|
||||
ret->xfs_dirblocksize = -1;
|
||||
ret->xfs_cimode = -1;
|
||||
ret->xfs_logname = NULL;
|
||||
ret->xfs_logblocksize = -1;
|
||||
ret->xfs_logblocks = -1;
|
||||
ret->xfs_logversion = -1;
|
||||
ret->xfs_logsectsize = -1;
|
||||
ret->xfs_logsunit = -1;
|
||||
ret->xfs_lazycount = -1;
|
||||
ret->xfs_rtname = NULL;
|
||||
ret->xfs_rtextsize = -1;
|
||||
ret->xfs_rtblocks = -1;
|
||||
ret->xfs_rtextents = -1;
|
||||
|
||||
for (i = 0; lines[i] != NULL; ++i) {
|
||||
if ((p = strstr (lines[i], "meta-data="))) {
|
||||
ret->xfs_mntpoint = split_strdup (p + 10);
|
||||
if (ret->xfs_mntpoint == NULL) goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "isize="))) {
|
||||
buf = split_strdup (p + 6);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_inodesize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "agcount="))) {
|
||||
buf = split_strdup (p + 8);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_agcount, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "agsize="))) {
|
||||
buf = split_strdup (p + 7);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_agsize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "sectsz="))) {
|
||||
buf = split_strdup (p + 7);
|
||||
if (buf == NULL) goto error;
|
||||
if (i == 1) {
|
||||
if (parse_uint32 (&ret->xfs_sectsize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 6) {
|
||||
if (parse_uint32 (&ret->xfs_logsectsize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "attr="))) {
|
||||
buf = split_strdup (p + 5);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_attr, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "bsize="))) {
|
||||
buf = split_strdup (p + 6);
|
||||
if (buf == NULL) goto error;
|
||||
if (i == 2) {
|
||||
if (parse_uint32 (&ret->xfs_blocksize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 4) {
|
||||
if (parse_uint32 (&ret->xfs_dirblocksize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 5) {
|
||||
if (parse_uint32 (&ret->xfs_logblocksize, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "blocks="))) {
|
||||
buf = split_strdup (p + 7);
|
||||
if (buf == NULL) goto error;
|
||||
if (i == 2) {
|
||||
if (parse_uint64 (&ret->xfs_datablocks, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 5) {
|
||||
if (parse_uint32 (&ret->xfs_logblocks, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 7) {
|
||||
if (parse_uint64 (&ret->xfs_rtblocks, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "imaxpct="))) {
|
||||
buf = split_strdup (p + 8);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_imaxpct, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "sunit="))) {
|
||||
buf = split_strdup (p + 6);
|
||||
if (buf == NULL) goto error;
|
||||
if (i == 3) {
|
||||
if (parse_uint32 (&ret->xfs_sunit, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else if (i == 6) {
|
||||
if (parse_uint32 (&ret->xfs_logsunit, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
} else goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "swidth="))) {
|
||||
buf = split_strdup (p + 7);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_swidth, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "naming =version "))) {
|
||||
buf = split_strdup (p + 18);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_dirversion, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "ascii-ci="))) {
|
||||
buf = split_strdup (p + 9);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_cimode, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "log ="))) {
|
||||
ret->xfs_logname = split_strdup (p + 10);
|
||||
if (ret->xfs_logname == NULL) goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "version="))) {
|
||||
buf = split_strdup (p + 8);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_logversion, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "lazy-count="))) {
|
||||
buf = split_strdup (p + 11);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint32 (&ret->xfs_lazycount, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
if ((p = strstr (lines[i], "realtime ="))) {
|
||||
ret->xfs_rtname = split_strdup (p + 10);
|
||||
if (ret->xfs_rtname == NULL) goto error;
|
||||
}
|
||||
if ((p = strstr (lines[i], "rtextents="))) {
|
||||
buf = split_strdup (p + 10);
|
||||
if (buf == NULL) goto error;
|
||||
if (parse_uint64 (&ret->xfs_rtextents, buf) == -1)
|
||||
goto error;
|
||||
free (buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret->xfs_mntpoint == NULL) {
|
||||
ret->xfs_mntpoint = strdup ("");
|
||||
if (ret->xfs_mntpoint == NULL) goto error;
|
||||
}
|
||||
if (ret->xfs_logname == NULL) {
|
||||
ret->xfs_logname = strdup ("");
|
||||
if (ret->xfs_logname == NULL) goto error;
|
||||
}
|
||||
if (ret->xfs_rtname == NULL) {
|
||||
ret->xfs_rtname = strdup ("");
|
||||
if (ret->xfs_rtname == NULL) goto error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
free (buf);
|
||||
free (ret->xfs_mntpoint);
|
||||
free (ret->xfs_logname);
|
||||
free (ret->xfs_rtname);
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guestfs_int_xfsinfo *
|
||||
do_xfs_info (const char *pathordevice)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
guestfs_int_xfsinfo *ret = NULL;
|
||||
int is_dev;
|
||||
|
||||
is_dev = STREQLEN (pathordevice, "/dev/", 5);
|
||||
buf = is_dev ? strdup (pathordevice)
|
||||
: sysroot_path (pathordevice);
|
||||
if (buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = command (&out, &err, "xfs_info", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
lines = split_lines (out);
|
||||
if (lines == NULL)
|
||||
goto error;
|
||||
|
||||
ret = parse_xfs_info (lines);
|
||||
|
||||
error:
|
||||
free (err);
|
||||
free (out);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
do_xfs_growfs (const char *path,
|
||||
int datasec, int logsec, int rtsec,
|
||||
int64_t datasize, int64_t logsize, int64_t rtsize,
|
||||
int64_t rtextsize, int32_t maxpct)
|
||||
{
|
||||
int r;
|
||||
char *buf;
|
||||
char *out = NULL, *err = NULL;
|
||||
const char *argv[MAX_ARGS];
|
||||
char datasize_s[64];
|
||||
char logsize_s[64];
|
||||
char rtsize_s[64];
|
||||
char rtextsize_s[64];
|
||||
char maxpct_s[32];
|
||||
size_t i = 0;
|
||||
|
||||
buf = sysroot_path (path);
|
||||
if (buf == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, "xfs_growfs");
|
||||
|
||||
/* Optional arguments */
|
||||
if (!(optargs_bitmask & GUESTFS_XFS_GROWFS_DATASEC_BITMASK))
|
||||
datasec = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_XFS_GROWFS_LOGSEC_BITMASK))
|
||||
logsec = 0;
|
||||
if (!(optargs_bitmask & GUESTFS_XFS_GROWFS_RTSEC_BITMASK))
|
||||
rtsec = 0;
|
||||
|
||||
if (datasec)
|
||||
ADD_ARG (argv, i, "-d");
|
||||
if (logsec)
|
||||
ADD_ARG (argv, i, "-l");
|
||||
if (rtsec)
|
||||
ADD_ARG (argv, i, "-r");
|
||||
|
||||
if (optargs_bitmask & GUESTFS_XFS_GROWFS_DATASIZE_BITMASK) {
|
||||
if (datasize < 0) {
|
||||
reply_with_error ("datasize must be >= 0");
|
||||
goto error;
|
||||
}
|
||||
snprintf (datasize_s, sizeof datasize_s, "%" PRIi64, datasize);
|
||||
ADD_ARG (argv, i, "-D");
|
||||
ADD_ARG (argv, i, datasize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_XFS_GROWFS_LOGSIZE_BITMASK) {
|
||||
if (logsize < 0) {
|
||||
reply_with_error ("logsize must be >= 0");
|
||||
goto error;
|
||||
}
|
||||
snprintf(logsize_s, sizeof logsize_s, "%" PRIi64, logsize);
|
||||
ADD_ARG (argv, i, "-L");
|
||||
ADD_ARG (argv, i, logsize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_XFS_GROWFS_RTSIZE_BITMASK) {
|
||||
if (rtsize < 0) {
|
||||
reply_with_error ("rtsize must be >= 0");
|
||||
goto error;
|
||||
}
|
||||
snprintf(rtsize_s, sizeof rtsize_s, "%" PRIi64, rtsize);
|
||||
ADD_ARG (argv, i, "-R");
|
||||
ADD_ARG (argv, i, rtsize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_XFS_GROWFS_RTEXTSIZE_BITMASK) {
|
||||
if (rtextsize < 0) {
|
||||
reply_with_error ("rtextsize must be >= 0");
|
||||
goto error;
|
||||
}
|
||||
snprintf(rtextsize_s, sizeof rtextsize_s, "%" PRIi64, rtextsize);
|
||||
ADD_ARG (argv, i, "-e");
|
||||
ADD_ARG (argv, i, rtextsize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_XFS_GROWFS_MAXPCT_BITMASK) {
|
||||
if (maxpct < 0) {
|
||||
reply_with_error ("maxpct must be >= 0");
|
||||
goto error;
|
||||
}
|
||||
snprintf(maxpct_s, sizeof maxpct_s, "%" PRIi32, maxpct);
|
||||
ADD_ARG (argv, i, "-m");
|
||||
ADD_ARG (argv, i, maxpct_s);
|
||||
}
|
||||
|
||||
ADD_ARG (argv, i, buf);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (&out, &err, argv);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", path, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return out;
|
||||
|
||||
error:
|
||||
if (buf) free (buf);
|
||||
if (err) free (err);
|
||||
return NULL;
|
||||
}
|
||||
@@ -228,35 +228,6 @@ do_is_zero_device (const char *device)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
random_name (char *p)
|
||||
{
|
||||
int fd;
|
||||
unsigned char c;
|
||||
|
||||
fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("/dev/urandom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (*p == 'X') {
|
||||
if (read (fd, &c, 1) != 1) {
|
||||
reply_with_perror ("read: /dev/urandom");
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
*p = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36];
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Current implementation is to create a file of all zeroes, then
|
||||
* delete it. The description of this function is left open in order
|
||||
* to allow better implementations in future, including
|
||||
@@ -277,8 +248,10 @@ do_zero_free_space (const char *dir)
|
||||
* compatible with any filesystem type inc. FAT.
|
||||
*/
|
||||
snprintf (filename, sysroot_len+len+14, "%s%s/XXXXXXXX.XXX", sysroot, dir);
|
||||
if (random_name (&filename[sysroot_len+len]) == -1)
|
||||
if (random_name (filename) == -1) {
|
||||
reply_with_perror ("random_name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf ("random filename: %s\n", filename);
|
||||
|
||||
@@ -28,11 +28,11 @@ bin_PROGRAMS = virt-df
|
||||
|
||||
SHARED_SOURCE_FILES = \
|
||||
../fish/config.c \
|
||||
../fish/domain.c \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c \
|
||||
../fish/virt.c
|
||||
../fish/options.c
|
||||
|
||||
virt_df_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
@@ -66,7 +66,7 @@ noinst_DATA = $(top_builddir)/html/virt-df.1.html
|
||||
virt-df.1 $(top_builddir)/html/virt-df.1.html: stamp-virt-df.pod
|
||||
|
||||
stamp-virt-df.pod: virt-df.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-df.1 \
|
||||
--html $(top_builddir)/html/virt-df.1.html \
|
||||
$<
|
||||
@@ -74,11 +74,7 @@ stamp-virt-df.pod: virt-df.pod
|
||||
|
||||
# Tests.
|
||||
|
||||
random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
MALLOC_PERTURB_=$(random_val) \
|
||||
$(top_builddir)/run
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS = test-virt-df.sh
|
||||
|
||||
44
df/df.c
44
df/df.c
@@ -30,6 +30,7 @@
|
||||
#endif
|
||||
|
||||
#include "progname.h"
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
@@ -115,17 +116,50 @@ df_on_handle (const char *name, const char *uuid, char **devices, int offset)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* dev is a device or partition name such as "/dev/sda" or "/dev/sda1".
|
||||
* See if dev occurs somewhere in the list of devices.
|
||||
*/
|
||||
static int
|
||||
find_dev_in_devices (const char *dev, char **devices)
|
||||
{
|
||||
size_t i;
|
||||
guestfs_error_handler_cb old_error_cb;
|
||||
void *old_error_data;
|
||||
size_t i, len;
|
||||
char *whole_disk;
|
||||
int free_whole_disk;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
if (STRPREFIX (dev, devices[i]))
|
||||
return 1;
|
||||
/* Convert 'dev' to a whole disk name. */
|
||||
len = strlen (dev);
|
||||
if (len > 0 && c_isdigit (dev[len-1])) {
|
||||
old_error_cb = guestfs_get_error_handler (g, &old_error_data);
|
||||
guestfs_set_error_handler (g, NULL, NULL);
|
||||
|
||||
whole_disk = guestfs_part_to_dev (g, dev);
|
||||
|
||||
guestfs_set_error_handler (g, old_error_cb, old_error_data);
|
||||
|
||||
if (!whole_disk) /* probably an MD device or similar */
|
||||
return 0;
|
||||
|
||||
free_whole_disk = 1;
|
||||
}
|
||||
else {
|
||||
whole_disk = (char *) dev;
|
||||
free_whole_disk = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
if (STREQ (whole_disk, devices[i])) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (free_whole_disk)
|
||||
free (whole_disk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
183
df/domains.c
183
df/domains.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
@@ -40,21 +41,14 @@
|
||||
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
|
||||
/* Limit the number of devices we will ever add to the appliance. The
|
||||
* overall limit in current libguestfs is 25: 26 = number of letters
|
||||
* in the English alphabet since we are only confident that
|
||||
* /dev/sd[a-z] will work because of various limits, minus 1 because
|
||||
* that may be used by the ext2 initial filesystem. (RHBZ#635373).
|
||||
*/
|
||||
#define MAX_DISKS 25
|
||||
|
||||
/* 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 */
|
||||
char *format; /* could be NULL */
|
||||
int failed; /* flag if disk failed when adding */
|
||||
};
|
||||
|
||||
struct domain {
|
||||
@@ -92,19 +86,24 @@ free_domain (struct domain *domain)
|
||||
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 void add_domains_by_id (virConnectPtr conn, int *ids, size_t n, size_t max_disks);
|
||||
static void add_domains_by_name (virConnectPtr conn, char **names, size_t n, size_t max_disks);
|
||||
static void add_domain (virDomainPtr dom, size_t max_disks);
|
||||
static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *domain_vp);
|
||||
static void multi_df (struct domain *, size_t n);
|
||||
static void multi_df (struct domain *, size_t n, size_t *errors);
|
||||
|
||||
void
|
||||
get_domains_from_libvirt (void)
|
||||
{
|
||||
virErrorPtr err;
|
||||
virConnectPtr conn;
|
||||
int n;
|
||||
size_t i, j, nr_disks_added;
|
||||
int n, r;
|
||||
size_t i, j, nr_disks_added, errors, max_disks;
|
||||
|
||||
r = guestfs_max_disks (g);
|
||||
if (r == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
max_disks = (size_t) r;
|
||||
|
||||
nr_domains = 0;
|
||||
domains = NULL;
|
||||
@@ -114,7 +113,7 @@ get_domains_from_libvirt (void)
|
||||
if (!conn) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s"),
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -123,7 +122,7 @@ get_domains_from_libvirt (void)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of running domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
}
|
||||
@@ -133,18 +132,18 @@ get_domains_from_libvirt (void)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list running domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
add_domains_by_id (conn, ids, n, max_disks);
|
||||
|
||||
n = virConnectNumOfDefinedDomains (conn);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of inactive domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
}
|
||||
@@ -154,12 +153,12 @@ get_domains_from_libvirt (void)
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list inactive domains (code %d, domain %d): %s"),
|
||||
_("%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);
|
||||
add_domains_by_name (conn, names, n, max_disks);
|
||||
|
||||
/* You must free these even though the libvirt documentation doesn't
|
||||
* mention it.
|
||||
@@ -180,24 +179,25 @@ get_domains_from_libvirt (void)
|
||||
|
||||
/* To minimize the number of times we have to launch the appliance,
|
||||
* shuffle as many domains together as we can, but not exceeding
|
||||
* MAX_DISKS per request. If --one-per-guest was requested then only
|
||||
* max_disks per request. If --one-per-guest was requested then only
|
||||
* request disks from a single guest each time.
|
||||
* Interesting application for NP-complete knapsack problem here.
|
||||
*/
|
||||
errors = 0;
|
||||
if (one_per_guest) {
|
||||
for (i = 0; i < nr_domains; ++i)
|
||||
multi_df (&domains[i], 1);
|
||||
multi_df (&domains[i], 1, &errors);
|
||||
} else {
|
||||
for (i = 0; i < nr_domains; /**/) {
|
||||
nr_disks_added = 0;
|
||||
|
||||
/* Make a request with domains [i..j-1]. */
|
||||
for (j = i; j < nr_domains; ++j) {
|
||||
if (nr_disks_added + domains[j].nr_disks > MAX_DISKS)
|
||||
if (nr_disks_added + domains[j].nr_disks > max_disks)
|
||||
break;
|
||||
nr_disks_added += domains[j].nr_disks;
|
||||
}
|
||||
multi_df (&domains[i], j-i);
|
||||
multi_df (&domains[i], j-i, &errors);
|
||||
|
||||
i = j;
|
||||
}
|
||||
@@ -207,10 +207,16 @@ get_domains_from_libvirt (void)
|
||||
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)
|
||||
add_domains_by_id (virConnectPtr conn, int *ids, size_t n, size_t max_disks)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
@@ -219,7 +225,7 @@ add_domains_by_id (virConnectPtr conn, int *ids, size_t n)
|
||||
if (ids[i] != 0) { /* RHBZ#538041 */
|
||||
dom = virDomainLookupByID (conn, ids[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
add_domain (dom, max_disks);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
@@ -227,7 +233,8 @@ add_domains_by_id (virConnectPtr conn, int *ids, size_t n)
|
||||
}
|
||||
|
||||
static void
|
||||
add_domains_by_name (virConnectPtr conn, char **names, size_t n)
|
||||
add_domains_by_name (virConnectPtr conn, char **names, size_t n,
|
||||
size_t max_disks)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
@@ -235,14 +242,14 @@ add_domains_by_name (virConnectPtr conn, char **names, size_t n)
|
||||
for (i = 0; i < n; ++i) {
|
||||
dom = virDomainLookupByName (conn, names[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
add_domain (dom, max_disks);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domain (virDomainPtr dom)
|
||||
add_domain (virDomainPtr dom, size_t max_disks)
|
||||
{
|
||||
struct domain *domain;
|
||||
|
||||
@@ -278,10 +285,10 @@ add_domain (virDomainPtr dom)
|
||||
exit (EXIT_FAILURE);
|
||||
domain->nr_disks = n;
|
||||
|
||||
if (domain->nr_disks > MAX_DISKS) {
|
||||
if (domain->nr_disks > max_disks) {
|
||||
fprintf (stderr,
|
||||
_("%s: ignoring %s, it has too many disks (%zu > %d)"),
|
||||
program_name, domain->name, domain->nr_disks, MAX_DISKS);
|
||||
_("%s: ignoring %s, it has too many disks (%zu > %zu)\n"),
|
||||
program_name, domain->name, domain->nr_disks, max_disks);
|
||||
free_domain (domain);
|
||||
nr_domains--;
|
||||
return;
|
||||
@@ -296,7 +303,7 @@ add_disk (guestfs_h *g,
|
||||
struct domain *domain = domain_vp;
|
||||
struct disk *disk;
|
||||
|
||||
disk = malloc (sizeof *disk);
|
||||
disk = calloc (1, sizeof *disk);
|
||||
if (disk == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
@@ -323,33 +330,29 @@ add_disk (guestfs_h *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_strings (char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; argv[i] != NULL; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void reset_guestfs_handle (void);
|
||||
static void add_disks_to_handle_reverse (struct disk *disk);
|
||||
static size_t add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r);
|
||||
static size_t count_non_failed_disks (struct disk *disk);
|
||||
static char **duplicate_first_n (char **, size_t n);
|
||||
|
||||
/* Perform 'df' operation on the domain(s) given in the list. */
|
||||
static void
|
||||
multi_df (struct domain *domains, size_t n)
|
||||
multi_df (struct domain *domains, size_t n, size_t *errors_r)
|
||||
{
|
||||
size_t i;
|
||||
size_t nd;
|
||||
size_t count;
|
||||
int r;
|
||||
char **devices;
|
||||
char **domain_devices;
|
||||
|
||||
/* Add all the disks to the handle (since they were added in reverse
|
||||
* order, we must add them here in reverse too).
|
||||
*/
|
||||
for (i = 0; i < n; ++i)
|
||||
add_disks_to_handle_reverse (domains[i].disks);
|
||||
for (i = 0, count = 0; i < n; ++i)
|
||||
count += add_disks_to_handle_reverse (domains[i].disks, errors_r);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
/* Launch the handle. */
|
||||
if (guestfs_launch (g) == -1)
|
||||
@@ -359,31 +362,28 @@ multi_df (struct domain *domains, size_t n)
|
||||
if (devices == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Check the number of disks we think we added is the same as the
|
||||
* number of devices returned by libguestfs.
|
||||
*/
|
||||
nd = 0;
|
||||
for (i = 0; i < n; ++i)
|
||||
nd += domains[i].nr_disks;
|
||||
assert (nd == count_strings (devices));
|
||||
for (i = 0, nd = 0; i < n; ++i) {
|
||||
/* Find out how many non-failed disks this domain has. */
|
||||
count = count_non_failed_disks (domains[i].disks);
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
nd = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
/* So that &devices[nd] is a NULL-terminated list of strings. */
|
||||
char *p = devices[nd + domains[i].nr_disks];
|
||||
devices[nd + domains[i].nr_disks] = NULL;
|
||||
/* Duplicate the devices into a separate list for convenience.
|
||||
* Note this doesn't duplicate the strings themselves.
|
||||
*/
|
||||
domain_devices = duplicate_first_n (&devices[nd], count);
|
||||
|
||||
r = df_on_handle (domains[i].name, domains[i].uuid, &devices[nd], nd);
|
||||
|
||||
/* Restore devices to original. */
|
||||
devices[nd + domains[i].nr_disks] = p;
|
||||
nd += domains[i].nr_disks;
|
||||
r = df_on_handle (domains[i].name, domains[i].uuid, domain_devices, nd);
|
||||
nd += count;
|
||||
free (domain_devices);
|
||||
|
||||
/* Something broke in df_on_handle. Give up on the remaining
|
||||
* devices for this handle, but keep going on the next handle.
|
||||
*/
|
||||
if (r == -1)
|
||||
if (r == -1) {
|
||||
(*errors_r)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; devices[i] != NULL; ++i)
|
||||
@@ -394,13 +394,15 @@ multi_df (struct domain *domains, size_t n)
|
||||
reset_guestfs_handle ();
|
||||
}
|
||||
|
||||
static void
|
||||
add_disks_to_handle_reverse (struct disk *disk)
|
||||
static size_t
|
||||
add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r)
|
||||
{
|
||||
if (disk == NULL)
|
||||
return;
|
||||
size_t nr_disks_added;
|
||||
|
||||
add_disks_to_handle_reverse (disk->next);
|
||||
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 };
|
||||
|
||||
@@ -412,8 +414,13 @@ add_disks_to_handle_reverse (struct disk *disk)
|
||||
optargs.format = disk->format;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive_opts_argv (g, disk->filename, &optargs) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
if (guestfs_add_drive_opts_argv (g, disk->filename, &optargs) == -1) {
|
||||
(*errors_r)++;
|
||||
disk->failed = 1;
|
||||
return nr_disks_added;
|
||||
}
|
||||
|
||||
return nr_disks_added+1;
|
||||
}
|
||||
|
||||
/* Close and reopen the libguestfs handle. */
|
||||
@@ -436,4 +443,32 @@ reset_guestfs_handle (void)
|
||||
guestfs_set_trace (g, trace);
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_non_failed_disks (struct disk *disk)
|
||||
{
|
||||
if (disk == NULL)
|
||||
return 0;
|
||||
else if (disk->failed)
|
||||
return count_non_failed_disks (disk->next);
|
||||
else
|
||||
return 1 + count_non_failed_disks (disk->next);
|
||||
}
|
||||
|
||||
static char **
|
||||
duplicate_first_n (char **strs, size_t n)
|
||||
{
|
||||
char **ret;
|
||||
|
||||
ret = malloc ((n+1) * sizeof (char *));
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memcpy (ret, strs, n * sizeof (char *));
|
||||
ret[n] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
102
df/output.c
102
df/output.c
@@ -24,6 +24,7 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <xvasprintf.h>
|
||||
#include <libintl.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -81,7 +82,7 @@ print_title (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void canonical_device (char *dev, int offset);
|
||||
static char *adjust_device_offset (const char *device, int offset);
|
||||
|
||||
void
|
||||
print_stat (const char *name, const char *uuid_param,
|
||||
@@ -101,13 +102,17 @@ print_stat (const char *name, const char *uuid_param,
|
||||
float percent;
|
||||
int hopts = human_round_to_nearest|human_autoscale|human_base_1024|human_SI;
|
||||
size_t i, len;
|
||||
char *dev;
|
||||
|
||||
/* Make the device canonical. */
|
||||
len = strlen (dev_param) + 1;
|
||||
char dev[len];
|
||||
strcpy (dev, dev_param);
|
||||
if (offset >= 0)
|
||||
canonical_device (dev, offset);
|
||||
/* Make a canonical name, adjusting the device offset if necessary. */
|
||||
dev = guestfs_canonical_device_name (g, dev_param);
|
||||
if (!dev)
|
||||
exit (EXIT_FAILURE);
|
||||
if (offset >= 0) {
|
||||
char *p = dev;
|
||||
dev = adjust_device_offset (p, offset);
|
||||
free (p);
|
||||
}
|
||||
|
||||
if (!inodes) { /* 1K blocks */
|
||||
if (!human) {
|
||||
@@ -189,20 +194,8 @@ print_stat (const char *name, const char *uuid_param,
|
||||
|
||||
putchar ('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/* /dev/vda1 -> /dev/sda, adjusting the device offset. */
|
||||
static void
|
||||
canonical_device (char *dev, int offset)
|
||||
{
|
||||
if (STRPREFIX (dev, "/dev/") &&
|
||||
(dev[5] == 'h' || dev[5] == 'v') &&
|
||||
dev[6] == 'd' &&
|
||||
c_isalpha (dev[7]) &&
|
||||
(c_isdigit (dev[8]) || dev[8] == '\0')) {
|
||||
dev[5] = 's';
|
||||
dev[7] -= offset;
|
||||
}
|
||||
free (dev);
|
||||
}
|
||||
|
||||
/* Function to quote CSV fields on output without requiring an
|
||||
@@ -240,3 +233,72 @@ write_csv_field (const char *field)
|
||||
}
|
||||
putchar ('"');
|
||||
}
|
||||
|
||||
static char *drive_name (int index, char *ret);
|
||||
|
||||
static char *
|
||||
adjust_device_offset (const char *device, int offset)
|
||||
{
|
||||
int index;
|
||||
int part_num;
|
||||
char *whole_device;
|
||||
int free_whole_device;
|
||||
size_t len;
|
||||
char *ret;
|
||||
|
||||
/* Could be a whole disk or a partition. guestfs_device_index will
|
||||
* only work with the whole disk name.
|
||||
*/
|
||||
len = strlen (device);
|
||||
if (len > 0 && c_isdigit (device[len-1])) {
|
||||
whole_device = guestfs_part_to_dev (g, device);
|
||||
if (whole_device == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
free_whole_device = 1;
|
||||
part_num = guestfs_part_to_partnum (g, device);
|
||||
if (part_num == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
} else {
|
||||
whole_device = (char *) device;
|
||||
free_whole_device = 0;
|
||||
part_num = 0;
|
||||
}
|
||||
|
||||
index = guestfs_device_index (g, whole_device);
|
||||
if (index == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if (free_whole_device)
|
||||
free (whole_device);
|
||||
|
||||
assert (index >= offset);
|
||||
|
||||
index -= offset;
|
||||
|
||||
/* Construct the final device name. */
|
||||
ret = malloc (128);
|
||||
if (!ret) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcpy (ret, "/dev/sd");
|
||||
drive_name (index, &ret[7]);
|
||||
len = strlen (ret);
|
||||
if (part_num > 0)
|
||||
snprintf (&ret[len], 128-len, "%d", part_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/ */
|
||||
static char *
|
||||
drive_name (int index, char *ret)
|
||||
{
|
||||
if (index >= 26)
|
||||
ret = drive_name (index/26 - 1, ret);
|
||||
index %= 26;
|
||||
*ret++ = 'a' + index;
|
||||
*ret = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ bin_PROGRAMS = virt-edit
|
||||
|
||||
SHARED_SOURCE_FILES = \
|
||||
../fish/config.c \
|
||||
../fish/domain.c \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c \
|
||||
../fish/virt.c
|
||||
../fish/options.c
|
||||
|
||||
virt_edit_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
@@ -58,7 +58,7 @@ noinst_DATA = $(top_builddir)/html/virt-edit.1.html
|
||||
virt-edit.1 $(top_builddir)/html/virt-edit.1.html: stamp-virt-edit.pod
|
||||
|
||||
stamp-virt-edit.pod: virt-edit.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-edit.1 \
|
||||
--html $(top_builddir)/html/virt-edit.1.html \
|
||||
$<
|
||||
@@ -66,11 +66,7 @@ stamp-virt-edit.pod: virt-edit.pod
|
||||
|
||||
# Tests.
|
||||
|
||||
random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
MALLOC_PERTURB_=$(random_val) \
|
||||
$(top_builddir)/run
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS = test-virt-edit.sh
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
rm -f test.qcow2
|
||||
|
||||
# Make a copy of the Fedora image so we can write to it then
|
||||
# discard it.
|
||||
cp ../tests/guests/fedora.img test.img
|
||||
qemu-img create -F raw -b ../tests/guests/fedora.img -f qcow2 test.qcow2
|
||||
|
||||
# Edit interactively. We have to simulate this by setting $EDITOR.
|
||||
# The command will be: echo newline >> /tmp/file
|
||||
export EDITOR='echo newline >>'
|
||||
./virt-edit -a test.img /etc/test3
|
||||
if [ "$(../cat/virt-cat -a test.img /etc/test3)" != "a
|
||||
./virt-edit -a test.qcow2 /etc/test3
|
||||
if [ "$(../cat/virt-cat -a test.qcow2 /etc/test3)" != "a
|
||||
b
|
||||
c
|
||||
d
|
||||
@@ -25,8 +27,8 @@ unset EDITOR
|
||||
|
||||
# Edit non-interactively, only if we have 'perl' binary.
|
||||
if perl --version >/dev/null 2>&1; then
|
||||
./virt-edit -a test.img /etc/test3 -e 's/^[a-f]/$lineno/'
|
||||
if [ "$(../cat/virt-cat -a test.img /etc/test3)" != "1
|
||||
./virt-edit -a test.qcow2 /etc/test3 -e 's/^[a-f]/$lineno/'
|
||||
if [ "$(../cat/virt-cat -a test.qcow2 /etc/test3)" != "1
|
||||
2
|
||||
3
|
||||
4
|
||||
@@ -40,7 +42,7 @@ fi
|
||||
|
||||
# Verify the mode of /etc/test3 is still 0600 and the UID:GID is 10:11.
|
||||
# See tests/guests/guest-aux/make-fedora-img.pl and RHBZ#788641.
|
||||
if [ "$(../fish/guestfish -i -a test.img --ro lstat /etc/test3 | grep -E '^(mode|uid|gid):' | sort)" != "gid: 11
|
||||
if [ "$(../fish/guestfish -i -a test.qcow2 --ro lstat /etc/test3 | grep -E '^(mode|uid|gid):' | sort)" != "gid: 11
|
||||
mode: 33152
|
||||
uid: 10" ]; then
|
||||
echo "$0: error: editing /etc/test3 did not preserve permissions or ownership"
|
||||
@@ -48,4 +50,4 @@ uid: 10" ]; then
|
||||
fi
|
||||
|
||||
# Discard test image.
|
||||
rm test.img
|
||||
rm test.qcow2
|
||||
|
||||
@@ -298,7 +298,7 @@ main (int argc, char *argv[])
|
||||
free (root);
|
||||
|
||||
/* Cleanly unmount the disks after editing. */
|
||||
if (guestfs_umount_all (g) == -1 || guestfs_sync (g) == -1)
|
||||
if (guestfs_shutdown (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
@@ -326,6 +326,20 @@ C<touch>, C<write> or C<upload> instead:
|
||||
|
||||
guestfish --rw -i -d domname upload localfile /newfile
|
||||
|
||||
=head1 CVE-2012-2690
|
||||
|
||||
Old versions of both virt-edit and the guestfish C<edit> command
|
||||
created a new file containing the changes but did not set the
|
||||
permissions, etc of the new file to match the old one. The result of
|
||||
this was that if you edited a security sensitive file such as
|
||||
C</etc/shadow> then it would be left world-readable after the edit.
|
||||
|
||||
This issue was assigned CVE-2012-2690, and is fixed in
|
||||
libguestfs E<ge> 1.16.
|
||||
|
||||
For further information, see
|
||||
L<https://bugzilla.redhat.com/show_bug.cgi?id=788642>
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 4
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -29,7 +29,7 @@ noinst_DATA = $(top_builddir)/html/guestfs-erlang.3.html
|
||||
guestfs-erlang.3 $(top_builddir)/html/guestfs-erlang.3.html: stamp-guestfs-erlang.pod
|
||||
|
||||
stamp-guestfs-erlang.pod: guestfs-erlang.pod create_disk.erl inspect_vm.erl
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--section 3 \
|
||||
--man guestfs-erlang.3 \
|
||||
--html $(top_builddir)/html/guestfs-erlang.3.html \
|
||||
|
||||
@@ -16,10 +16,6 @@ main(_) ->
|
||||
% Set the trace flag so that we can see each libguestfs call.
|
||||
ok = guestfs:set_trace(G, true),
|
||||
|
||||
% Set the autosync flag so that the disk will be synchronized
|
||||
% automatically when the libguestfs handle is closed.
|
||||
ok = guestfs:set_autosync(G, true),
|
||||
|
||||
% Attach the disk image to libguestfs.
|
||||
ok = guestfs:add_drive_opts(G, Output,
|
||||
[{format, "raw"}, {readonly, false}]),
|
||||
@@ -55,10 +51,11 @@ main(_) ->
|
||||
% the disk image.
|
||||
ok = guestfs:upload(G, "/etc/resolv.conf", "/foo/resolv.conf"),
|
||||
|
||||
% Because 'autosync' was set (above) we can just close the handle
|
||||
% and the disk contents will be synchronized. You can also do
|
||||
% this manually by calling guestfs:umount_all and guestfs:sync.
|
||||
%
|
||||
% Because we wrote to the disk and we want to detect write
|
||||
% errors, call guestfs:shutdown. You don't need to do this:
|
||||
% guestfs:close will do it implicitly.
|
||||
ok = guestfs:shutdown(G),
|
||||
|
||||
% Note also that handles are automatically closed if they are
|
||||
% reaped by the garbage collector. You only need to call close
|
||||
% if you want to close the handle right away.
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
EXTRA_DIST = \
|
||||
LICENSE \
|
||||
guestfs-examples.pod \
|
||||
guestfs-faq.pod \
|
||||
guestfs-performance.pod \
|
||||
guestfs-recipes.pod \
|
||||
guestfs-testing.pod
|
||||
|
||||
CLEANFILES = \
|
||||
stamp-guestfs-examples.pod \
|
||||
stamp-guestfs-faq.pod \
|
||||
stamp-guestfs-performance.pod \
|
||||
stamp-guestfs-recipes.pod \
|
||||
stamp-guestfs-testing.pod
|
||||
@@ -35,6 +37,9 @@ endif
|
||||
if HAVE_HIVEX
|
||||
noinst_PROGRAMS += virt-dhcp-address
|
||||
endif
|
||||
if HAVE_FUSE
|
||||
noinst_PROGRAMS += mount_local
|
||||
endif
|
||||
|
||||
if HAVE_LIBVIRT
|
||||
copy_over_SOURCES = copy_over.c
|
||||
@@ -73,6 +78,19 @@ inspect_vm_CFLAGS = \
|
||||
inspect_vm_LDADD = \
|
||||
$(top_builddir)/src/libguestfs.la
|
||||
|
||||
if HAVE_FUSE
|
||||
mount_local_SOURCES = mount_local.c
|
||||
mount_local_CFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
-I$(top_srcdir)/src -I$(top_builddir)/src \
|
||||
$(FUSE_CFLAGS) \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
mount_local_LDADD = \
|
||||
$(FUSE_LIBS) -lulockmgr \
|
||||
$(top_builddir)/src/libguestfs.la
|
||||
endif
|
||||
|
||||
if HAVE_HIVEX
|
||||
virt_dhcp_address_SOURCES = virt-dhcp-address.c
|
||||
virt_dhcp_address_CFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
@@ -82,14 +100,17 @@ virt_dhcp_address_CFLAGS = \
|
||||
virt_dhcp_address_LDADD = \
|
||||
$(HIVEX_LIBS) \
|
||||
$(top_builddir)/src/libguestfs.la
|
||||
endif
|
||||
|
||||
man_MANS = \
|
||||
guestfs-examples.3 \
|
||||
guestfs-faq.1 \
|
||||
guestfs-performance.1 \
|
||||
guestfs-recipes.1 \
|
||||
guestfs-testing.1
|
||||
noinst_DATA = \
|
||||
$(top_builddir)/html/guestfs-examples.3.html \
|
||||
$(top_builddir)/html/guestfs-faq.1.html \
|
||||
$(top_builddir)/html/guestfs-performance.1.html \
|
||||
$(top_builddir)/html/guestfs-recipes.1.html \
|
||||
$(top_builddir)/html/guestfs-testing.1.html
|
||||
@@ -97,7 +118,7 @@ noinst_DATA = \
|
||||
guestfs-examples.3 $(top_builddir)/html/guestfs-examples.3.html: stamp-guestfs-examples.pod
|
||||
|
||||
stamp-guestfs-examples.pod: guestfs-examples.pod create_disk.c inspect_vm.c
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--section 3 \
|
||||
--man guestfs-examples.3 \
|
||||
--html $(top_builddir)/html/guestfs-examples.3.html \
|
||||
@@ -106,10 +127,20 @@ stamp-guestfs-examples.pod: guestfs-examples.pod create_disk.c inspect_vm.c
|
||||
$<
|
||||
touch $@
|
||||
|
||||
guestfs-faq.1 $(top_builddir)/html/guestfs-faq.1.html: stamp-guestfs-faq.pod
|
||||
|
||||
stamp-guestfs-faq.pod: guestfs-faq.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-faq.1 \
|
||||
--html $(top_builddir)/html/guestfs-faq.1.html \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
guestfs-performance.1 $(top_builddir)/html/guestfs-performance.1.html: stamp-guestfs-performance.pod
|
||||
|
||||
stamp-guestfs-performance.pod: guestfs-performance.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-performance.1 \
|
||||
--html $(top_builddir)/html/guestfs-performance.1.html \
|
||||
@@ -119,7 +150,7 @@ stamp-guestfs-performance.pod: guestfs-performance.pod
|
||||
guestfs-recipes.1 $(top_builddir)/html/guestfs-recipes.1.html: stamp-guestfs-recipes.pod
|
||||
|
||||
stamp-guestfs-recipes.pod: guestfs-recipes.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-recipes.1 \
|
||||
--html $(top_builddir)/html/guestfs-recipes.1.html \
|
||||
@@ -129,7 +160,7 @@ stamp-guestfs-recipes.pod: guestfs-recipes.pod
|
||||
guestfs-testing.1 $(top_builddir)/html/guestfs-testing.1.html: stamp-guestfs-testing.pod
|
||||
|
||||
stamp-guestfs-testing.pod: guestfs-testing.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-testing.1 \
|
||||
--html $(top_builddir)/html/guestfs-testing.1.html \
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <pthread.h>
|
||||
|
||||
#include <guestfs.h>
|
||||
#include <libvirt/libvirt.h>
|
||||
|
||||
struct threaddata {
|
||||
const char *src;
|
||||
@@ -66,9 +65,6 @@ main (int argc, char *argv[])
|
||||
struct timeval start_t, end_t;
|
||||
int64_t ms;
|
||||
|
||||
/* This is required when using libvirt from multiple threads. */
|
||||
virInitialize ();
|
||||
|
||||
if (argc != 5) {
|
||||
usage ();
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -145,7 +141,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
if (guestfs_umount_all (destg) == -1)
|
||||
if (guestfs_shutdown (destg) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
guestfs_close (destg);
|
||||
|
||||
@@ -193,10 +189,6 @@ start_srcthread (void *arg)
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
if (guestfs_umount_all (srcg) == -1) {
|
||||
pthread_cancel (threaddata->mainthread);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
guestfs_close (srcg);
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -37,11 +37,6 @@ main (int argc, char *argv[])
|
||||
/* Set the trace flag so that we can see each libguestfs call. */
|
||||
guestfs_set_trace (g, 1);
|
||||
|
||||
/* Set the autosync flag so that the disk will be synchronized
|
||||
* automatically when the libguestfs handle is closed.
|
||||
*/
|
||||
guestfs_set_autosync (g, 1);
|
||||
|
||||
/* Add the disk image to libguestfs. */
|
||||
if (guestfs_add_drive_opts (g, "disk.img",
|
||||
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", /* raw format */
|
||||
@@ -104,10 +99,13 @@ main (int argc, char *argv[])
|
||||
if (guestfs_upload (g, "/etc/resolv.conf", "/foo/resolv.conf") == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Because 'autosync' was set (above) we can just close the handle
|
||||
* and the disk contents will be synchronized. You can also do
|
||||
* this manually by calling guestfs_umount_all and guestfs_sync.
|
||||
/* Because we wrote to the disk and we want to detect write
|
||||
* errors, call guestfs_shutdown. You don't need to do this:
|
||||
* guestfs_close will do it implicitly.
|
||||
*/
|
||||
if (guestfs_shutdown (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
/* Free up the lists. */
|
||||
|
||||
684
examples/guestfs-faq.pod
Normal file
684
examples/guestfs-faq.pod
Normal file
@@ -0,0 +1,684 @@
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
guestfs-faq - libguestfs Frequently Asked Questions (FAQ)
|
||||
|
||||
=head1 ABOUT LIBGUESTFS
|
||||
|
||||
=head2 What is libguestfs?
|
||||
|
||||
libguestfs is a way to create, access and modify disk images. You can
|
||||
look inside disk images, modify the files they contain, create them
|
||||
from scratch, resize them, and much more. It's especially useful from
|
||||
scripts and programs and from the command line.
|
||||
|
||||
libguestfs is a C library (hence "lib-"), and a set of tools built on
|
||||
this library, and a set of bindings in many different programming
|
||||
languages.
|
||||
|
||||
For more information about what libguestfs can do read the
|
||||
introduction on the home page (L<http://libguestfs.org>).
|
||||
|
||||
=head2 What are the virt tools?
|
||||
|
||||
Virt tools (website: L<http://virt-tools.org>) are a whole set of
|
||||
virtualization management tools aimed at system administrators. Some
|
||||
of them come from libguestfs, some from libvirt and many others from
|
||||
other open source projects. So virt tools is a superset of
|
||||
libguestfs. However libguestfs comes with many important tools. See
|
||||
L<http://libguestfs.org> for a full list.
|
||||
|
||||
=head2 Does libguestfs need { libvirt / KVM / Red Hat / Fedora }?
|
||||
|
||||
No!
|
||||
|
||||
libvirt is not a requirement for libguestfs.
|
||||
|
||||
libguestfs works with any disk image, including ones created in
|
||||
VMware, KVM, qemu, VirtualBox, Xen, and many other hypervisors, and
|
||||
ones which you have created from scratch.
|
||||
|
||||
Red Hat sponsors (ie. pays for) development of libguestfs and a huge
|
||||
number of other open source projects. But you can run libguestfs and
|
||||
the virt tools on many different Linux distros and Mac OS X. Some
|
||||
virt tools have been ported to Windows.
|
||||
|
||||
=head2 How does libguestfs compare to other tools?
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<vs. kpartx>
|
||||
|
||||
Libguestfs takes a different approach from kpartx. kpartx needs root,
|
||||
and mounts filesystems on the host kernel (which can be insecure - see
|
||||
L<guestfs(3)/SECURITY>). Libguestfs isolates your host kernel from
|
||||
guests, is more flexible, scriptable, supports LVM, doesn't require
|
||||
root, is isolated from other processes, and cleans up after itself.
|
||||
Libguestfs is more than just file access because you can use it to
|
||||
create images from scratch.
|
||||
|
||||
=item I<vs. vdfuse>
|
||||
|
||||
vdfuse is like kpartx but for VirtualBox images. See the kpartx
|
||||
comparison above. You can use libguestfs on the partition files
|
||||
exposed by vdfuse, although it's not necessary since libguestfs can
|
||||
access VirtualBox images directly.
|
||||
|
||||
=item I<vs. qemu-nbd>
|
||||
|
||||
nbd is like kpartx but for qcow2 images. See the kpartx comparison
|
||||
above. You can use libguestfs and qemu-nbd together for access to
|
||||
block devices over the network.
|
||||
|
||||
=item I<vs. mounting filesystems in the host>
|
||||
|
||||
Mounting guest filesystems in the host is insecure and should be
|
||||
avoided completely for untrusted guests. Use libguestfs to provide a
|
||||
layer of protection against filesystem exploits. See also
|
||||
L<guestmount(1)>.
|
||||
|
||||
=item I<vs. parted>
|
||||
|
||||
Libguestfs supports LVM. Libguestfs uses parted and provides most
|
||||
parted features through the libguestfs API.
|
||||
|
||||
=back
|
||||
|
||||
=head1 GETTING HELP AND REPORTING BUGS
|
||||
|
||||
=head2 How do I know what version I'm using?
|
||||
|
||||
The simplest method is:
|
||||
|
||||
guestfish --version
|
||||
|
||||
Libguestfs development happens along an unstable branch and we
|
||||
periodically create a stable branch which we backport stable patches
|
||||
to. To find out more, read L<guestfs(3)/LIBGUESTFS VERSION NUMBERS>.
|
||||
|
||||
=head2 How can I get help?
|
||||
What mailing lists or chat rooms are available?
|
||||
|
||||
If you are a Red Hat customer using Red Hat Enterprise Linux, please
|
||||
contact Red Hat Support: L<http://redhat.com/support>
|
||||
|
||||
There is a mailing list, mainly for development, but users are also
|
||||
welcome to ask questions about libguestfs and the virt tools:
|
||||
L<https://www.redhat.com/mailman/listinfo/libguestfs>
|
||||
|
||||
You can also talk to us on IRC channel C<#libguestfs> on FreeNode.
|
||||
We're not always around, so please stay in the channel after asking
|
||||
your question and someone will get back to you.
|
||||
|
||||
For other virt tools (not ones supplied with libguestfs) there is a
|
||||
general virt tools mailing list:
|
||||
L<https://www.redhat.com/mailman/listinfo/virt-tools-list>
|
||||
|
||||
=head2 How do I report bugs?
|
||||
|
||||
Please use the following link to enter a bug in Bugzilla:
|
||||
|
||||
L<https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools>
|
||||
|
||||
Include as much detail as you can and a way to reproduce the problem.
|
||||
|
||||
Include the full output of L<libguestfs-test-tool(1)>.
|
||||
|
||||
=head1 COMMON ERRORS
|
||||
|
||||
=head2 "child process died unexpectedly"
|
||||
|
||||
This error indicates that qemu failed or the host kernel could not boot.
|
||||
To get further information about the failure, you have to run:
|
||||
|
||||
libguestfs-test-tool
|
||||
|
||||
If, after using this, you still don't understand the failure, contact
|
||||
us (see previous section).
|
||||
|
||||
=head1 COMMON PROBLEMS
|
||||
|
||||
See also L<guestfs(3)/LIBGUESTFS GOTCHAS> for some "gotchas" with
|
||||
using the libguestfs API.
|
||||
|
||||
=head2 Non-ASCII characters don't appear on VFAT filesystems.
|
||||
|
||||
Typical symptoms of this problem:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
You get an error when you create a file where the filename contains
|
||||
non-ASCII characters, particularly non 8-bit characters from Asian
|
||||
languages (Chinese, Japanese, etc). The filesystem is VFAT.
|
||||
|
||||
=item *
|
||||
|
||||
When you list a directory from a VFAT filesystem, filenames appear as
|
||||
question marks.
|
||||
|
||||
=back
|
||||
|
||||
This is a design flaw of the GNU/Linux system.
|
||||
|
||||
VFAT stores long filenames as UTF-16 characters. When opening or
|
||||
returning filenames, the Linux kernel has to translate these to some
|
||||
form of 8 bit string. UTF-8 would be the obvious choice, except for
|
||||
Linux users who persist in using non-UTF-8 locales (the user's locale
|
||||
is not known to the kernel because it's a function of libc).
|
||||
|
||||
Therefore you have to tell the kernel what translation you want done
|
||||
when you mount the filesystem. The two methods are the C<iocharset>
|
||||
parameter (which is not relevant to libguestfs) and the C<utf8> flag.
|
||||
|
||||
So to use a VFAT filesystem you must add the C<utf8> flag when
|
||||
mounting. From guestfish, use:
|
||||
|
||||
><fs> mount-options utf8 /dev/sda1 /
|
||||
|
||||
or on the guestfish command line:
|
||||
|
||||
guestfish [...] -m /dev/sda1:/:utf8
|
||||
|
||||
or from the API:
|
||||
|
||||
guestfs_mount_options (g, "utf8", "/dev/sda1", "/");
|
||||
|
||||
The kernel will then translate filenames to and from UTF-8 strings.
|
||||
|
||||
We considered adding this mount option transparently, but
|
||||
unfortunately there are several problems with doing that:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
On some Linux systems, the C<utf8> mount option doesn't work. We
|
||||
don't precisely understand what systems or why, but this was reliably
|
||||
reported by one user.
|
||||
|
||||
=item *
|
||||
|
||||
It would prevent you from using the C<iocharset> parameter because it
|
||||
is incompatible with C<utf8>. It is probably not a good idea to use
|
||||
this parameter, but we don't want to prevent it.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Non-ASCII characters appear as underscore (_) on ISO9660 filesystems.
|
||||
|
||||
The filesystem was not prepared correctly with mkisofs or genisoimage.
|
||||
Make sure the filesystem was created using Joliet and/or Rock Ridge
|
||||
extensions. libguestfs does not require any special mount options to
|
||||
handle the filesystem.
|
||||
|
||||
=head1 DOWNLOADING, INSTALLING, COMPILING LIBGUESTFS
|
||||
|
||||
=begin html
|
||||
|
||||
<!-- old anchor for the next section -->
|
||||
<a name="binaries"/>
|
||||
|
||||
=end html
|
||||
|
||||
=head2 Where can I get the latest binaries for ...?
|
||||
|
||||
=over 4
|
||||
|
||||
=item Fedora E<ge> 11, RHEL E<ge> 5.3, EPEL 5
|
||||
|
||||
Use:
|
||||
|
||||
yum install '*guestf*'
|
||||
|
||||
For the latest builds, see:
|
||||
L<http://koji.fedoraproject.org/koji/packageinfo?packageID=8391>
|
||||
|
||||
=item Red Hat Enterprise Linux 6
|
||||
|
||||
It is part of the default install. On RHEL 6 (only) you have to
|
||||
install C<libguestfs-winsupport> to get Windows guest support.
|
||||
|
||||
=item RHEL 6.3
|
||||
|
||||
Preview packages are available here:
|
||||
L<http://people.redhat.com/~rjones/libguestfs-RHEL-6.3-preview/>
|
||||
|
||||
=item Debian Squeeze (6)
|
||||
|
||||
Use Hilko Bengen's backport repository:
|
||||
L<http://people.debian.org/~bengen/libguestfs/>
|
||||
|
||||
=item Debian Wheezy and later (7+)
|
||||
|
||||
Official Debian packages are available:
|
||||
L<http://packages.debian.org/search?keywords=libguestfs>
|
||||
(thanks Hilko Bengen).
|
||||
|
||||
=item Ubuntu
|
||||
|
||||
We don't have an Ubuntu maintainer, and the packages supplied by
|
||||
Canonical (which are outside our control) are often broken. Try
|
||||
compiling from source (next section).
|
||||
|
||||
Canonical decided to change the permissions on the kernel so that it's
|
||||
not readable except by root. This is completely stupid, but they
|
||||
won't change it
|
||||
(L<https://bugs.launchpad.net/ubuntu/+source/linux/+bug/759725>).
|
||||
So every user should do this:
|
||||
|
||||
sudo chmod 0644 /boot/vmlinuz*
|
||||
|
||||
=item Ubuntu 10.04
|
||||
|
||||
See:
|
||||
L<http://libguestfs.org/download/binaries/ubuntu1004-packages/>
|
||||
|
||||
=item Ubuntu 12.04
|
||||
|
||||
libguestfs in this version of Ubuntu works, but you need to update
|
||||
febootstrap and seabios to the latest versions.
|
||||
|
||||
You need febootstrap E<ge> 3.14-2 from:
|
||||
L<http://packages.ubuntu.com/precise/febootstrap>
|
||||
|
||||
After installing or updating febootstrap, rebuild the appliance:
|
||||
|
||||
sudo update-guestfs-appliance
|
||||
|
||||
You need seabios E<ge> 0.6.2-0ubuntu2.1 or E<ge> 0.6.2-0ubuntu3 from:
|
||||
L<http://packages.ubuntu.com/precise-updates/seabios>
|
||||
or
|
||||
L<http://packages.ubuntu.com/quantal/seabios>
|
||||
|
||||
Also you need to do (see above):
|
||||
|
||||
sudo chmod 0644 /boot/vmlinuz*
|
||||
|
||||
=item Gentoo
|
||||
|
||||
Libguestfs was added to Gentoo in 2012-07. Do:
|
||||
|
||||
emerge libguestfs
|
||||
|
||||
=item Other Linux distro
|
||||
|
||||
Compile from source (next section).
|
||||
|
||||
=item Other non-Linux distro
|
||||
|
||||
You'll have to compile from source, and port it.
|
||||
|
||||
=back
|
||||
|
||||
=head2 How can I compile and install libguestfs from source?
|
||||
|
||||
If your Linux distro has a working port of febootstrap (that is,
|
||||
Fedora, Red Hat Enterprise Linux >= 6.3, Debian, Ubuntu and ArchLinux)
|
||||
then you should just be able to compile from source in the usual way.
|
||||
Download the latest tarball from L<http://libguestfs.org/download>,
|
||||
unpack it, and start by reading the README file.
|
||||
|
||||
If you I<don't> have febootstrap, you will need to use the "fixed
|
||||
appliance method". See:
|
||||
L<http://libguestfs.org/download/binaries/appliance/>
|
||||
|
||||
Patches to port febootstrap to more Linux distros are welcome.
|
||||
|
||||
=head2 Why do I get an error when I try to rebuild from the source
|
||||
RPMs supplied by Red Hat / Fedora?
|
||||
|
||||
Because of the complexity of building the libguestfs appliance, the
|
||||
source RPMs provided cannot be rebuilt directly using C<rpmbuild> or
|
||||
C<mock>.
|
||||
|
||||
If you use Koji (which is open source software and may be installed
|
||||
locally), then the SRPMs can be rebuilt in Koji.
|
||||
L<https://fedoraproject.org/wiki/Koji>
|
||||
|
||||
If you don't have or want to use Koji, then you have to give
|
||||
libguestfs access to the network so it can download the RPMs for
|
||||
building the appliance. You also need to set an RPM macro to tell
|
||||
libguestfs to use the network. Put the following line into a file
|
||||
called C<$HOME/.rpmmacros>:
|
||||
|
||||
%libguestfs_buildnet 1
|
||||
|
||||
If you are using mock, do:
|
||||
|
||||
mock -D '%libguestfs_buildnet 1' [etc]
|
||||
|
||||
=head2 Libguestfs has a really long list of dependencies!
|
||||
|
||||
That's because it does a lot of things.
|
||||
|
||||
=head2 How can I speed up libguestfs builds?
|
||||
|
||||
By far the most important thing you can do is to install and properly
|
||||
configure Squid. Note that the default configuration that ships with
|
||||
Squid is rubbish, so configuring it is not optional.
|
||||
|
||||
A very good place to start with Squid configuration is here:
|
||||
L<https://fedoraproject.org/wiki/Extras/MockTricks#Using_Squid_to_Speed_Up_Mock_package_downloads>
|
||||
|
||||
Make sure Squid is running, and that the environment variables
|
||||
C<$http_proxy> and C<$ftp_proxy> are pointing to it.
|
||||
|
||||
With Squid running and correctly configured, appliance builds should
|
||||
be reduced to a few minutes.
|
||||
|
||||
=head1 SPEED, DISK SPACE USED BY LIBGUESTFS
|
||||
|
||||
Note: Most of the information in this section has moved:
|
||||
L<guestfs-performance(1)>.
|
||||
|
||||
=head2 Upload or write seem very slow.
|
||||
|
||||
In libguestfs E<lt> 1.13.16, the mount command
|
||||
(L<guestfs(3)/guestfs_mount>) enabled option C<-o sync> implicitly.
|
||||
This causes very poor write performance, and was one of the main
|
||||
gotchas for new libguestfs users.
|
||||
|
||||
For libguestfs E<lt> 1.13.16, replace mount with C<mount-options>,
|
||||
leaving the first parameter as an empty string.
|
||||
|
||||
You can also do this with more recent versions of libguestfs, but if
|
||||
you know that you are using libguestfs ≥ 1.13.16 then it's safe to use
|
||||
plain mount.
|
||||
|
||||
If the underlying disk is not fully allocated (eg. sparse raw or
|
||||
qcow2) then writes can be slow because the host operating system has
|
||||
to do costly disk allocations while you are writing. The solution is
|
||||
to use a fully allocated format instead, ie. non-sparse raw, or qcow2
|
||||
with the C<preallocation=metadata> option.
|
||||
|
||||
=head2 Libguestfs uses too much disk space!
|
||||
|
||||
libguestfs caches a large-ish appliance in:
|
||||
|
||||
/var/tmp/.guestfs-<UID>
|
||||
|
||||
If the environment variable C<TMPDIR> is defined, then
|
||||
C<$TMPDIR/.guestfs-E<lt>UIDE<gt>> is used instead.
|
||||
|
||||
It is safe to delete this directory when you are not using libguestfs.
|
||||
|
||||
=head1 USING LIBGUESTFS IN YOUR OWN PROGRAMS
|
||||
|
||||
=head2 The API has hundreds of methods, where do I start?
|
||||
|
||||
We recommend you start by reading the API overview:
|
||||
L<guestfs(3)/API OVERVIEW>.
|
||||
|
||||
Although the API overview covers the C API, it is still worth reading
|
||||
even if you are going to use another programming language, because the
|
||||
API is the same, just with simple logical changes to the names of the
|
||||
calls:
|
||||
|
||||
C guestfs_ln_sf (g, target, linkname);
|
||||
Python g.ln_sf (target, linkname);
|
||||
OCaml g#ln_sf target linkname;
|
||||
Perl $g->ln_sf (target, linkname);
|
||||
Shell (guestfish) ln-sf target linkname
|
||||
PHP guestfs_ln_sf ($g, $target, $linkname);
|
||||
|
||||
Once you're familiar with the API overview, you should look at this
|
||||
list of starting points for other language bindings:
|
||||
L<guestfs(3)/USING LIBGUESTFS WITH OTHER PROGRAMMING LANGUAGES>.
|
||||
|
||||
=begin html
|
||||
|
||||
<!-- old anchor for the next section -->
|
||||
<a name="debug"/>
|
||||
|
||||
=end html
|
||||
|
||||
=head2 Can I use libguestfs in my proprietary / closed source / commercial program?
|
||||
|
||||
In general, yes. However this is not legal advice. You should read
|
||||
the license that comes with libguestfs, and if you have specific
|
||||
questions about your obligations when distributing libguestfs, contact
|
||||
a lawyer. In the source tree the license is in the file
|
||||
C<COPYING.LIB> (LGPLv2+ for the library and bindings) and C<COPYING>
|
||||
(GPLv2+ for the standalone programs).
|
||||
|
||||
=head1 DEBUGGING LIBGUESTFS
|
||||
|
||||
=head2 How do I debug when using any libguestfs program or tool
|
||||
(eg. virt-v2v or virt-df)?
|
||||
|
||||
There are two C<LIBGUESTFS_*> environment variables you can set in
|
||||
order to get more information from libguestfs.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<LIBGUESTFS_TRACE>
|
||||
|
||||
Set this to 1 and libguestfs will print out each command / API call in
|
||||
a format which is similar to guestfish commands.
|
||||
|
||||
=item C<LIBGUESTFS_DEBUG>
|
||||
|
||||
Set this to 1 in order to enable massive amounts of debug messages.
|
||||
If you think there is some problem inside the libguestfs appliance,
|
||||
then you should use this option.
|
||||
|
||||
=back
|
||||
|
||||
To set these from the shell, do this before running the program:
|
||||
|
||||
export LIBGUESTFS_TRACE=1
|
||||
export LIBGUESTFS_DEBUG=1
|
||||
|
||||
For csh/tcsh the equivalent commands would be:
|
||||
|
||||
setenv LIBGUESTFS_TRACE 1
|
||||
setenv LIBGUESTFS_DEBUG 1
|
||||
|
||||
For further information, see: L<guestfs(3)/ENVIRONMENT VARIABLES>.
|
||||
|
||||
=head2 How do I debug when using guestfish?
|
||||
|
||||
You can use the same environment variables above. Alternatively use
|
||||
the guestfish options -x (to trace commands) or -v (to get the full
|
||||
debug output), or both.
|
||||
|
||||
For further information, see: L<guestfish(1)>.
|
||||
|
||||
=head2 How do I debug when using the API?
|
||||
|
||||
Call L<guestfs(3)/guestfs_set_trace> to enable command traces, and/or
|
||||
L<guestfs(3)/guestfs_set_verbose> to enable debug messages.
|
||||
|
||||
For best results, call these functions as early as possible, just
|
||||
after creating the guestfs handle if you can, and definitely before
|
||||
calling launch.
|
||||
|
||||
=head2 How do I capture debug output and put it into my logging system?
|
||||
|
||||
Use the event API. For examples, see:
|
||||
L<guestfs(3)/SETTING CALLBACKS TO HANDLE EVENTS>.
|
||||
|
||||
=head2 Digging deeper into the appliance boot process.
|
||||
|
||||
Enable debugging and then read this documentation on the appliance
|
||||
boot process: L<guestfs(3)/INTERNALS>.
|
||||
|
||||
=head2 libguestfs hangs or fails during run/launch.
|
||||
|
||||
Enable debugging and look at the full output. If you cannot work out
|
||||
what is going on, file a bug report, including the I<complete> output
|
||||
of L<libguestfs-test-tool(1)>.
|
||||
|
||||
=head1 DESIGN/INTERNALS OF LIBGUESTFS
|
||||
|
||||
=head2 Why don't you do everything through the FUSE / filesystem
|
||||
interface?
|
||||
|
||||
We offer a command called L<guestmount(1)> which lets you mount guest
|
||||
filesystems on the host. This is implemented as a FUSE module. Why
|
||||
don't we just implement the whole of libguestfs using this mechanism,
|
||||
instead of having the large and rather complicated API?
|
||||
|
||||
The reasons are twofold. Firstly, libguestfs offers API calls for
|
||||
doing things like creating and deleting partitions and logical
|
||||
volumes, which don't fit into a filesystem model very easily. Or
|
||||
rather, you could fit them in: for example, creating a partition could
|
||||
be mapped to C<mkdir /fs/hda1> but then you'd have to specify some
|
||||
method to choose the size of the partition (maybe C<echo 100M E<gt>
|
||||
/fs/hda1/.size>), and the partition type, start and end sectors etc.,
|
||||
but once you've done that the filesystem-based API starts to look more
|
||||
complicated than the call-based API we currently have.
|
||||
|
||||
The second reason is for efficiency. FUSE itself is reasonably
|
||||
efficient, but it does make lots of small, independent calls into the
|
||||
FUSE module. In guestmount these have to be translated into messages
|
||||
to the libguestfs appliance which has a big overhead (in time and
|
||||
round trips). For example, reading a file in 64 KB chunks is
|
||||
inefficient because each chunk would turn into a single round trip.
|
||||
In the libguestfs API it is much more efficient to download an entire
|
||||
file or directory through one of the streaming calls like
|
||||
C<guestfs_download> or C<guestfs_tar_out>.
|
||||
|
||||
=head2 Why don't you do everything through GVFS?
|
||||
|
||||
The problems are similar to the problems with FUSE.
|
||||
|
||||
GVFS is a better abstraction than POSIX/FUSE. There is an FTP backend
|
||||
for GVFS, which is encouraging because FTP is conceptually similar to
|
||||
the libguestfs API. However the GVFS FTP backend makes multiple
|
||||
simultaneous connections in order to keep interactivity, which we
|
||||
can't easily do with libguestfs.
|
||||
|
||||
=head2 Can I use C<guestfish --ro> as a way to backup my virtual machines?
|
||||
|
||||
Usually this is not a good idea. The question is answered in more
|
||||
detail in this mailing list posting:
|
||||
L<https://www.redhat.com/archives/libguestfs/2010-August/msg00024.html>
|
||||
|
||||
=head2 What's the difference between guestfish and virt-rescue?
|
||||
|
||||
A lot of people are confused by the two superficially similar tools we
|
||||
provide:
|
||||
|
||||
$ guestfish --ro -a guest.img
|
||||
><fs> run
|
||||
><fs> fsck /dev/sda1
|
||||
|
||||
$ virt-rescue --ro guest.img
|
||||
><rescue> /sbin/fsck /dev/sda1
|
||||
|
||||
And the related question which then arises is why you can't type in
|
||||
full shell commands with all the --options in guestfish (but you can
|
||||
in L<virt-rescue(1)>).
|
||||
|
||||
L<guestfish(1)> is a program providing structured access to the
|
||||
L<guestfs(3)> API. It happens to be a nice interactive shell too, but
|
||||
its primary purpose is structured access from shell scripts. Think of
|
||||
it more like a language binding, like Python and other bindings, but
|
||||
for shell. The key differentiating factor of guestfish (and the
|
||||
libguestfs API in general) is the ability to automate changes.
|
||||
|
||||
L<virt-rescue(1)> is a free-for-all freeform way to boot the
|
||||
libguestfs appliance and make arbitrary changes to your VM. It's not
|
||||
structured, you can't automate it, but for making quick ad-hoc fixes
|
||||
to your guests, it can be quite useful.
|
||||
|
||||
But, libguestfs also has a "backdoor" into the appliance allowing you
|
||||
to send arbitrary shell commands. It's not as flexible as
|
||||
virt-rescue, because you can't interact with the shell commands, but
|
||||
here it is anyway:
|
||||
|
||||
><fs> debug sh "cmd arg1 arg2 ..."
|
||||
|
||||
Note that you should B<not> rely on this. It could be removed or
|
||||
changed in future. If your program needs some operation, please add it
|
||||
to the libguestfs API instead.
|
||||
|
||||
=head2 What's the deal with C<guestfish -i>?
|
||||
Why does virt-cat only work on a real VM image, but virt-df works on
|
||||
any disk image?
|
||||
What does "no root device found in this operating system image" mean?
|
||||
|
||||
These questions are all related at a fundamental level which may not
|
||||
be immediately obvious.
|
||||
|
||||
At the L<guestfs(3)> API level, a "disk image" is just a pile of
|
||||
partitions and filesystems.
|
||||
|
||||
In contrast, when the virtual machine boots, it mounts those
|
||||
filesystems into a consistent hierarchy such as:
|
||||
|
||||
/ (/dev/sda2)
|
||||
|
|
||||
+-- /boot (/dev/sda1)
|
||||
|
|
||||
+-- /home (/dev/vg_external/Homes)
|
||||
|
|
||||
+-- /usr (/dev/vg_os/lv_usr)
|
||||
|
|
||||
+-- /var (/dev/vg_os/lv_var)
|
||||
|
||||
(or drive letters on Windows).
|
||||
|
||||
The API first of all sees the disk image at the "pile of filesystems"
|
||||
level. But it also has a way to inspect the disk image to see if it
|
||||
contains an operating system, and how the disks are mounted when the
|
||||
operating system boots: L<guestfs(3)/INSPECTION>.
|
||||
|
||||
Users expect some tools (like L<virt-cat(1)>) to work with VM paths:
|
||||
|
||||
virt-cat fedora.img /var/log/messages
|
||||
|
||||
How does virt-cat know that C</var> is a separate partition? The
|
||||
trick is that virt-cat performs inspection on the disk image, and uses
|
||||
that to translate the path correctly.
|
||||
|
||||
Some tools (including L<virt-cat(1)>, L<virt-edit(1)>, L<virt-ls(1)>)
|
||||
use inspection to map VM paths. Other tools, such as L<virt-df(1)>
|
||||
and L<virt-filesystems(1)> operate entirely at the raw "big pile of
|
||||
filesystems" level of the libguestfs API, and don't use inspection.
|
||||
|
||||
L<guestfish(1)> is in an interesting middle ground. If you use the
|
||||
I<-a> and I<-m> command line options, then you have to tell guestfish
|
||||
exactly how to add disk images and where to mount partitions. This is
|
||||
the raw API level.
|
||||
|
||||
If you use the I<-i> option, libguestfs performs inspection and mounts
|
||||
the filesystems for you.
|
||||
|
||||
The error C<no root device found in this operating system image> is
|
||||
related to this. It means inspection was unable to locate an
|
||||
operating system within the disk image you gave it. You might see
|
||||
this from programs like virt-cat if you try to run them on something
|
||||
which is just a disk image, not a virtual machine disk image.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfish(1)>,
|
||||
L<guestfs(3)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2012 Red Hat Inc. L<http://libguestfs.org/>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
=begin comment
|
||||
|
||||
pod2man and pod2html have differing bugs which makes it hard to write
|
||||
URLs here. The only way which works for both sorts of output is to
|
||||
just write the URL directly. Do NOT use L<...> for URLs.
|
||||
|
||||
We break with tradition here and don't use ALL CAPS for the section
|
||||
headings, as this makes them much easier to read.
|
||||
|
||||
@@ -25,7 +21,7 @@ libguestfs, L<guestfish(1)> and the virt tools.
|
||||
The link below contains a small program which can be used to audit a
|
||||
Linux virtual machine to see what setuid and setgid files it contains.
|
||||
|
||||
https://rwmj.wordpress.com/2010/12/15/tip-audit-virtual-machine-for-setuid-files/#content
|
||||
L<https://rwmj.wordpress.com/2010/12/15/tip-audit-virtual-machine-for-setuid-files/#content>
|
||||
|
||||
=head1 Change the background image in a Windows XP VM
|
||||
|
||||
@@ -34,8 +30,8 @@ background image for a user of a Windows XP VM. Unfortunately the
|
||||
technique appears to be substantially different for each version of
|
||||
Windows.
|
||||
|
||||
https://lists.fedoraproject.org/pipermail/virt/2011-May/002655.html
|
||||
https://lists.fedoraproject.org/pipermail/virt/2011-May/002658.html
|
||||
L<https://lists.fedoraproject.org/pipermail/virt/2011-May/002655.html>
|
||||
L<https://lists.fedoraproject.org/pipermail/virt/2011-May/002658.html>
|
||||
|
||||
=head1 Cloning a virtual machine (Linux)
|
||||
|
||||
@@ -43,12 +39,12 @@ The guestfish technique described in the link below works well for
|
||||
most Linux VMs. Depending on the Linux distro you may need to change
|
||||
the paths slightly.
|
||||
|
||||
https://rwmj.wordpress.com/2010/09/24/tip-my-procedure-for-cloning-a-fedora-vm/#content
|
||||
L<https://rwmj.wordpress.com/2010/09/24/tip-my-procedure-for-cloning-a-fedora-vm/#content>
|
||||
|
||||
Avoid L<virt-clone(1)>. Currently what to do about virt-clone is
|
||||
under discussion.
|
||||
|
||||
https://www.redhat.com/archives/virt-tools-list/2011-May/msg00019.html
|
||||
L<https://www.redhat.com/archives/virt-tools-list/2011-May/msg00019.html>
|
||||
|
||||
=head1 Cloning a virtual machine (Windows)
|
||||
|
||||
@@ -57,8 +53,8 @@ straightforward. Currently there is code in the Aeolus Oz project
|
||||
which does this (using libguestfs). As part of our review of the
|
||||
virt-clone tool, we may add sysprepping ability.
|
||||
|
||||
https://github.com/clalancette/oz
|
||||
https://www.redhat.com/archives/virt-tools-list/2011-May/msg00019.html
|
||||
L<https://github.com/clalancette/oz>
|
||||
L<https://www.redhat.com/archives/virt-tools-list/2011-May/msg00019.html>
|
||||
|
||||
=head1 Convert a CD-ROM / DVD / ISO to a tarball
|
||||
|
||||
@@ -75,7 +71,7 @@ To export just a subdirectory, eg. C</files>, do:
|
||||
You can use the L<guestfish(1)> I<-N> option to create empty disk
|
||||
images. The useful guide below explains the options available.
|
||||
|
||||
https://rwmj.wordpress.com/2010/09/08/new-guestfish-n-options-in-1-5-9/#content
|
||||
L<https://rwmj.wordpress.com/2010/09/08/new-guestfish-n-options-in-1-5-9/#content>
|
||||
|
||||
=head1 Dump raw filesystem content from inside a disk image or VM
|
||||
|
||||
@@ -152,7 +148,7 @@ To get the output as a compressed tarball, do:
|
||||
|
||||
Although it sounds tempting, this is usually not a reliable way to get
|
||||
a backup from a running guest. See the entry in the FAQ:
|
||||
http://libguestfs.org/FAQ.html#backup
|
||||
L<http://libguestfs.org/FAQ.html#backup>
|
||||
|
||||
=head1 Find out which user is using the most space
|
||||
|
||||
@@ -181,7 +177,7 @@ using the most space in their home directory:
|
||||
The link below explains the many different possible techniques for
|
||||
getting the last assigned DHCP address of a virtual machine.
|
||||
|
||||
https://rwmj.wordpress.com/2011/03/31/tip-code-for-getting-dhcp-address-from-a-virtual-machine-disk-image/#content
|
||||
L<https://rwmj.wordpress.com/2011/03/31/tip-code-for-getting-dhcp-address-from-a-virtual-machine-disk-image/#content>
|
||||
|
||||
In the libguestfs source examples directory you will find the latest
|
||||
version of the C<virt-dhcp-address.c> program.
|
||||
@@ -217,7 +213,7 @@ language:
|
||||
The link below contains a program to print the default boot kernel for
|
||||
a Linux VM.
|
||||
|
||||
https://rwmj.wordpress.com/2010/10/30/tip-use-augeas-to-get-the-default-boot-kernel-for-a-vm/#content
|
||||
L<https://rwmj.wordpress.com/2010/10/30/tip-use-augeas-to-get-the-default-boot-kernel-for-a-vm/#content>
|
||||
|
||||
It uses Augeas, and the technique is generally applicable for many
|
||||
different tasks, such as:
|
||||
@@ -246,7 +242,7 @@ listing who was logged in recently
|
||||
|
||||
=back
|
||||
|
||||
http://augeas.net/
|
||||
L<http://augeas.net/>
|
||||
|
||||
=head1 Install RPMs in a guest
|
||||
|
||||
@@ -256,7 +252,7 @@ script that installs them next time the guest is booted. You could
|
||||
use this technique to install vital security updates in an offline
|
||||
guest.
|
||||
|
||||
https://rwmj.wordpress.com/2010/12/01/tip-install-rpms-in-a-guest/#content
|
||||
L<https://rwmj.wordpress.com/2010/12/01/tip-install-rpms-in-a-guest/#content>
|
||||
|
||||
=head1 List applications installed in a VM
|
||||
|
||||
@@ -318,21 +314,21 @@ The link below contains a script that can be used to list out the
|
||||
services from a Windows VM, and whether those services run at boot
|
||||
time or are loaded on demand.
|
||||
|
||||
https://rwmj.wordpress.com/2010/12/10/tip-list-services-in-a-windows-guest/#content
|
||||
L<https://rwmj.wordpress.com/2010/12/10/tip-list-services-in-a-windows-guest/#content>
|
||||
|
||||
=head1 Make a disk image sparse
|
||||
|
||||
The link below contains some guides for making a disk image sparse (or
|
||||
reintroducing sparseness).
|
||||
|
||||
https://rwmj.wordpress.com/2010/10/19/tip-making-a-disk-image-sparse/#content
|
||||
L<https://rwmj.wordpress.com/2010/10/19/tip-making-a-disk-image-sparse/#content>
|
||||
|
||||
=head1 Monitor disk usage over time
|
||||
|
||||
You can use L<virt-df(1)> to monitor disk usage of your guests over
|
||||
time. The link below contains a guide.
|
||||
|
||||
http://virt-tools.org/learning/advanced-virt-df/
|
||||
L<http://virt-tools.org/learning/advanced-virt-df/>
|
||||
|
||||
=head1 Reading the Windows Event Log from Windows Vista (or later)
|
||||
|
||||
@@ -340,7 +336,7 @@ L<guestfish(1)> plus the tools described in the link below can be used
|
||||
to read out the Windows Event Log from any virtual machine running
|
||||
Windows Vista or a later version.
|
||||
|
||||
https://rwmj.wordpress.com/2011/04/17/decoding-the-windows-event-log-using-guestfish/#content
|
||||
L<https://rwmj.wordpress.com/2011/04/17/decoding-the-windows-event-log-using-guestfish/#content>
|
||||
|
||||
=head1 Remove root password (Linux)
|
||||
|
||||
@@ -356,7 +352,7 @@ password from a Windows VM, or to be more precise, it gives you a
|
||||
command prompt the next time you log in which you can use to bypass
|
||||
any security:
|
||||
|
||||
https://mdbooth.wordpress.com/2010/10/18/resetting-a-windows-guests-administrator-password-with-guestfish/
|
||||
L<https://mdbooth.wordpress.com/2010/10/18/resetting-a-windows-guests-administrator-password-with-guestfish/>
|
||||
|
||||
=head1 Unpack a live CD
|
||||
|
||||
@@ -364,14 +360,14 @@ Linux live CDs often contain multiple layers of disk images wrapped
|
||||
like a Russian doll. You can use L<guestfish(1)> to look inside these
|
||||
multiple layers, as outlined in the guide below.
|
||||
|
||||
https://rwmj.wordpress.com/2009/07/15/unpack-the-russian-doll-of-a-f11-live-cd/#content
|
||||
L<https://rwmj.wordpress.com/2009/07/15/unpack-the-russian-doll-of-a-f11-live-cd/#content>
|
||||
|
||||
=head1 Uploading and downloading files
|
||||
|
||||
The link below contains general tips on uploading (copying in)
|
||||
and downloading (copying out) files from VMs.
|
||||
|
||||
https://rwmj.wordpress.com/2010/12/02/tip-uploading-and-downloading/#content
|
||||
L<https://rwmj.wordpress.com/2010/12/02/tip-uploading-and-downloading/#content>
|
||||
|
||||
=head1 Use libguestfs tools on VMware ESX guests
|
||||
|
||||
@@ -379,7 +375,7 @@ The link below explains how to use libguestfs, L<guestfish(1)> and the
|
||||
virt tools on any VMware ESX guests, by first sharing the VMware VMFS
|
||||
over sshfs.
|
||||
|
||||
https://rwmj.wordpress.com/2011/05/10/tip-use-libguestfs-on-vmware-esx-guests/#content
|
||||
L<https://rwmj.wordpress.com/2011/05/10/tip-use-libguestfs-on-vmware-esx-guests/#content>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ After a few runs, the time should settle down to a few seconds (under
|
||||
|
||||
How to check for hardware virt:
|
||||
|
||||
http://virt-tools.org/learning/check-hardware-virt/
|
||||
L<http://virt-tools.org/learning/check-hardware-virt/>
|
||||
|
||||
If the command above does not work at all, use
|
||||
L<libguestfs-test-tool(1)>.
|
||||
@@ -135,8 +135,8 @@ Run:
|
||||
Now try to load this into your favorite spreadsheet or database. Are
|
||||
the results reproduced faithfully in the spreadsheet/database?
|
||||
|
||||
http://www.postgresql.org/docs/8.1/static/sql-copy.html
|
||||
http://dev.mysql.com/doc/refman/5.1/en/load-data.html
|
||||
L<http://www.postgresql.org/docs/8.1/static/sql-copy.html>
|
||||
L<http://dev.mysql.com/doc/refman/5.1/en/load-data.html>
|
||||
|
||||
=head2 B<*> Edit a file in a B<shut off> guest.
|
||||
|
||||
|
||||
206
examples/mount_local.c
Normal file
206
examples/mount_local.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* Demonstrate the use of the 'mount-local' API.
|
||||
*
|
||||
* Run this program as (eg) mount_local /tmp/test.img. Note that
|
||||
* '/tmp/test.img' is created or overwritten. Follow the instructions
|
||||
* on screen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <guestfs.h>
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
/* Define a list of filesystem mount options (used on the libguestfs
|
||||
* side, nothing to do with FUSE). An empty string may be used here
|
||||
* instead.
|
||||
*/
|
||||
#define MOUNT_OPTIONS "acl,user_xattr"
|
||||
|
||||
/* Size of the disk (megabytes). */
|
||||
#define SIZE_MB 512
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Usage: mount_local disk.img\n"
|
||||
"\n"
|
||||
"NOTE: disk.img will be created or overwritten.\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guestfs_h *g;
|
||||
int fd, r;
|
||||
char tempdir[] = "/tmp/mlXXXXXX";
|
||||
pid_t pid;
|
||||
char *shell, *p;
|
||||
guestfs_error_handler_cb old_error_cb;
|
||||
void *old_error_data;
|
||||
|
||||
if (argc != 2) {
|
||||
usage ();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("\n"
|
||||
"This is the 'mount-local' demonstration program. Follow the\n"
|
||||
"instructions on screen.\n"
|
||||
"\n"
|
||||
"Creating and formatting the disk image, please wait a moment ...\n");
|
||||
fflush (stdout);
|
||||
|
||||
/* Create the output disk image: raw sparse. */
|
||||
fd = open (argv[1], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
|
||||
if (fd == -1) {
|
||||
perror (argv[1]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (ftruncate (fd, SIZE_MB * 1024 * 1024) == -1) {
|
||||
perror ("truncate");
|
||||
close (fd);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (close (fd) == -1) {
|
||||
perror ("close");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Guestfs handle. */
|
||||
g = guestfs_create ();
|
||||
if (g == NULL) {
|
||||
perror ("could not create libguestfs handle");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Create the disk image and format it with a partition and a filesystem. */
|
||||
if (guestfs_add_drive_opts (g, argv[1],
|
||||
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
|
||||
-1) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if (guestfs_launch (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Mount the empty filesystem. */
|
||||
if (guestfs_mount_options (g, MOUNT_OPTIONS, "/dev/sda1", "/") == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Create a file in the new filesystem. */
|
||||
if (guestfs_touch (g, "/PUT_FILES_AND_DIRECTORIES_HERE") == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Create a temporary mount directory. */
|
||||
if (mkdtemp (tempdir) == NULL) {
|
||||
perror ("mkdtemp");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Mount the filesystem. */
|
||||
if (guestfs_mount_local (g, tempdir, -1) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
/* Fork the shell for the user. */
|
||||
pid = fork ();
|
||||
if (pid == -1) {
|
||||
perror ("fork");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid == 0) { /* Child. */
|
||||
if (chdir (tempdir) == -1) {
|
||||
perror (tempdir);
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("\n"
|
||||
"The _current directory_ is a FUSE filesystem backed by the disk\n"
|
||||
"image which is managed by libguestfs. Any files or directories\n"
|
||||
"you copy into here (up to %d MB) will be saved into the disk\n"
|
||||
"image. You can also delete files, create certain special files\n"
|
||||
"and so on.\n"
|
||||
"\n"
|
||||
"When you have finished adding files, hit ^D or exit to exit the\n"
|
||||
"shell and return to the mount-local program.\n"
|
||||
"\n",
|
||||
SIZE_MB);
|
||||
|
||||
shell = getenv ("SHELL");
|
||||
if (!shell)
|
||||
r = system ("/bin/sh");
|
||||
else {
|
||||
/* Set a magic prompt. We only know how to do this for bash. */
|
||||
p = strrchr (shell, '/');
|
||||
if (p && strcmp (p+1, "bash") == 0) {
|
||||
size_t len = 64 + strlen (shell);
|
||||
char buf[len];
|
||||
|
||||
snprintf (buf, len, "PS1='mount-local-shell> ' %s --norc -i", shell);
|
||||
r = system (buf);
|
||||
} else
|
||||
r = system (shell);
|
||||
}
|
||||
if (r == -1) {
|
||||
fprintf (stderr, "error: failed to run sub-shell (%s) "
|
||||
"(is $SHELL set correctly?)\n",
|
||||
shell);
|
||||
//FALLTHROUGH
|
||||
}
|
||||
|
||||
chdir ("/");
|
||||
guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Note that we are *not* waiting for the child yet. We want to
|
||||
* run the FUSE code in parallel with the subshell.
|
||||
*/
|
||||
|
||||
/* We're going to hide libguestfs errors here, but in a real program
|
||||
* you would probably want to log them somewhere.
|
||||
*/
|
||||
old_error_cb = guestfs_get_error_handler (g, &old_error_data);
|
||||
guestfs_set_error_handler (g, NULL, NULL);
|
||||
|
||||
/* Now run the FUSE thread. */
|
||||
if (guestfs_mount_local_run (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_set_error_handler (g, old_error_cb, old_error_data);
|
||||
|
||||
waitpid (pid, NULL, 0);
|
||||
|
||||
/* Shutdown the handle explicitly so write errors can be detected. */
|
||||
if (guestfs_shutdown (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
printf ("\n"
|
||||
"Any files or directories that you copied in have been saved into\n"
|
||||
"the disk image called '%s'.\n"
|
||||
"\n"
|
||||
"Try opening the disk image with guestfish to see those files:\n"
|
||||
"\n"
|
||||
" guestfish -a %s -m /dev/sda1\n"
|
||||
"\n",
|
||||
argv[1], argv[1]);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
@@ -169,7 +169,9 @@ print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile)
|
||||
char **lines, *p;
|
||||
size_t len;
|
||||
|
||||
lines = guestfs_egrep (g, "dhclient.*: bound to ", logfile);
|
||||
lines = guestfs_grep_opts (g, "dhclient.*: bound to ", logfile,
|
||||
GUESTFS_GREP_OPTS_EXTENDED, 1,
|
||||
-1);
|
||||
if (lines == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ bin_PROGRAMS = guestfish
|
||||
|
||||
generator_built = \
|
||||
cmds.c \
|
||||
cmds_gperf.gperf \
|
||||
cmds-gperf.gperf \
|
||||
completion.c \
|
||||
event-names.c \
|
||||
fish-cmds.h \
|
||||
@@ -39,7 +39,7 @@ generator_built = \
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(generator_built) \
|
||||
cmds_gperf.c \
|
||||
cmds-gperf.c \
|
||||
rc_protocol.h \
|
||||
rc_protocol.c
|
||||
|
||||
@@ -64,19 +64,19 @@ EXTRA_DIST = \
|
||||
# files must not include other guestfish files.
|
||||
SHARED_SOURCE_FILES = \
|
||||
config.c \
|
||||
domain.c \
|
||||
inspect.c \
|
||||
keys.c \
|
||||
options.h \
|
||||
options.c \
|
||||
progress.h \
|
||||
progress.c \
|
||||
virt.c
|
||||
progress.c
|
||||
|
||||
guestfish_SOURCES = \
|
||||
$(generator_built) \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
alloc.c \
|
||||
cmds_gperf.h \
|
||||
cmds-gperf.h \
|
||||
copy.c \
|
||||
destpaths.c \
|
||||
display.c \
|
||||
@@ -92,11 +92,11 @@ guestfish_SOURCES = \
|
||||
man.c \
|
||||
more.c \
|
||||
prep.c \
|
||||
prep_disk.c \
|
||||
prep_part.c \
|
||||
prep_fs.c \
|
||||
prep_lv.c \
|
||||
prep_boot.c \
|
||||
prep-disk.c \
|
||||
prep-part.c \
|
||||
prep-fs.c \
|
||||
prep-lv.c \
|
||||
prep-boot.c \
|
||||
rc.c \
|
||||
reopen.c \
|
||||
setenv.c \
|
||||
@@ -111,10 +111,10 @@ librc_protocol_la_CFLAGS = -Wall -Wno-unused -fno-strict-aliasing
|
||||
|
||||
# Build the command lookup perfect hash code. The generated code has
|
||||
# lots of warnings so we must compile it in a separate mini-library.
|
||||
libcmds_la_SOURCES = cmds_gperf.c
|
||||
libcmds_la_SOURCES = cmds-gperf.c
|
||||
libcmds_la_CFLAGS =
|
||||
|
||||
cmds_gperf.c: cmds_gperf.gperf
|
||||
cmds-gperf.c: cmds-gperf.gperf
|
||||
rm -f $@
|
||||
$(GPERF) -t $< > $@-t
|
||||
mv $@-t $@
|
||||
@@ -138,16 +138,25 @@ noinst_LTLIBRARIES = libcmds.la librc_protocol.la
|
||||
guestfish_LDADD += libcmds.la librc_protocol.la ../gnulib/lib/libgnu.la
|
||||
|
||||
if HAVE_RPCGEN
|
||||
RPCGEN_DEFS =
|
||||
if HAVE_XDR_U_INT64_T
|
||||
RPCGEN_DEFS += -DHAVE_XDR_U_INT64_T=1
|
||||
else
|
||||
if HAVE_XDR_UINT64_T
|
||||
RPCGEN_DEFS += -DHAVE_XDR_UINT64_T=1
|
||||
endif
|
||||
endif
|
||||
|
||||
rc_protocol.c: rc_protocol.x
|
||||
rm -f $@-t $@-t2
|
||||
$(RPCGEN) -c -o $@-t $<
|
||||
$(RPCGEN) $(RPCGEN_DEFS) -c -o $@-t $<
|
||||
sed 's,\.\./\(\.\./\)*fish,.,' < $@-t > $@-t2
|
||||
rm $@-t
|
||||
mv $@-t2 $@
|
||||
|
||||
rc_protocol.h: rc_protocol.x
|
||||
rm -f $@-t
|
||||
$(RPCGEN) -h -o $@-t $<
|
||||
$(RPCGEN) $(RPCGEN_DEFS) -h -o $@-t $<
|
||||
mv $@-t $@
|
||||
endif
|
||||
|
||||
@@ -173,7 +182,7 @@ noinst_DATA = \
|
||||
guestfish.1 $(top_builddir)/html/guestfish.1.html: stamp-guestfish.pod
|
||||
|
||||
stamp-guestfish.pod: guestfish.pod guestfish-actions.pod guestfish-commands.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man guestfish.1 \
|
||||
--html $(top_builddir)/html/guestfish.1.html \
|
||||
--insert $(srcdir)/guestfish-actions.pod:@ACTIONS@ \
|
||||
@@ -184,7 +193,7 @@ stamp-guestfish.pod: guestfish.pod guestfish-actions.pod guestfish-commands.pod
|
||||
virt-copy-in.1 $(top_builddir)/html/virt-copy-in.1.html: stamp-virt-copy-in.pod
|
||||
|
||||
stamp-virt-copy-in.pod: virt-copy-in.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-copy-in.1 \
|
||||
--html $(top_builddir)/html/virt-copy-in.1.html \
|
||||
$<
|
||||
@@ -193,7 +202,7 @@ stamp-virt-copy-in.pod: virt-copy-in.pod
|
||||
virt-copy-out.1 $(top_builddir)/html/virt-copy-out.1.html: stamp-virt-copy-out.pod
|
||||
|
||||
stamp-virt-copy-out.pod: virt-copy-out.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-copy-out.1 \
|
||||
--html $(top_builddir)/html/virt-copy-out.1.html \
|
||||
$<
|
||||
@@ -202,7 +211,7 @@ stamp-virt-copy-out.pod: virt-copy-out.pod
|
||||
virt-tar-in.1 $(top_builddir)/html/virt-tar-in.1.html: stamp-virt-tar-in.pod
|
||||
|
||||
stamp-virt-tar-in.pod: virt-tar-in.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-tar-in.1 \
|
||||
--html $(top_builddir)/html/virt-tar-in.1.html \
|
||||
$<
|
||||
@@ -211,7 +220,7 @@ stamp-virt-tar-in.pod: virt-tar-in.pod
|
||||
virt-tar-out.1 $(top_builddir)/html/virt-tar-out.1.html: stamp-virt-tar-out.pod
|
||||
|
||||
stamp-virt-tar-out.pod: virt-tar-out.pod
|
||||
$(top_builddir)/podwrapper.sh \
|
||||
$(PODWRAPPER) \
|
||||
--man virt-tar-out.1 \
|
||||
--html $(top_builddir)/html/virt-tar-out.1.html \
|
||||
$<
|
||||
@@ -229,11 +238,7 @@ bashcompletion_DATA = guestfish-bash-completion.sh
|
||||
|
||||
# Tests.
|
||||
|
||||
random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
MALLOC_PERTURB_=$(random_val) \
|
||||
$(top_builddir)/run
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
TESTS = \
|
||||
test-a.sh \
|
||||
@@ -248,8 +253,9 @@ TESTS += \
|
||||
test-copy.sh \
|
||||
test-edit.sh \
|
||||
test-find0.sh \
|
||||
test-glob.sh \
|
||||
test-mount-local.sh \
|
||||
test-read_file.sh \
|
||||
test-read-file.sh \
|
||||
test-remote.sh \
|
||||
test-reopen.sh \
|
||||
test-stringlist.sh \
|
||||
@@ -265,8 +271,9 @@ EXTRA_DIST += \
|
||||
test-escapes.sh \
|
||||
test-events.sh \
|
||||
test-find0.sh \
|
||||
test-glob.sh \
|
||||
test-mount-local.sh \
|
||||
test-read_file.sh \
|
||||
test-read-file.sh \
|
||||
test-remote.sh \
|
||||
test-reopen.sh \
|
||||
test-stringlist.sh \
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "xstrtol.h"
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#ifdef HAVE_LIBCONFIG
|
||||
#include <libconfig.h>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
21
fish/edit.c
21
fish/edit.c
@@ -24,6 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
@@ -32,7 +33,6 @@
|
||||
|
||||
static char *generate_random_name (const char *filename);
|
||||
static int copy_attributes (const char *src, const char *dest);
|
||||
static int feature_available (guestfs_h *g, const char *feature);
|
||||
|
||||
/* guestfish edit command, suggested by Ján Ondrej, implemented by RWMJ */
|
||||
|
||||
@@ -241,22 +241,3 @@ copy_attributes (const char *src, const char *dest)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
feature_available (guestfs_h *g, const char *feature)
|
||||
{
|
||||
/* If there's an error we should ignore it, so to do that we have to
|
||||
* temporarily replace the error handler with a null one.
|
||||
*/
|
||||
guestfs_error_handler_cb old_error_cb;
|
||||
void *old_error_data;
|
||||
old_error_cb = guestfs_get_error_handler (g, &old_error_data);
|
||||
guestfs_set_error_handler (g, NULL, NULL);
|
||||
|
||||
const char *groups[] = { feature, NULL };
|
||||
int r = guestfs_available (g, (char * const *) groups);
|
||||
|
||||
guestfs_set_error_handler (g, old_error_cb, old_error_data);
|
||||
|
||||
return r == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <libintl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
40
fish/fish.c
40
fish/fish.c
@@ -30,6 +30,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
#include <readline/readline.h>
|
||||
@@ -73,6 +74,7 @@ static void add_history_line (const char *);
|
||||
|
||||
static int override_progress_bars = -1;
|
||||
static struct progress_bar *bar = NULL;
|
||||
static int pipe_error = 0;
|
||||
|
||||
/* Currently open libguestfs handle. */
|
||||
guestfs_h *g = NULL;
|
||||
@@ -125,6 +127,7 @@ usage (int status)
|
||||
" -m|--mount dev[:mnt[:opts]] Mount dev on mnt (if omitted, /)\n"
|
||||
" -n|--no-sync Don't autosync\n"
|
||||
" -N|--new type Create prepared disk (test1.img, ...)\n"
|
||||
" --pipe-error Pipe commands can detect write errors\n"
|
||||
" --progress-bars Enable progress bars even when not interactive\n"
|
||||
" --no-progress-bars Disable progress bars\n"
|
||||
" --remote[=pid] Send commands to remote %s\n"
|
||||
@@ -157,6 +160,7 @@ main (int argc, char *argv[])
|
||||
/* Set global program name that is not polluted with libtool artifacts. */
|
||||
set_program_name (argv[0]);
|
||||
|
||||
/* Initialize gnulib closeout module. */
|
||||
atexit (close_stdout);
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
@@ -189,6 +193,7 @@ main (int argc, char *argv[])
|
||||
{ "new", 1, 0, 'N' },
|
||||
{ "no-dest-paths", 0, 0, 'D' },
|
||||
{ "no-sync", 0, 0, 'n' },
|
||||
{ "pipe-error", 0, 0, 0 },
|
||||
{ "progress-bars", 0, 0, 0 },
|
||||
{ "no-progress-bars", 0, 0, 0 },
|
||||
{ "remote", 2, 0, 0 },
|
||||
@@ -279,6 +284,8 @@ main (int argc, char *argv[])
|
||||
remote_control_csh = 1;
|
||||
} else if (STREQ (long_options[option_index].name, "live")) {
|
||||
live = 1;
|
||||
} else if (STREQ (long_options[option_index].name, "pipe-error")) {
|
||||
pipe_error = 1;
|
||||
} else {
|
||||
fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
|
||||
program_name, long_options[option_index].name, option_index);
|
||||
@@ -546,6 +553,9 @@ main (int argc, char *argv[])
|
||||
else
|
||||
cmdline (argv, optind, argc);
|
||||
|
||||
if (guestfs_shutdown (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
out_after_handle_close:
|
||||
@@ -1128,6 +1138,15 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd,
|
||||
perror ("failed to flush standard output");
|
||||
return -1;
|
||||
}
|
||||
if (ferror (stdout)) {
|
||||
if (!pipecmd || pipe_error) {
|
||||
fprintf (stderr, "%s: write error%s\n", program_name,
|
||||
pipecmd ? " on pipe" : "");
|
||||
r = -1;
|
||||
}
|
||||
/* We've dealt with this error, so clear the flag. */
|
||||
clearerr (stdout);
|
||||
}
|
||||
|
||||
if (pipecmd) {
|
||||
close (1);
|
||||
@@ -1436,7 +1455,7 @@ cleanup_readline (void)
|
||||
int fd;
|
||||
|
||||
if (histfile[0] != '\0') {
|
||||
fd = open (histfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
|
||||
fd = open (histfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600);
|
||||
if (fd == -1) {
|
||||
perror (histfile);
|
||||
return;
|
||||
@@ -1774,3 +1793,22 @@ progress_callback (guestfs_h *g, void *data,
|
||||
|
||||
progress_bar_set (bar, position, total);
|
||||
}
|
||||
|
||||
int
|
||||
feature_available (guestfs_h *g, const char *feature)
|
||||
{
|
||||
/* If there's an error we should ignore it, so to do that we have to
|
||||
* temporarily replace the error handler with a null one.
|
||||
*/
|
||||
guestfs_error_handler_cb old_error_cb;
|
||||
void *old_error_data;
|
||||
old_error_cb = guestfs_get_error_handler (g, &old_error_data);
|
||||
guestfs_set_error_handler (g, NULL, NULL);
|
||||
|
||||
const char *groups[] = { feature, NULL };
|
||||
int r = guestfs_available (g, (char * const *) groups);
|
||||
|
||||
guestfs_set_error_handler (g, old_error_cb, old_error_data);
|
||||
|
||||
return r == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
14
fish/fish.h
14
fish/fish.h
@@ -31,21 +31,8 @@
|
||||
#define SOCK_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETTEXT
|
||||
#include "gettext.h"
|
||||
#define _(str) dgettext(PACKAGE, (str))
|
||||
#define N_(str) dgettext(PACKAGE, (str))
|
||||
#else
|
||||
#define _(str) str
|
||||
#define N_(str) str
|
||||
#endif
|
||||
|
||||
#if !ENABLE_NLS
|
||||
#undef textdomain
|
||||
#define textdomain(Domainname) /* empty */
|
||||
#undef bindtextdomain
|
||||
#define bindtextdomain(Domainname, Dirname) /* empty */
|
||||
#endif
|
||||
|
||||
#define STREQ(a,b) (strcmp((a),(b)) == 0)
|
||||
#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
|
||||
@@ -89,6 +76,7 @@ extern void free_file_in (char *s);
|
||||
extern char *file_out (const char *arg);
|
||||
extern void extended_help_message (void);
|
||||
extern void progress_callback (guestfs_h *g, void *data, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);
|
||||
extern int feature_available (guestfs_h *g, const char *feature);
|
||||
|
||||
/* in cmds.c (auto-generated) */
|
||||
extern void list_commands (void);
|
||||
|
||||
235
fish/glob.c
235
fish/glob.c
@@ -22,12 +22,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
/* A bit tricky because in the case where there are multiple
|
||||
* paths we have to perform a Cartesian product.
|
||||
*/
|
||||
|
||||
static char **expand_pathname (guestfs_h *g, const char *path);
|
||||
static char **expand_devicename (guestfs_h *g, const char *device);
|
||||
static int add_strings_matching (char **pp, const char *glob, char ***ret, size_t *size_r);
|
||||
static int add_string (const char *str, char ***ret, size_t *size_r);
|
||||
static char **single_element_list (const char *element);
|
||||
static void glob_issue (char *cmd, size_t argc, char ***globs, size_t *posn, size_t *count, int *r);
|
||||
|
||||
int
|
||||
@@ -66,52 +75,31 @@ run_glob (const char *cmd, size_t argc, char *argv[])
|
||||
for (i = 1; i < argc; ++i) {
|
||||
char **pp;
|
||||
|
||||
/* Only if it begins with '/' can it possibly be a globbable path. */
|
||||
if (argv[i][0] == '/') {
|
||||
pp = guestfs_glob_expand (g, argv[i]);
|
||||
if (pp == NULL) { /* real error in glob_expand */
|
||||
fprintf (stderr, _("glob: guestfs_glob_expand call failed: %s\n"),
|
||||
argv[i]);
|
||||
goto error0;
|
||||
/* If it begins with "/dev/" then treat it as a globbable device
|
||||
* name.
|
||||
*/
|
||||
if (STRPREFIX (argv[i], "/dev/")) {
|
||||
pp = expand_devicename (g, argv[i]);
|
||||
if (pp == NULL) {
|
||||
r = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If there were no matches, then we add a single element list
|
||||
* containing just the original argv[i] string.
|
||||
*/
|
||||
if (pp[0] == NULL) {
|
||||
char **pp2;
|
||||
|
||||
pp2 = realloc (pp, sizeof (char *) * 2);
|
||||
if (pp2 == NULL) {
|
||||
perror ("realloc");
|
||||
free (pp);
|
||||
goto error0;
|
||||
}
|
||||
pp = pp2;
|
||||
|
||||
pp[0] = strdup (argv[i]);
|
||||
if (pp[0] == NULL) {
|
||||
perror ("strdup");
|
||||
free (pp);
|
||||
goto error0;
|
||||
}
|
||||
pp[1] = NULL;
|
||||
}
|
||||
/* If it begins with "/" it might be a globbable pathname. */
|
||||
else if (argv[i][0] == '/') {
|
||||
pp = expand_pathname (g, argv[i]);
|
||||
if (pp == NULL) {
|
||||
r = -1;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
/* Doesn't begin with '/' */
|
||||
else {
|
||||
pp = malloc (sizeof (char *) * 2);
|
||||
pp = single_element_list (argv[i]);
|
||||
if (pp == NULL) {
|
||||
perror ("malloc");
|
||||
goto error0;
|
||||
r = -1;
|
||||
goto error;
|
||||
}
|
||||
pp[0] = strdup (argv[i]);
|
||||
if (pp[0] == NULL) {
|
||||
perror ("strdup");
|
||||
free (pp);
|
||||
goto error0;
|
||||
}
|
||||
pp[1] = NULL;
|
||||
}
|
||||
|
||||
globs[i] = pp;
|
||||
@@ -122,13 +110,180 @@ run_glob (const char *cmd, size_t argc, char *argv[])
|
||||
glob_issue (argv[0], argc, globs, posn, count, &r);
|
||||
|
||||
/* Free resources. */
|
||||
error0:
|
||||
error:
|
||||
for (i = 1; i < argc; ++i)
|
||||
if (globs[i])
|
||||
free_strings (globs[i]);
|
||||
return r;
|
||||
}
|
||||
|
||||
static char **
|
||||
expand_pathname (guestfs_h *g, const char *path)
|
||||
{
|
||||
char **pp;
|
||||
|
||||
pp = guestfs_glob_expand (g, path);
|
||||
if (pp == NULL) { /* real error in glob_expand */
|
||||
fprintf (stderr, _("glob: guestfs_glob_expand call failed: %s\n"), path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pp[0] != NULL)
|
||||
return pp; /* Return the non-empty list of matches. */
|
||||
|
||||
/* If there were no matches, then we add a single element list
|
||||
* containing just the original string.
|
||||
*/
|
||||
free (pp);
|
||||
return single_element_list (path);
|
||||
}
|
||||
|
||||
/* Glob-expand device patterns, such as "/dev/sd*" (RHBZ#635971).
|
||||
*
|
||||
* There is no 'guestfs_glob_expand_device' function because the
|
||||
* equivalent can be implemented using functions like
|
||||
* 'guestfs_list_devices'.
|
||||
*
|
||||
* It's not immediately clear what it means to expand a pattern like
|
||||
* "/dev/sd*". Should that include device name translation? Should
|
||||
* the result include partitions as well as devices?
|
||||
*
|
||||
* Should "/dev/" + "*" return every possible device and filesystem?
|
||||
* How about VGs? LVs?
|
||||
*
|
||||
* To solve this what we do is build up a list of every device,
|
||||
* partition, etc., then glob against that list.
|
||||
*
|
||||
* Notes for future work (XXX):
|
||||
* - This doesn't handle device name translation. It wouldn't be
|
||||
* too hard to add.
|
||||
* - Could have an API function for returning all device-like things.
|
||||
*/
|
||||
static char **
|
||||
expand_devicename (guestfs_h *g, const char *device)
|
||||
{
|
||||
char **pp = NULL;
|
||||
char **ret = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
pp = guestfs_list_devices (g);
|
||||
if (pp == NULL) goto error;
|
||||
if (add_strings_matching (pp, device, &ret, &size) == -1) goto error;
|
||||
free_strings (pp);
|
||||
|
||||
pp = guestfs_list_partitions (g);
|
||||
if (pp == NULL) goto error;
|
||||
if (add_strings_matching (pp, device, &ret, &size) == -1) goto error;
|
||||
free_strings (pp);
|
||||
|
||||
pp = guestfs_list_md_devices (g);
|
||||
if (pp == NULL) goto error;
|
||||
if (add_strings_matching (pp, device, &ret, &size) == -1) goto error;
|
||||
free_strings (pp);
|
||||
|
||||
if (feature_available (g, "lvm2")) {
|
||||
pp = guestfs_lvs (g);
|
||||
if (pp == NULL) goto error;
|
||||
if (add_strings_matching (pp, device, &ret, &size) == -1) goto error;
|
||||
free_strings (pp);
|
||||
pp = NULL;
|
||||
}
|
||||
|
||||
/* None matched? Add the original glob pattern. */
|
||||
if (ret == NULL)
|
||||
ret = single_element_list (device);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
if (pp)
|
||||
free_strings (pp);
|
||||
if (ret)
|
||||
free_strings (ret);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Using fnmatch, find strings in the list 'pp' which match pattern
|
||||
* 'glob'. Add strings which match to the 'ret' array. '*size_r' is
|
||||
* the current size of the 'ret' array, which is updated with the new
|
||||
* size.
|
||||
*/
|
||||
static int
|
||||
add_strings_matching (char **pp, const char *glob,
|
||||
char ***ret, size_t *size_r)
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
for (i = 0; pp[i] != NULL; ++i) {
|
||||
errno = 0;
|
||||
r = fnmatch (glob, pp[i], FNM_PATHNAME);
|
||||
if (r == 0) { /* matches - add it */
|
||||
if (add_string (pp[i], ret, size_r) == -1)
|
||||
return -1;
|
||||
}
|
||||
else if (r != FNM_NOMATCH) { /* error */
|
||||
/* I checked the glibc impl and it returns random negative
|
||||
* numbers for errors. It doesn't always set errno. Do our
|
||||
* best here to record the error state.
|
||||
*/
|
||||
fprintf (stderr, "glob: fnmatch: error (r = %d, errno = %d)\n",
|
||||
r, errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
add_string (const char *str, char ***ret, size_t *size_r)
|
||||
{
|
||||
char **new_ret = *ret;
|
||||
size_t size = *size_r;
|
||||
|
||||
new_ret = realloc (new_ret, (size + 2) * (sizeof (char *)));
|
||||
if (!new_ret) {
|
||||
perror ("realloc");
|
||||
return -1;
|
||||
}
|
||||
*ret = new_ret;
|
||||
|
||||
new_ret[size] = strdup (str);
|
||||
if (new_ret[size] == NULL) {
|
||||
perror ("strdup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size++;
|
||||
new_ret[size] = NULL;
|
||||
*size_r = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a single element list containing 'element'. */
|
||||
static char **
|
||||
single_element_list (const char *element)
|
||||
{
|
||||
char **pp;
|
||||
|
||||
pp = malloc (sizeof (char *) * 2);
|
||||
if (pp == NULL) {
|
||||
perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
pp[0] = strdup (element);
|
||||
if (pp[0] == NULL) {
|
||||
perror ("strdup");
|
||||
free (pp);
|
||||
return NULL;
|
||||
}
|
||||
pp[1] = NULL;
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
static void
|
||||
glob_issue (char *cmd, size_t argc,
|
||||
char ***globs, size_t *posn, size_t *count,
|
||||
|
||||
@@ -253,7 +253,7 @@ auto-detection for C<another.img>.
|
||||
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). See also
|
||||
L</add-drive-opts>.
|
||||
L</add>.
|
||||
|
||||
=item B<-i>
|
||||
|
||||
@@ -350,6 +350,18 @@ alternative to the I<-a> option: whereas I<-a> adds an existing disk,
|
||||
I<-N> creates a preformatted disk with a filesystem and adds it.
|
||||
See L</PREPARED DISK IMAGES> below.
|
||||
|
||||
=item B<--pipe-error>
|
||||
|
||||
If writes fail to pipe commands (see L</PIPES> below), then the
|
||||
command returns an error.
|
||||
|
||||
The default (also for historical reasons) is to ignore such errors so
|
||||
that:
|
||||
|
||||
><fs> command_with_lots_of_output | head
|
||||
|
||||
doesn't give an error.
|
||||
|
||||
=item B<--progress-bars>
|
||||
|
||||
Enable progress bars, even when guestfish is used non-interactively.
|
||||
@@ -582,11 +594,11 @@ Some commands take optional arguments. These arguments appear in this
|
||||
documentation as C<[argname:..]>. You can use them as in these
|
||||
examples:
|
||||
|
||||
add-drive-opts filename
|
||||
add filename
|
||||
|
||||
add-drive-opts filename readonly:true
|
||||
add filename readonly:true
|
||||
|
||||
add-drive-opts filename format:qcow2 readonly:false
|
||||
add filename format:qcow2 readonly:false
|
||||
|
||||
Each optional argument can appear at most once. All optional
|
||||
arguments must appear after the required ones.
|
||||
@@ -1161,6 +1173,11 @@ home directory can be used. See L</FILES>.
|
||||
|
||||
Pass additional options to the guest kernel.
|
||||
|
||||
=item LIBGUESTFS_ATTACH_METHOD
|
||||
|
||||
Choose the default way to create the appliance. See
|
||||
L<guestfs(3)/guestfs_set_attach_method>.
|
||||
|
||||
=item LIBGUESTFS_DEBUG
|
||||
|
||||
Set C<LIBGUESTFS_DEBUG=1> to enable verbose messages. This has the
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "guestfs.h"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
@@ -102,8 +104,7 @@ add_drives (struct drv *drv, char next_drive)
|
||||
return next_drive;
|
||||
}
|
||||
|
||||
static void display_mountpoints_on_failure (const char *mp_device);
|
||||
static void canonical_device_name (char *dev);
|
||||
static void display_mountpoints_on_failure (const char *mp_device, const char *user_supplied_options);
|
||||
|
||||
/* List is built in reverse order, so mount them in reverse order. */
|
||||
void
|
||||
@@ -122,13 +123,9 @@ mount_mps (struct mp *mp)
|
||||
else
|
||||
options = "";
|
||||
|
||||
/* Don't use guestfs_mount here because that will default to mount
|
||||
* options -o sync,noatime. For more information, see guestfs(3)
|
||||
* section "LIBGUESTFS GOTCHAS".
|
||||
*/
|
||||
r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
|
||||
if (r == -1) {
|
||||
display_mountpoints_on_failure (mp->device);
|
||||
display_mountpoints_on_failure (mp->device, mp->options);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -138,9 +135,10 @@ mount_mps (struct mp *mp)
|
||||
* message listing the mountpoints.
|
||||
*/
|
||||
static void
|
||||
display_mountpoints_on_failure (const char *mp_device)
|
||||
display_mountpoints_on_failure (const char *mp_device,
|
||||
const char *user_supplied_options)
|
||||
{
|
||||
char **fses;
|
||||
char **fses, *p;
|
||||
size_t i;
|
||||
|
||||
fses = guestfs_list_filesystems (g);
|
||||
@@ -151,13 +149,22 @@ display_mountpoints_on_failure (const char *mp_device)
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf (stderr,
|
||||
_("%s: '%s' could not be mounted. Did you mean one of these?\n"),
|
||||
fprintf (stderr, _("%s: '%s' could not be mounted.\n"),
|
||||
program_name, mp_device);
|
||||
|
||||
if (user_supplied_options)
|
||||
fprintf (stderr, _("%s: Check mount(8) man page to ensure options '%s'\n"
|
||||
"%s: are supported by the filesystem that is being mounted.\n"),
|
||||
program_name, user_supplied_options, program_name);
|
||||
|
||||
fprintf (stderr, _("%s: Did you mean to mount one of these filesystems?\n"),
|
||||
program_name);
|
||||
|
||||
for (i = 0; fses[i] != NULL; i += 2) {
|
||||
canonical_device_name (fses[i]);
|
||||
fprintf (stderr, "\t%s (%s)\n", fses[i], fses[i+1]);
|
||||
p = guestfs_canonical_device_name (g, fses[i]);
|
||||
fprintf (stderr, "%s: \t%s (%s)\n", program_name,
|
||||
p ? p : fses[i], fses[i+1]);
|
||||
free (p);
|
||||
free (fses[i]);
|
||||
free (fses[i+1]);
|
||||
}
|
||||
@@ -165,17 +172,6 @@ display_mountpoints_on_failure (const char *mp_device)
|
||||
free (fses);
|
||||
}
|
||||
|
||||
static void
|
||||
canonical_device_name (char *dev)
|
||||
{
|
||||
if (STRPREFIX (dev, "/dev/") &&
|
||||
(dev[5] == 'h' || dev[5] == 'v') &&
|
||||
dev[6] == 'd' &&
|
||||
c_isalpha (dev[7]) &&
|
||||
(c_isdigit (dev[8]) || dev[8] == '\0'))
|
||||
dev[5] = 's';
|
||||
}
|
||||
|
||||
void
|
||||
free_drives (struct drv *drv)
|
||||
{
|
||||
|
||||
@@ -19,22 +19,12 @@
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#ifdef HAVE_GETTEXT
|
||||
#include "gettext.h"
|
||||
#ifndef _
|
||||
#define _(str) dgettext(PACKAGE, (str))
|
||||
#endif
|
||||
#ifndef N_
|
||||
#define N_(str) dgettext(PACKAGE, (str))
|
||||
#endif
|
||||
#else
|
||||
#ifndef _
|
||||
#define _(str) str
|
||||
#endif
|
||||
#ifndef _
|
||||
#define N_(str) str
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STREQ
|
||||
#define STREQ(a,b) (strcmp((a),(b)) == 0)
|
||||
@@ -105,6 +95,11 @@ struct drv {
|
||||
void (*data_free)(void*); /* function to free 'data' */
|
||||
} N;
|
||||
};
|
||||
|
||||
/* Opaque pointer. Not used by the options-parsing code, and so
|
||||
* available for the program to use for any purpose.
|
||||
*/
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
struct mp {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
#include "prepopts.h"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
@@ -39,6 +40,9 @@ run_reopen (const char *cmd, size_t argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (guestfs_shutdown (g) == -1)
|
||||
return -1;
|
||||
|
||||
/* Open the new handle first, so we can copy the settings from the
|
||||
* old one to the new one, and also so if it fails we still have an
|
||||
* open handle.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user