mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 16:26:17 +00:00
Compare commits
1254 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30f202da43 | ||
|
|
8ae8f1453b | ||
|
|
20d524f4fa | ||
|
|
d0f89fed85 | ||
|
|
12905a9bbb | ||
|
|
1e321b883b | ||
|
|
0ff561f332 | ||
|
|
1f98450995 | ||
|
|
4749bff379 | ||
|
|
ca488a6d7b | ||
|
|
8f80f9fdae | ||
|
|
efb2d07ad6 | ||
|
|
7f1f7dd44f | ||
|
|
b19f007bd2 | ||
|
|
69c5f3045a | ||
|
|
74105fdab1 | ||
|
|
3454cfb73c | ||
|
|
b5b475ab82 | ||
|
|
fdfdc883fc | ||
|
|
e866ee7c79 | ||
|
|
556fc92e8a | ||
|
|
bc03a48c71 | ||
|
|
36e71e0cf4 | ||
|
|
f77ddb9e11 | ||
|
|
d14557d434 | ||
|
|
6e5916e0f4 | ||
|
|
6483c506b9 | ||
|
|
6710296b7a | ||
|
|
4ba8b5a00d | ||
|
|
a9c4efdcfd | ||
|
|
ff8bfd3e92 | ||
|
|
4a2e8e8957 | ||
|
|
3d0e937b84 | ||
|
|
43369e1bd4 | ||
|
|
2f321ced21 | ||
|
|
a41629deb9 | ||
|
|
5d9f10c312 | ||
|
|
fd81d3f9b2 | ||
|
|
5638cd3024 | ||
|
|
e8ad3efbc4 | ||
|
|
2d89aef897 | ||
|
|
715afda341 | ||
|
|
5c44c691f2 | ||
|
|
ee5f18293b | ||
|
|
cb4284b9e3 | ||
|
|
3636c5fcff | ||
|
|
c4a3ea066b | ||
|
|
765d14dc05 | ||
|
|
ab360c48d4 | ||
|
|
ac2ddfd90a | ||
|
|
73631705cf | ||
|
|
e884abfd06 | ||
|
|
b2663be064 | ||
|
|
02ecd048d3 | ||
|
|
f9ab256f0e | ||
|
|
2c9e532566 | ||
|
|
17090bd09f | ||
|
|
fcf8032cbd | ||
|
|
99377e2748 | ||
|
|
a74f168168 | ||
|
|
a270faefef | ||
|
|
2deb235cf4 | ||
|
|
56c7967cad | ||
|
|
04a8cffee7 | ||
|
|
599a1930b0 | ||
|
|
25ff0db3b4 | ||
|
|
2d220f5da2 | ||
|
|
b460d9f32e | ||
|
|
a3b6751863 | ||
|
|
2013e005bd | ||
|
|
692701f382 | ||
|
|
dedf10aaa9 | ||
|
|
1586bbb951 | ||
|
|
1efed122c0 | ||
|
|
e8d937bd73 | ||
|
|
ebe5ca7771 | ||
|
|
101fd44fc5 | ||
|
|
3b06bee2fb | ||
|
|
6ac943fbef | ||
|
|
4bd61ed322 | ||
|
|
4f6060b9d9 | ||
|
|
46449f6894 | ||
|
|
6c539fa0a6 | ||
|
|
9a1a0c67ac | ||
|
|
58720cc968 | ||
|
|
6f34b81321 | ||
|
|
f56bc8edd5 | ||
|
|
4cfc277674 | ||
|
|
f39478424f | ||
|
|
226457de3d | ||
|
|
dd9bbeb060 | ||
|
|
bafd822914 | ||
|
|
4c285dd8f6 | ||
|
|
6871400223 | ||
|
|
de129a1363 | ||
|
|
f5194e6b0a | ||
|
|
eb185eef29 | ||
|
|
72e19deee7 | ||
|
|
8c66ba455d | ||
|
|
ccf5c6ae56 | ||
|
|
f491f3a958 | ||
|
|
3884bc7d7a | ||
|
|
63a091e21d | ||
|
|
269460770d | ||
|
|
e6f8a589ee | ||
|
|
dd09744432 | ||
|
|
bad5c7d5a5 | ||
|
|
9de4dfddc7 | ||
|
|
3c1d85ae95 | ||
|
|
7271c9146d | ||
|
|
835ae2c43c | ||
|
|
f7a67914c0 | ||
|
|
5c8f073786 | ||
|
|
91c07d2a06 | ||
|
|
a66fd2fac2 | ||
|
|
6e63636869 | ||
|
|
0e0bea70dd | ||
|
|
af5ec9381e | ||
|
|
95b83ef9d4 | ||
|
|
a3598aa257 | ||
|
|
019b840e47 | ||
|
|
7917e55ddb | ||
|
|
a0ead23016 | ||
|
|
8d4f3f85f2 | ||
|
|
fa209341f8 | ||
|
|
2e90f43129 | ||
|
|
2dab72794e | ||
|
|
773fa61141 | ||
|
|
67e483689c | ||
|
|
978d16ec76 | ||
|
|
25ec619a46 | ||
|
|
99bd15ad0e | ||
|
|
3d46f7dc03 | ||
|
|
8a89c72821 | ||
|
|
c164cc9bea | ||
|
|
ec1d239872 | ||
|
|
a0722c7ad8 | ||
|
|
c9acb029ed | ||
|
|
471f4e64d3 | ||
|
|
9466060201 | ||
|
|
389cb608df | ||
|
|
f65c9bfcf2 | ||
|
|
1c1630bb23 | ||
|
|
c36456cf03 | ||
|
|
626ca8e74f | ||
|
|
d83d17e9db | ||
|
|
07d0546f5d | ||
|
|
085bf7c97a | ||
|
|
96a76c79e4 | ||
|
|
325d67c615 | ||
|
|
64e8e0011c | ||
|
|
bdfe221671 | ||
|
|
467fb589b9 | ||
|
|
e6e999eac2 | ||
|
|
15b9ed3ed2 | ||
|
|
67e9572286 | ||
|
|
911a16a9fa | ||
|
|
91b2238fc8 | ||
|
|
f4a2aecd5f | ||
|
|
c34dcf184e | ||
|
|
77ce157db8 | ||
|
|
316c2a6fc7 | ||
|
|
2e388e8a37 | ||
|
|
7376811983 | ||
|
|
33f49d85c2 | ||
|
|
a03f536f0d | ||
|
|
0032c60336 | ||
|
|
b54fa22cd0 | ||
|
|
e10647e334 | ||
|
|
e4bca563b4 | ||
|
|
d9e5b514aa | ||
|
|
45c9fbd6f5 | ||
|
|
0a85fbc946 | ||
|
|
18b7f09f36 | ||
|
|
7786d56db8 | ||
|
|
3ad44c8660 | ||
|
|
ed7fda161e | ||
|
|
8354dc46fd | ||
|
|
62e56876c8 | ||
|
|
63eae6fa6f | ||
|
|
9f24ac2db0 | ||
|
|
6867b0a3fb | ||
|
|
328510121a | ||
|
|
92feed7d66 | ||
|
|
1467ea00b8 | ||
|
|
013fb91a69 | ||
|
|
9bd3d5bc6d | ||
|
|
8e198dc1c5 | ||
|
|
60650da1ed | ||
|
|
4a4ca0c01d | ||
|
|
df2469a48f | ||
|
|
378e5d6722 | ||
|
|
572291c64e | ||
|
|
6f53d49a27 | ||
|
|
9ea6e97014 | ||
|
|
55b7c4df78 | ||
|
|
6cd040fcdf | ||
|
|
8d63edaa93 | ||
|
|
91617069b9 | ||
|
|
f7e138835a | ||
|
|
4f3048c6be | ||
|
|
ca2e65275d | ||
|
|
b44d82ec8d | ||
|
|
9b7813c5bd | ||
|
|
f7f746a98e | ||
|
|
19b29c3637 | ||
|
|
d19e557df5 | ||
|
|
a8056050c0 | ||
|
|
7fc838cca3 | ||
|
|
b3bf53714b | ||
|
|
c9cccb776e | ||
|
|
45d459f402 | ||
|
|
0c2aab966a | ||
|
|
a297a9348f | ||
|
|
790c1a0c7b | ||
|
|
db6a851240 | ||
|
|
a95d4261b8 | ||
|
|
a3d7f5bc17 | ||
|
|
1949016e89 | ||
|
|
55fef0e4e6 | ||
|
|
09c372ea25 | ||
|
|
ab0610d752 | ||
|
|
0e7d3de002 | ||
|
|
1b364d74a8 | ||
|
|
763ec36cf0 | ||
|
|
71f87d9a8f | ||
|
|
e5d01c21d7 | ||
|
|
e482f2faf0 | ||
|
|
b36b44af9e | ||
|
|
64cc0dafd0 | ||
|
|
8aa8eb205b | ||
|
|
840deea120 | ||
|
|
181de70feb | ||
|
|
d6c11b0a3d | ||
|
|
245608a735 | ||
|
|
ae0f60744b | ||
|
|
88c406feba | ||
|
|
aeb2f76a58 | ||
|
|
157b5006db | ||
|
|
7e4b197cb6 | ||
|
|
e4ef926d6f | ||
|
|
a3ce000599 | ||
|
|
5479b8db58 | ||
|
|
f9f0767e20 | ||
|
|
a2dc3dbad0 | ||
|
|
74283d58cf | ||
|
|
2e17d78178 | ||
|
|
e128a627fb | ||
|
|
c387b69cba | ||
|
|
176bd182d3 | ||
|
|
3988dec9b7 | ||
|
|
72ab351ace | ||
|
|
369709177e | ||
|
|
552576c7f9 | ||
|
|
2100ba14fb | ||
|
|
cb13ffe190 | ||
|
|
2337b9ccd7 | ||
|
|
fbdcfe2b77 | ||
|
|
b95fff1357 | ||
|
|
e942c02a2e | ||
|
|
946ae89a78 | ||
|
|
e6bd0b87eb | ||
|
|
2fd51c28fd | ||
|
|
509dd90c43 | ||
|
|
eeb0c598ec | ||
|
|
2cac8d490e | ||
|
|
44a11e955b | ||
|
|
6361810b53 | ||
|
|
d26f402361 | ||
|
|
b0cefb417d | ||
|
|
90b7c53b70 | ||
|
|
2383d7a78e | ||
|
|
a67129b0fb | ||
|
|
d6bb49a172 | ||
|
|
9fce75aa13 | ||
|
|
6272e49f51 | ||
|
|
da75618fb2 | ||
|
|
8747ff7432 | ||
|
|
dec73f70fc | ||
|
|
cd8976a5b5 | ||
|
|
188b44ee45 | ||
|
|
5a46eadd3d | ||
|
|
ae137124ca | ||
|
|
57d089fd6d | ||
|
|
6951becfdb | ||
|
|
244e9a2ac4 | ||
|
|
19da851610 | ||
|
|
2c59af7754 | ||
|
|
6575ac4c61 | ||
|
|
5b02c8d0bc | ||
|
|
834747a85d | ||
|
|
aa9e0057b1 | ||
|
|
281b155800 | ||
|
|
8acdc23622 | ||
|
|
d9a98dc1cd | ||
|
|
97a1439d90 | ||
|
|
81c682f129 | ||
|
|
3d84ca76fe | ||
|
|
169ac913e9 | ||
|
|
dc8aca2cf9 | ||
|
|
9c4097dfd8 | ||
|
|
bdb5689f58 | ||
|
|
853feb971f | ||
|
|
c4171ad58f | ||
|
|
cc4b3139d1 | ||
|
|
05beac65e5 | ||
|
|
8248a346d7 | ||
|
|
2e36adf83c | ||
|
|
6fdf1f40fa | ||
|
|
77f70a5f7c | ||
|
|
381c067d54 | ||
|
|
9e4ac650e4 | ||
|
|
d03361b1af | ||
|
|
4ed981bd5f | ||
|
|
e388c4f3fd | ||
|
|
1030e8aba0 | ||
|
|
26732678c6 | ||
|
|
47ddb77fb1 | ||
|
|
faaedeb343 | ||
|
|
9f8ba4e8d1 | ||
|
|
efdc2bae40 | ||
|
|
20902e7ce0 | ||
|
|
b6413f8dbe | ||
|
|
c659cf8ea6 | ||
|
|
98bf41d80d | ||
|
|
3820a2578c | ||
|
|
f65dee769d | ||
|
|
d331fd70e2 | ||
|
|
11d655ab83 | ||
|
|
b799bc58a8 | ||
|
|
a1d981edea | ||
|
|
d754f4a5a3 | ||
|
|
42b892a8c5 | ||
|
|
3ed3e23ed0 | ||
|
|
3728c122f1 | ||
|
|
b17d189616 | ||
|
|
87cb154976 | ||
|
|
4e6bf1ed65 | ||
|
|
0306c98d31 | ||
|
|
4aa1464d42 | ||
|
|
163e030ee1 | ||
|
|
0573c19950 | ||
|
|
c945609ac9 | ||
|
|
a7de51b3c8 | ||
|
|
8af32b9d5f | ||
|
|
7036a3bccf | ||
|
|
bcbad66b18 | ||
|
|
2d6bf3ba70 | ||
|
|
8742713050 | ||
|
|
1ac36e4f36 | ||
|
|
9ef22fa921 | ||
|
|
b2378a81bb | ||
|
|
288cc74d77 | ||
|
|
8a723ca62e | ||
|
|
228d49bb84 | ||
|
|
044c5b26d7 | ||
|
|
684efb3706 | ||
|
|
15cd9dde5e | ||
|
|
40b9c14ca9 | ||
|
|
9ef36632ca | ||
|
|
cab48ce73c | ||
|
|
81709b5b70 | ||
|
|
512f21c965 | ||
|
|
67a803e1f2 | ||
|
|
ddc67d94f3 | ||
|
|
540fbfcf34 | ||
|
|
23b7fe09e1 | ||
|
|
0a275bd090 | ||
|
|
d555a68ca6 | ||
|
|
f23a5c468e | ||
|
|
c2ac512f12 | ||
|
|
670e4f7f12 | ||
|
|
c638e1f03d | ||
|
|
52a60349ab | ||
|
|
20ba04d83e | ||
|
|
2f97bf873b | ||
|
|
f1d98bbc79 | ||
|
|
e89e180d2b | ||
|
|
e1e8b3a1cf | ||
|
|
e3bb1f7c92 | ||
|
|
dcd35cb55c | ||
|
|
984044043d | ||
|
|
52e38c7bdc | ||
|
|
1e4c6e36a6 | ||
|
|
5f234548ed | ||
|
|
9fd4d16819 | ||
|
|
0d2e70b1c7 | ||
|
|
d944a491ac | ||
|
|
ad6870102f | ||
|
|
87cf749cde | ||
|
|
10d48bef30 | ||
|
|
1454751b73 | ||
|
|
9f59d11625 | ||
|
|
faf548a4bd | ||
|
|
11b78a7107 | ||
|
|
5e67277463 | ||
|
|
cd1627e804 | ||
|
|
d67e6ea75d | ||
|
|
781d72f558 | ||
|
|
64098f18d0 | ||
|
|
8f3c0fd98d | ||
|
|
99cfc1f36e | ||
|
|
99759da25c | ||
|
|
92e241440d | ||
|
|
d6e1d82267 | ||
|
|
92a0ac5037 | ||
|
|
07eb702163 | ||
|
|
6952505694 | ||
|
|
a69f44f56f | ||
|
|
1b4d8e2cca | ||
|
|
8ee5190768 | ||
|
|
dc66dd32c2 | ||
|
|
118932fbea | ||
|
|
735ce57cda | ||
|
|
96d3ac28d6 | ||
|
|
9d85eba3c3 | ||
|
|
294bee38bc | ||
|
|
50d904c018 | ||
|
|
0f33a1d90c | ||
|
|
6f5447abe3 | ||
|
|
e9ef74ebc2 | ||
|
|
856e78a2ce | ||
|
|
cc25afcc35 | ||
|
|
5abd7bfc4c | ||
|
|
7f9f281865 | ||
|
|
46cf4a7e87 | ||
|
|
4b8ac43729 | ||
|
|
22607a97cd | ||
|
|
8fd6f1bebe | ||
|
|
ba61236d0d | ||
|
|
16f22d89eb | ||
|
|
704e46af9c | ||
|
|
9526f632d8 | ||
|
|
f6de298d04 | ||
|
|
bd35b3c055 | ||
|
|
e3f356bda1 | ||
|
|
fad0f53dc8 | ||
|
|
7dd2389359 | ||
|
|
449bd4b50f | ||
|
|
3234a1f903 | ||
|
|
42e8c093b7 | ||
|
|
e990e80c26 | ||
|
|
94f133f25b | ||
|
|
5ea795aa48 | ||
|
|
f5208ab865 | ||
|
|
ce35eb90a2 | ||
|
|
c1a269513c | ||
|
|
637b06ab13 | ||
|
|
690bdaa392 | ||
|
|
d23293db7e | ||
|
|
4dbae7cc06 | ||
|
|
864ef706a8 | ||
|
|
84c897c93a | ||
|
|
22da2cb0ae | ||
|
|
769a6f24c6 | ||
|
|
2c046c0d6f | ||
|
|
2295b09f25 | ||
|
|
f3b21b4da5 | ||
|
|
32e5bab3ee | ||
|
|
42d404fa64 | ||
|
|
159b1479cc | ||
|
|
9fab546206 | ||
|
|
b93d004c7c | ||
|
|
589db4e42a | ||
|
|
198cc630f0 | ||
|
|
a05623cd71 | ||
|
|
7d6f76709e | ||
|
|
04b475b414 | ||
|
|
1fe6f1f7bb | ||
|
|
47410e7999 | ||
|
|
87602b09ea | ||
|
|
083125f709 | ||
|
|
2a87261dfc | ||
|
|
7fa67427c6 | ||
|
|
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 | ||
|
|
7916f5d43c | ||
|
|
8d41470b6f | ||
|
|
97ef9afca7 | ||
|
|
03d321d022 | ||
|
|
c844a38d6e | ||
|
|
2152affd30 | ||
|
|
36f1eb9225 | ||
|
|
e97b6a1bb1 | ||
|
|
c253c69d09 | ||
|
|
58a5b5bd94 | ||
|
|
5d6a323b93 | ||
|
|
b0b5fdc69f | ||
|
|
4542401fee | ||
|
|
158479ffc0 | ||
|
|
255882a3f6 | ||
|
|
7995c513ba | ||
|
|
6065f21b10 | ||
|
|
84d450210b | ||
|
|
8d3d5a52d2 | ||
|
|
fb401ebff8 | ||
|
|
5ec0fba56e | ||
|
|
3c843e2129 | ||
|
|
63cb25236b | ||
|
|
6c2b8340c3 | ||
|
|
8104b2dfab | ||
|
|
9ccde76f61 | ||
|
|
2a5a5e15e2 | ||
|
|
1f373aa246 | ||
|
|
ecdfd2c8cc | ||
|
|
b288f21e0c | ||
|
|
4b0e525d1d | ||
|
|
e14f545f81 | ||
|
|
a9bd90abfb | ||
|
|
d2183a62aa | ||
|
|
4be630edb3 | ||
|
|
4dba0e1e9d | ||
|
|
a97e9429ea | ||
|
|
5b414f581f | ||
|
|
681377f1b2 | ||
|
|
96b6504b09 | ||
|
|
a996f0d370 | ||
|
|
6c276606d7 | ||
|
|
ed2a06708c | ||
|
|
292664c3ac | ||
|
|
287d5a126e | ||
|
|
307e8bc51a | ||
|
|
3e164f15b7 | ||
|
|
c1fb89e7fc | ||
|
|
de2dc9f71d | ||
|
|
b6dd7e7250 | ||
|
|
0f7de2279a | ||
|
|
f237ae2ad6 | ||
|
|
4ee518508f | ||
|
|
16b2ffa97e | ||
|
|
a3d6629a0b | ||
|
|
edca57b49e | ||
|
|
b8fbbcf791 | ||
|
|
b10a3d718e | ||
|
|
7fe9905c4b | ||
|
|
5e054f8731 | ||
|
|
60b87d0a5c | ||
|
|
8ae322e5a7 | ||
|
|
669c0bd407 | ||
|
|
12a56dfc8a | ||
|
|
f2ac7c18a7 | ||
|
|
418a048215 | ||
|
|
d9f77f214b | ||
|
|
4b86f1ad03 | ||
|
|
ec162e7d58 | ||
|
|
19494b1988 | ||
|
|
465c97ebf4 | ||
|
|
999aac63eb | ||
|
|
5c8a241e5c | ||
|
|
04ddf3cfa2 | ||
|
|
25d156f262 | ||
|
|
a1d88b60e3 | ||
|
|
817cebe3ad | ||
|
|
50009403b3 | ||
|
|
77ac6b73cd | ||
|
|
f8a88def14 | ||
|
|
95123a9144 | ||
|
|
6282d92b1b | ||
|
|
9cb976ab5f | ||
|
|
b1f997164e | ||
|
|
de656448f7 | ||
|
|
6c88ae851f | ||
|
|
65e20e34dd | ||
|
|
64550dcad2 | ||
|
|
94e94550ed | ||
|
|
7ed21d9a5c | ||
|
|
3a58a00483 | ||
|
|
3b94cf5046 | ||
|
|
6e3de76278 | ||
|
|
ad43dde9c8 | ||
|
|
026f616650 | ||
|
|
d00596dfbb | ||
|
|
e430ce8908 | ||
|
|
dd126109e5 | ||
|
|
ed96872bd2 | ||
|
|
b2cddfe2f5 | ||
|
|
c6f09fac06 | ||
|
|
49fdba0ae9 | ||
|
|
1c5dc612bd | ||
|
|
b9cb387a10 | ||
|
|
d67da6419a | ||
|
|
0c9361a356 | ||
|
|
4db251048b | ||
|
|
17c828d995 | ||
|
|
2b9167540f | ||
|
|
3b0cb4dfdc | ||
|
|
3311e110c7 | ||
|
|
321748d3c2 | ||
|
|
e49bd34fb7 | ||
|
|
574d104b15 | ||
|
|
e3758fc430 | ||
|
|
6b13952657 | ||
|
|
ed5cc90ed5 | ||
|
|
9863dd387f | ||
|
|
1004b2ec25 | ||
|
|
b0ebf37a94 | ||
|
|
4d0aa08b00 | ||
|
|
5ea27d740e | ||
|
|
3d174b39bf | ||
|
|
f2fae5151f | ||
|
|
b169b03dd4 | ||
|
|
8111b108d2 | ||
|
|
f35aadcd86 | ||
|
|
a33ea71601 | ||
|
|
a138063acb | ||
|
|
e8ef35df26 | ||
|
|
13e5f1a3b1 | ||
|
|
09a4e7664b | ||
|
|
f5c31db5ed | ||
|
|
f1d10672c7 | ||
|
|
88b5ee9d95 | ||
|
|
fc198a3b9a | ||
|
|
a14021078b | ||
|
|
55c4e7a0d3 | ||
|
|
7d2027295f | ||
|
|
a8f8af950d | ||
|
|
3f6cc550ff | ||
|
|
65ebec4a7a | ||
|
|
f62db21d8b | ||
|
|
7526df547c | ||
|
|
c7dff02ccb | ||
|
|
b8fc61bd9b | ||
|
|
e1ffb10115 | ||
|
|
752bd8f632 | ||
|
|
7c2ebad357 | ||
|
|
a4fd393663 | ||
|
|
05461175c4 | ||
|
|
fd7a5a8bbd | ||
|
|
f9c4fdfeea | ||
|
|
a6f47c285f | ||
|
|
14938b46a7 | ||
|
|
a43f35f5bb | ||
|
|
d17218c210 | ||
|
|
6bee63beb4 | ||
|
|
c8630300b8 | ||
|
|
710ec49bac | ||
|
|
974dffc676 | ||
|
|
553e50c105 | ||
|
|
5749de39c2 | ||
|
|
5411f3fd45 | ||
|
|
85a701c10c | ||
|
|
98f066e274 | ||
|
|
1c1ecb2c41 | ||
|
|
7283a5a276 | ||
|
|
31c26be91f | ||
|
|
8c9f6a64be | ||
|
|
b05611d8ef | ||
|
|
79c4ecc0f3 | ||
|
|
03d4345c8c | ||
|
|
d9bdb9587b | ||
|
|
7934ea2395 | ||
|
|
91cede3465 | ||
|
|
2bc922dd8e | ||
|
|
c23f3b8e52 | ||
|
|
e743eb3984 | ||
|
|
606732d02e | ||
|
|
13e7a1b400 | ||
|
|
d042e56f2a | ||
|
|
6b233bd39e | ||
|
|
302309921a | ||
|
|
5da61d3052 | ||
|
|
9974c42a29 | ||
|
|
f876271521 | ||
|
|
7e32d892d7 | ||
|
|
f76a88011a | ||
|
|
14df5fa5d1 | ||
|
|
d66dd2260c | ||
|
|
17182af3a6 | ||
|
|
f7c744bbf8 | ||
|
|
b3a9e81868 | ||
|
|
1f603bfd6d | ||
|
|
2c8ead5aa0 | ||
|
|
100e30763e | ||
|
|
099e3dd9f1 | ||
|
|
5cad29043f | ||
|
|
6292e630da | ||
|
|
e9e0920c00 | ||
|
|
13c2db39ab | ||
|
|
46d1280100 | ||
|
|
4bcd0b3c17 | ||
|
|
cd3f2986ee | ||
|
|
1aa72017ca | ||
|
|
3d279d15c1 | ||
|
|
b8cdf6c2b9 | ||
|
|
24413ac4d8 | ||
|
|
e6f18c59d5 | ||
|
|
5b7b1c43ab | ||
|
|
2fb545b840 | ||
|
|
4c9218658e | ||
|
|
99923c7cd0 | ||
|
|
dfe30bdfe7 | ||
|
|
d0cf52b911 | ||
|
|
baa5e1ea51 | ||
|
|
f1f045adf8 | ||
|
|
99702fe443 | ||
|
|
f8e7a41e67 | ||
|
|
2912e4e117 | ||
|
|
0721464b83 | ||
|
|
270daae52b | ||
|
|
3f3b08a6bc | ||
|
|
b2c1d8be39 | ||
|
|
3345444ccc | ||
|
|
ae0f9f149b | ||
|
|
3b3d9ca4e1 | ||
|
|
4dd26c28a3 | ||
|
|
d0453c0254 | ||
|
|
fbf10d7f68 | ||
|
|
cba36e7305 | ||
|
|
855aaf414a | ||
|
|
618954a6b0 | ||
|
|
35d5be22b1 | ||
|
|
0ffa223a75 | ||
|
|
109d3ad34a | ||
|
|
07a8c3c0c2 | ||
|
|
10f240a07f | ||
|
|
5503d95e1b | ||
|
|
0fdcc76901 | ||
|
|
4504f424f5 | ||
|
|
2f126e07bb | ||
|
|
cfa0f9b381 | ||
|
|
a9510b7b22 | ||
|
|
518cdb596e | ||
|
|
4d8ae8f5a2 | ||
|
|
e40f408fae | ||
|
|
2c9c0525eb | ||
|
|
b9061ddf2d | ||
|
|
b106dda97c | ||
|
|
3bf5d0d0e4 | ||
|
|
deaae55072 | ||
|
|
715f7e2809 | ||
|
|
705971b509 | ||
|
|
49611f121f | ||
|
|
b11e9f4919 | ||
|
|
3b78b3a849 | ||
|
|
5e8a4627d9 | ||
|
|
49726b9269 | ||
|
|
ba468e9c5e | ||
|
|
d6f736ab18 | ||
|
|
48a5cb2a2c | ||
|
|
88ba4da4d6 | ||
|
|
a93d4a9dc1 | ||
|
|
d1711dae9d | ||
|
|
e567f064e2 | ||
|
|
51aa51884e | ||
|
|
2e788ca45e | ||
|
|
b5cc1fa049 | ||
|
|
9e5c0b39c6 | ||
|
|
db2cb21a85 | ||
|
|
5fa7aace20 | ||
|
|
afed7e493d | ||
|
|
c9ea94810e | ||
|
|
6a70cb337c | ||
|
|
84a4160fd3 | ||
|
|
cd06ddf442 | ||
|
|
1b15e543a8 | ||
|
|
07081591cf | ||
|
|
ba443ae048 | ||
|
|
c8a11468c4 | ||
|
|
9403c5516f | ||
|
|
badf2d6c4d | ||
|
|
7c21e49c2c | ||
|
|
ddae5abf80 | ||
|
|
ca80e44904 | ||
|
|
ac58ddcd1a | ||
|
|
39625b59ee | ||
|
|
df3c6acacd | ||
|
|
088546af9d | ||
|
|
a2b3e0900e | ||
|
|
6ca8a2db6d | ||
|
|
a915d78ef9 | ||
|
|
24d7889eba | ||
|
|
016ae77e6c | ||
|
|
2cbf5ea543 | ||
|
|
f504cb02e1 | ||
|
|
518edc506f | ||
|
|
0559f038ad | ||
|
|
825b5e65c0 | ||
|
|
21a9efcad5 | ||
|
|
a98170e0e2 | ||
|
|
3c9ef0e978 | ||
|
|
590d8c3c37 | ||
|
|
b7a7ad1d11 | ||
|
|
330fbea5b2 | ||
|
|
90d6386c13 | ||
|
|
d60d5c091f | ||
|
|
0042898880 | ||
|
|
e3f15780c8 | ||
|
|
6e703c1316 | ||
|
|
03684e7a61 | ||
|
|
a3ac2cc788 | ||
|
|
d33c70fd64 | ||
|
|
8fd5a377b8 | ||
|
|
eb68a31413 | ||
|
|
799852e646 | ||
|
|
7972b1da81 | ||
|
|
8f564ae7a2 | ||
|
|
d5bc69e545 | ||
|
|
93e443ccad | ||
|
|
de00aa84af | ||
|
|
3d0c9f3fc6 | ||
|
|
0a4d181063 | ||
|
|
09227c9d66 | ||
|
|
9f8e9dcc70 | ||
|
|
b1ace67381 | ||
|
|
dd25638fc1 | ||
|
|
8bad4d1c47 | ||
|
|
6568dd85f4 | ||
|
|
501561742b | ||
|
|
8ac5391935 | ||
|
|
a05ddcd2a7 | ||
|
|
9700708a19 | ||
|
|
86f64c37b9 | ||
|
|
94a7fb9fc5 | ||
|
|
ff2e685828 | ||
|
|
4c2101362e | ||
|
|
aa978b75ae | ||
|
|
43a6974cb3 | ||
|
|
f86c3a45ae | ||
|
|
9f8f1fd856 | ||
|
|
f65f653ab1 | ||
|
|
9cf7ecbe4f | ||
|
|
84242a8d0b | ||
|
|
d08806adfc | ||
|
|
b7122eaa58 | ||
|
|
22224254fa | ||
|
|
734b1f662f | ||
|
|
51c199ca6f |
789
.gitignore
vendored
789
.gitignore
vendored
@@ -1,389 +1,440 @@
|
||||
*~
|
||||
*.a
|
||||
ABOUT-NLS
|
||||
aclocal.m4
|
||||
align/stamp-virt-alignment-scan.pod
|
||||
align/virt-alignment-scan
|
||||
align/virt-alignment-scan.1
|
||||
appliance/excludelist
|
||||
appliance/make.sh
|
||||
appliance/packagelist
|
||||
appliance/stamp-supermin
|
||||
appliance/supermin.d
|
||||
autom4te.cache
|
||||
*.bak
|
||||
bindtests.tmp
|
||||
/build-aux
|
||||
cat/stamp-virt-*.pod
|
||||
cat/virt-cat
|
||||
cat/virt-cat.1
|
||||
cat/virt-filesystems
|
||||
cat/virt-filesystems.1
|
||||
cat/virt-ls
|
||||
cat/virt-ls.1
|
||||
ChangeLog
|
||||
*.class
|
||||
clone/stamp-virt-sysprep.pod
|
||||
clone/virt-sysprep
|
||||
clone/virt-sysprep.1
|
||||
*.cma
|
||||
*.cmi
|
||||
*.cmo
|
||||
*.cmx
|
||||
*.cmxa
|
||||
compile
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
cscope.out
|
||||
csharp/Libguestfs.cs
|
||||
daemon/actions.h
|
||||
daemon/errnostring.c
|
||||
daemon/errnostring_gperf.c
|
||||
daemon/errnostring_gperf.gperf
|
||||
daemon/errnostring.h
|
||||
daemon/guestfsd
|
||||
daemon/guestfsd.exe
|
||||
daemon/guestfs_protocol.c
|
||||
daemon/guestfs_protocol.h
|
||||
daemon/install-sh
|
||||
daemon/missing
|
||||
daemon/names.c
|
||||
daemon/optgroups.c
|
||||
daemon/optgroups.h
|
||||
daemon/stubs.c
|
||||
depcomp
|
||||
.deps
|
||||
df/stamp-virt-df.pod
|
||||
df/virt-df
|
||||
df/virt-df.1
|
||||
*.diff
|
||||
edit/stamp-virt-*.pod
|
||||
edit/virt-edit
|
||||
edit/virt-edit.1
|
||||
*.eml
|
||||
emptydisk
|
||||
erlang/erl-guestfs
|
||||
erlang/erl-guestfs.c
|
||||
erlang/examples/guestfs-erlang.3
|
||||
erlang/examples/stamp-guestfs-erlang.pod
|
||||
erlang/guestfs.beam
|
||||
erlang/guestfs.erl
|
||||
examples/create_disk
|
||||
examples/guestfs-examples.3
|
||||
examples/guestfs-recipes.1
|
||||
examples/guestfs-testing.1
|
||||
examples/inspect_vm
|
||||
examples/stamp-guestfs-examples.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/completion.c
|
||||
fish/event-names.c
|
||||
fish/fish-cmds.h
|
||||
fish/guestfish
|
||||
fish/guestfish.1
|
||||
fish/guestfish-actions.pod
|
||||
fish/guestfish-commands.pod
|
||||
fish/prepopts.c
|
||||
fish/prepopts.h
|
||||
fish/rc_protocol.c
|
||||
fish/rc_protocol.h
|
||||
fish/stamp-guestfish.pod
|
||||
fish/stamp-virt-copy-in.pod
|
||||
fish/stamp-virt-copy-out.pod
|
||||
fish/stamp-virt-tar-in.pod
|
||||
fish/stamp-virt-tar-out.pod
|
||||
fish/virt-copy-in.1
|
||||
fish/virt-copy-out.1
|
||||
fish/virt-tar-in.1
|
||||
fish/virt-tar-out.1
|
||||
format/stamp-virt-format.pod
|
||||
format/virt-format
|
||||
format/virt-format.1
|
||||
fuse/guestmount
|
||||
fuse/guestmount.1
|
||||
fuse/stamp-guestmount.pod
|
||||
generator/.depend
|
||||
generator/files-generated.txt
|
||||
generator/generator
|
||||
generator/.pod2text.data*
|
||||
generator/stamp-generator
|
||||
.gitattributes
|
||||
.git-module-status
|
||||
/gnulib
|
||||
/GNUmakefile
|
||||
gobject/bindtests.js
|
||||
gobject/Guestfs-1.0.gir
|
||||
gobject/Guestfs-1.0.typelib
|
||||
gobject/guestfs-gobject.c
|
||||
gobject/guestfs-gobject.h
|
||||
.guestfs-*
|
||||
guestfs.*
|
||||
guestfsd-in-wine.log
|
||||
haskell/Bindtests
|
||||
haskell/Bindtests.hs
|
||||
haskell/Guestfs005Load
|
||||
haskell/Guestfs010Basic
|
||||
haskell/Guestfs.hs
|
||||
*.hi
|
||||
html/guestfish.1.html
|
||||
html/guestfs.3.html
|
||||
html/guestfs-erlang.3.html
|
||||
html/guestfs-examples.3.html
|
||||
html/guestfs-java.3.html
|
||||
html/guestfs-ocaml.3.html
|
||||
html/guestfs-perl.3.html
|
||||
html/guestfs-python.3.html
|
||||
html/guestfs-recipes.1.html
|
||||
html/guestfs-ruby.3.html
|
||||
html/guestfs-testing.1.html
|
||||
html/guestmount.1.html
|
||||
html/virt-alignment-scan.1.html
|
||||
html/virt-cat.1.html
|
||||
html/virt-copy-in.1.html
|
||||
html/virt-copy-out.1.html
|
||||
html/virt-df.1.html
|
||||
html/virt-edit.1.html
|
||||
html/virt-filesystems.1.html
|
||||
html/virt-format.1.html
|
||||
html/virt-inspector.1.html
|
||||
html/virt-list-filesystems.1.html
|
||||
html/virt-list-partitions.1.html
|
||||
html/virt-ls.1.html
|
||||
html/virt-make-fs.1.html
|
||||
html/virt-rescue.1.html
|
||||
html/virt-resize.1.html
|
||||
html/virt-sparsify.1.html
|
||||
html/virt-sysprep.1.html
|
||||
html/virt-tar.1.html
|
||||
html/virt-tar-in.1.html
|
||||
html/virt-tar-out.1.html
|
||||
html/virt-win-reg.1.html
|
||||
inspector/stamp-virt-inspector.pod
|
||||
inspector/virt-inspector
|
||||
inspector/virt-inspector.1
|
||||
install-sh
|
||||
*.jar
|
||||
java/api
|
||||
java/Bindtests.java
|
||||
java/com/redhat/et/libguestfs/Application.java
|
||||
java/com/redhat/et/libguestfs/Dirent.java
|
||||
java/com_redhat_et_libguestfs_GuestFS.c
|
||||
java/com_redhat_et_libguestfs_GuestFS.h
|
||||
java/com/redhat/et/libguestfs/GuestFS.java
|
||||
java/com/redhat/et/libguestfs/INotifyEvent.java
|
||||
java/com/redhat/et/libguestfs/IntBool.java
|
||||
java/com/redhat/et/libguestfs/LV.java
|
||||
java/com/redhat/et/libguestfs/Partition.java
|
||||
java/com/redhat/et/libguestfs/PV.java
|
||||
java/com/redhat/et/libguestfs/Stat.java
|
||||
java/com/redhat/et/libguestfs/StatVFS.java
|
||||
java/com/redhat/et/libguestfs/Version.java
|
||||
java/com/redhat/et/libguestfs/VG.java
|
||||
java/com/redhat/et/libguestfs/XAttr.java
|
||||
java/doc-stamp
|
||||
java/examples/guestfs-java.3
|
||||
java/examples/stamp-guestfs-java.pod
|
||||
*.la
|
||||
libguestfs.pc
|
||||
libguestfs.spec
|
||||
libguestfs-*.tar.gz
|
||||
.libs
|
||||
libtool
|
||||
*.lo
|
||||
/local*
|
||||
ltmain.sh
|
||||
m4/gnulib-cache.m4
|
||||
m4/intmax.m4
|
||||
m4/libtool.m4
|
||||
m4/lt~obsolete.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
/maint.mk
|
||||
Makefile
|
||||
Makefile.in
|
||||
missing
|
||||
*.o
|
||||
ocaml/bindtests
|
||||
ocaml/bindtests.ml
|
||||
ocaml/.depend
|
||||
ocaml/dllmlguestfs.so
|
||||
ocaml/examples/create_disk
|
||||
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.ml
|
||||
ocaml/guestfs.mli
|
||||
ocamlinit-stamp
|
||||
ocaml/META
|
||||
ocaml/t/guestfs_005_load
|
||||
ocaml/t/guestfs_010_basic
|
||||
ocaml/t/guestfs_070_threads
|
||||
ocaml/t/guestfs_080_optargs
|
||||
ocaml/t/guestfs_400_events
|
||||
ocaml/t/guestfs_400_progress
|
||||
*.orig
|
||||
*.patch
|
||||
perl/bindtests.pl
|
||||
perl/blib
|
||||
perl/examples/guestfs-perl.3
|
||||
perl/examples/stamp-guestfs-perl.pod
|
||||
perl/Guestfs.bs
|
||||
perl/Guestfs.c
|
||||
perl/Guestfs.xs
|
||||
perl/lib/Sys/Guestfs.pm
|
||||
perl/Makefile-pl
|
||||
perl/Makefile.PL
|
||||
perl/Makefile-pl.old
|
||||
perl/MYMETA.yml
|
||||
perl/pm_to_blib
|
||||
php/extension/acinclude.m4
|
||||
php/extension/build/
|
||||
php/extension/config.nice
|
||||
php/extension/configure.in
|
||||
php/extension/guestfs_php.c
|
||||
php/extension/guestfs_php_*.diff
|
||||
php/extension/guestfs_php_*.exp
|
||||
php/extension/guestfs_php_*.log
|
||||
php/extension/guestfs_php_*.out
|
||||
php/extension/guestfs_php_*.php
|
||||
php/extension/guestfs_php_*.sh
|
||||
php/extension/Makefile.fragments
|
||||
php/extension/Makefile.global
|
||||
php/extension/Makefile.objects
|
||||
php/extension/mkinstalldirs
|
||||
php/extension/modules/
|
||||
php/extension/php_guestfs_php.h
|
||||
php/extension/run-tests.php
|
||||
php/extension/tmp-php.ini
|
||||
po/boldquot.sed
|
||||
pod2htm?.tmp
|
||||
po-docs/*/*.1
|
||||
po-docs/*/*.3
|
||||
po-docs/*/*.pl
|
||||
po-docs/po4a.conf
|
||||
po-docs/*/*.pod
|
||||
podwrapper.sh
|
||||
po/en@boldquot.header
|
||||
po/en@quot.header
|
||||
po/*.gmo
|
||||
po/insert-header.sin
|
||||
po/LINGUAS
|
||||
po/Makevars.template
|
||||
po/POTFILES
|
||||
po/quot.sed
|
||||
po/remove-potcdate.sed
|
||||
po/remove-potcdate.sin
|
||||
po/Rules-quot
|
||||
po/stamp-it
|
||||
po/stamp-po
|
||||
python/bindtests.py
|
||||
python/examples/guestfs-python.3
|
||||
python/examples/stamp-guestfs-python.pod
|
||||
python/guestfs.py
|
||||
python/guestfs-py.c
|
||||
python/guestfs.pyc
|
||||
python/__pycache__
|
||||
*.rej
|
||||
rescue/stamp-virt-rescue.pod
|
||||
rescue/virt-rescue
|
||||
rescue/virt-rescue.1
|
||||
resize/.depend
|
||||
resize/stamp-virt-resize.pod
|
||||
resize/utils_tests
|
||||
resize/virt-resize
|
||||
resize/virt-resize.1
|
||||
ruby/bindtests.rb
|
||||
ruby/doc/site/api
|
||||
ruby/examples/guestfs-ruby.3
|
||||
ruby/examples/stamp-guestfs-ruby.pod
|
||||
ruby/ext/guestfs/extconf.h
|
||||
ruby/ext/guestfs/_guestfs.bundle
|
||||
ruby/ext/guestfs/_guestfs.c
|
||||
ruby/ext/guestfs/_guestfs.so
|
||||
ruby/ext/guestfs/mkmf.log
|
||||
ruby/Rakefile
|
||||
run
|
||||
sparsify/.depend
|
||||
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.h
|
||||
src/guestfs.3
|
||||
src/guestfs-actions.pod
|
||||
src/guestfs-availability.pod
|
||||
src/guestfs.h
|
||||
src/guestfs-internal-actions.h
|
||||
src/guestfs_protocol.c
|
||||
src/guestfs_protocol.h
|
||||
src/guestfs_protocol.x
|
||||
src/guestfs-structs.pod
|
||||
src/libguestfs.syms
|
||||
src/.libs/libguestfs.so
|
||||
src/stamp-guestfs.pod
|
||||
stamp-h1
|
||||
*.swp
|
||||
test1.img
|
||||
test2.img
|
||||
test.err
|
||||
test.out
|
||||
tests/c-api/test-add-drive-opts
|
||||
tests/c-api/test-add-libvirt-dom
|
||||
tests/c-api/test-command
|
||||
tests/c-api/test-config
|
||||
tests/c-api/test-create-handle
|
||||
tests/c-api/test-debug-to-file
|
||||
tests/c-api/test*.img
|
||||
tests/c-api/test-just-header
|
||||
tests/c-api/test-last-errno
|
||||
tests/c-api/test.log
|
||||
tests/c-api/test-private-data
|
||||
tests/c-api/tests
|
||||
tests/c-api/tests.c
|
||||
tests/c-api/test*.tmp
|
||||
tests/c-api/test-user-cancel
|
||||
tests/data/100kallnewlines
|
||||
tests/data/100kallspaces
|
||||
tests/data/100kallzeroes
|
||||
tests/data/100krandom
|
||||
tests/data/10klines
|
||||
tests/data/abssymlink
|
||||
tests/data/hello.b64
|
||||
tests/data/initrd
|
||||
tests/data/initrd-x86_64.img
|
||||
tests/data/initrd-x86_64.img.gz
|
||||
tests/data/test-grep.txt.gz
|
||||
tests/data/test.iso
|
||||
tests/extra/valgrind.log
|
||||
tests/guests/debian.img
|
||||
tests/guests/fedora.img
|
||||
tests/guests/fedora-md1.img
|
||||
tests/guests/fedora-md2.img
|
||||
tests/guests/guest-aux/fedora-name.db
|
||||
tests/guests/guest-aux/fedora-packages.db
|
||||
tests/guests/ubuntu.img
|
||||
tests/guests/windows.img
|
||||
tests/regressions/rhbz501893
|
||||
test-tool/libguestfs-test-tool
|
||||
test-tool/libguestfs-test-tool.1
|
||||
test-tool/libguestfs-test-tool-helper
|
||||
tools/test.img
|
||||
tools/virt-*.1
|
||||
tools/virt-*.pl
|
||||
|
||||
bindtests.tmp
|
||||
cscope.out
|
||||
.deps
|
||||
.gdb_history
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
/ABOUT-NLS
|
||||
/aclocal.m4
|
||||
/align/stamp-virt-alignment-scan.pod
|
||||
/align/virt-alignment-scan
|
||||
/align/virt-alignment-scan.1
|
||||
/appliance/excludelist
|
||||
/appliance/libguestfs-make-fixed-appliance
|
||||
/appliance/libguestfs-make-fixed-appliance.1
|
||||
/appliance/make.sh
|
||||
/appliance/packagelist
|
||||
/appliance/stamp-libguestfs-make-fixed-appliance.pod
|
||||
/appliance/stamp-supermin
|
||||
/appliance/supermin.d
|
||||
/autom4te.cache
|
||||
/build-aux
|
||||
/cat/stamp-virt-*.pod
|
||||
/cat/virt-cat
|
||||
/cat/virt-cat.1
|
||||
/cat/virt-filesystems
|
||||
/cat/virt-filesystems.1
|
||||
/cat/virt-ls
|
||||
/cat/virt-ls.1
|
||||
/ChangeLog
|
||||
/compile
|
||||
/config.cache
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/csharp/Libguestfs.cs
|
||||
/daemon/actions.h
|
||||
/daemon/errnostring.c
|
||||
/daemon/errnostring-gperf.c
|
||||
/daemon/errnostring-gperf.gperf
|
||||
/daemon/errnostring.h
|
||||
/daemon/guestfsd
|
||||
/daemon/guestfsd.8
|
||||
/daemon/guestfsd.exe
|
||||
/daemon/guestfs_protocol.c
|
||||
/daemon/guestfs_protocol.h
|
||||
/daemon/install-sh
|
||||
/daemon/missing
|
||||
/daemon/names.c
|
||||
/daemon/optgroups.c
|
||||
/daemon/optgroups.h
|
||||
/daemon/stamp-guestfsd.pod
|
||||
/daemon/stubs.c
|
||||
/depcomp
|
||||
/df/stamp-virt-df.pod
|
||||
/df/virt-df
|
||||
/df/virt-df.1
|
||||
/edit/stamp-virt-*.pod
|
||||
/edit/virt-edit
|
||||
/edit/virt-edit.1
|
||||
/erlang/bindtests.erl
|
||||
/erlang/erl-guestfs
|
||||
/erlang/erl-guestfs.c
|
||||
/erlang/examples/guestfs-erlang.3
|
||||
/erlang/examples/stamp-guestfs-erlang.pod
|
||||
/erlang/guestfs.beam
|
||||
/erlang/guestfs.erl
|
||||
/examples/copy_over
|
||||
/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/libvirt_auth
|
||||
/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/completion.c
|
||||
/fish/event-names.c
|
||||
/fish/fish-cmds.h
|
||||
/fish/guestfish
|
||||
/fish/guestfish.1
|
||||
/fish/guestfish-actions.pod
|
||||
/fish/guestfish-commands.pod
|
||||
/fish/prepopts.c
|
||||
/fish/prepopts.h
|
||||
/fish/rc_protocol.c
|
||||
/fish/rc_protocol.h
|
||||
/fish/stamp-guestfish.pod
|
||||
/fish/stamp-virt-copy-in.pod
|
||||
/fish/stamp-virt-copy-out.pod
|
||||
/fish/stamp-virt-tar-in.pod
|
||||
/fish/stamp-virt-tar-out.pod
|
||||
/fish/virt-copy-in.1
|
||||
/fish/virt-copy-out.1
|
||||
/fish/virt-tar-in.1
|
||||
/fish/virt-tar-out.1
|
||||
/format/stamp-virt-format.pod
|
||||
/format/virt-format
|
||||
/format/virt-format.1
|
||||
/fuse/guestmount
|
||||
/fuse/guestmount.1
|
||||
/fuse/stamp-guestmount.pod
|
||||
/generator/.depend
|
||||
/generator/files-generated.txt
|
||||
/generator/generator
|
||||
/generator/.pod2text.data*
|
||||
/generator/stamp-generator
|
||||
/.gitattributes
|
||||
/.git-module-status
|
||||
/gnulib
|
||||
/GNUmakefile
|
||||
/gobject/bindtests.js
|
||||
/gobject/Guestfs-1.0.gir
|
||||
/gobject/Guestfs-1.0.typelib
|
||||
/gobject/guestfs-gobject*.c
|
||||
/gobject/guestfs-gobject*.h
|
||||
/guestfs-release-notes.1
|
||||
/guestfsd-in-wine.log
|
||||
/haskell/Bindtests
|
||||
/haskell/Bindtests.hs
|
||||
/haskell/Guestfs005Load
|
||||
/haskell/Guestfs010Basic
|
||||
/haskell/Guestfs.hs
|
||||
/html/guestfish.1.html
|
||||
/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-lua.3.html
|
||||
/html/guestfs-ocaml.3.html
|
||||
/html/guestfs-performance.1.html
|
||||
/html/guestfs-perl.3.html
|
||||
/html/guestfs-python.3.html
|
||||
/html/guestfs-recipes.1.html
|
||||
/html/guestfs-release-notes.1.html
|
||||
/html/guestfs-ruby.3.html
|
||||
/html/guestfs-testing.1.html
|
||||
/html/guestfsd.8.html
|
||||
/html/guestmount.1.html
|
||||
/html/libguestfs-make-fixed-appliance.1.html
|
||||
/html/libguestfs-test-tool.1.html
|
||||
/html/virt-alignment-scan.1.html
|
||||
/html/virt-cat.1.html
|
||||
/html/virt-copy-in.1.html
|
||||
/html/virt-copy-out.1.html
|
||||
/html/virt-df.1.html
|
||||
/html/virt-edit.1.html
|
||||
/html/virt-filesystems.1.html
|
||||
/html/virt-format.1.html
|
||||
/html/virt-inspector.1.html
|
||||
/html/virt-list-filesystems.1.html
|
||||
/html/virt-list-partitions.1.html
|
||||
/html/virt-ls.1.html
|
||||
/html/virt-make-fs.1.html
|
||||
/html/virt-rescue.1.html
|
||||
/html/virt-resize.1.html
|
||||
/html/virt-sparsify.1.html
|
||||
/html/virt-sysprep.1.html
|
||||
/html/virt-tar.1.html
|
||||
/html/virt-tar-in.1.html
|
||||
/html/virt-tar-out.1.html
|
||||
/html/virt-win-reg.1.html
|
||||
/inspector/stamp-virt-inspector.pod
|
||||
/inspector/test-xmllint.sh
|
||||
/inspector/virt-inspector
|
||||
/inspector/virt-inspector.1
|
||||
/install-sh
|
||||
/java/api
|
||||
/java/Bindtests.java
|
||||
/java/com_redhat_et_libguestfs_GuestFS.c
|
||||
/java/com_redhat_et_libguestfs_GuestFS.h
|
||||
/java/com/redhat/et/libguestfs/GuestFS.java
|
||||
/java/doc-stamp
|
||||
/java/examples/guestfs-java.3
|
||||
/java/examples/stamp-guestfs-java.pod
|
||||
/libguestfs.spec
|
||||
/libguestfs-*.tar.gz
|
||||
/libtool
|
||||
/local*
|
||||
/ltmain.sh
|
||||
/lua/bindtests.lua
|
||||
/lua/examples/guestfs-lua.3
|
||||
/lua/examples/stamp-guestfs-lua.pod
|
||||
/lua/guestfs.so
|
||||
/lua/lua-guestfs.c
|
||||
/lua/test.img
|
||||
/m4/ChangeLog
|
||||
/m4/gnulib-cache.m4
|
||||
/m4/intmax.m4
|
||||
/m4/libtool.m4
|
||||
/m4/lt~obsolete.m4
|
||||
/m4/ltoptions.m4
|
||||
/m4/ltsugar.m4
|
||||
/m4/ltversion.m4
|
||||
/maint.mk
|
||||
/missing
|
||||
/ocaml/bindtests.bc
|
||||
/ocaml/bindtests.opt
|
||||
/ocaml/bindtests.ml
|
||||
/ocaml/.depend
|
||||
/ocaml/dllmlguestfs.so
|
||||
/ocaml/examples/create_disk
|
||||
/ocaml/examples/guestfs-ocaml.3
|
||||
/ocaml/examples/inspect_vm
|
||||
/ocaml/examples/stamp-guestfs-ocaml.pod
|
||||
/ocaml/guestfs-c-actions.c
|
||||
/ocaml/guestfs.ml
|
||||
/ocaml/guestfs.mli
|
||||
/ocamlinit-stamp
|
||||
/ocaml/META
|
||||
/ocaml/t/guestfs_005_load.bc
|
||||
/ocaml/t/guestfs_005_load.opt
|
||||
/ocaml/t/guestfs_010_basic.bc
|
||||
/ocaml/t/guestfs_010_basic.opt
|
||||
/ocaml/t/guestfs_070_threads.bc
|
||||
/ocaml/t/guestfs_070_threads.opt
|
||||
/ocaml/t/guestfs_080_optargs.bc
|
||||
/ocaml/t/guestfs_080_optargs.opt
|
||||
/ocaml/t/guestfs_400_events.bc
|
||||
/ocaml/t/guestfs_400_events.opt
|
||||
/ocaml/t/guestfs_400_progress.bc
|
||||
/ocaml/t/guestfs_400_progress.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
|
||||
/perl/examples/stamp-guestfs-perl.pod
|
||||
/perl/Guestfs.bs
|
||||
/perl/Guestfs.c
|
||||
/perl/Guestfs.xs
|
||||
/perl/lib/Sys/Guestfs.pm
|
||||
/perl/Makefile-pl
|
||||
/perl/Makefile.PL
|
||||
/perl/Makefile-pl.old
|
||||
/perl/MYMETA.json
|
||||
/perl/MYMETA.yml
|
||||
/perl/pm_to_blib
|
||||
/php/extension/acinclude.m4
|
||||
/php/extension/aclocal.m4
|
||||
/php/extension/autom4te.cache
|
||||
/php/extension/build/
|
||||
/php/extension/config.guess
|
||||
/php/extension/config.h
|
||||
/php/extension/config.h.in
|
||||
/php/extension/config.log
|
||||
/php/extension/config.nice
|
||||
/php/extension/config.status
|
||||
/php/extension/config.sub
|
||||
/php/extension/configure
|
||||
/php/extension/configure.in
|
||||
/php/extension/guestfs_php.c
|
||||
/php/extension/guestfs_php_*.diff
|
||||
/php/extension/guestfs_php_*.exp
|
||||
/php/extension/guestfs_php_*.log
|
||||
/php/extension/guestfs_php_*.out
|
||||
/php/extension/guestfs_php_*.php
|
||||
/php/extension/guestfs_php_*.sh
|
||||
/php/extension/install-sh
|
||||
/php/extension/libtool
|
||||
/php/extension/ltmain.sh
|
||||
/php/extension/Makefile.fragments
|
||||
/php/extension/Makefile.global
|
||||
/php/extension/Makefile.objects
|
||||
/php/extension/mkinstalldirs
|
||||
/php/extension/missing
|
||||
/php/extension/modules/
|
||||
/php/extension/php_guestfs_php.h
|
||||
/php/extension/run-tests.php
|
||||
/php/extension/tmp-php.ini
|
||||
/pick-guests.pl
|
||||
/po-docs/*/*.1
|
||||
/po-docs/*/*.3
|
||||
/po-docs/*/*.8
|
||||
/po-docs/*/*.pl
|
||||
/po-docs/po4a.conf
|
||||
/po-docs/*/*.pod
|
||||
/po-docs/*/stamp-update-po
|
||||
/podwrapper.pl
|
||||
/po/*.gmo
|
||||
/python/bindtests.py
|
||||
/python/examples/guestfs-python.3
|
||||
/python/examples/stamp-guestfs-python.pod
|
||||
/python/guestfs.py
|
||||
/python/guestfs-py.c
|
||||
/python/guestfs.pyc
|
||||
/python/guestfs.pyo
|
||||
/python/__pycache__
|
||||
/qemu-wrapper.sh
|
||||
/rescue/stamp-virt-rescue.pod
|
||||
/rescue/virt-rescue
|
||||
/rescue/virt-rescue.1
|
||||
/resize/.depend
|
||||
/resize/resize_gettext.ml
|
||||
/resize/resize_utils_tests
|
||||
/resize/stamp-virt-resize.pod
|
||||
/resize/virt-resize
|
||||
/resize/virt-resize.1
|
||||
/ruby/bindtests.rb
|
||||
/ruby/doc/site/api
|
||||
/ruby/examples/guestfs-ruby.3
|
||||
/ruby/examples/stamp-guestfs-ruby.pod
|
||||
/ruby/ext/guestfs/extconf.h
|
||||
/ruby/ext/guestfs/_guestfs.bundle
|
||||
/ruby/ext/guestfs/_guestfs.c
|
||||
/ruby/ext/guestfs/_guestfs.so
|
||||
/ruby/ext/guestfs/mkmf.log
|
||||
/ruby/Rakefile
|
||||
/run
|
||||
/sparsify/.depend
|
||||
/sparsify/sparsify_gettext.ml
|
||||
/sparsify/stamp-virt-sparsify.pod
|
||||
/sparsify/virt-sparsify
|
||||
/sparsify/virt-sparsify.1
|
||||
/src/actions-?.c
|
||||
/src/actions-variants.c
|
||||
/src/bindtests.c
|
||||
/src/errnostring.c
|
||||
/src/errnostring-gperf.c
|
||||
/src/errnostring-gperf.gperf
|
||||
/src/errnostring.h
|
||||
/src/free-structs.c
|
||||
/src/guestfs.3
|
||||
/src/guestfs-actions.pod
|
||||
/src/guestfs-availability.pod
|
||||
/src/guestfs.h
|
||||
/src/guestfs-internal-actions.h
|
||||
/src/guestfs_protocol.c
|
||||
/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
|
||||
/stamp-guestfs-release-notes.pod
|
||||
/stamp-h1
|
||||
/sysprep/.depend
|
||||
/sysprep/stamp-script1.sh
|
||||
/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
|
||||
/test1.img
|
||||
/test2.img
|
||||
/test.err
|
||||
/test.out
|
||||
/tests/c-api/test-add-drive-opts
|
||||
/tests/c-api/test-add-libvirt-dom
|
||||
/tests/c-api/test-command
|
||||
/tests/c-api/test-config
|
||||
/tests/c-api/test-create-handle
|
||||
/tests/c-api/test-debug-to-file
|
||||
/tests/c-api/test-environment
|
||||
/tests/c-api/test*.img
|
||||
/tests/c-api/test-just-header
|
||||
/tests/c-api/test-just-header-cxx
|
||||
/tests/c-api/test-last-errno
|
||||
/tests/c-api/test.log
|
||||
/tests/c-api/test-private-data
|
||||
/tests/c-api/tests
|
||||
/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
|
||||
/tests/data/100krandom
|
||||
/tests/data/10klines
|
||||
/tests/data/abssymlink
|
||||
/tests/data/hello.b64
|
||||
/tests/data/initrd
|
||||
/tests/data/initrd-x86_64.img
|
||||
/tests/data/initrd-x86_64.img.gz
|
||||
/tests/data/test-grep.txt.gz
|
||||
/tests/data/test.iso
|
||||
/tests/guests/debian.img
|
||||
/tests/guests/fedora.img
|
||||
/tests/guests/fedora-md1.img
|
||||
/tests/guests/fedora-md2.img
|
||||
/tests/guests/guest-aux/fedora-name.db
|
||||
/tests/guests/guest-aux/fedora-packages.db
|
||||
/tests/guests/stamp-fedora-md.img
|
||||
/tests/guests/ubuntu.img
|
||||
/tests/guests/windows.img
|
||||
/tests/mount-local/test-parallel-mount-local
|
||||
/tests/parallel/test-parallel
|
||||
/tests/regressions/rhbz501893
|
||||
/tests/regressions/rhbz790721
|
||||
/tests/rsync/rsyncd.pid
|
||||
/test-tool/libguestfs-test-tool
|
||||
/test-tool/libguestfs-test-tool.1
|
||||
/test-tool/libguestfs-test-tool-helper
|
||||
/test-tool/stamp-libguestfs-test-tool.pod
|
||||
/tools/test.img
|
||||
/tools/virt-*.1
|
||||
/tools/virt-*.pl
|
||||
/valgrind.log*
|
||||
|
||||
2
.gnulib
2
.gnulib
Submodule .gnulib updated: eec8a69158...0cd711b27b
@@ -10,4 +10,3 @@ source_lang = en
|
||||
file_filter = po-docs/<lang>.po
|
||||
source_file = po-docs/libguestfs-docs.pot
|
||||
source_lang = en
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
^appliance/debian/modules/
|
||||
^tests/data/
|
||||
^COPYING(.LIB)?$
|
||||
^\.gitmodules$
|
||||
|
||||
9
AUTHORS
9
AUTHORS
@@ -4,21 +4,30 @@ 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>
|
||||
Hilko Bengen <bengen@hilluzination.de>
|
||||
Jaswinder Singh <jsingh@redhat.com>
|
||||
Jim Meyering <jim@meyering.net>
|
||||
Jiri Popelka <jpopelka@redhat.com>
|
||||
John Eckersberg <jeckersb@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>
|
||||
Nikita A Menkovich <menkovich@gmail.com>
|
||||
Nikos Skalkotos <skalkoto@gmail.com>
|
||||
Olaf Hering <olaf@aepfle.de>
|
||||
Piotr Drąg <piotrdrag@gmail.com>
|
||||
Qin Guan <qguan@redhat.com>
|
||||
Rajesh Ranjan <rranjan@redhat.com>
|
||||
Richard W.M. Jones <rich@annexia.org>
|
||||
Sandeep Shedmake <sshedmak@redhat.com>
|
||||
Shankar Prasad <svenkate@redhat.com>
|
||||
Thomas S Hatch <thatch45@gmail.com>
|
||||
Wanlong Gao <gaowanlong@cn.fujitsu.com>
|
||||
Wulf C. Krueger <philantrop@exherbo.org>
|
||||
|
||||
307
BUGS
307
BUGS
@@ -1,5 +1,5 @@
|
||||
NOTE: This file is automatically generated from "update-bugs.sh".
|
||||
Last updated: 2012-01-22
|
||||
Last updated: 2012-11-20
|
||||
|
||||
This contains a local list of the bugs that are open against
|
||||
libguestfs. Bugs are tracked in the Red Hat Bugzilla database
|
||||
@@ -20,105 +20,27 @@ When reporting a new bug, please check:
|
||||
--------------------------------------------------
|
||||
Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
|
||||
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"
|
||||
|
||||
709326 NEW https://bugzilla.redhat.com/show_bug.cgi?id=709326
|
||||
virt-inspector cannot detect ReactOS
|
||||
|
||||
719879 NEW https://bugzilla.redhat.com/show_bug.cgi?id=719879
|
||||
Rebase libguestfs in RHEL 6.3
|
||||
|
||||
728224 NEW https://bugzilla.redhat.com/show_bug.cgi?id=728224
|
||||
configure can't find qemu on PPC
|
||||
|
||||
729076 NEW https://bugzilla.redhat.com/show_bug.cgi?id=729076
|
||||
libguestfs confuses Hp_recovery partition with Windows root filesystem
|
||||
|
||||
731742 NEW https://bugzilla.redhat.com/show_bug.cgi?id=731742
|
||||
libguestfs should escape special/non-printing characters in debug output
|
||||
|
||||
737261 NEW https://bugzilla.redhat.com/show_bug.cgi?id=737261
|
||||
libguestfs grub-install API needs grub1
|
||||
|
||||
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
|
||||
|
||||
760221 NEW https://bugzilla.redhat.com/show_bug.cgi?id=760221
|
||||
RFE: Support inspection of cciss devices
|
||||
|
||||
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
|
||||
|
||||
769304 NEW https://bugzilla.redhat.com/show_bug.cgi?id=769304
|
||||
virt-resize on RHEL 6 kernel fails to re-read the partition table
|
||||
|
||||
769359 NEW https://bugzilla.redhat.com/show_bug.cgi?id=769359
|
||||
virt-resize on RHEL 6 kernel fails to re-read the partition table
|
||||
|
||||
770075 NEW https://bugzilla.redhat.com/show_bug.cgi?id=770075
|
||||
FEBOOTSTRAP_MODULES fails if modules directory is not under /lib
|
||||
|
||||
770076 NEW https://bugzilla.redhat.com/show_bug.cgi?id=770076
|
||||
FEBOOTSTRAP_KERNEL causes appliance build to fail
|
||||
|
||||
782167 NEW https://bugzilla.redhat.com/show_bug.cgi?id=782167
|
||||
libguestfs doesn't recognize Windows Dynamic disks in some configurations, eg. spanned
|
||||
|
||||
563450 NEW https://bugzilla.redhat.com/show_bug.cgi?id=563450
|
||||
list-devices returns devices of different types out of order
|
||||
|
||||
696445 NEW https://bugzilla.redhat.com/show_bug.cgi?id=696445
|
||||
Backport virt-inspector for virt-v2v
|
||||
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
|
||||
|
||||
672485 NEW https://bugzilla.redhat.com/show_bug.cgi?id=672485
|
||||
[RFE] virt-edit/tar/inspector do not support encrypted system
|
||||
|
||||
679737 NEW https://bugzilla.redhat.com/show_bug.cgi?id=679737
|
||||
libguestfs: improve error message when zerofree is not available in the appliance
|
||||
|
||||
745282 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745282
|
||||
[RFE] Support to use virt-filesystems with remote libvirt systems
|
||||
|
||||
507278 NEW https://bugzilla.redhat.com/show_bug.cgi?id=507278
|
||||
libguestfs fails to build on Fedora sparc64
|
||||
|
||||
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
|
||||
|
||||
592910 NEW https://bugzilla.redhat.com/show_bug.cgi?id=592910
|
||||
'guestfish --remote run' hangs in a shell command substitution context
|
||||
|
||||
593511 NEW https://bugzilla.redhat.com/show_bug.cgi?id=593511
|
||||
[RFE] function to get partition name
|
||||
|
||||
@@ -134,71 +56,224 @@ Bugs in NEW or ASSIGNED state are open and waiting for someone to fix.
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
693064 NEW https://bugzilla.redhat.com/show_bug.cgi?id=693064
|
||||
Symbolic links on ntfs-3g are not followed correctly by some commands
|
||||
|
||||
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
|
||||
|
||||
741183 NEW 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
|
||||
709326 NEW https://bugzilla.redhat.com/show_bug.cgi?id=709326
|
||||
virt-inspector cannot detect ReactOS
|
||||
|
||||
713678 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=713678
|
||||
Not all febootstrap messages are redirected to log callbacks
|
||||
737261 NEW https://bugzilla.redhat.com/show_bug.cgi?id=737261
|
||||
libguestfs grub-install API needs grub1
|
||||
|
||||
721160 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=721160
|
||||
Missing btrfs support
|
||||
745282 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745282
|
||||
[RFE] Support to use virt-filesystems with remote libvirt systems
|
||||
|
||||
583974 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=583974
|
||||
mount hangs there when you lack proper permission to guest image
|
||||
745576 NEW https://bugzilla.redhat.com/show_bug.cgi?id=745576
|
||||
libguestfs (or qemu?) hangs if sparse file runs out of disk space
|
||||
|
||||
647174 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=647174
|
||||
RHEL6: virt-clone should remove old udev rules when changing MAC address
|
||||
761565 NEW https://bugzilla.redhat.com/show_bug.cgi?id=761565
|
||||
Missing deps on netpbm-progs and icoutils
|
||||
|
||||
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
|
||||
770075 NEW https://bugzilla.redhat.com/show_bug.cgi?id=770075
|
||||
FEBOOTSTRAP_MODULES fails if modules directory is not under /lib
|
||||
|
||||
770076 NEW https://bugzilla.redhat.com/show_bug.cgi?id=770076
|
||||
FEBOOTSTRAP_KERNEL causes appliance build to fail
|
||||
|
||||
782167 NEW https://bugzilla.redhat.com/show_bug.cgi?id=782167
|
||||
libguestfs doesn't recognize Windows Dynamic disks in some configurations, eg. spanned
|
||||
|
||||
785603 NEW https://bugzilla.redhat.com/show_bug.cgi?id=785603
|
||||
copy-out can't find root directory
|
||||
|
||||
790837 NEW https://bugzilla.redhat.com/show_bug.cgi?id=790837
|
||||
Use of atexit to clean up handles is wrong in multithreaded programs
|
||||
|
||||
798979 NEW https://bugzilla.redhat.com/show_bug.cgi?id=798979
|
||||
Ubuntu install CDs from oneiric onwards are not recognized: "multi-boot operating systems are not supported"
|
||||
|
||||
801117 NEW https://bugzilla.redhat.com/show_bug.cgi?id=801117
|
||||
libguestfs cannot get icon for Windows 8 preview
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
811265 NEW https://bugzilla.redhat.com/show_bug.cgi?id=811265
|
||||
the list-filesystems can detect the reiserFS,but can not mount it.and minix filesystem too.
|
||||
|
||||
811395 NEW https://bugzilla.redhat.com/show_bug.cgi?id=811395
|
||||
virt-inspector to detect ia64 Windows 2k3 install media
|
||||
|
||||
811398 NEW https://bugzilla.redhat.com/show_bug.cgi?id=811398
|
||||
virt-inspector fails to detect Win2k, Win2k8, Win2k8r2, WinVista, Win7 install media
|
||||
|
||||
812970 NEW https://bugzilla.redhat.com/show_bug.cgi?id=812970
|
||||
virt-rescue cannot set ><rescue> prompt, on Ubuntu 12.04
|
||||
|
||||
813290 NEW https://bugzilla.redhat.com/show_bug.cgi?id=813290
|
||||
mdadm (md-detail) test occasionally fails with 'md device /dev/md125 does not appear to be active.'
|
||||
|
||||
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"
|
||||
|
||||
819086 NEW https://bugzilla.redhat.com/show_bug.cgi?id=819086
|
||||
look for qemu-kvm on /usr/libexec
|
||||
|
||||
822538 NEW https://bugzilla.redhat.com/show_bug.cgi?id=822538
|
||||
libguestfs tools hang on qcow2 encrypted disks
|
||||
|
||||
824021 NEW https://bugzilla.redhat.com/show_bug.cgi?id=824021
|
||||
inspection cannot recognize guest which uses btrfs subvolumes for root
|
||||
|
||||
824782 NEW https://bugzilla.redhat.com/show_bug.cgi?id=824782
|
||||
virt-resize cannot resize PowerPC guests
|
||||
|
||||
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
|
||||
|
||||
833362 NEW https://bugzilla.redhat.com/show_bug.cgi?id=833362
|
||||
virt-make-fs test fails on ppc64 because filesystem block size is 64k
|
||||
|
||||
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)
|
||||
|
||||
835622 NEW https://bugzilla.redhat.com/show_bug.cgi?id=835622
|
||||
virt-sparsify to LVM thin raw volume isn't sparse
|
||||
|
||||
837941 NEW https://bugzilla.redhat.com/show_bug.cgi?id=837941
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
838081 NEW https://bugzilla.redhat.com/show_bug.cgi?id=838081
|
||||
ocaml/t/guestfs_500_parallel_mount_local crashes in caml_thread_reinitialize
|
||||
|
||||
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.
|
||||
|
||||
843188 NEW https://bugzilla.redhat.com/show_bug.cgi?id=843188
|
||||
Ruby bindings segfault in event callbacks when the Ruby GC is invoked.
|
||||
|
||||
845234 NEW https://bugzilla.redhat.com/show_bug.cgi?id=845234
|
||||
RFE: virt-ls on Windows guest doesn't support drive letters
|
||||
|
||||
846676 NEW https://bugzilla.redhat.com/show_bug.cgi?id=846676
|
||||
guestfs_launch() hangs with Debian qemu-kvm 1.1.0
|
||||
|
||||
848464 NEW https://bugzilla.redhat.com/show_bug.cgi?id=848464
|
||||
gobject javascript bindings cannot use 64 bit integers
|
||||
|
||||
857763 NEW https://bugzilla.redhat.com/show_bug.cgi?id=857763
|
||||
libguestfs 'file-architecture' returns 'ARM' for arm binaries
|
||||
|
||||
863696 NEW https://bugzilla.redhat.com/show_bug.cgi?id=863696
|
||||
[F18] libguestfs fails to mount a disk image file(in this case qcow2) as 'root'
|
||||
|
||||
864871 NEW https://bugzilla.redhat.com/show_bug.cgi?id=864871
|
||||
libvirt error: could not create appliance through libvirt: unable to set security context 'unconfined_u:object_r:svirt_image_t:s0:cXXX,cYYY' on '.../console.sock'
|
||||
|
||||
865923 NEW https://bugzilla.redhat.com/show_bug.cgi?id=865923
|
||||
Check that new qemu -machine option doesn't break libguestfs.
|
||||
|
||||
866994 NEW https://bugzilla.redhat.com/show_bug.cgi?id=866994
|
||||
tgz-out causes memory leak in guestfsd
|
||||
|
||||
869179 NEW https://bugzilla.redhat.com/show_bug.cgi?id=869179
|
||||
libguestfs fail to startup on latest rhel7 tree
|
||||
|
||||
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
|
||||
|
||||
691389 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=691389
|
||||
Extended attributes don't work over guestmount (FUSE)
|
||||
|
||||
803643 ASSIGNED https://bugzilla.redhat.com/show_bug.cgi?id=803643
|
||||
inspect-is-multipart return false when inspection results should be true
|
||||
|
||||
(70 bugs)
|
||||
|
||||
--------------------------------------------------
|
||||
Bugs in MODIFIED, POST or ON_QA state are fixed.
|
||||
You can help by testing the fixes.
|
||||
|
||||
691389 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=691389
|
||||
Extended attributes don't work over guestmount (FUSE)
|
||||
837691 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=837691
|
||||
Data loss when writing to qcow2-format disk files
|
||||
|
||||
750889 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=750889
|
||||
Python code incompatible with Python v3.
|
||||
(1 bugs)
|
||||
|
||||
657499 MODIFIED https://bugzilla.redhat.com/show_bug.cgi?id=657499
|
||||
checksum: wrong check sum type causes umount to fail
|
||||
--------------------------------------------------
|
||||
These bugs are in the VERIFIED state.
|
||||
|
||||
749828 ON_QA https://bugzilla.redhat.com/show_bug.cgi?id=749828
|
||||
p2v does not support raid devices
|
||||
801640 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=801640
|
||||
[RFE] the error reported by resize2fs-M need to be more clear
|
||||
|
||||
816839 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=816839
|
||||
data overflow error when debug progress -1
|
||||
|
||||
822626 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=822626
|
||||
virt-ls error: "libguestfs: error: checksum: path: parameter cannot be NULL"
|
||||
|
||||
830135 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=830135
|
||||
libguestfs should support mount-local APIs in RHEL 6 (for OpenStack)
|
||||
|
||||
836501 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=836501
|
||||
dependency on fuse suggested
|
||||
|
||||
838609 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=838609
|
||||
guestmount + fusermount allows a race condition when unmounting and immediately using the disk image
|
||||
|
||||
853763 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=853763
|
||||
virt-sparsify should use a more robust method to detect the input format
|
||||
|
||||
858126 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858126
|
||||
virt-inspector fail to work with some windows guests
|
||||
|
||||
858128 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858128
|
||||
libguestfs fail to list devices added by add-drive-ro-with-if twice
|
||||
|
||||
858648 VERIFIED https://bugzilla.redhat.com/show_bug.cgi?id=858648
|
||||
libguestfs can not be installed with recent iptables
|
||||
|
||||
(10 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.
|
||||
|
||||
|
||||
228
Makefile.am
228
Makefile.am
@@ -15,6 +15,8 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
-include $(top_builddir)/localenv
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
@@ -37,16 +39,27 @@ if ENABLE_APPLIANCE
|
||||
SUBDIRS += tests/qemu
|
||||
SUBDIRS += tests/guests
|
||||
SUBDIRS += tests/c-api
|
||||
SUBDIRS += tests/tmpdirs
|
||||
SUBDIRS += tests/protocol
|
||||
SUBDIRS += tests/parallel
|
||||
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/rsync
|
||||
SUBDIRS += tests/bigdirs
|
||||
SUBDIRS += tests/disk-labels
|
||||
SUBDIRS += tests/hotplug
|
||||
SUBDIRS += tests/regressions
|
||||
endif
|
||||
|
||||
# Extra tests don't run by default. You have to do 'make extra-tests'.
|
||||
SUBDIRS += tests/extra
|
||||
|
||||
# libguestfs-test-tool
|
||||
SUBDIRS += test-tool
|
||||
|
||||
@@ -81,6 +94,9 @@ endif
|
||||
if HAVE_ERLANG
|
||||
SUBDIRS += erlang erlang/examples
|
||||
endif
|
||||
if HAVE_LUA
|
||||
SUBDIRS += lua lua/examples
|
||||
endif
|
||||
if HAVE_GOBJECT
|
||||
SUBDIRS += gobject
|
||||
endif
|
||||
@@ -88,9 +104,9 @@ endif
|
||||
# Unconditional because nothing is built yet.
|
||||
SUBDIRS += csharp
|
||||
|
||||
# virt-resize (new version) and virt-sparsify are written in OCaml.
|
||||
# OCaml tools.
|
||||
if HAVE_OCAML
|
||||
SUBDIRS += resize sparsify
|
||||
SUBDIRS += resize sparsify sysprep
|
||||
endif
|
||||
|
||||
# Perl tools.
|
||||
@@ -103,11 +119,6 @@ if HAVE_FUSE
|
||||
SUBDIRS += fuse
|
||||
endif
|
||||
|
||||
# virt-tools in shell. This uses guestmount and virt-inspector.
|
||||
if HAVE_FUSE
|
||||
SUBDIRS += clone
|
||||
endif
|
||||
|
||||
# po-docs must come after tools, inspector.
|
||||
if HAVE_PO4A
|
||||
SUBDIRS += po-docs
|
||||
@@ -115,17 +126,27 @@ endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(generator_built) \
|
||||
BUGS HACKING RELEASE-NOTES ROADMAP TODO \
|
||||
BUGS HACKING ROADMAP TODO \
|
||||
.gitignore \
|
||||
.lvimrc \
|
||||
.tx/config \
|
||||
bugs-in-changelog.sh \
|
||||
autogen.sh \
|
||||
bindtests \
|
||||
contrib/autobuild/autobuild.sh \
|
||||
contrib/guestfsd-in-wine.sh \
|
||||
contrib/intro/libguestfs-intro.html \
|
||||
contrib/intro/overview.png \
|
||||
contrib/intro/overview.svg \
|
||||
contrib/intro/talk.txt \
|
||||
contrib/intro/tools.png \
|
||||
contrib/intro/tools.svg \
|
||||
contrib/intro/virt-manager-t.png \
|
||||
contrib/intro/virt-manager.png \
|
||||
contrib/intro/vmm-icons-t.png \
|
||||
contrib/intro/vmm-icons.png \
|
||||
contrib/intro/win7.xml \
|
||||
contrib/make-check-on-installed.pl \
|
||||
contrib/README \
|
||||
contrib/visualize-alignment/.gitignore \
|
||||
contrib/visualize-alignment/guestfish-add-mount.qtr \
|
||||
@@ -137,55 +158,40 @@ EXTRA_DIST = \
|
||||
contrib/visualize-alignment/qemu-0.13-trace-block-device-access.patch \
|
||||
contrib/visualize-alignment/README \
|
||||
contrib/visualize-alignment/tracetops.ml \
|
||||
debian/.gitignore \
|
||||
debian/changelog \
|
||||
debian/compat \
|
||||
debian/control \
|
||||
debian/copyright \
|
||||
debian/docs \
|
||||
debian/guestfish.dirs \
|
||||
debian/guestfish.install \
|
||||
debian/guestfsd.dirs \
|
||||
debian/guestfsd.install \
|
||||
debian/guestmount.dirs \
|
||||
debian/guestmount.install \
|
||||
debian/libguestfs-dev.dirs \
|
||||
debian/libguestfs-dev.install \
|
||||
debian/libguestfs-doc.docs \
|
||||
debian/libguestfs-perl.examples \
|
||||
debian/libguestfs-perl.install \
|
||||
debian/libguestfs-tools.dirs \
|
||||
debian/libguestfs-tools.install \
|
||||
debian/libguestfs0.dirs \
|
||||
debian/libguestfs0.install \
|
||||
debian/patches/series \
|
||||
debian/python-guestfs.install \
|
||||
debian/pyversions \
|
||||
debian/rules \
|
||||
debian/shlibs.local \
|
||||
debian/watch \
|
||||
guestfs-release-notes.pod \
|
||||
guestfs-release-notes.txt \
|
||||
html/draft.png \
|
||||
html/draft.svg \
|
||||
html/pod.css \
|
||||
libguestfs.pc libguestfs.pc.in \
|
||||
libtool-kill-dependency_libs.sh \
|
||||
logo/fish.svg logo/fish.png \
|
||||
m4/.gitignore \
|
||||
run \
|
||||
update-bugs.sh
|
||||
tmp/.gitignore \
|
||||
tx-pull.sh \
|
||||
update-bugs.sh \
|
||||
valgrind-suppressions
|
||||
|
||||
# The website.
|
||||
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-lua.3.html \
|
||||
html/guestfs-ocaml.3.html \
|
||||
html/guestfs-performance.1.html \
|
||||
html/guestfs-perl.3.html \
|
||||
html/guestfs-python.3.html \
|
||||
html/guestfs-recipes.1.html \
|
||||
html/guestfs-release-notes.1.html \
|
||||
html/guestfs-ruby.3.html \
|
||||
html/guestfs-testing.1.html \
|
||||
html/guestfsd.8.html \
|
||||
html/guestfish.1.html \
|
||||
html/guestmount.1.html \
|
||||
html/libguestfs-make-fixed-appliance.1.html \
|
||||
html/libguestfs-test-tool.1.html \
|
||||
html/virt-alignment-scan.1.html \
|
||||
html/virt-cat.1.html \
|
||||
html/virt-copy-in.1.html \
|
||||
@@ -208,7 +214,9 @@ HTMLFILES = \
|
||||
html/virt-tar-out.1.html \
|
||||
html/virt-win-reg.1.html
|
||||
|
||||
TEXTFILES = BUGS README RELEASE-NOTES ROADMAP TODO
|
||||
HTMLSUPPORTFILES = html/draft.png html/pod.css
|
||||
|
||||
TEXTFILES = BUGS README ROADMAP TODO
|
||||
|
||||
WEBSITEDIR = $(HOME)/d/redhat/websites/libguestfs
|
||||
|
||||
@@ -217,7 +225,7 @@ WEBSITEDIR = $(HOME)/d/redhat/websites/libguestfs
|
||||
website: $(HTMLFILES) $(TEXTFILES)
|
||||
find -name 'stamp-*.pod' -delete
|
||||
$(MAKE)
|
||||
cp $(HTMLFILES) $(WEBSITEDIR)
|
||||
cp $(HTMLFILES) $(HTMLSUPPORTFILES) $(WEBSITEDIR)
|
||||
for f in $(TEXTFILES); do cp $$f $(WEBSITEDIR)/$$f.txt; done
|
||||
cd $(WEBSITEDIR) && \
|
||||
date=`date +%F`; \
|
||||
@@ -239,7 +247,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) \
|
||||
@@ -253,43 +263,135 @@ all-local:
|
||||
grep -v '^perl/examples/' | \
|
||||
grep -v '/guestfs_protocol.c' | \
|
||||
grep -v '/rc_protocol.c' | \
|
||||
grep -v 'appliance/debian/root' | \
|
||||
grep -v '^po-docs/' | \
|
||||
grep -v '^images/' | \
|
||||
LC_ALL=C sort | \
|
||||
sed 's,^\./,,' > po/POTFILES.in
|
||||
sed 's,^\./,,' > po/POTFILES
|
||||
cd $(srcdir); \
|
||||
find resize sparsify sysprep -name '*.ml' | \
|
||||
LC_ALL=C sort > po/POTFILES-ml
|
||||
|
||||
# Pkgconfig.
|
||||
# Manual pages in top level directory.
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libguestfs.pc
|
||||
man_MANS = \
|
||||
guestfs-release-notes.1
|
||||
noinst_DATA = \
|
||||
$(top_builddir)/html/guestfs-release-notes.1.html
|
||||
|
||||
guestfs-release-notes.1 guestfs-release-notes.txt $(top_builddir)/html/guestfs-release-notes.1.html: stamp-guestfs-release-notes.pod
|
||||
|
||||
stamp-guestfs-release-notes.pod: guestfs-release-notes.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 1 \
|
||||
--man guestfs-release-notes.1 \
|
||||
--text guestfs-release-notes.txt \
|
||||
--html $(top_builddir)/html/guestfs-release-notes.1.html \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# Make clean.
|
||||
|
||||
CLEANFILES = \
|
||||
html/*.html \
|
||||
pod2htm?.tmp \
|
||||
html/*.html
|
||||
qemu-wrapper.sh \
|
||||
stamp-guestfs-release-notes.pod
|
||||
|
||||
# If you don't want to run all of the tests ('make check') then this
|
||||
# will just run libguestfs-test-tool for a quick check. Note this
|
||||
# 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.
|
||||
# Non-standard tests.
|
||||
|
||||
extra-tests:
|
||||
make -C tests/extra $@
|
||||
$(MAKE) -j1 \
|
||||
valgrind \
|
||||
valgrind-local-guests \
|
||||
check-with-appliance \
|
||||
check-with-upstream-qemu \
|
||||
check-with-upstream-libvirt \
|
||||
check-slow
|
||||
|
||||
# Make binary distribution.
|
||||
check-valgrind: build-test-guests
|
||||
@for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) -C `dirname $$f` $@; \
|
||||
$(MAKE) -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
|
||||
BINTMPDIR = /tmp/libguestfs-bin
|
||||
bindist:
|
||||
rm -rf $(BINTMPDIR)
|
||||
mkdir $(BINTMPDIR)
|
||||
$(MAKE)
|
||||
$(MAKE) DESTDIR=$(BINTMPDIR) install
|
||||
-find $(BINTMPDIR) -type d -exec rmdir --ignore-fail-on-non-empty {} \;
|
||||
(cd $(BINTMPDIR) && tar cf - .) | \
|
||||
gzip -c -9 > libguestfs-$(VERSION)-$(DISTRO)-$(host_cpu).tar.gz
|
||||
check-valgrind-local-guests:
|
||||
@GUESTS=`$(top_builddir)/run ./pick-guests.pl 5`; \
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) GUESTS="$$GUESTS" -C `dirname $$f` $@; \
|
||||
$(MAKE) GUESTS="$$GUESTS" -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
|
||||
check-slow: build-test-guests
|
||||
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
|
||||
echo $(MAKE) -C `dirname $$f` $@; \
|
||||
$(MAKE) -C `dirname $$f` $@ || exit $$?; \
|
||||
done
|
||||
|
||||
build-test-guests:
|
||||
$(MAKE) -C tests/guests check
|
||||
|
||||
check-with-appliance:
|
||||
@method=`$(top_builddir)/run ./fish/guestfish get-attach-method`; \
|
||||
if [ "$$method" != "appliance" ]; then \
|
||||
$(MAKE) LIBGUESTFS_ATTACH_METHOD=appliance check || exit $$?; \
|
||||
fi
|
||||
|
||||
QEMUDIR = $(HOME)/d/qemu
|
||||
QEMUBINARY = $(QEMUDIR)/x86_64-softmmu/qemu-system-x86_64
|
||||
|
||||
check-with-upstream-qemu:
|
||||
@if $(QEMUBINARY) --help >/dev/null 2>&1; then \
|
||||
$(MAKE) check-with-upstream-qemu-1 || exit $$?; \
|
||||
fi
|
||||
|
||||
check-with-upstream-qemu-1: $(top_builddir)/qemu-wrapper.sh
|
||||
$(QEMUBINARY) --version
|
||||
$(MAKE) LIBGUESTFS_QEMU=$(top_builddir)/qemu-wrapper.sh check
|
||||
|
||||
$(top_builddir)/qemu-wrapper.sh: Makefile
|
||||
rm -f $@ $@-t
|
||||
echo exec "$(QEMUBINARY)" -L "$(QEMUDIR)/pc-bios" "$$@" > $@-t
|
||||
chmod +x,-w $@-t
|
||||
mv $@-t $@
|
||||
|
||||
LIBVIRTDIR = $(HOME)/d/libvirt
|
||||
|
||||
check-with-upstream-libvirt:
|
||||
@method=`$(top_builddir)/run ./fish/guestfish get-attach-method`; \
|
||||
if [ "$$method" = "libvirt" ] && [ -x "$(LIBVIRTDIR)/run" ]; then \
|
||||
$(LIBVIRTDIR)/run $(MAKE) check || exit $$?; \
|
||||
fi
|
||||
|
||||
# Provide help on common Makefile targets.
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo "make Build everything."
|
||||
@echo
|
||||
@echo "make check Run the standard tests."
|
||||
@echo "make check-valgrind Run a subset of the tests under valgrind."
|
||||
@echo "make check-valgrind-local-tests Test under valgrind using local guests."
|
||||
@echo "make check-with-appliance Test using appliance attach-method."
|
||||
@echo "make check-with-upstream-qemu Test using upstream qemu."
|
||||
@echo "make check-with-upstream-libvirt Test using upstream libvirt."
|
||||
@echo "make check-slow Slow/long-running tests."
|
||||
@echo "make extra-tests Same as check-* (but not 'make check')"
|
||||
@echo "make syntax-check Check syntax and style problems in the code."
|
||||
@echo
|
||||
@echo "make install Install everything."
|
||||
@echo
|
||||
@echo "make clean Clean everything."
|
||||
@echo
|
||||
@echo "To run programs without installing:"
|
||||
@echo " ./run ./fish/guestfish [or any other program]"
|
||||
@echo
|
||||
@echo "For more information, see EXTENDING LIBGUESTFS in guestfs(3); and README."
|
||||
@echo
|
||||
|
||||
124
README
124
README
@@ -26,9 +26,18 @@ Fedora/RHEL users:
|
||||
|
||||
Debian/Ubuntu users:
|
||||
|
||||
Take a look at the debian/control file and install everything listed
|
||||
in "Build-Depends". If that is successful, you don't need to bother
|
||||
with the rest of this section.
|
||||
Use:
|
||||
|
||||
apt-get build-dep libguestfs
|
||||
|
||||
to install all build dependencies. If that doesn't work, take a
|
||||
look at the Debian source package:
|
||||
http://packages.debian.org/source/libguestfs
|
||||
at the list of 'build-depends' and 'build-depends-indep', and
|
||||
install everything listed there.
|
||||
|
||||
If either of those techniques is successful, you don't need to
|
||||
bother with the rest of this section.
|
||||
|
||||
The full requirements are described below.
|
||||
|
||||
@@ -37,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.
|
||||
|
||||
@@ -46,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.20
|
||||
|
||||
Notes: (1) febootstrap 2.x WILL NOT WORK
|
||||
(2) febootstrap 3.x is distro-independent, and is required on
|
||||
Debian and other distros as well as Fedora
|
||||
(3) that is the minimum version, but later versions are better
|
||||
|
||||
- XDR, rpcgen (on Linux these are provided by glibc)
|
||||
|
||||
@@ -66,7 +76,7 @@ For basic functionality and the C tools:
|
||||
|
||||
- libmagic (the library that corresponds to the 'file' command) (optional)
|
||||
|
||||
- libvirt (optional)
|
||||
- libvirt (optional, >= 0.10.2 to use the libvirt launch method)
|
||||
|
||||
- libxml2 (optional)
|
||||
|
||||
@@ -80,16 +90,19 @@ 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)
|
||||
|
||||
- xmllint (part of libxml2) to validate virt-inspector
|
||||
RELAX NG schema (optional)
|
||||
|
||||
- OCaml if you want to rebuild the generated files, and
|
||||
also to build the OCaml bindings (optional)
|
||||
- OCaml compiler. Optional when compiling from the tarball, but
|
||||
mandatory if you compile from git.
|
||||
|
||||
- ocaml-gettext if you want to translate OCaml tools (optional)
|
||||
|
||||
- po4a for translating manpages and POD files.
|
||||
This is optional when compiling from the tarball, but mandatory
|
||||
@@ -97,12 +110,20 @@ For basic functionality and the C tools:
|
||||
|
||||
- getfacl, getfattr libraries and programs (optional)
|
||||
|
||||
To build FUSE support (guestmount):
|
||||
- netpbm, icoutils (optional)
|
||||
These programs are used to render icons from guests.
|
||||
|
||||
- Perl Expect module (optional)
|
||||
This is used to test virt-rescue.
|
||||
|
||||
To build FUSE support in the core library, and guestmount:
|
||||
|
||||
- FUSE libraries and kernel module (optional)
|
||||
|
||||
To build language bindings:
|
||||
|
||||
- OCaml compiler to build the OCaml bindings (optional, but see above)
|
||||
|
||||
- Perl if you want to build the perl bindings (optional)
|
||||
|
||||
- Python if you want to build the python bindings (optional)
|
||||
@@ -130,10 +151,6 @@ To build the Perl tools:
|
||||
|
||||
- perl-libintl for translating perl code (optional)
|
||||
|
||||
To run virt-sysprep:
|
||||
|
||||
- virt-sysprep requires FUSE support since it uses guestmount
|
||||
|
||||
|
||||
Building
|
||||
----------------------------------------------------------------------
|
||||
@@ -147,13 +164,19 @@ Finally run the tests:
|
||||
|
||||
make check
|
||||
|
||||
There are some extra tests, but these require that you have some
|
||||
libvirt guests installed, that these guests' disks are accessible by
|
||||
the current user, and these tests may fail for other reasons which are
|
||||
not necessarily because of real problems. If you want to run these
|
||||
extra tests do:
|
||||
Also:
|
||||
|
||||
make extra-tests
|
||||
make check-valgrind
|
||||
|
||||
runs a subset of the test suite under valgrind (requires valgrind to
|
||||
be installed obviously).
|
||||
|
||||
make extra-tests
|
||||
|
||||
runs check-valgrind + even more tests, but these require that you have
|
||||
some libvirt guests installed, that these guests' disks are accessible
|
||||
by the current user, and these tests may fail for other reasons which
|
||||
are not necessarily because of real problems.
|
||||
|
||||
If everything works, you can install the library and tools by running
|
||||
this command as root:
|
||||
@@ -161,8 +184,8 @@ this command as root:
|
||||
make install
|
||||
|
||||
You can run guestfish, guestmount and the virt tools without needing
|
||||
to install, using the "run" script in the top directory. This script
|
||||
sets up some environment variables. For example:
|
||||
to install, using the "./run" script in the top directory. This
|
||||
script sets up some environment variables. For example:
|
||||
|
||||
./run ./fish/guestfish [usual guestfish args ...]
|
||||
|
||||
@@ -185,6 +208,10 @@ You can also run the C programs under valgrind like this:
|
||||
|
||||
./run valgrind [valgrind opts...] ./cat/virt-cat [virt-cat opts...]
|
||||
|
||||
or under gdb:
|
||||
|
||||
./run gdb --args ./cat/virt-cat [virt-cat opts...]
|
||||
|
||||
This also works with sudo (eg. if you need root access for libvirt or
|
||||
to access a block device):
|
||||
|
||||
@@ -220,7 +247,7 @@ these instructions:
|
||||
|
||||
On some systems, this will work too:
|
||||
|
||||
chmod o+rw /dev/kvm
|
||||
chmod 0666 /dev/kvm
|
||||
|
||||
On some systems, the chmod will not survive a reboot, and you will
|
||||
need to make edits to the udev configuration.
|
||||
@@ -258,6 +285,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
|
||||
----------------------------------------------------------------------
|
||||
|
||||
@@ -266,3 +340,5 @@ Copyright (C) 2009-2012 Red Hat Inc.
|
||||
The library is distributed under the LGPLv2+. The programs are
|
||||
distributed under the GPLv2+. Please see the files COPYING and
|
||||
COPYING.LIB for full license information.
|
||||
|
||||
The examples are under a very liberal license.
|
||||
|
||||
23
ROADMAP
23
ROADMAP
@@ -3,7 +3,7 @@ Roadmap for future releases
|
||||
|
||||
Before you read this:
|
||||
|
||||
(1) To see what's in the current release, read 'RELEASE-NOTES'.
|
||||
(1) To see what's in the current release, read 'guestfs-release-notes(1)'.
|
||||
|
||||
(2) To see the list of bugs, read 'BUGS'.
|
||||
|
||||
@@ -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
|
||||
@@ -33,20 +33,7 @@ Beyond 1.18
|
||||
for 1.10 but there's not nearly enough adoption of the new
|
||||
'guestfish --rw' option out there to do this yet.
|
||||
|
||||
* Allow alternate methods to start the appliance, including through
|
||||
libvirt, by connecting to an existing appliance, and remotely over
|
||||
ssh. Libvirt integration was originally planned for 1.10 but we
|
||||
didn't get patches in time.
|
||||
|
||||
* Write a new partition handling library to replace parted, and use it
|
||||
instead of parted. (RHBZ#593511, RHBZ#642821).
|
||||
|
||||
* Hot plugging of disks using QMP. This would allow more efficient
|
||||
reuse of the appliance in some circumstances: multiple disks
|
||||
(ie. VMs) can be added in turn to the same appliance. In particular
|
||||
this would help virt-df.
|
||||
|
||||
[Note this requires upstream work on QMP, see:
|
||||
https://www.redhat.com/archives/libguestfs/2011-March/msg00124.html]
|
||||
|
||||
See TODO and BUGS files.
|
||||
|
||||
373
TODO
373
TODO
@@ -43,75 +43,36 @@ data, at least partially. This would be just another output type so:
|
||||
Note that recent versions of libvirt/virt-install allow guests to be
|
||||
imported, so this is not so useful any more.
|
||||
|
||||
"Standalone/local mode"
|
||||
-----------------------
|
||||
|
||||
Instead of running guestfsd (the daemon) inside qemu, there should be
|
||||
an option to just run guestfsd directly.
|
||||
|
||||
The architecture in this mode would look like:
|
||||
|
||||
+------------------+
|
||||
| main program |
|
||||
|------------------|
|
||||
| libguestfs |
|
||||
+--------^---------+
|
||||
| | reply
|
||||
cmd | |
|
||||
+----v-------------+
|
||||
| guestfsd |
|
||||
+------------------+
|
||||
|
||||
Notes:
|
||||
|
||||
(1) This only makes sense if we are running as root.
|
||||
|
||||
(2) There is no console / kernel messages in this configuration, but
|
||||
we might consider capturing stderr from the daemon.
|
||||
|
||||
(3) guestfs_config and guestfs_add_drive become no-ops.
|
||||
|
||||
Obviously in this configuration, commands are run directly on the
|
||||
local machine's disks. You could just run the commands themselves
|
||||
directly, but libguestfs provides a convenient API and language
|
||||
bindings. Also deals with tricky stuff like parsing the output of the
|
||||
LVM commands. Also we get to leverage other code such as
|
||||
virt-inspector.
|
||||
|
||||
This is mainly useful from live CDs, ie. virt-p2v.
|
||||
|
||||
Should we bother having the daemon at all and just link the guestfsd
|
||||
code directly into libguestfs?
|
||||
|
||||
Ideas for extra commands
|
||||
------------------------
|
||||
|
||||
General glibc / core programs:
|
||||
chgrp
|
||||
more mk*temp calls
|
||||
|
||||
ext2 properties:
|
||||
chattr
|
||||
lsattr
|
||||
badblocks
|
||||
debugfs
|
||||
dumpe2fs
|
||||
e2image
|
||||
e2undo
|
||||
filefrag
|
||||
findfs
|
||||
logsave
|
||||
mklost+found
|
||||
|
||||
SELinux:
|
||||
chcat
|
||||
restorecon
|
||||
ch???
|
||||
[Wanlong Gao submitted patches for restorecon, but
|
||||
there are problems with using the restorecon binary
|
||||
from the host on the guest. Most of the time it
|
||||
would do more harm than good.]
|
||||
setfiles
|
||||
|
||||
Oddball:
|
||||
pivot_root
|
||||
fts(3) / ftw(3)
|
||||
|
||||
sh-in, sh-out: run shell command with large input/output
|
||||
debug sh-in, debug sh-out: debug versions of the above
|
||||
|
||||
Other initrd-* commands
|
||||
-----------------------
|
||||
|
||||
@@ -120,74 +81,6 @@ Such as:
|
||||
initrd-extract
|
||||
initrd-replace
|
||||
|
||||
Simple editing of configuration files
|
||||
-------------------------------------
|
||||
|
||||
Some easy non-Augeas methods to edit configuration files.
|
||||
I'm thinking:
|
||||
|
||||
replace /etc/file key value
|
||||
|
||||
which would look in /etc/file for any instances of
|
||||
|
||||
key=...
|
||||
key ...
|
||||
key:...
|
||||
|
||||
and replace them with
|
||||
|
||||
key=value
|
||||
key value
|
||||
key:value
|
||||
|
||||
That would solve about 50% of reconfiguration needs, and for the
|
||||
rest you'd use Augeas, 'download'+'upload' or 'edit'.
|
||||
|
||||
RWMJ: I had a go at implementing this, but it's quite error-prone to
|
||||
do this sort of editing inside the C-based daemon code. It's far
|
||||
better to do it with Augeas, or else to use an external language like
|
||||
Perl.
|
||||
|
||||
Quick Perl scripts
|
||||
------------------
|
||||
|
||||
Currently we can't do Perl "one-liners". ie. The current syntax for
|
||||
any short Perl one-liner would be:
|
||||
|
||||
perl -MSys::Guestfs -e '$g = Sys::Guestfs->new(); $g->add_drive ("foo"); $g->launch; $g->mount ("/dev/sda1", "/"); ....'
|
||||
|
||||
You can see we're well beyond a single line just getting to the point
|
||||
of adding drives and mounting.
|
||||
|
||||
First suggestion:
|
||||
|
||||
$h = create ($filename, \"/dev/sda1\" => \"/\");
|
||||
|
||||
$h = create ([$file1, $file2], \"/dev/sda1\" => \"/\");
|
||||
|
||||
To mount read-only, add C<ro =E<gt> 1> like this:
|
||||
|
||||
$h = create ($filename, \"/dev/sda1\" => \"/\", ro => 1);
|
||||
|
||||
which is equivalent to the following sequence of calls:
|
||||
|
||||
$h = Sys::Guestfs->new ();
|
||||
$h->add_drive_ro ($filename);
|
||||
$h->launch ();
|
||||
$h->mount_ro (\"/dev/sda1\", \"/\");
|
||||
|
||||
Command-line form would be:
|
||||
|
||||
perl -MSys::Guestfs=:all -e '$_=create("guest.img", "/dev/sda1" => "/"); $_->cat ("/etc/fstab");'
|
||||
|
||||
That's not brief enough for one-liners, so we could have an extra
|
||||
autogenerated module which creates a Sys::Guestfs handle singleton
|
||||
(the handle is an implicit global variable as in guestfish), eg:
|
||||
|
||||
perl -MSys::Guestfs::One -e 'inspect("guest.img"); cat ("/etc/fstab");'
|
||||
|
||||
How would editing files work?
|
||||
|
||||
virt-rescue pty
|
||||
---------------
|
||||
|
||||
@@ -208,14 +101,6 @@ Windows-based daemon/appliance
|
||||
See discussion on list:
|
||||
https://www.redhat.com/archives/libguestfs/2009-November/msg00165.html
|
||||
|
||||
qemu locking
|
||||
------------
|
||||
|
||||
Add -drive file=...,lock=exclusive and -drive file=...,lock=shared
|
||||
|
||||
Change libguestfs and libvirt to do the right thing, so that multiple
|
||||
instances of qemu cannot stomp on each other.
|
||||
|
||||
virt-disk-explore
|
||||
-----------------
|
||||
|
||||
@@ -256,12 +141,6 @@ http://sourceforge.net/projects/aide/
|
||||
http://osiris.shmoo.com/
|
||||
http://sourceforge.net/projects/tripwire/
|
||||
|
||||
Fix 'file'
|
||||
----------
|
||||
|
||||
https://www.redhat.com/archives/libguestfs/2010-June/msg00053.html
|
||||
https://www.redhat.com/archives/libguestfs/2010-June/msg00079.html
|
||||
|
||||
Freeze/thaw filesystems
|
||||
-----------------------
|
||||
|
||||
@@ -293,13 +172,6 @@ Could we make guestfish interactive if commands are used without params?
|
||||
Image name? disk.img
|
||||
Size of image? 10M
|
||||
|
||||
Common problems
|
||||
---------------
|
||||
|
||||
How can we solve these common user problems?
|
||||
|
||||
[space for common problems here]
|
||||
|
||||
Better support for encrypted devices
|
||||
------------------------------------
|
||||
|
||||
@@ -318,8 +190,6 @@ Display the structure of an image file as a PS.
|
||||
Greater use of blkid / libblkid
|
||||
-------------------------------
|
||||
|
||||
guestfs_zero should use wipefs. See wipefs(8).
|
||||
|
||||
There are various useful functions in libblkid for listing partitions,
|
||||
devices etc which we are essentially duplicating in the daemon. It
|
||||
would make more sense to just use libblkid for this.
|
||||
@@ -327,6 +197,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
|
||||
-------------
|
||||
|
||||
@@ -371,23 +244,13 @@ $EDITOR without any corresponding ability to set them.
|
||||
echo $EDITOR # or %{EDITOR}
|
||||
edit /etc/resolv.conf
|
||||
|
||||
live CD inspection for Windows 7
|
||||
--------------------------------
|
||||
|
||||
Windows 7 install CDs are quite different and pretty impenetrable.
|
||||
There are no obvious files to parse.
|
||||
|
||||
More ntfs tools
|
||||
---------------
|
||||
|
||||
ntfsprogs actually has a lot more useful tools than we currently
|
||||
use. Interesting ones are:
|
||||
|
||||
ntfslabel: display or change filesystem label (we should unify all
|
||||
set*label APIs into a single set_vfs_label which can deal with any
|
||||
filesystem)
|
||||
|
||||
ntfsclone: clone, image, restore, rescue NTFS
|
||||
ntfscluster: display file(s) that occupy a cluster or sector
|
||||
|
||||
ntfsinfo: print various information about NTFS volume and files
|
||||
|
||||
@@ -510,23 +373,6 @@ would be some sort of modified attach method (see link above).
|
||||
The complexity here is that we would no longer have access to
|
||||
stdin/stdout (or we'd have to direct that somewhere else).
|
||||
|
||||
GObject Introspection
|
||||
---------------------
|
||||
|
||||
We periodically get asked to implement gobject-introspection (it's a
|
||||
GNOME thing):
|
||||
|
||||
http://live.gnome.org/GObjectIntrospection
|
||||
|
||||
This would require a separate Gtk C API since the main guestfs handle
|
||||
would have to be encapsulated in a GObject. However the main
|
||||
difficulty is that the annotations supported to define types are not
|
||||
very rich. Notably missing are support for optional arguments
|
||||
(defined but not implemented), support for structs (unless mapped to
|
||||
other objects).
|
||||
|
||||
Also note that the libguestfs API is not "object oriented".
|
||||
|
||||
libosinfo mappings for virt-inspector
|
||||
-------------------------------------
|
||||
|
||||
@@ -535,21 +381,11 @@ 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
|
||||
- homedirs/.ssh directory, especially /root/.ssh (Steve Grubb)
|
||||
- if drives are encrypted, then dm-crypt key should be changed
|
||||
and drives all re-encrypted
|
||||
- /etc/pki
|
||||
@@ -560,17 +396,33 @@ virt-sysprep ideas
|
||||
that you would want to look into.
|
||||
- secure erase of inodes etc using scrub (Steve Grubb)
|
||||
- other directories that could require cleaning include:
|
||||
/var/cache/gdm/*
|
||||
/var/lib/fprint/*
|
||||
/var/run/*
|
||||
/var/lib/AccountService/users/*
|
||||
/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:
|
||||
|
||||
- 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)
|
||||
- Windows login script/service
|
||||
|
||||
Launch remote sessions over ssh
|
||||
-------------------------------
|
||||
|
||||
@@ -601,3 +453,160 @@ to do a kind of migration of guests by simply recreating the guest
|
||||
from the description on the target machine.
|
||||
|
||||
It would be ideal to integrate this and/or use inspection to do this.
|
||||
|
||||
Ongoing code cleanups
|
||||
---------------------
|
||||
|
||||
Examine every use of 'int' in C code for signed overflow problems.
|
||||
|
||||
All file descriptors in the library and daemon should normally be
|
||||
opened with O_CLOEXEC. Therefore we need to examine every call to:
|
||||
|
||||
- open, openat
|
||||
- creat
|
||||
- pipe (see also: pipe2)
|
||||
- dup, dup2 (see also: dup3)
|
||||
- socket, socketpair
|
||||
- accept (see also: accept4)
|
||||
- signalfd, timerfd, epoll_create
|
||||
|
||||
virt-sparsify enhancements
|
||||
--------------------------
|
||||
|
||||
TMPDIR should be checked to ensure that we won't run out of space
|
||||
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.
|
||||
|
||||
Reimplement some APIs to avoid protocol limits
|
||||
----------------------------------------------
|
||||
|
||||
We should reimplement the following APIs to avoid protocol limits.
|
||||
These would be changed from daemon_functions to non_daemon_functions,
|
||||
with the non-daemon versions implemented using guestfs_upload and
|
||||
guestfs_download (and others). This change should be transparent from
|
||||
the p.o.v of the API and ABI.
|
||||
|
||||
- guestfs_readdir
|
||||
|
||||
hivex
|
||||
-----
|
||||
|
||||
Add more of hivex to the API, especially for writing.
|
||||
|
||||
Reimplement virt-win-reg to use this API. (This is difficult because
|
||||
the Perl libraries underneath access the hivex API directly).
|
||||
|
||||
ruby
|
||||
----
|
||||
|
||||
Implement blocking calls. The API for this:
|
||||
|
||||
http://www.spacevatican.org/2012/7/5/whos-afraid-of-the-big-bad-lock/
|
||||
|
||||
is very poorly designed and essentially impossible for us to use:
|
||||
|
||||
https://bugs.ruby-lang.org/issues/5543
|
||||
|
||||
particularly if we also want to maintain backwards compatibility with
|
||||
Ruby 1.8, and/or maintain volatile VALUEs on the stack.
|
||||
|
||||
ACLs and capabilities
|
||||
---------------------
|
||||
|
||||
We need to model both filesystem ACLs and filesystem capabilities
|
||||
through the API. This is particularly important in order to be able
|
||||
to implement SCAP.
|
||||
|
||||
ACLs can be read and written using the acl(5) library and the
|
||||
functions like acl_set_file(3) etc.
|
||||
|
||||
Setting the ACL on a file sets the extended attribute
|
||||
'system.posix_acl_access' to a binary blob. The kernel has a whole
|
||||
bunch of complex code that seems to interpret these
|
||||
(linux/fs/posix_acl.c).
|
||||
|
||||
Filesystem capabilities can be read and written using the libcap(3)
|
||||
library and functions like cap_get_file, cap_set_file.
|
||||
|
||||
Setting fs capabilities on a file sets the extended attribute
|
||||
'security.capability' to a binary blob. These are implemented using a
|
||||
Linux Security Module (security/capability.c) and presumably by
|
||||
something in exec, but I couldn't see exactly how this works.
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-virt-alignment-scan.sh \
|
||||
virt-alignment-scan.pod
|
||||
|
||||
CLEANFILES = stamp-virt-alignment-scan.pod
|
||||
@@ -26,15 +27,17 @@ 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) \
|
||||
scan.c
|
||||
domains.c \
|
||||
scan.c \
|
||||
scan.h
|
||||
|
||||
virt_alignment_scan_CFLAGS = \
|
||||
-DGUESTFS_WARN_DEPRECATED=1 \
|
||||
@@ -60,18 +63,23 @@ 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 \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# Tests.
|
||||
|
||||
# random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
# TESTS_ENVIRONMENT = \
|
||||
# MALLOC_PERTURB_=$(random_val) \
|
||||
# $(top_builddir)/run
|
||||
TESTS =
|
||||
|
||||
# TESTS = test-virt-alignment-scan.sh
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS += \
|
||||
test-virt-alignment-scan.sh
|
||||
endif
|
||||
|
||||
check-valgrind:
|
||||
$(MAKE) VG="$(top_builddir)/run @VG@" check
|
||||
|
||||
359
align/domains.c
Normal file
359
align/domains.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/* virt-alignment-scan
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#ifdef HAVE_LIBVIRT
|
||||
#include <libvirt/libvirt.h>
|
||||
#include <libvirt/virterror.h>
|
||||
#endif
|
||||
|
||||
#include "progname.h"
|
||||
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
#define GUESTFS_PRIVATE_FOR_EACH_DISK 1
|
||||
#endif
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
#include "scan.h"
|
||||
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
|
||||
/* The list of domains and disks that we build up in
|
||||
* get_domains_from_libvirt.
|
||||
*/
|
||||
struct disk {
|
||||
struct disk *next;
|
||||
char *filename;
|
||||
char *format; /* could be NULL */
|
||||
};
|
||||
|
||||
struct domain {
|
||||
char *name;
|
||||
char *uuid;
|
||||
struct disk *disks;
|
||||
size_t nr_disks;
|
||||
};
|
||||
|
||||
struct domain *domains = NULL;
|
||||
size_t nr_domains;
|
||||
|
||||
static int
|
||||
compare_domain_names (const void *p1, const void *p2)
|
||||
{
|
||||
const struct domain *d1 = p1;
|
||||
const struct domain *d2 = p2;
|
||||
|
||||
return strcmp (d1->name, d2->name);
|
||||
}
|
||||
|
||||
static void
|
||||
free_domain (struct domain *domain)
|
||||
{
|
||||
struct disk *disk, *next;
|
||||
|
||||
for (disk = domain->disks; disk; disk = next) {
|
||||
next = disk->next;
|
||||
free (disk->filename);
|
||||
free (disk->format);
|
||||
free (disk);
|
||||
}
|
||||
|
||||
free (domain->name);
|
||||
free (domain->uuid);
|
||||
}
|
||||
|
||||
static void add_domains_by_id (virConnectPtr conn, int *ids, size_t n);
|
||||
static void add_domains_by_name (virConnectPtr conn, char **names, size_t n);
|
||||
static void add_domain (virDomainPtr dom);
|
||||
static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *domain_vp);
|
||||
static size_t add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r);
|
||||
static void reset_guestfs_handle (void);
|
||||
|
||||
void
|
||||
get_domains_from_libvirt (int uuid, size_t *worst_alignment_ptr)
|
||||
{
|
||||
virErrorPtr err;
|
||||
virConnectPtr conn;
|
||||
int n;
|
||||
size_t i, count, errors;
|
||||
const char *prefix;
|
||||
|
||||
nr_domains = 0;
|
||||
domains = NULL;
|
||||
|
||||
/* Get the list of all domains. */
|
||||
conn = virConnectOpenReadOnly (libvirt_uri);
|
||||
if (!conn) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not connect to libvirt (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n = virConnectNumOfDomains (conn);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of running domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int ids[n];
|
||||
n = virConnectListDomains (conn, ids, n);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list running domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
add_domains_by_id (conn, ids, n);
|
||||
|
||||
n = virConnectNumOfDefinedDomains (conn);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not get number of inactive domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *names[n];
|
||||
n = virConnectListDefinedDomains (conn, names, n);
|
||||
if (n == -1) {
|
||||
err = virGetLastError ();
|
||||
fprintf (stderr,
|
||||
_("%s: could not list inactive domains (code %d, domain %d): %s\n"),
|
||||
program_name, err->code, err->domain, err->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
add_domains_by_name (conn, names, n);
|
||||
|
||||
/* You must free these even though the libvirt documentation doesn't
|
||||
* mention it.
|
||||
*/
|
||||
for (i = 0; i < (size_t) n; ++i)
|
||||
free (names[i]);
|
||||
|
||||
virConnectClose (conn);
|
||||
|
||||
/* No domains? */
|
||||
if (nr_domains == 0)
|
||||
return;
|
||||
|
||||
/* Sort the domains alphabetically by name for display. */
|
||||
qsort (domains, nr_domains, sizeof (struct domain), compare_domain_names);
|
||||
|
||||
errors = 0;
|
||||
for (i = 0; i < nr_domains; ++i) {
|
||||
if (domains[i].disks == NULL)
|
||||
continue;
|
||||
|
||||
count = add_disks_to_handle_reverse (domains[i].disks, &errors);
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
if (guestfs_launch (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
prefix = !uuid ? domains[i].name : domains[i].uuid;
|
||||
|
||||
/* Perform the scan. */
|
||||
scan (worst_alignment_ptr, prefix);
|
||||
|
||||
if (i < nr_domains - 1)
|
||||
reset_guestfs_handle ();
|
||||
}
|
||||
|
||||
/* Free up domains structure. */
|
||||
for (i = 0; i < nr_domains; ++i)
|
||||
free_domain (&domains[i]);
|
||||
free (domains);
|
||||
|
||||
if (errors > 0) {
|
||||
fprintf (stderr, _("%s: failed to analyze a disk, see error(s) above\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domains_by_id (virConnectPtr conn, int *ids, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ids[i] != 0) { /* RHBZ#538041 */
|
||||
dom = virDomainLookupByID (conn, ids[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domains_by_name (virConnectPtr conn, char **names, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
virDomainPtr dom;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
dom = virDomainLookupByName (conn, names[i]);
|
||||
if (dom) { /* transient errors are possible here, ignore them */
|
||||
add_domain (dom);
|
||||
virDomainFree (dom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_domain (virDomainPtr dom)
|
||||
{
|
||||
struct domain *domain;
|
||||
|
||||
domains = realloc (domains, (nr_domains + 1) * sizeof (struct domain));
|
||||
if (domains == NULL) {
|
||||
perror ("realloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
domain = &domains[nr_domains];
|
||||
nr_domains++;
|
||||
|
||||
domain->name = strdup (virDomainGetName (dom));
|
||||
if (domain->name == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char uuid[VIR_UUID_STRING_BUFLEN];
|
||||
if (virDomainGetUUIDString (dom, uuid) == 0) {
|
||||
domain->uuid = strdup (uuid);
|
||||
if (domain->uuid == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
domain->uuid = NULL;
|
||||
|
||||
domain->disks = NULL;
|
||||
int n = guestfs___for_each_disk (g, dom, add_disk, domain);
|
||||
if (n == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
domain->nr_disks = n;
|
||||
}
|
||||
|
||||
static int
|
||||
add_disk (guestfs_h *g,
|
||||
const char *filename, const char *format, int readonly,
|
||||
void *domain_vp)
|
||||
{
|
||||
struct domain *domain = domain_vp;
|
||||
struct disk *disk;
|
||||
|
||||
disk = malloc (sizeof *disk);
|
||||
if (disk == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
disk->next = domain->disks;
|
||||
domain->disks = disk;
|
||||
|
||||
disk->filename = strdup (filename);
|
||||
if (disk->filename == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
if (format) {
|
||||
disk->format = strdup (format);
|
||||
if (disk->format == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
disk->format = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
add_disks_to_handle_reverse (struct disk *disk, size_t *errors_r)
|
||||
{
|
||||
size_t nr_disks_added;
|
||||
|
||||
if (disk == NULL)
|
||||
return 0;
|
||||
|
||||
nr_disks_added = add_disks_to_handle_reverse (disk->next, errors_r);
|
||||
|
||||
struct guestfs_add_drive_opts_argv optargs = { .bitmask = 0 };
|
||||
|
||||
optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
|
||||
optargs.readonly = 1;
|
||||
|
||||
if (disk->format) {
|
||||
optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
|
||||
optargs.format = disk->format;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive_opts_argv (g, disk->filename, &optargs) == -1) {
|
||||
(*errors_r)++;
|
||||
return nr_disks_added;
|
||||
}
|
||||
|
||||
return nr_disks_added+1;
|
||||
}
|
||||
|
||||
/* Close and reopen the libguestfs handle. */
|
||||
static void
|
||||
reset_guestfs_handle (void)
|
||||
{
|
||||
/* Copy the settings from the old handle. */
|
||||
int verbose = guestfs_get_verbose (g);
|
||||
int trace = guestfs_get_trace (g);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
g = guestfs_create ();
|
||||
if (g == NULL) {
|
||||
fprintf (stderr, _("guestfs_create: failed to create handle\n"));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
guestfs_set_verbose (g, verbose);
|
||||
guestfs_set_trace (g, trace);
|
||||
}
|
||||
|
||||
#endif
|
||||
86
align/scan.c
86
align/scan.c
@@ -35,10 +35,10 @@
|
||||
#endif
|
||||
|
||||
#include "progname.h"
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
#include "scan.h"
|
||||
|
||||
/* These globals are shared with options.c. */
|
||||
guestfs_h *g;
|
||||
@@ -53,8 +53,6 @@ int inspector = 0;
|
||||
|
||||
static int quiet = 0; /* --quiet */
|
||||
|
||||
static int scan (void);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
@@ -111,6 +109,7 @@ main (int argc, char *argv[])
|
||||
{ "format", 2, 0, 0 },
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "quiet", 0, 0, 'q' },
|
||||
{ "uuid", 0, 0, 0, },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -120,6 +119,9 @@ main (int argc, char *argv[])
|
||||
const char *format = NULL;
|
||||
int c;
|
||||
int option_index;
|
||||
int uuid = 0;
|
||||
/* This just needs to be larger than any alignment we care about. */
|
||||
size_t worst_alignment = UINT_MAX;
|
||||
int exit_code;
|
||||
|
||||
g = guestfs_create ();
|
||||
@@ -141,6 +143,8 @@ main (int argc, char *argv[])
|
||||
format = NULL;
|
||||
else
|
||||
format = optarg;
|
||||
} else if (STREQ (long_options[option_index].name, "uuid")) {
|
||||
uuid = 1;
|
||||
} else {
|
||||
fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
|
||||
program_name, long_options[option_index].name, option_index);
|
||||
@@ -197,31 +201,51 @@ main (int argc, char *argv[])
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
/* The user didn't specify any drives to scan. */
|
||||
if (drvs == NULL)
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
/* Add domains/drives from the command line (for a single guest). */
|
||||
add_drives (drvs, 'a');
|
||||
|
||||
if (guestfs_launch (g) == -1)
|
||||
if (drvs == NULL) {
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
get_domains_from_libvirt (uuid, &worst_alignment);
|
||||
#else
|
||||
fprintf (stderr, _("%s: compiled without support for libvirt and/or libxml2.\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
#endif
|
||||
} else {
|
||||
if (uuid) {
|
||||
fprintf (stderr, _("%s: --uuid option cannot be used with -a or -d\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Free up data structures, no longer needed after this point. */
|
||||
free_drives (drvs);
|
||||
/* Add domains/drives from the command line (for a single guest). */
|
||||
add_drives (drvs, 'a');
|
||||
|
||||
/* Perform the scan. */
|
||||
exit_code = scan ();
|
||||
if (guestfs_launch (g) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs_close (g);
|
||||
/* Free up data structures, no longer needed after this point. */
|
||||
free_drives (drvs);
|
||||
|
||||
/* Perform the scan. */
|
||||
scan (&worst_alignment, NULL);
|
||||
|
||||
guestfs_close (g);
|
||||
}
|
||||
|
||||
/* Decide on an appropriate exit code. */
|
||||
if (worst_alignment < 10) /* 2^10 = 4096 */
|
||||
exit_code = 3;
|
||||
else if (worst_alignment < 16) /* 2^16 = 65536 */
|
||||
exit_code = 2;
|
||||
else
|
||||
exit_code = 0;
|
||||
|
||||
exit (exit_code);
|
||||
}
|
||||
|
||||
static int
|
||||
scan (void)
|
||||
void
|
||||
scan (size_t *worst_alignment, const char *prefix)
|
||||
{
|
||||
int exit_code = 0;
|
||||
char **devices;
|
||||
char **devices, *p;
|
||||
size_t i, j;
|
||||
size_t alignment;
|
||||
uint64_t start;
|
||||
@@ -237,19 +261,23 @@ scan (void)
|
||||
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. */
|
||||
start = parts->val[j].part_start;
|
||||
|
||||
if (!quiet)
|
||||
if (!quiet) {
|
||||
if (prefix)
|
||||
printf ("%s:", prefix);
|
||||
|
||||
printf ("%s%d %12" PRIu64 " ",
|
||||
devices[i], (int) parts->val[j].part_num, start);
|
||||
}
|
||||
|
||||
/* What's the alignment? */
|
||||
if (start == 0) /* Probably not possible, but anyway. */
|
||||
@@ -267,13 +295,13 @@ scan (void)
|
||||
printf ("- ");
|
||||
}
|
||||
|
||||
if (alignment < *worst_alignment)
|
||||
*worst_alignment = alignment;
|
||||
|
||||
if (alignment < 12) { /* Bad in general: < 4K alignment */
|
||||
exit_code = 3;
|
||||
if (!quiet)
|
||||
printf ("bad (%s)\n", _("alignment < 4K"));
|
||||
} else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */
|
||||
if (exit_code < 2)
|
||||
exit_code = 2;
|
||||
if (!quiet)
|
||||
printf ("bad (%s)\n", _("alignment < 64K"));
|
||||
} else {
|
||||
@@ -286,6 +314,4 @@ scan (void)
|
||||
free (devices[i]);
|
||||
}
|
||||
free (devices);
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
30
align/scan.h
Normal file
30
align/scan.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* virt-alignment-scan
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUESTFS_VIRT_ALIGNMENT_SCAN_H_
|
||||
#define GUESTFS_VIRT_ALIGNMENT_SCAN_H_
|
||||
|
||||
/* domains.c */
|
||||
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
|
||||
extern void get_domains_from_libvirt (int uuid, size_t *worst_alignment);
|
||||
#endif
|
||||
|
||||
/* scan.c */
|
||||
extern void scan (size_t *worst_alignment, const char *prefix);
|
||||
|
||||
#endif /* GUESTFS_VIRT_ALIGNMENT_SCAN_H_ */
|
||||
25
align/test-virt-alignment-scan.sh
Executable file
25
align/test-virt-alignment-scan.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# 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.
|
||||
|
||||
$VG ./virt-alignment-scan -a ../tests/guests/fedora.img
|
||||
r=$?
|
||||
|
||||
# 0, 2 and 3 are reasonable non-error exit codes. Others are errors.
|
||||
if [ $r -ne 0 -a $r -ne 2 -a $r -ne 3 ]; then
|
||||
exit $r
|
||||
fi
|
||||
@@ -10,6 +10,8 @@ virt-alignment-scan - Check alignment of virtual machine partitions
|
||||
|
||||
virt-alignment-scan [--options] -a disk.img [-a disk.img ...]
|
||||
|
||||
virt-alignment-scan [--options]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
When older operating systems install themselves, the partitioning
|
||||
@@ -51,16 +53,28 @@ possibly the I<-c> option:
|
||||
/dev/sda2 105906176 1024K ok
|
||||
/dev/sdb1 65536 64K ok
|
||||
|
||||
Run virt-alignment-scan without any I<-a> or I<-d> options to scan all
|
||||
libvirt domains.
|
||||
|
||||
# virt-alignment-scan
|
||||
F16x64:/dev/sda1 1048576 1024K ok
|
||||
F16x64:/dev/sda2 2097152 2048K ok
|
||||
F16x64:/dev/sda3 526385152 2048K ok
|
||||
|
||||
The output consists of 4 or more whitespace-separated columns. Only
|
||||
the first 4 columns are signficant if you want to parse this from a
|
||||
the first 4 columns are significant if you want to parse this from a
|
||||
program. The columns are:
|
||||
|
||||
=over 4
|
||||
|
||||
=item col 1
|
||||
|
||||
the device and partition name (eg. C</dev/sda1> meaning the
|
||||
first partition on the first block device)
|
||||
The device and partition name (eg. C</dev/sda1> meaning the
|
||||
first partition on the first block device).
|
||||
|
||||
When listing all libvirt domains (no I<-a> or I<-d> option given) this
|
||||
column is prefixed by the libvirt name or UUID (if I<--uuid> is
|
||||
given). eg: C<WinXP:/dev/sda1>
|
||||
|
||||
=item col 2
|
||||
|
||||
@@ -151,6 +165,15 @@ security problem with malicious guests (CVE-2010-3851).
|
||||
Don't produce any output. Just set the exit code
|
||||
(see L</EXIT STATUS> below).
|
||||
|
||||
=item B<--uuid>
|
||||
|
||||
Print UUIDs instead of names. This is useful for following a guest
|
||||
even when the guest is migrated or renamed, or when two guests happen
|
||||
to have the same name.
|
||||
|
||||
This option only applies when listing all libvirt domains (when no
|
||||
I<-a> or I<-d> options are specified).
|
||||
|
||||
=item B<-v>
|
||||
|
||||
=item B<--verbose>
|
||||
@@ -365,17 +388,3 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2011 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.
|
||||
|
||||
17
appliance/99-guestfs-serial.rules
Normal file
17
appliance/99-guestfs-serial.rules
Normal file
@@ -0,0 +1,17 @@
|
||||
# For libguestfs, create /dev/disk/guestfs/<serial>
|
||||
# and /dev/disk/guestfs/<serial><partnum>
|
||||
|
||||
KERNEL=="sd*[!0-9]", ENV{DEVTYPE}=="disk", ENV{ID_SCSI_SERIAL}=="?*", \
|
||||
SYMLINK+="disk/guestfs/$env{ID_SCSI_SERIAL}"
|
||||
KERNEL=="sd*", ENV{DEVTYPE}=="partition", ENV{ID_SCSI_SERIAL}=="?*", \
|
||||
SYMLINK+="disk/guestfs/$env{ID_SCSI_SERIAL}%n"
|
||||
|
||||
# As written, it's likely the above only works with virtio-scsi
|
||||
# because ID_SCSI_SERIAL is specific to the output of the 'scsi_id'
|
||||
# program. The following will not work because ID_SERIAL contains
|
||||
# some unwanted text.
|
||||
|
||||
#KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", \
|
||||
# SYMLINK+="disk/guestfs/$env{ID_SERIAL}"
|
||||
#KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", \
|
||||
# SYMLINK+="disk/guestfs/$env{ID_SERIAL}%n"
|
||||
@@ -15,13 +15,20 @@
|
||||
# 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 = \
|
||||
packagelist.in \
|
||||
99-guestfs-serial.rules \
|
||||
excludelist.in \
|
||||
guestfsd.suppressions \
|
||||
init \
|
||||
make.sh.in
|
||||
libguestfs-make-fixed-appliance.in \
|
||||
libguestfs-make-fixed-appliance.pod \
|
||||
make.sh.in \
|
||||
packagelist.in
|
||||
|
||||
fsdir = $(libdir)/guestfs
|
||||
superminfsdir = $(libdir)/guestfs/supermin.d
|
||||
@@ -31,26 +38,35 @@ superminfs_DATA = \
|
||||
supermin.d/base.img \
|
||||
supermin.d/daemon.img \
|
||||
supermin.d/init.img \
|
||||
supermin.d/hostfiles
|
||||
supermin.d/hostfiles \
|
||||
supermin.d/udev-rules.img
|
||||
|
||||
# This used to be a configure-generated file (as is update.sh still).
|
||||
# However config.status always touches the destination file, which
|
||||
# means the appliance got rebuilt too often.
|
||||
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: packagelist.in
|
||||
cpp -undef -D$(DISTRO)=1 < $< | \
|
||||
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
|
||||
mv $@-t $@
|
||||
PACKAGELIST_CPP_FLAGS = -D$(DISTRO)=1
|
||||
if VALGRIND_DAEMON
|
||||
PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1
|
||||
endif
|
||||
|
||||
excludelist: excludelist.in
|
||||
cpp -undef -D$(DISTRO)=1 < $< | \
|
||||
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 Makefile
|
||||
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \
|
||||
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
supermin.d/base.img supermin.d/hostfiles: stamp-supermin
|
||||
stamp-supermin: make.sh packagelist excludelist
|
||||
@@ -59,13 +75,15 @@ stamp-supermin: make.sh packagelist excludelist
|
||||
./make.sh
|
||||
touch $@
|
||||
|
||||
supermin.d/daemon.img: ../daemon/guestfsd
|
||||
supermin.d/daemon.img: ../daemon/guestfsd guestfsd.suppressions
|
||||
mkdir -p supermin.d
|
||||
rm -f $@ $@-t
|
||||
mkdir sbin
|
||||
cd sbin && ln ../../daemon/guestfsd
|
||||
echo -e "sbin\nsbin/guestfsd" | cpio --quiet -o -H newc > $@-t
|
||||
rm -r sbin
|
||||
rm -rf tmp-d
|
||||
mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc
|
||||
ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd
|
||||
ln $(srcdir)/guestfsd.suppressions tmp-d/etc/guestfsd.suppressions
|
||||
( cd tmp-d && find | cpio --quiet -o -H newc ) > $@-t
|
||||
rm -rf tmp-d
|
||||
mv $@-t $@
|
||||
|
||||
supermin.d/init.img: init
|
||||
@@ -75,9 +93,46 @@ supermin.d/init.img: init
|
||||
echo "init" | cpio --quiet -o -H newc > $@-t
|
||||
mv $@-t $@
|
||||
|
||||
# We should put this file in /lib/udev/rules.d, but put it in /etc so
|
||||
# we don't have to deal with all the UsrMove crap in Fedora.
|
||||
supermin.d/udev-rules.img: 99-guestfs-serial.rules
|
||||
mkdir -p supermin.d
|
||||
rm -f $@ $@-t
|
||||
rm -rf tmp-u
|
||||
mkdir -p tmp-u/etc/udev/rules.d
|
||||
for f in $^; do ln $$f tmp-u/etc/udev/rules.d/$$f; done
|
||||
( cd tmp-u && find | cpio --quiet -o -H newc ) > $@-t
|
||||
rm -rf tmp-u
|
||||
mv $@-t $@
|
||||
|
||||
# If installing the daemon, install the udev rules too.
|
||||
|
||||
if INSTALL_DAEMON
|
||||
udevrulesdir = /lib/udev/rules.d
|
||||
udevrules_DATA = 99-guestfs-serial.rules
|
||||
endif
|
||||
|
||||
# libguestfs-make-fixed-appliance script and man page.
|
||||
|
||||
sbin_SCRIPTS = libguestfs-make-fixed-appliance
|
||||
|
||||
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
|
||||
$(PODWRAPPER) \
|
||||
--man libguestfs-make-fixed-appliance.1 \
|
||||
--html $(top_builddir)/html/libguestfs-make-fixed-appliance.1.html \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# Make clean.
|
||||
|
||||
CLEANFILES = packagelist excludelist
|
||||
CLEANFILES = packagelist excludelist \
|
||||
libguestfs-make-fixed-appliance.1 \
|
||||
stamp-libguestfs-make-fixed-appliance.pod
|
||||
|
||||
clean-local:
|
||||
rm -rf supermin.d
|
||||
|
||||
@@ -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
|
||||
|
||||
19
appliance/guestfsd.suppressions
Normal file
19
appliance/guestfsd.suppressions
Normal file
@@ -0,0 +1,19 @@
|
||||
# This file is only used when libguestfs is configured with
|
||||
#
|
||||
# ./configure --enable-valgrind-daemon
|
||||
#
|
||||
# (only used for development, and only used in the regular supermin
|
||||
# appliance, not libguestfs live).
|
||||
#
|
||||
# If there are any valgrind errors in the base libraries such as
|
||||
# glibc, then we can suppress them here, so we only see errors in
|
||||
# libguestfs daemon code.
|
||||
|
||||
# libdl
|
||||
{
|
||||
libdl_index_cond
|
||||
Memcheck:Cond
|
||||
fun:index
|
||||
fun:expand_dynamic_string_token
|
||||
fun:_dl_map_object
|
||||
}
|
||||
@@ -12,12 +12,17 @@ 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
|
||||
|
||||
# devtmpfs is required since udev 176
|
||||
mount -t devtmpfs /dev /dev
|
||||
|
||||
if [ ! -L /etc/init.d/udev -a -x /etc/init.d/udev ]; then
|
||||
if type service >/dev/null 2>&1; then
|
||||
service udev start
|
||||
@@ -26,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
|
||||
/sbin/udevadm trigger
|
||||
/sbin/udevadm settle
|
||||
elif [ -x /lib/udev/udevd ]; then
|
||||
echo -e '\000\000\000\000' > /proc/sys/kernel/hotplug
|
||||
/lib/udev/udevd --daemon
|
||||
/sbin/udevadm trigger
|
||||
/sbin/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
|
||||
@@ -66,9 +74,13 @@ fi
|
||||
hwclock -u -s
|
||||
|
||||
# Set up the network.
|
||||
ifconfig lo 127.0.0.1
|
||||
ifconfig eth0 169.254.2.10
|
||||
route add default gw 169.254.2.2
|
||||
ip addr add 127.0.0.1/8 brd + dev lo scope host
|
||||
ip link set dev lo up
|
||||
|
||||
ip addr add 169.254.2.10/16 brd + dev eth0 scope global
|
||||
ip link set dev eth0 up
|
||||
|
||||
ip route add default via 169.254.2.2
|
||||
|
||||
# Scan for MDs.
|
||||
mdadm -As --auto=yes --run
|
||||
@@ -94,8 +106,8 @@ if grep -sq guestfs_verbose=1 /proc/cmdline; then
|
||||
lvm pvs
|
||||
lvm vgs
|
||||
lvm lvs
|
||||
ifconfig
|
||||
netstat -rn
|
||||
ip a
|
||||
ip r
|
||||
lsmod
|
||||
#hwclock -r
|
||||
date
|
||||
@@ -106,8 +118,19 @@ if grep -sq guestfs_verbose=1 /proc/cmdline; then
|
||||
fi
|
||||
|
||||
if ! grep -sq guestfs_rescue=1 /proc/cmdline; then
|
||||
# Run the daemon under valgrind if ./configure --enable-valgrind-daemon
|
||||
vg_channel=/dev/virtio-ports/org.libguestfs.valgrind
|
||||
if [ -w $vg_channel ]; then
|
||||
if [ -r /etc/guestfsd.suppressions ]; then
|
||||
suppressions="--suppressions=/etc/guestfsd.suppressions"
|
||||
fi
|
||||
exec 3>$vg_channel
|
||||
vg="valgrind --leak-check=full --log-fd=3 --error-exitcode=119 --max-stackframe=8388608 --child-silent-after-fork=yes $suppressions"
|
||||
echo "enabling valgrind: $vg"
|
||||
fi
|
||||
|
||||
# The host will kill qemu abruptly if guestfsd shuts down normally
|
||||
guestfsd
|
||||
$vg guestfsd
|
||||
|
||||
# Otherwise we try to clean up gracefully. For example, this ensures that a
|
||||
# core dump generated by the guest daemon will be written to disk.
|
||||
@@ -132,4 +155,4 @@ else
|
||||
fi
|
||||
|
||||
sync
|
||||
/sbin/reboot -f
|
||||
reboot -f
|
||||
|
||||
161
appliance/libguestfs-make-fixed-appliance.in
Normal file
161
appliance/libguestfs-make-fixed-appliance.in
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# libguestfs-make-fixed-appliance tool
|
||||
# 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.
|
||||
|
||||
unset CDPATH
|
||||
|
||||
program="libguestfs-make-fixed-appliance"
|
||||
version="@PACKAGE_VERSION@"
|
||||
|
||||
TEMP=`getopt \
|
||||
-o V \
|
||||
--long help,version,xz \
|
||||
-n $program -- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$program: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $program [--options] OUTPUTDIR"
|
||||
echo " $program [--options] --xz"
|
||||
echo
|
||||
echo "Read $program(1) man page for more information."
|
||||
exit $1
|
||||
}
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-V|--version)
|
||||
echo "$program $version"
|
||||
exit 0;;
|
||||
--xz)
|
||||
xz_mode=1
|
||||
shift;;
|
||||
--help)
|
||||
usage 0;;
|
||||
--)
|
||||
shift
|
||||
break;;
|
||||
*)
|
||||
echo "internal error ($1)"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Either xz_mode or we expect one extra parameter (output directory).
|
||||
if [ -n "$xz_mode" ]; then
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "error: $program: extra parameters on the command line"
|
||||
echo
|
||||
usage 1
|
||||
fi
|
||||
else
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "error: $program: missing output directory"
|
||||
echo
|
||||
usage 1
|
||||
fi
|
||||
outputdir="$1"
|
||||
fi
|
||||
|
||||
# end of command line parsing
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
set -e
|
||||
|
||||
# The two ways to build the appliance are roughly the same, except for
|
||||
# --xz we build into a temporary directory and tar it up at the end.
|
||||
|
||||
if [ -n "$xz_mode" ]; then
|
||||
tmpdir="$(mktemp -d)"
|
||||
outputdir="$tmpdir/appliance"
|
||||
|
||||
cleanup ()
|
||||
{
|
||||
rm -rf $tmpdir ||:
|
||||
}
|
||||
trap cleanup EXIT ERR
|
||||
fi
|
||||
|
||||
# Create the output directory.
|
||||
mkdir -p "$outputdir"
|
||||
|
||||
# Build the supermin appliance, if not already.
|
||||
guestfish -a /dev/null run
|
||||
|
||||
# Find the location of the appliance.
|
||||
cachedir="$(guestfish get-cachedir)"
|
||||
euid="$(id -u)"
|
||||
appliancedir="$cachedir/.guestfs-$euid"
|
||||
|
||||
cp "$appliancedir/kernel" "$outputdir/kernel"
|
||||
cp "$appliancedir/initrd" "$outputdir/initrd"
|
||||
cp --sparse=always "$appliancedir/root" "$outputdir/root"
|
||||
|
||||
cat <<EOF >"$outputdir/README.fixed"
|
||||
This is the "fixed appliance", a pre-built binary appliance for
|
||||
libguestfs. This was built using $program.
|
||||
|
||||
Unpack the appliance directory:
|
||||
|
||||
tar -Jxvf appliance-<VERSION>.tar.xz
|
||||
|
||||
Then copy all four files:
|
||||
|
||||
* kernel
|
||||
* initrd
|
||||
* root
|
||||
* README.fixed
|
||||
|
||||
into a directory somewhere, eg. /usr/local/lib/guestfs/appliance/
|
||||
|
||||
Then build libguestfs (>= 1.16.7 or >= 1.18) from source, disabling
|
||||
the normal appliance and daemon:
|
||||
|
||||
./configure --disable-appliance --disable-daemon
|
||||
make
|
||||
sudo make install
|
||||
|
||||
Set LIBGUESTFS_PATH to the path where you unpacked these files, eg:
|
||||
|
||||
export LIBGUESTFS_PATH=/usr/local/lib/guestfs/appliance/
|
||||
|
||||
and run the libguestfs programs and virt tools in the normal way.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
This appliance contains software under a variety of open source
|
||||
licenses. The software is from Fedora (https://fedoraproject.org/),
|
||||
and to rebuild it you need to download Fedora 17+ and
|
||||
libguestfs >= 1.17.10, and build libguestfs from source in the usual
|
||||
way.
|
||||
|
||||
EOF
|
||||
|
||||
# If --xz, compress the result. Note -S option to preserve sparseness.
|
||||
if [ -n "$xz_mode" ]; then
|
||||
tar -C "$tmpdir" -S -cf - appliance | xz --best > "appliance-$version.tar.xz"
|
||||
rm -rf "$tmpdir" ||:
|
||||
trap - EXIT ERR
|
||||
fi
|
||||
159
appliance/libguestfs-make-fixed-appliance.pod
Normal file
159
appliance/libguestfs-make-fixed-appliance.pod
Normal file
@@ -0,0 +1,159 @@
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
libguestfs-make-fixed-appliance - Make a "fixed appliance" for libguestfs
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
libguestfs-make-fixed-appliance [--options] OUTPUTDIR
|
||||
|
||||
libguestfs-make-fixed-appliance [--options] --xz
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
libguestfs-make-fixed-appliance lets you make a pre-built binary
|
||||
appliance for libguestfs.
|
||||
|
||||
B<Note that ordinary users should not need to run this tool>. The
|
||||
only reason to use it is if you want to make a self-contained
|
||||
libguestfs appliance that can be copied to another machine or platform
|
||||
that doesn't support L<febootstrap(8)>. To understand why you might
|
||||
need to use this tool, read the section L</FIXED APPLIANCE> below.
|
||||
|
||||
Instead of running this tool, you can download fixed appliances from
|
||||
L<http://libguestfs.org/download/binaries/appliance/>. These
|
||||
appliances were made using this tool.
|
||||
|
||||
There are two ways to use this tool.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Specify an output directory, for example:
|
||||
|
||||
libguestfs-make-fixed-appliance /usr/local/lib/guestfs/appliance
|
||||
|
||||
The output directory is created if it does not exist. Four files are
|
||||
created in this directory:
|
||||
|
||||
<OUTPUTDIR>/kernel
|
||||
<OUTPUTDIR>/initrd
|
||||
<OUTPUTDIR>/root
|
||||
<OUTPUTDIR>/README.fixed
|
||||
|
||||
Note that C<I<OUTPUTDIR>/root> is a sparse file, so take care when
|
||||
copying it.
|
||||
|
||||
You can then run libguestfs (possibly after copying this directory to
|
||||
another machine) by setting the environment variable LIBGUESTFS_PATH
|
||||
to C<OUTPUTDIR>.
|
||||
|
||||
=item *
|
||||
|
||||
The alternative method is to use the I<--xz> option to create a
|
||||
compressed tarball:
|
||||
|
||||
libguestfs-make-fixed-appliance --xz
|
||||
|
||||
This creates a tarball in the I<current> directory called:
|
||||
|
||||
appliance-<VERSION>.tar.xz
|
||||
|
||||
(where C<VERSION> is the version of libguestfs). The tarball contains
|
||||
the four files:
|
||||
|
||||
appliance/kernel
|
||||
appliance/initrd
|
||||
appliance/root
|
||||
appliance/README.fixed
|
||||
|
||||
Note that C<appliance/root> is a sparse file, so take care when
|
||||
copying it.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display short usage information and exit.
|
||||
|
||||
=item B<-V>
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Display the version number and exit.
|
||||
|
||||
=item B<--xz>
|
||||
|
||||
Instead of creating the appliance in an output directory, create a
|
||||
compressed tarball of the appliance in the current directory called
|
||||
C<appliance-I<VERSION>.tar.xz> where C<VERSION> is the version of
|
||||
libguestfs.
|
||||
|
||||
Using I<--xz> can take some time. If working normally, the tool is
|
||||
completely silent when it is running.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FIXED APPLIANCE
|
||||
|
||||
When libguestfs (or libguestfs tools) are run, they search a path
|
||||
looking for an appliance. The path is built into libguestfs, or can
|
||||
be set using the C<LIBGUESTFS_PATH> environment variable.
|
||||
|
||||
Normally a supermin appliance is located on this path (see
|
||||
L<febootstrap(8)/SUPERMIN APPLIANCE>). libguestfs reconstructs this
|
||||
into a full appliance by running L<febootstrap-supermin-helper(8)>.
|
||||
|
||||
However, a simpler "fixed appliance" can also be used. libguestfs
|
||||
detects this by looking for a directory on the path containing four
|
||||
files called C<kernel>, C<initrd>, C<root> and C<README.fixed> (note
|
||||
the C<README.fixed> file must be present as well).
|
||||
|
||||
If the fixed appliance is found, libguestfs skips febootstrap entirely
|
||||
and just runs qemu with the kernel, initrd and root disk from the
|
||||
fixed appliance.
|
||||
|
||||
Thus the fixed appliance can be used when a platform or Linux distro
|
||||
does not support febootstrap. You build the fixed appliance on a
|
||||
platform that does support febootstrap, and copy it over, and use that
|
||||
to run libguestfs.
|
||||
|
||||
=head1 LICENSING
|
||||
|
||||
The fixed appliance is a complete Linux binary distro. If you
|
||||
distribute it, you may need to distribute corresponding source files
|
||||
to remain in legal compliance with the licenses of the software in the
|
||||
appliance (such as the GNU General Public License).
|
||||
|
||||
=head1 EXIT STATUS
|
||||
|
||||
libguestfs-make-fixed-appliance returns I<0> if the appliance was
|
||||
built without errors.
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
For the full list of environment variables which may affect
|
||||
libguestfs, please see the L<guestfs(3)> manual page.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfs(3)>,
|
||||
L<febootstrap(8)>,
|
||||
L<febootstrap-supermin-helper(8)>,
|
||||
L<xz(1)>,
|
||||
L<http://libguestfs.org/>,
|
||||
L<http://qemu.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
@@ -23,7 +23,6 @@
|
||||
btrfs-progs
|
||||
cryptsetup
|
||||
cryptsetup-luks /* old name used before Fedora 17 */
|
||||
diffutils
|
||||
e2fsprogs
|
||||
/* e4fsprogs only exists on RHEL 5, will be ignored everywhere else. */
|
||||
e4fsprogs
|
||||
@@ -31,16 +30,17 @@
|
||||
gfs2-utils
|
||||
grub
|
||||
hfsplus-tools
|
||||
hivex
|
||||
iputils
|
||||
kernel
|
||||
MAKEDEV
|
||||
nilfs-utils
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
openssh-clients
|
||||
reiserfs-utils
|
||||
libselinux
|
||||
systemd /* for /sbin/reboot */
|
||||
udev
|
||||
systemd /* for /sbin/reboot and udevd */
|
||||
util-linux-ng
|
||||
vim-minimal
|
||||
xz
|
||||
@@ -51,7 +51,6 @@
|
||||
bsdmainutils
|
||||
btrfs-tools
|
||||
cryptsetup
|
||||
diff
|
||||
e2fsprogs
|
||||
gfs-tools
|
||||
gfs2-tools
|
||||
@@ -59,12 +58,13 @@
|
||||
hfsplus
|
||||
iproute
|
||||
libaugeas0
|
||||
libhivex0
|
||||
linux-image
|
||||
nilfs-tools
|
||||
ntfs-3g
|
||||
ntfsprogs
|
||||
openssh-client
|
||||
reiserfsprogs
|
||||
udev
|
||||
ufsutils
|
||||
util-linux
|
||||
vim-tiny
|
||||
@@ -77,8 +77,8 @@
|
||||
vim
|
||||
btrfs-progs-unstable
|
||||
cryptsetup
|
||||
diffutils
|
||||
augeas
|
||||
hivex
|
||||
zfs-fuse
|
||||
e2fsprogs
|
||||
grub
|
||||
@@ -87,7 +87,6 @@
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
reiserfsprogs
|
||||
udev
|
||||
util-linux-ng
|
||||
xz
|
||||
#endif /* ARCHLINUX */
|
||||
@@ -96,22 +95,26 @@ acl
|
||||
attr
|
||||
bash
|
||||
binutils
|
||||
bzip2
|
||||
coreutils
|
||||
cpio
|
||||
diffutils
|
||||
dosfstools
|
||||
file
|
||||
findutils
|
||||
gawk
|
||||
genisoimage
|
||||
grep
|
||||
gzip
|
||||
iproute
|
||||
jfsutils
|
||||
libxml2
|
||||
lsof
|
||||
lsscsi
|
||||
lvm2
|
||||
lzop
|
||||
mdadm
|
||||
module-init-tools
|
||||
net-tools
|
||||
/*
|
||||
Enabling this pulls out 140 extra packages
|
||||
into the appliance:
|
||||
@@ -120,9 +123,11 @@ ocfs2-tools
|
||||
parted
|
||||
procps
|
||||
psmisc
|
||||
rsync
|
||||
scrub
|
||||
strace
|
||||
tar
|
||||
udev
|
||||
#ifndef UBUNTU
|
||||
/* on Ubuntu contains a file in /lib64 which conflicts with libc6 that has
|
||||
* /lib64 as a symbolic link
|
||||
@@ -130,3 +135,7 @@ tar
|
||||
xfsprogs
|
||||
#endif
|
||||
zerofree
|
||||
|
||||
#ifdef VALGRIND_DAEMON
|
||||
valgrind
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ fi
|
||||
|
||||
# If no arguments were specified and configure has run before, use the previous
|
||||
# arguments
|
||||
if test $# == 0 && test -x ./config.status; then
|
||||
if test $# -eq 0 && test -x ./config.status; then
|
||||
./config.status --recheck
|
||||
else
|
||||
$CONFIGUREDIR/configure "$@"
|
||||
|
||||
77
bindtests
77
bindtests
@@ -9,8 +9,9 @@ false
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: true
|
||||
oint: 1
|
||||
oint64: unset
|
||||
oint64: 9223372036854775807
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
null
|
||||
[]
|
||||
@@ -24,6 +25,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: 1
|
||||
ostring: string
|
||||
ostringlist: unset
|
||||
|
||||
def
|
||||
[]
|
||||
@@ -35,8 +37,9 @@ false
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: false
|
||||
oint: unset
|
||||
oint64: unset
|
||||
oint64: -9223372036854775808
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
|
||||
|
||||
[]
|
||||
@@ -50,6 +53,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -63,6 +67,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1", "2"]
|
||||
@@ -76,6 +81,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -89,6 +95,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -102,6 +109,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -115,6 +123,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -128,6 +137,7 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
@@ -141,12 +151,13 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
false
|
||||
4095
|
||||
4095
|
||||
9223372036854775807
|
||||
123
|
||||
456
|
||||
<61><62><63><00><61><62><63>
|
||||
@@ -154,12 +165,13 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
["1"]
|
||||
false
|
||||
0
|
||||
0
|
||||
-9223372036854775808
|
||||
|
||||
|
||||
<61><62><63><00><61><62><63>
|
||||
@@ -167,4 +179,61 @@ obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: unset
|
||||
abc
|
||||
def
|
||||
[]
|
||||
false
|
||||
0
|
||||
0
|
||||
123
|
||||
456
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: []
|
||||
abc
|
||||
def
|
||||
[]
|
||||
false
|
||||
0
|
||||
0
|
||||
123
|
||||
456
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: ["optelem1"]
|
||||
abc
|
||||
def
|
||||
[]
|
||||
false
|
||||
0
|
||||
0
|
||||
123
|
||||
456
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: ["optelem1", "optelem2"]
|
||||
abc
|
||||
def
|
||||
[]
|
||||
false
|
||||
0
|
||||
0
|
||||
123
|
||||
456
|
||||
<61><62><63><00><61><62><63>
|
||||
obool: unset
|
||||
oint: unset
|
||||
oint64: unset
|
||||
ostring: unset
|
||||
ostringlist: ["optelem1", "optelem2", "optelem3"]
|
||||
EOF
|
||||
|
||||
20
bootstrap
20
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.
|
||||
@@ -44,13 +37,17 @@ gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
|
||||
(cd daemon && mkdir -p tests lib && ../$gnulib_tool --update)
|
||||
|
||||
modules='
|
||||
accept4
|
||||
arpa_inet
|
||||
byteswap
|
||||
c-ctype
|
||||
cloexec
|
||||
closeout
|
||||
connect
|
||||
dup3
|
||||
error
|
||||
filevercmp
|
||||
fstatat
|
||||
fsusage
|
||||
fts
|
||||
full-read
|
||||
@@ -69,11 +66,13 @@ ignore-value
|
||||
lock
|
||||
maintainer-makefile
|
||||
manywarnings
|
||||
memmem
|
||||
mkdtemp
|
||||
netdb
|
||||
netinet_in
|
||||
openat
|
||||
perror
|
||||
pipe2
|
||||
pread
|
||||
progname
|
||||
read-file
|
||||
@@ -82,6 +81,7 @@ select
|
||||
setenv
|
||||
sleep
|
||||
socket
|
||||
stat-time
|
||||
strchrnul
|
||||
strerror
|
||||
strndup
|
||||
@@ -98,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 \
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# Used when preparing the RELEASE-NOTES file. This script looks at
|
||||
# the bugs noted in the git changelog since the last stable release
|
||||
# (or any release). To use it, the only parameter should be the git
|
||||
# commit range, eg:
|
||||
# Used when preparing the guestfs-release-notes(1) man page. This
|
||||
# script looks at the bugs noted in the git changelog since the last
|
||||
# stable release (or any release). To use it, the only parameter
|
||||
# should be the git commit range, eg:
|
||||
#
|
||||
# ./bugs-in-changelog.sh "1.0.89.."
|
||||
|
||||
@@ -42,5 +42,10 @@ bugids=$(
|
||||
# Filter out any bugs which may still be in NEW or ASSIGNED:
|
||||
bugzilla query -b "$bugids" \
|
||||
-t MODIFIED,POST,ON_QA,PASSES_QA,VERIFIED,RELEASE_PENDING,CLOSED \
|
||||
--outputformat=' - %{bug_id} %{short_desc}' |
|
||||
sort -n -r
|
||||
--outputformat='%{bug_id} %{short_desc}' |
|
||||
sort -n -r |
|
||||
perl -pe '
|
||||
s{([0-9]+)\s+(.*)}{
|
||||
sprintf ("=item L<https://bugzilla.redhat.com/%s>\n\n%s\n",
|
||||
$1, $2)
|
||||
}xe'
|
||||
|
||||
@@ -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,38 +102,48 @@ 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 \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
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 \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
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 \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# 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
|
||||
TESTS = \
|
||||
test-virt-cat.sh \
|
||||
test-virt-filesystems.sh \
|
||||
test-virt-ls.sh
|
||||
endif ENABLE_APPLIANCE
|
||||
|
||||
check-valgrind:
|
||||
$(MAKE) VG="$(top_builddir)/run @VG@" check
|
||||
|
||||
check-valgrind-local-guests:
|
||||
for g in $(GUESTS); do \
|
||||
$(top_builddir)/run --test @VG@ ./virt-filesystems -c "$(libvirt_ro_uri)" -d "$$g" --all --long -h --uuid || exit $$?; \
|
||||
done
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
# Read out the test files from the image using virt-cat.
|
||||
if [ "$(./virt-cat ../tests/guests/fedora.img /etc/test1)" != "abcdefg" ]; then
|
||||
if [ "$($VG ./virt-cat ../tests/guests/fedora.img /etc/test1)" != "abcdefg" ]; then
|
||||
echo "$0: error: mismatch in file test1"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(./virt-cat ../tests/guests/fedora.img /etc/test2)" != "" ]; then
|
||||
if [ "$($VG ./virt-cat ../tests/guests/fedora.img /etc/test2)" != "" ]; then
|
||||
echo "$0: error: mismatch in file test2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
output="$(./virt-filesystems -a ../tests/guests/fedora.img | sort)"
|
||||
output="$($VG ./virt-filesystems -a ../tests/guests/fedora.img | sort)"
|
||||
expected="/dev/VG/LV1
|
||||
/dev/VG/LV2
|
||||
/dev/VG/LV3
|
||||
@@ -16,7 +32,7 @@ if [ "$output" != "$expected" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output="$(./virt-filesystems -a ../tests/guests/fedora.img --all --long --uuid -h --no-title | awk '{print $1}' | sort -u)"
|
||||
output="$($VG ./virt-filesystems -a ../tests/guests/fedora.img --all --long --uuid -h --no-title | awk '{print $1}' | sort -u)"
|
||||
expected="/dev/VG
|
||||
/dev/VG/LV1
|
||||
/dev/VG/LV2
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# 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.
|
||||
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
# Read out the test directory using virt-ls.
|
||||
if [ "$(./virt-ls ../tests/guests/fedora.img /bin)" != "ls
|
||||
if [ "$($VG ./virt-ls ../tests/guests/fedora.img /bin)" != "ls
|
||||
test1
|
||||
test2
|
||||
test3
|
||||
@@ -17,7 +33,7 @@ test7" ]; then
|
||||
fi
|
||||
|
||||
# Try the -lR option.
|
||||
output="$(./virt-ls -lR ../tests/guests/fedora.img /boot | awk '{print $1 $2 $4}')"
|
||||
output="$($VG ./virt-ls -lR ../tests/guests/fedora.img /boot | awk '{print $1 $2 $4}')"
|
||||
expected="d0755/boot
|
||||
d0755/boot/grub
|
||||
-0644/boot/grub/grub.conf
|
||||
@@ -31,3 +47,7 @@ if [ "$output" != "$expected" ]; then
|
||||
echo "--------------------------------------------------"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Try the -l and -R options. XXX Should check the output.
|
||||
$VG ./virt-ls -l ../tests/guests/fedora.img /
|
||||
$VG ./virt-ls -R ../tests/guests/fedora.img /
|
||||
|
||||
@@ -158,9 +158,6 @@ main (int argc, char *argv[])
|
||||
OPTION_d;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
case 'v':
|
||||
OPTION_v;
|
||||
break;
|
||||
|
||||
@@ -256,17 +256,3 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2010-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.
|
||||
|
||||
@@ -36,15 +36,6 @@
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
|
||||
#define DISABLE_GUESTFS_ERRORS_FOR(stmt) do { \
|
||||
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); \
|
||||
stmt; \
|
||||
guestfs_set_error_handler (g, old_error_cb, old_error_data); \
|
||||
} while (0)
|
||||
|
||||
/* These globals are shared with options.c. */
|
||||
guestfs_h *g;
|
||||
|
||||
@@ -77,16 +68,18 @@ static int output = 0;
|
||||
#define COLUMN_VFS_LABEL 8 /* if --filesystems */
|
||||
#define COLUMN_MBR 16
|
||||
#define COLUMN_SIZE 32 /* bytes, or human-readable if -h */
|
||||
#define COLUMN_PARENT_NAME 64 /* only for partitions, LVs */
|
||||
#define COLUMN_PARENTS 64
|
||||
#define COLUMN_UUID 128 /* if --uuid */
|
||||
#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);
|
||||
|
||||
static struct guestfs_lvm_pv_list *get_pvs (void);
|
||||
static void free_pvs (void);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
{
|
||||
@@ -334,8 +327,7 @@ main (int argc, char *argv[])
|
||||
columns |= COLUMN_VFS_TYPE;
|
||||
columns |= COLUMN_VFS_LABEL;
|
||||
}
|
||||
if ((output & (OUTPUT_PARTITIONS|OUTPUT_LVS)))
|
||||
columns |= COLUMN_PARENT_NAME;
|
||||
columns |= COLUMN_PARENTS;
|
||||
if ((output & OUTPUT_PARTITIONS))
|
||||
columns |= COLUMN_MBR;
|
||||
if (uuid)
|
||||
@@ -365,6 +357,8 @@ main (int argc, char *argv[])
|
||||
do_output ();
|
||||
do_output_end ();
|
||||
|
||||
free_pvs ();
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
@@ -376,9 +370,18 @@ static void do_output_vgs (void);
|
||||
static void do_output_pvs (void);
|
||||
static void do_output_partitions (void);
|
||||
static void do_output_blockdevs (void);
|
||||
static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, const char *parent_name, const char *uuid);
|
||||
|
||||
static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, char **parents, const char *uuid);
|
||||
static void write_row_strings (char **strings, size_t len);
|
||||
|
||||
static char **no_parents (void);
|
||||
static int is_md (char *device);
|
||||
static char **parents_of_md (char *device);
|
||||
static char **parents_of_vg (char *vg);
|
||||
|
||||
static void free_strings (char **strings);
|
||||
static size_t count_strings (char **strings);
|
||||
|
||||
static void
|
||||
do_output_title (void)
|
||||
{
|
||||
@@ -398,7 +401,7 @@ do_output_title (void)
|
||||
headings[len++] = "MBR";
|
||||
if ((columns & COLUMN_SIZE))
|
||||
headings[len++] = "Size";
|
||||
if ((columns & COLUMN_PARENT_NAME))
|
||||
if ((columns & COLUMN_PARENTS))
|
||||
headings[len++] = "Parent";
|
||||
if ((columns & COLUMN_UUID))
|
||||
headings[len++] = "UUID";
|
||||
@@ -444,6 +447,7 @@ do_output_filesystems (void)
|
||||
|
||||
for (i = 0; fses[i] != NULL; i += 2) {
|
||||
char *dev, *vfs_label = NULL, *vfs_uuid = NULL;
|
||||
char **parents;
|
||||
int64_t size = -1;
|
||||
|
||||
/* Skip swap and unknown, unless --extra flag was given. */
|
||||
@@ -451,15 +455,17 @@ 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.
|
||||
*/
|
||||
if ((columns & COLUMN_VFS_LABEL)) {
|
||||
DISABLE_GUESTFS_ERRORS_FOR (
|
||||
vfs_label = guestfs_vfs_label (g, fses[i]);
|
||||
);
|
||||
guestfs_push_error_handler (g, NULL, NULL);
|
||||
vfs_label = guestfs_vfs_label (g, fses[i]);
|
||||
guestfs_pop_error_handler (g);
|
||||
if (vfs_label == NULL) {
|
||||
vfs_label = strdup ("");
|
||||
if (!vfs_label) {
|
||||
@@ -469,9 +475,9 @@ do_output_filesystems (void)
|
||||
}
|
||||
}
|
||||
if ((columns & COLUMN_UUID)) {
|
||||
DISABLE_GUESTFS_ERRORS_FOR (
|
||||
vfs_uuid = guestfs_vfs_uuid (g, fses[i]);
|
||||
);
|
||||
guestfs_push_error_handler (g, NULL, NULL);
|
||||
vfs_uuid = guestfs_vfs_uuid (g, fses[i]);
|
||||
guestfs_pop_error_handler (g);
|
||||
if (vfs_uuid == NULL) {
|
||||
vfs_uuid = strdup ("");
|
||||
if (!vfs_uuid) {
|
||||
@@ -486,9 +492,15 @@ do_output_filesystems (void)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
write_row (dev, "filesystem",
|
||||
fses[i+1], vfs_label, -1, size, NULL, vfs_uuid);
|
||||
if (is_md (fses[i]))
|
||||
parents = parents_of_md (fses[i]);
|
||||
else
|
||||
parents = no_parents ();
|
||||
|
||||
write_row (dev, "filesystem",
|
||||
fses[i+1], vfs_label, -1, size, parents, vfs_uuid);
|
||||
|
||||
free_strings (parents);
|
||||
free (dev);
|
||||
free (vfs_label);
|
||||
free (vfs_uuid);
|
||||
@@ -513,6 +525,7 @@ do_output_lvs (void)
|
||||
|
||||
for (i = 0; lvs[i] != NULL; ++i) {
|
||||
char *uuid = NULL, *parent_name = NULL;
|
||||
const char *parents[2];
|
||||
int64_t size = -1;
|
||||
|
||||
if ((columns & COLUMN_SIZE)) {
|
||||
@@ -525,7 +538,7 @@ do_output_lvs (void)
|
||||
if (uuid == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if ((columns & COLUMN_PARENT_NAME)) {
|
||||
if ((columns & COLUMN_PARENTS)) {
|
||||
parent_name = strdup (lvs[i]);
|
||||
if (parent_name == NULL) {
|
||||
perror ("strdup");
|
||||
@@ -534,10 +547,12 @@ do_output_lvs (void)
|
||||
char *p = strrchr (parent_name, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
parents[0] = parent_name;
|
||||
parents[1] = NULL;
|
||||
}
|
||||
|
||||
write_row (lvs[i], "lv",
|
||||
NULL, NULL, -1, size, parent_name, uuid);
|
||||
NULL, NULL, -1, size, (char **) parents, uuid);
|
||||
|
||||
free (uuid);
|
||||
free (parent_name);
|
||||
@@ -558,46 +573,78 @@ do_output_vgs (void)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
for (i = 0; i < vgs->len; ++i) {
|
||||
char name[PATH_MAX];
|
||||
char *name;
|
||||
char uuid[33];
|
||||
char **parents;
|
||||
|
||||
if (asprintf (&name, "/dev/%s", vgs->val[i].vg_name) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcpy (name, "/dev/");
|
||||
strcpy (&name[5], vgs->val[i].vg_name);
|
||||
memcpy (uuid, vgs->val[i].vg_uuid, 32);
|
||||
uuid[32] = '\0';
|
||||
write_row (name, "vg",
|
||||
NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, NULL, uuid);
|
||||
|
||||
parents = parents_of_vg (vgs->val[i].vg_name);
|
||||
|
||||
write_row (name, "vg",
|
||||
NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, parents, uuid);
|
||||
|
||||
free (name);
|
||||
free_strings (parents);
|
||||
}
|
||||
|
||||
guestfs_free_lvm_vg_list (vgs);
|
||||
}
|
||||
|
||||
/* Cache the output of guestfs_pvs_full, since we use it in a few places. */
|
||||
static struct guestfs_lvm_pv_list *pvs_ = NULL;
|
||||
|
||||
static struct guestfs_lvm_pv_list *
|
||||
get_pvs (void)
|
||||
{
|
||||
if (pvs_)
|
||||
return pvs_;
|
||||
|
||||
pvs_ = guestfs_pvs_full (g);
|
||||
if (pvs_ == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
return pvs_;
|
||||
}
|
||||
|
||||
static void
|
||||
free_pvs (void)
|
||||
{
|
||||
if (pvs_)
|
||||
guestfs_free_lvm_pv_list (pvs_);
|
||||
|
||||
pvs_ = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
do_output_pvs (void)
|
||||
{
|
||||
struct guestfs_lvm_pv_list *pvs;
|
||||
size_t i;
|
||||
|
||||
pvs = guestfs_pvs_full (g);
|
||||
if (pvs == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
struct guestfs_lvm_pv_list *pvs = get_pvs ();
|
||||
|
||||
for (i = 0; i < pvs->len; ++i) {
|
||||
char *dev;
|
||||
char uuid[33];
|
||||
const char *parents[1] = { NULL };
|
||||
|
||||
dev = 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';
|
||||
write_row (dev, "pv",
|
||||
NULL, NULL, -1, (int64_t) pvs->val[i].pv_size, NULL, uuid);
|
||||
NULL, NULL, -1, (int64_t) pvs->val[i].pv_size,
|
||||
(char **) parents, uuid);
|
||||
|
||||
free (dev);
|
||||
}
|
||||
|
||||
guestfs_free_lvm_pv_list (pvs);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -606,23 +653,20 @@ get_mbr_id (const char *dev, const char *parent_name)
|
||||
char *parttype = NULL;
|
||||
int mbr_id = -1, partnum;
|
||||
|
||||
DISABLE_GUESTFS_ERRORS_FOR (
|
||||
parttype = guestfs_part_get_parttype (g, parent_name);
|
||||
);
|
||||
guestfs_push_error_handler (g, NULL, NULL);
|
||||
|
||||
parttype = guestfs_part_get_parttype (g, parent_name);
|
||||
|
||||
if (parttype && STREQ (parttype, "msdos")) {
|
||||
DISABLE_GUESTFS_ERRORS_FOR (
|
||||
partnum = guestfs_part_to_partnum (g, dev);
|
||||
);
|
||||
if (partnum >= 0) {
|
||||
DISABLE_GUESTFS_ERRORS_FOR (
|
||||
mbr_id = guestfs_part_get_mbr_id (g, parent_name, partnum);
|
||||
);
|
||||
}
|
||||
partnum = guestfs_part_to_partnum (g, dev);
|
||||
if (partnum >= 0)
|
||||
mbr_id = guestfs_part_get_mbr_id (g, parent_name, partnum);
|
||||
}
|
||||
|
||||
free (parttype);
|
||||
|
||||
guestfs_pop_error_handler (g);
|
||||
|
||||
return mbr_id;
|
||||
}
|
||||
|
||||
@@ -638,17 +682,20 @@ do_output_partitions (void)
|
||||
|
||||
for (i = 0; parts[i] != NULL; ++i) {
|
||||
char *dev, *parent_name = NULL;
|
||||
const char *parents[2];
|
||||
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]);
|
||||
if (size == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if ((columns & COLUMN_PARENT_NAME)) {
|
||||
if ((columns & COLUMN_PARENTS)) {
|
||||
parent_name = guestfs_part_to_dev (g, parts[i]);
|
||||
if (parent_name == NULL)
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -656,13 +703,18 @@ 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;
|
||||
|
||||
parents[0] = parent_name;
|
||||
parents[1] = NULL;
|
||||
}
|
||||
|
||||
write_row (dev, "partition",
|
||||
NULL, NULL, mbr_id, size, parent_name, NULL);
|
||||
NULL, NULL, mbr_id, size, (char **) parents, NULL);
|
||||
|
||||
free (dev);
|
||||
free (parent_name);
|
||||
@@ -685,8 +737,11 @@ do_output_blockdevs (void)
|
||||
for (i = 0; devices[i] != NULL; ++i) {
|
||||
int64_t size = -1;
|
||||
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]);
|
||||
@@ -694,32 +749,188 @@ do_output_blockdevs (void)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (is_md (devices[i]))
|
||||
parents = parents_of_md (devices[i]);
|
||||
else
|
||||
parents = no_parents ();
|
||||
|
||||
write_row (dev, "device",
|
||||
NULL, NULL, -1, size, NULL, NULL);
|
||||
NULL, NULL, -1, size, parents, NULL);
|
||||
|
||||
free (dev);
|
||||
free (devices[i]);
|
||||
free_strings (parents);
|
||||
}
|
||||
|
||||
free (devices);
|
||||
}
|
||||
|
||||
/* /dev/vda1 -> /dev/sda. Returns a string which the caller must free. */
|
||||
static char *
|
||||
canonical_device (const char *dev)
|
||||
/* Returns an empty list of parents. Note this must be freed using
|
||||
* free_strings.
|
||||
*/
|
||||
static char **
|
||||
no_parents (void)
|
||||
{
|
||||
char *ret = strdup (dev);
|
||||
if (ret == NULL) {
|
||||
perror ("strdup");
|
||||
char **ret;
|
||||
|
||||
ret = malloc (sizeof (char *));
|
||||
if (!ret) {
|
||||
perror ("malloc");
|
||||
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';
|
||||
ret[0] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* XXX Should be a better test than this. */
|
||||
static int
|
||||
is_md (char *device)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!STRPREFIX (device, "/dev/md"))
|
||||
return 0;
|
||||
|
||||
p = device + 7;
|
||||
while (*p) {
|
||||
if (!c_isdigit (*p))
|
||||
return 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char **
|
||||
parents_of_md (char *device)
|
||||
{
|
||||
struct guestfs_mdstat_list *stats;
|
||||
char **ret;
|
||||
size_t i;
|
||||
|
||||
stats = guestfs_md_stat (g, device);
|
||||
if (!stats)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
ret = malloc ((stats->len + 1) * sizeof (char *));
|
||||
if (!ret) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
guestfs_free_mdstat_list (stats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Specialized PV UUID comparison function.
|
||||
* pvuuid1: from vgpvuuids, this may contain '-' characters which
|
||||
* should be ignored.
|
||||
* pvuuid2: from pvs-full, this is 32 characters long and NOT
|
||||
* terminated by \0
|
||||
*/
|
||||
static int
|
||||
compare_pvuuids (const char *pvuuid1, const char *pvuuid2)
|
||||
{
|
||||
size_t i;
|
||||
const char *p = pvuuid1;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
while (*p && !c_isalnum (*p))
|
||||
p++;
|
||||
if (!*p)
|
||||
return 0;
|
||||
if (*p != pvuuid2[i])
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char **
|
||||
parents_of_vg (char *vg)
|
||||
{
|
||||
struct guestfs_lvm_pv_list *pvs = get_pvs ();
|
||||
char **pvuuids;
|
||||
char **ret;
|
||||
size_t n, i, j;
|
||||
|
||||
pvuuids = guestfs_vgpvuuids (g, vg);
|
||||
if (!pvuuids)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
n = count_strings (pvuuids);
|
||||
|
||||
ret = malloc ((n + 1) * sizeof (char *));
|
||||
if (!ret) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Resolve each PV UUID back to a PV. */
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < pvs->len; ++j) {
|
||||
if (compare_pvuuids (pvuuids[i], pvs->val[j].pv_uuid) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!ret[i]) {
|
||||
perror ("strndup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret[i] = NULL;
|
||||
|
||||
free_strings (pvuuids);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
join_comma (char **strings)
|
||||
{
|
||||
size_t i, count;
|
||||
char *ret;
|
||||
|
||||
for (count = i = 0; strings[i] != NULL; ++i) {
|
||||
if (i > 0)
|
||||
count++;
|
||||
count += strlen (strings[i]);
|
||||
}
|
||||
|
||||
ret = malloc (count + 1);
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (count = i = 0; strings[i] != NULL; ++i) {
|
||||
if (i > 0)
|
||||
ret[count++] = ',';
|
||||
strcpy (&ret[count], strings[i]);
|
||||
count += strlen (strings[i]);
|
||||
}
|
||||
ret[count] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -727,9 +938,10 @@ canonical_device (const char *dev)
|
||||
static void
|
||||
write_row (const char *name, const char *type,
|
||||
const char *vfs_type, const char *vfs_label, int mbr_id,
|
||||
int64_t size, const char *parent_name, const char *uuid)
|
||||
int64_t size, char **parents, const char *uuid)
|
||||
{
|
||||
const char *strings[NR_COLUMNS];
|
||||
char *parents_str = NULL;
|
||||
size_t len = 0;
|
||||
char hum[LONGEST_HUMAN_READABLE];
|
||||
char num[256];
|
||||
@@ -767,13 +979,18 @@ write_row (const char *name, const char *type,
|
||||
else
|
||||
strings[len++] = NULL;
|
||||
}
|
||||
if ((columns & COLUMN_PARENT_NAME))
|
||||
strings[len++] = parent_name;
|
||||
if ((columns & COLUMN_PARENTS)) {
|
||||
/* Internally comma-separated field. */
|
||||
parents_str = join_comma (parents);
|
||||
strings[len++] = parents_str;
|
||||
}
|
||||
if ((columns & COLUMN_UUID))
|
||||
strings[len++] = uuid;
|
||||
assert (len <= NR_COLUMNS);
|
||||
|
||||
write_row_strings ((char **) strings, len);
|
||||
|
||||
free (parents_str);
|
||||
}
|
||||
|
||||
static void add_row (char **strings, size_t len);
|
||||
@@ -942,3 +1159,23 @@ do_output_end (void)
|
||||
}
|
||||
free (rows);
|
||||
}
|
||||
|
||||
static void
|
||||
free_strings (char **strings)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; strings[i] != NULL; ++i)
|
||||
free (strings[i]);
|
||||
free (strings);
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_strings (char **strings)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; strings[i] != NULL; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -332,10 +332,14 @@ then the size is displayed in a human-readable form.
|
||||
=item B<Parent>
|
||||
|
||||
The parent column records the parent relationship between objects.
|
||||
|
||||
For example, if the object is a partition, then this column contains
|
||||
the name of the containing device. If the object is a logical volume,
|
||||
then this column is the name of the volume group.
|
||||
|
||||
If there is more than one parent, then this column is (internal to the
|
||||
column) a comma-separated list, eg. C</dev/sda,/dev/sdb>.
|
||||
|
||||
=item B<UUID>
|
||||
|
||||
If the object has a UUID (used for identifying and mounting
|
||||
@@ -399,18 +403,4 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2010 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.
|
||||
Copyright (C) 2010-2012 Red Hat Inc.
|
||||
|
||||
241
cat/virt-ls.c
241
cat/virt-ls.c
@@ -82,9 +82,7 @@ static int is_fifo (int64_t mode);
|
||||
static int is_lnk (int64_t mode);
|
||||
static int is_sock (int64_t mode);
|
||||
|
||||
static size_t count_strings (char **);
|
||||
static void free_strings (char **);
|
||||
static char **take_strings (char **, size_t n, char ***);
|
||||
|
||||
static inline char *
|
||||
bad_cast (char const *s)
|
||||
@@ -443,71 +441,26 @@ do_ls_l (const char *dir)
|
||||
static int
|
||||
do_ls_R (const char *dir)
|
||||
{
|
||||
/* This is TMP_TEMPLATE_ON_STACK expanded from fish.h. */
|
||||
const char *tmpdir = guestfs_tmpdir ();
|
||||
char tmpfile[strlen (tmpdir) + 32];
|
||||
sprintf (tmpfile, "%s/virtlsXXXXXX", tmpdir);
|
||||
char **dirs;
|
||||
size_t i;
|
||||
|
||||
int fd = mkstemp (tmpfile);
|
||||
if (fd == -1) {
|
||||
perror ("mkstemp");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char buf[BUFSIZ]; /* also used below */
|
||||
snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
|
||||
|
||||
if (guestfs_find0 (g, dir, buf) == -1)
|
||||
dirs = guestfs_find (g, dir);
|
||||
if (dirs == NULL)
|
||||
return -1;
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror (tmpfile);
|
||||
exit (EXIT_FAILURE);
|
||||
for (i = 0; dirs[i] != NULL; ++i) {
|
||||
puts (dirs[i]);
|
||||
free (dirs[i]);
|
||||
}
|
||||
free (dirs);
|
||||
|
||||
/* The output of find0 is a \0-separated file. Turn each \0 into
|
||||
* a \n character.
|
||||
*/
|
||||
fd = open (tmpfile, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror (tmpfile);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ssize_t r;
|
||||
while ((r = read (fd, buf, sizeof buf)) > 0) {
|
||||
size_t i;
|
||||
for (i = 0; i < (size_t) r; ++i)
|
||||
if (buf[i] == '\0')
|
||||
buf[i] = '\n';
|
||||
|
||||
size_t n = r;
|
||||
while (n > 0) {
|
||||
r = write (1, buf, n);
|
||||
if (r == -1) {
|
||||
perror ("write");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
n -= r;
|
||||
}
|
||||
}
|
||||
|
||||
if (r == -1 || close (fd) == -1) {
|
||||
perror (tmpfile);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unlink (tmpfile);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adapted from
|
||||
https://rwmj.wordpress.com/2010/12/15/tip-audit-virtual-machine-for-setuid-files/
|
||||
*/
|
||||
static char *full_path (const char *dir, const char *name);
|
||||
static struct guestfs_stat_list *lstatlist (const char *dir, char **names);
|
||||
static struct guestfs_xattr_list *lxattrlist (const char *dir, char **names);
|
||||
static int show_file (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs);
|
||||
|
||||
typedef int (*visitor_function) (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs);
|
||||
@@ -553,11 +506,11 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
if (names == NULL)
|
||||
goto out;
|
||||
|
||||
stats = lstatlist (dir, names);
|
||||
stats = guestfs_lstatlist (g, dir, names);
|
||||
if (stats == NULL)
|
||||
goto out;
|
||||
|
||||
xattrs = lxattrlist (dir, names);
|
||||
xattrs = guestfs_lxattrlist (g, dir, names);
|
||||
if (xattrs == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -577,8 +530,12 @@ visit (int depth, const char *dir, visitor_function f)
|
||||
program_name, dir, names[i]);
|
||||
goto out;
|
||||
}
|
||||
/* lxattrlist function made sure attrval was \0-terminated, so we can do */
|
||||
if (sscanf (xattrs->val[xattrp].attrval, "%zu", &nr_xattrs) != 1) {
|
||||
/* attrval is not \0-terminated. */
|
||||
char attrval[xattrs->val[xattrp].attrval_len+1];
|
||||
memcpy (attrval, xattrs->val[xattrp].attrval,
|
||||
xattrs->val[xattrp].attrval_len);
|
||||
attrval[xattrs->val[xattrp].attrval_len] = '\0';
|
||||
if (sscanf (attrval, "%zu", &nr_xattrs) != 1) {
|
||||
fprintf (stderr, _("%s: error: cannot parse xattr count for %s %s\n"),
|
||||
program_name, dir, names[i]);
|
||||
goto out;
|
||||
@@ -635,129 +592,6 @@ full_path (const char *dir, const char *name)
|
||||
return path;
|
||||
}
|
||||
|
||||
/* This calls guestfs_lstatlist, but it splits the names list up so that we
|
||||
* don't overrun the libguestfs protocol limit.
|
||||
*/
|
||||
#define LSTATLIST_MAX 1000
|
||||
|
||||
static struct guestfs_stat_list *
|
||||
lstatlist (const char *dir, char **names)
|
||||
{
|
||||
size_t len = count_strings (names);
|
||||
char **first;
|
||||
size_t old_len;
|
||||
struct guestfs_stat_list *ret, *stats;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ret->len = 0;
|
||||
ret->val = NULL;
|
||||
|
||||
while (len > 0) {
|
||||
first = take_strings (names, LSTATLIST_MAX, &names);
|
||||
len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX;
|
||||
|
||||
stats = guestfs_lstatlist (g, dir, first);
|
||||
/* Note we don't need to free up the strings because take_strings
|
||||
* does not do a deep copy.
|
||||
*/
|
||||
free (first);
|
||||
|
||||
if (stats == NULL) {
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append stats to ret. */
|
||||
old_len = ret->len;
|
||||
ret->len += stats->len;
|
||||
ret->val = realloc (ret->val, ret->len * sizeof (struct guestfs_stat));
|
||||
if (ret->val == NULL) {
|
||||
perror ("realloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
memcpy (&ret->val[old_len], stats->val,
|
||||
stats->len * sizeof (struct guestfs_stat));
|
||||
|
||||
guestfs_free_stat_list (stats);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as above, for lxattrlist. Note the rather peculiar format
|
||||
* used to return the list of extended attributes (see
|
||||
* guestfs_lxattrlist documentation).
|
||||
*/
|
||||
#define LXATTRLIST_MAX 1000
|
||||
|
||||
static struct guestfs_xattr_list *
|
||||
lxattrlist (const char *dir, char **names)
|
||||
{
|
||||
size_t len = count_strings (names);
|
||||
char **first;
|
||||
size_t i, old_len;
|
||||
struct guestfs_xattr_list *ret, *xattrs;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ret->len = 0;
|
||||
ret->val = NULL;
|
||||
|
||||
while (len > 0) {
|
||||
first = take_strings (names, LXATTRLIST_MAX, &names);
|
||||
len = len <= LXATTRLIST_MAX ? 0 : len - LXATTRLIST_MAX;
|
||||
|
||||
xattrs = guestfs_lxattrlist (g, dir, first);
|
||||
/* Note we don't need to free up the strings because take_strings
|
||||
* does not do a deep copy.
|
||||
*/
|
||||
free (first);
|
||||
|
||||
if (xattrs == NULL) {
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append xattrs to ret. */
|
||||
old_len = ret->len;
|
||||
ret->len += xattrs->len;
|
||||
ret->val = realloc (ret->val, ret->len * sizeof (struct guestfs_xattr));
|
||||
if (ret->val == NULL) {
|
||||
perror ("realloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
for (i = 0; i < xattrs->len; ++i, ++old_len) {
|
||||
/* We have to make a deep copy of the attribute name and value.
|
||||
* The attrval contains 8 bit data. However make sure also that
|
||||
* it is \0-terminated, because that makes the calling code
|
||||
* simpler.
|
||||
*/
|
||||
ret->val[old_len].attrname = strdup (xattrs->val[i].attrname);
|
||||
ret->val[old_len].attrval = malloc (xattrs->val[i].attrval_len + 1);
|
||||
if (ret->val[old_len].attrname == NULL ||
|
||||
ret->val[old_len].attrval == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ret->val[old_len].attrval_len = xattrs->val[i].attrval_len;
|
||||
memcpy (ret->val[old_len].attrval, xattrs->val[i].attrval,
|
||||
xattrs->val[i].attrval_len);
|
||||
ret->val[i].attrval[ret->val[i].attrval_len] = '\0';
|
||||
}
|
||||
|
||||
guestfs_free_xattr_list (xattrs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_ls_lR (const char *dir)
|
||||
{
|
||||
@@ -777,7 +611,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 ();
|
||||
@@ -829,6 +663,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)
|
||||
@@ -837,7 +673,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))
|
||||
@@ -1133,16 +968,6 @@ is_sock (int64_t mode)
|
||||
}
|
||||
|
||||
/* String functions. */
|
||||
static size_t
|
||||
count_strings (char **names)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
while (names[ret] != NULL)
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
free_strings (char **names)
|
||||
{
|
||||
@@ -1152,29 +977,3 @@ free_strings (char **names)
|
||||
free (names[i]);
|
||||
free (names);
|
||||
}
|
||||
|
||||
/* Take the first 'n' names, returning a newly allocated list. The
|
||||
* strings themselves are not duplicated. If 'lastp' is not NULL,
|
||||
* then it is updated with the pointer to the list of remaining names.
|
||||
*/
|
||||
static char **
|
||||
take_strings (char **names, size_t n, char ***lastp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
char **ret = malloc ((n+1) * sizeof (char *));
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; names[i] != NULL && i < n; ++i)
|
||||
ret[i] = names[i];
|
||||
|
||||
ret[i] = NULL;
|
||||
|
||||
if (lastp)
|
||||
*lastp = &names[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -511,17 +511,3 @@ Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
=head1 COPYRIGHT
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
34
cfg.mk
34
cfg.mk
@@ -1,5 +1,5 @@
|
||||
# Customize Makefile.maint. -*- makefile -*-
|
||||
# Copyright (C) 2003-2009 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003-2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,17 @@ gnu_rel_host = $(gnu_ftp_host-$(RELEASE_TYPE))
|
||||
url_dir_list = \
|
||||
ftp://$(gnu_rel_host)/gnu/coreutils
|
||||
|
||||
# Exclude some filenames.
|
||||
exclude_file_name_regexp--sc_bindtextdomain = ^(daemon|erlang|examples|tests)/
|
||||
exclude_file_name_regexp--sc_error_message_period = ^php/
|
||||
exclude_file_name_regexp--sc_prohibit_always-defined_macros = ^examples/
|
||||
exclude_file_name_regexp--sc_prohibit_doubled_word = ^po/
|
||||
exclude_file_name_regexp--sc_prohibit_magic_number_exit = ^(po|po-docs)/|\.pod$
|
||||
exclude_file_name_regexp--sc_prohibit_strcmp = ^examples/
|
||||
exclude_file_name_regexp--sc_prohibit_strcmp_and_strncmp = ^examples/
|
||||
exclude_file_name_regexp--sc_prohibit_strncpy = ^src/launch-.*\.c$
|
||||
exclude_file_name_regexp--sc_require_config_h = ^examples/|^tests/c-api/test-just-header\.c$
|
||||
|
||||
# Tests not to run as part of "make distcheck".
|
||||
local-checks-to-skip = \
|
||||
sc_po_check \
|
||||
@@ -41,7 +52,8 @@ local-checks-to-skip = \
|
||||
sc_error_message_uppercase \
|
||||
sc_program_name \
|
||||
$(disable_temporarily) \
|
||||
sc_useless_cpp_parens
|
||||
sc_useless_cpp_parens \
|
||||
sc_cast_of_argument_to_free
|
||||
|
||||
disable_temporarily = \
|
||||
sc_makefile_check \
|
||||
@@ -82,14 +94,6 @@ sc_prohibit_ctype_h:
|
||||
{ echo "$(ME): don't use ctype.h; instead, use c-ctype.h" \
|
||||
1>&2; exit 1; } || :
|
||||
|
||||
# Ensure that no C source file uses TABs for indentation.
|
||||
# Exclude some version-controlled symlinks.
|
||||
sc_TAB_in_indentation:
|
||||
@grep -lE '^ * ' /dev/null \
|
||||
$$($(VC_LIST_EXCEPT)) && \
|
||||
{ echo '$(ME): found TAB(s) used for indentation in C sources;'\
|
||||
'use spaces' 1>&2; exit 1; } || :
|
||||
|
||||
ctype_re = isalnum|isalpha|isascii|isblank|iscntrl|isdigit|isgraph|islower\
|
||||
|isprint|ispunct|isspace|isupper|isxdigit|tolower|toupper
|
||||
|
||||
@@ -111,16 +115,6 @@ sc_prohibit_gethostby:
|
||||
halt='use getaddrinfo, not gethostby*' \
|
||||
$(_sc_search_regexp)
|
||||
|
||||
# Disallow trailing blank lines.
|
||||
sc_prohibit_trailing_blank_lines:
|
||||
@$(VC_LIST_EXCEPT) \
|
||||
| xargs perl -ln -0777 -e \
|
||||
'-f $$ARGV or next; /\n\n+$$/ and print $$ARGV' > $@-t
|
||||
@found=0; test -s $@-t && { found=1; cat $@-t 1>&2; \
|
||||
echo '$(ME): found trailing blank line(s)' 1>&2; }; \
|
||||
rm -f $@-t; \
|
||||
test $$found = 0
|
||||
|
||||
# We don't use this feature of maint.mk.
|
||||
prev_version_file = /dev/null
|
||||
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# libguestfs virt-sysprep tool
|
||||
# Copyright (C) 2011 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.
|
||||
|
||||
unset CDPATH
|
||||
program="virt-sysprep"
|
||||
version="@PACKAGE_VERSION@"
|
||||
|
||||
# Uncomment this to see every shell command that is executed.
|
||||
#set -x
|
||||
|
||||
TEMP=`getopt \
|
||||
-o a:c:d:vVx \
|
||||
--long help,add:,connect:,domain:,enable:,format::,hostname:,list-operations,selinux-relabel,no-selinux-relabel,verbose,version \
|
||||
-n $program -- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$program: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
# This array accumulates the arguments we pass through to guestmount.
|
||||
declare -a params
|
||||
i=0
|
||||
|
||||
verbose=
|
||||
add_params=0
|
||||
enable=
|
||||
hostname_param=localhost.localdomain
|
||||
selinux_relabel=auto
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $program [--options] -d domname"
|
||||
echo " $program [--options] -a disk.img [-a disk.img ...]"
|
||||
echo
|
||||
echo "Read $program(1) man page for more information."
|
||||
echo
|
||||
echo "NOTE: $program modifies the guest or disk image *in place*."
|
||||
exit $1
|
||||
}
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-a|--add)
|
||||
params[i++]="-a"
|
||||
params[i++]="$2"
|
||||
((add_params++))
|
||||
shift 2;;
|
||||
-c|--connect)
|
||||
params[i++]="-c"
|
||||
params[i++]="$2"
|
||||
shift 2;;
|
||||
-d|--domain)
|
||||
params[i++]="-d"
|
||||
params[i++]="$2"
|
||||
((add_params++))
|
||||
shift 2;;
|
||||
--enable)
|
||||
if [ -n "$enable" ]; then
|
||||
echo "error: --enable option can only be given once"
|
||||
exit 1
|
||||
fi
|
||||
enable="$2"
|
||||
shift 2;;
|
||||
--format)
|
||||
if [ -n "$2" ]; then
|
||||
params[i++]="--format=$2"
|
||||
else
|
||||
params[i++]="--format"
|
||||
fi
|
||||
shift 2;;
|
||||
--help)
|
||||
usage 0;;
|
||||
--hostname)
|
||||
hostname_param="$2"
|
||||
shift 2;;
|
||||
--list-operations)
|
||||
enable=list
|
||||
shift;;
|
||||
--selinux-relabel)
|
||||
selinux_relabel=yes
|
||||
shift;;
|
||||
--no-selinux-relabel)
|
||||
selinux_relabel=no
|
||||
shift;;
|
||||
-v|--verbose)
|
||||
params[i++]="-v"
|
||||
verbose=yes
|
||||
shift;;
|
||||
-V|--version)
|
||||
echo "$program $version"
|
||||
exit 0;;
|
||||
-x)
|
||||
# Can't pass the -x option directly to guestmount because
|
||||
# that stops guestmount from forking, which means we can't
|
||||
# coordinate with guestmount when it has finished
|
||||
# initializing. So instead set just the underlying option
|
||||
# in libguestfs by exporting LIBGUESTFS_TRACE.
|
||||
# Unfortunately (a) this omits FUSE calls, but don't worry
|
||||
# about that for now, and more importantly (b) trace
|
||||
# messages disappear into never-never land after the fork.
|
||||
export LIBGUESTFS_TRACE=1
|
||||
shift;;
|
||||
--)
|
||||
shift
|
||||
break;;
|
||||
*)
|
||||
echo "Internal error!"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Different sysprep operations that can be enabled. Default is to
|
||||
# enable all of these, although some of them are only done on certain
|
||||
# guest types (see details below).
|
||||
if [ -z "$enable" ]; then
|
||||
cron_spool=yes
|
||||
dhcp_client_state=yes
|
||||
dhcp_server_state=yes
|
||||
hostname=yes
|
||||
logfiles=yes
|
||||
mail_spool=yes
|
||||
net_hwaddr=yes
|
||||
random_seed=yes
|
||||
rhn_systemid=yes
|
||||
smolt_uuid=yes
|
||||
ssh_hostkeys=yes
|
||||
udev_persistent_net=yes
|
||||
utmp=yes
|
||||
yum_uuid=yes
|
||||
elif [ "$enable" = "list" ]; then
|
||||
echo "cron-spool"
|
||||
echo "dhcp-client-state"
|
||||
echo "dhcp-server-state"
|
||||
echo "hostname"
|
||||
echo "logfiles"
|
||||
echo "mail-spool"
|
||||
echo "net-hwaddr"
|
||||
echo "random-seed"
|
||||
echo "rhn-systemid"
|
||||
echo "smolt-uuid"
|
||||
echo "ssh-hostkeys"
|
||||
echo "udev-persistent-net"
|
||||
echo "utmp"
|
||||
echo "yum-uuid"
|
||||
exit 0
|
||||
else
|
||||
for opt in $(echo "$enable" | sed 's/,/ /g'); do
|
||||
case "$opt" in
|
||||
cron-spool) cron_spool=yes ;;
|
||||
dhcp-client-state) dhcp_client_state=yes ;;
|
||||
dhcp-server-state) dhcp_server_state=yes ;;
|
||||
hostname) hostname=yes ;;
|
||||
logfiles) logfiles=yes ;;
|
||||
mail-spool) mail_spool=yes ;;
|
||||
net-hwaddr) net_hwaddr=yes ;;
|
||||
random-seed) random_seed=yes ;;
|
||||
rhn-systemid) rhn_systemid=yes ;;
|
||||
smolt-uuid) smolt_uuid=yes ;;
|
||||
ssh-hostkeys) ssh_hostkeys=yes ;;
|
||||
udev-persistent-net) udev_persistent_net=yes ;;
|
||||
utmp) utmp=yes ;;
|
||||
yum-uuid) yum_uuid=yes ;;
|
||||
*)
|
||||
echo "error: unknown --enable feature: $opt"
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Make sure there were no extra parameters on the command line.
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "error: $program: extra parameters on the command line"
|
||||
echo
|
||||
usage 1
|
||||
fi
|
||||
|
||||
# Did the user specify at least one -a or -d option?
|
||||
if [ $add_params -eq 0 ]; then
|
||||
echo "error: $program: you need at least one -a or -d option"
|
||||
echo
|
||||
usage 1
|
||||
fi
|
||||
|
||||
# end of command line parsing
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$verbose" = "yes" ]; then
|
||||
echo params: "${params[@]}"
|
||||
fi
|
||||
|
||||
# Create a temporary directory for general purpose use during operations.
|
||||
tmpdir="$(mktemp -d)"
|
||||
|
||||
cleanup ()
|
||||
{
|
||||
if [ -d $tmpdir/mnt ]; then
|
||||
fusermount -u $tmpdir/mnt >/dev/null 2>&1 ||:
|
||||
fi
|
||||
rm -rf $tmpdir ||:
|
||||
}
|
||||
trap cleanup EXIT ERR
|
||||
|
||||
# Run virt-inspector and grab inspection information about this guest.
|
||||
virt-inspector "${params[@]}" > $tmpdir/xml
|
||||
virt-inspector --xpath \
|
||||
"string(/operatingsystems/operatingsystem[position()=1]/name)" \
|
||||
< $tmpdir/xml > $tmpdir/type
|
||||
virt-inspector --xpath \
|
||||
"string(/operatingsystems/operatingsystem[position()=1]/distro)" \
|
||||
< $tmpdir/xml > $tmpdir/distro ||:
|
||||
virt-inspector --xpath \
|
||||
"string(/operatingsystems/operatingsystem[position()=1]/package_format)" \
|
||||
< $tmpdir/xml > $tmpdir/package_format ||:
|
||||
virt-inspector --xpath \
|
||||
"string(/operatingsystems/operatingsystem[position()=1]/package_management)" \
|
||||
< $tmpdir/xml > $tmpdir/package_management ||:
|
||||
|
||||
type="$(cat $tmpdir/type)"
|
||||
distro="$(cat $tmpdir/distro)"
|
||||
package_format="$(cat $tmpdir/package_format)"
|
||||
package_management="$(cat $tmpdir/package_management)"
|
||||
|
||||
# Mount the disk.
|
||||
mkdir $tmpdir/mnt
|
||||
guestmount --rw -i "${params[@]}" $tmpdir/mnt
|
||||
|
||||
mnt="$tmpdir/mnt"
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# The sysprep operations.
|
||||
|
||||
if [ "$cron_spool" = "yes" ]; then
|
||||
rm -rf $mnt/var/spool/cron/*
|
||||
fi
|
||||
|
||||
if [ "$dhcp_client_state" = "yes" ]; then
|
||||
case "$type" in
|
||||
linux)
|
||||
rm -rf $mnt/var/lib/dhclient/*
|
||||
# RHEL 3:
|
||||
rm -rf $mnt/var/lib/dhcp/*
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$dhcp_server_state" = "yes" ]; then
|
||||
case "$type" in
|
||||
linux)
|
||||
rm -rf $mnt/var/lib/dhcpd/*
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$hostname" = "yes" ]; then
|
||||
case "$type/$distro" in
|
||||
linux/fedora)
|
||||
echo "HOSTNAME=$hostname_param" > $mnt/etc/sysconfig/network.new
|
||||
sed '/^HOSTNAME=/d' < $mnt/etc/sysconfig/network >> $mnt/etc/sysconfig/network.new
|
||||
mv -f $mnt/etc/sysconfig/network.new $mnt/etc/sysconfig/network
|
||||
created_files=yes
|
||||
;;
|
||||
linux/debian|linux/ubuntu)
|
||||
echo "$hostname_param" > $mnt/etc/hostname
|
||||
created_files=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$logfiles" = "yes" ]; then
|
||||
case "$type" in
|
||||
linux)
|
||||
rm -rf $mnt/var/log/*.log*
|
||||
rm -rf $mnt/var/log/audit/*
|
||||
rm -rf $mnt/var/log/btmp*
|
||||
rm -rf $mnt/var/log/cron*
|
||||
rm -rf $mnt/var/log/dmesg*
|
||||
rm -rf $mnt/var/log/lastlog*
|
||||
rm -rf $mnt/var/log/maillog*
|
||||
rm -rf $mnt/var/log/mail/*
|
||||
rm -rf $mnt/var/log/messages*
|
||||
rm -rf $mnt/var/log/secure*
|
||||
rm -rf $mnt/var/log/spooler*
|
||||
rm -rf $mnt/var/log/tallylog*
|
||||
rm -rf $mnt/var/log/wtmp*
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$mail_spool" = "yes" ]; then
|
||||
rm -rf $mnt/var/spool/mail/*
|
||||
rm -rf $mnt/var/mail/*
|
||||
fi
|
||||
|
||||
if [ "$net_hwaddr" = "yes" ]; then
|
||||
case "$type/$distro" in
|
||||
linux/fedora)
|
||||
if [ -d $mnt/etc/sysconfig/network-scripts ]; then
|
||||
rm_hwaddr ()
|
||||
{
|
||||
sed '/^HWADDR=/d' < "$1" > "$1.new"
|
||||
mv -f "$1.new" "$1"
|
||||
}
|
||||
export -f rm_hwaddr
|
||||
find $mnt/etc/sysconfig/network-scripts \
|
||||
-name 'ifcfg-*' -type f \
|
||||
-exec bash -c 'rm_hwaddr "$0"' {} \;
|
||||
created_files=yes
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$random_seed" = "yes" -a "$type" = "linux" ]; then
|
||||
f=
|
||||
if [ -f $mnt/var/lib/random-seed ]; then
|
||||
# Fedora
|
||||
f=$mnt/var/lib/random-seed
|
||||
elif [ -f $mnt/var/lib/urandom/random-seed ]; then
|
||||
# Debian
|
||||
f=$mnt/var/lib/urandom/random-seed
|
||||
fi
|
||||
if [ -n "$f" ]; then
|
||||
dd if=/dev/urandom of="$f" bs=8 count=1 conv=nocreat,notrunc 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$rhn_systemid" = "yes" -a "$type/$distro" = "linux/rhel" ]; then
|
||||
rm -f $mnt/etc/sysconfig/rhn/systemid
|
||||
fi
|
||||
|
||||
if [ "$smolt_uuid" = "yes" -a "$type" = "linux" ]; then
|
||||
rm -f $mnt/etc/sysconfig/hw-uuid
|
||||
rm -f $mnt/etc/smolt/uuid
|
||||
rm -f $mnt/etc/smolt/hw-uuid
|
||||
fi
|
||||
|
||||
if [ "$ssh_hostkeys" = "yes" -a "$type" != "windows" ]; then
|
||||
rm -rf $mnt/etc/ssh/*_host_*
|
||||
fi
|
||||
|
||||
if [ "$udev_persistent_net" = "yes" -a "$type" = "linux" ]; then
|
||||
rm -f $mnt/etc/udev/rules.d/70-persistent-net.rules
|
||||
fi
|
||||
|
||||
if [ "$utmp" = "yes" -a "$type" != "windows" ]; then
|
||||
rm -f $mnt/var/run/utmp
|
||||
fi
|
||||
|
||||
if [ "$yum_uuid" = "yes" -a "$package_management" = "yum" ]; then
|
||||
rm -f $mnt/var/lib/yum/uuid
|
||||
fi
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Clean up and close down.
|
||||
|
||||
# If we created any new files and the guest uses SELinux, then we have
|
||||
# to relabel the filesystem on boot. Could do with a better way to
|
||||
# test "guest uses SELinux" (XXX).
|
||||
case "$selinux_relabel/$created_files" in
|
||||
yes/*)
|
||||
touch $mnt/.autorelabel;;
|
||||
auto/yes)
|
||||
case "$type/$distro" in
|
||||
linux/fedora|linux/rhel|linux/centos|linux/scientificlinux|linux/redhat-based)
|
||||
touch $mnt/.autorelabel
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
sync
|
||||
|
||||
fusermount -u $tmpdir/mnt
|
||||
rm -rf $tmpdir
|
||||
|
||||
trap - EXIT ERR
|
||||
|
||||
exit 0
|
||||
917
configure.ac
917
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -5,25 +5,6 @@ autobuild/
|
||||
The autobuild script that we use to build and test the
|
||||
tarballs on Debian and elsewhere.
|
||||
|
||||
centos5.3-libguestfs.spec
|
||||
[REMOVED]
|
||||
This used to be a centos5.3 specfile. Please use the specfile
|
||||
from EL-5 here:
|
||||
http://pkgs.fedoraproject.org/gitweb/?p=libguestfs.git;a=shortlog;h=refs/heads/el5/master
|
||||
or the RHEL 5 source RPMs here:
|
||||
http://libguestfs.org/download/binaries/rhel5-packages/
|
||||
|
||||
febootstrap/
|
||||
[REMOVED]
|
||||
An experimental, non-working attempt to use febootstrap
|
||||
to install operating systems.
|
||||
|
||||
fedora-libguestfs.spec
|
||||
[REMOVED]
|
||||
This used to be a Fedora 10+ specfile. Please use the specfile
|
||||
from Fedora instead:
|
||||
http://pkgs.fedoraproject.org/gitweb/?p=libguestfs.git
|
||||
|
||||
guestfsd-in-wine.sh
|
||||
Run a Windows-compiled guestfsd under Wine. Read the
|
||||
instructions at the top of this file carefully.
|
||||
@@ -34,6 +15,13 @@ intro/ "Slides" for an intro to libguestfs. This is a short (10-15
|
||||
self-contained HTML page with a handful images that can be
|
||||
easily distributed before the talk.
|
||||
|
||||
make-check-on-installed.pl
|
||||
This Perl script allows you to run the test suite (ie. 'make
|
||||
check', 'make extra-tests' etc) on an installed RPM. This is
|
||||
useful for adding another layer of testing to packages before
|
||||
we release them. Note that a checked out copy of the source
|
||||
from git is required. Read the top of the file before using.
|
||||
|
||||
visualize-alignment/
|
||||
Tests for visualizing block device reads and writes and
|
||||
alignment using a patched qemu. See the README file in that
|
||||
|
||||
@@ -119,6 +119,7 @@ char *
|
||||
return get_blkid_tag (device, "TYPE");
|
||||
}
|
||||
|
||||
GUESTFSD_EXT_CMD(str_blkid, blkid);
|
||||
static char *
|
||||
get_blkid_tag (const char *device, const char *tag)
|
||||
{
|
||||
@@ -126,7 +127,7 @@ get_blkid_tag (const char *device, const char *tag)
|
||||
int r;
|
||||
|
||||
r = commandr (&out, &err,
|
||||
"blkid",
|
||||
str_blkid,
|
||||
"-c", "/dev/null",
|
||||
"-o", "value", "-s", tag, device, NULL);
|
||||
if (r != 0 && r != 2) {
|
||||
@@ -182,9 +183,9 @@ get_blkid_tag (const char *device, const char *tag)
|
||||
<tr><td valign="top" style="padding-bottom: 1.5em;" colspan="2">
|
||||
<pre>
|
||||
<b>guestfish -N bootrootlv:/dev/VG/LV:ext4:ext4:10G:256M <<EOF</b>
|
||||
<font style="color: green;">mount-options "" /dev/VG/LV /
|
||||
<font style="color: green;">mount /dev/VG/LV /
|
||||
mkdir /boot
|
||||
mount-options "" /dev/sda1 /boot
|
||||
mount /dev/sda1 /boot
|
||||
txz-in filesystem.tar.xz /
|
||||
write /etc/HOSTNAME "test01.example.com\n"
|
||||
upload /etc/resolv.conf /etc/resolv.conf</font>
|
||||
|
||||
@@ -159,4 +159,3 @@ screenshots shown. But many people will simply want to mount
|
||||
a filesystem on the host using guestmount, and then use
|
||||
ordinary tools. At the bottom is a screenshot of GNOME
|
||||
Nautilus browsing into a guest filesystem.
|
||||
|
||||
|
||||
177
contrib/make-check-on-installed.pl
Executable file
177
contrib/make-check-on-installed.pl
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/perl -w
|
||||
# libguestfs
|
||||
# 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
|
||||
# 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.
|
||||
|
||||
# This script allows you to run the test suite ('make check' etc) on
|
||||
# an installed copy of libguestfs. Currently only RPM installs are
|
||||
# supported, but adding support for dpkg would be relatively
|
||||
# straightforward. It works by examining the installed packages, and
|
||||
# copying binaries (eg. '/usr/bin/guestfish') and libraries into the
|
||||
# correct place in the local directory.
|
||||
#
|
||||
# * You MUST have the full source tree unpacked locally. Either
|
||||
# use the same source tarball as the version you are testing, or
|
||||
# check it out from git and 'git-reset' to the right version tag.
|
||||
#
|
||||
# * You MUST do a successful local build from source before using
|
||||
# this script (ie. './autogen.sh && make').
|
||||
#
|
||||
# Run the script from the top builddir. Usually:
|
||||
#
|
||||
# ./contrib/make-check-on-installed.pl
|
||||
#
|
||||
# If the script runs successfully, then run the test suite as normal:
|
||||
#
|
||||
# make check
|
||||
# make extra-tests
|
||||
#
|
||||
# To switch back to running the test suite on the locally built
|
||||
# version, do:
|
||||
#
|
||||
# make clean && make
|
||||
|
||||
use strict;
|
||||
|
||||
die "wrong directory -- read the file before running\n" unless -f "BUGS";
|
||||
|
||||
my $cmd;
|
||||
|
||||
# Remove all libtool crappage.
|
||||
$cmd = "find -name 'lt-*' | grep -v '/tests/' | grep '/.libs/lt-' | xargs -r rm";
|
||||
system ($cmd) == 0 or die "$cmd: failed\n";
|
||||
|
||||
$cmd = "find -name 'lib*.so*' | grep -v '/tests/' | grep '/.libs/lib' | xargs -r rm";
|
||||
system ($cmd) == 0 or die "$cmd: failed\n";
|
||||
|
||||
# Map of installed file to local file. Key is a regexp.
|
||||
# Remember that ONLY libraries and binaries need to be copied.
|
||||
my %mapping = (
|
||||
'/bin/erl-guestfs$' => "erlang",
|
||||
'/bin/libguestfs-test-tool$' => "test-tool",
|
||||
'/bin/guestfish$' => "fish",
|
||||
'/bin/guestmount$' => "fuse",
|
||||
'/bin/virt-alignment-scan$' => "align",
|
||||
'/bin/virt-cat$' => "cat",
|
||||
'/bin/virt-copy-in$' => "fish",
|
||||
'/bin/virt-copy-out$' => "fish",
|
||||
'/bin/virt-df$' => "df",
|
||||
'/bin/virt-edit$' => "edit",
|
||||
'/bin/virt-filesystems$' => "cat",
|
||||
'/bin/virt-format$' => "format",
|
||||
'/bin/virt-inspector$' => "inspector",
|
||||
'/bin/virt-list-filesystems$' => "tools",
|
||||
'/bin/virt-list-partitions$' => "tools",
|
||||
'/bin/virt-ls$' => "cat",
|
||||
'/bin/virt-make-fs$' => "tools",
|
||||
'/bin/virt-rescue$' => "rescue",
|
||||
'/bin/virt-resize$' => "resize",
|
||||
'/bin/virt-sparsify$' => "sparsify",
|
||||
'/bin/virt-sysprep$' => "sysprep",
|
||||
'/bin/virt-tar$' => "tools",
|
||||
'/bin/virt-tar-in$' => "fish",
|
||||
'/bin/virt-tar-out$' => "fish",
|
||||
'/bin/virt-win-reg$' => "tools",
|
||||
|
||||
# Ignore this because the daemon is included in the appliance.
|
||||
'/sbin/guestfsd$' => "IGNORE",
|
||||
|
||||
'/erlang/lib/libguestfs-.*/ebin/guestfs\.beam$' => "erlang",
|
||||
|
||||
'/girepository-1\.0/Guestfs-1\.0\.typelib$' => "gobject",
|
||||
'/gir-1.0/Guestfs-1.0.gir$' => "gobject",
|
||||
|
||||
'/guestfs/supermin.d/.*' => "appliance/supermin.d",
|
||||
|
||||
'/java/libguestfs-.*\.jar$' => "java",
|
||||
|
||||
'/libguestfs\.so.*' => "src/.libs",
|
||||
'/libguestfs_jni\.so.*' => "java/.libs",
|
||||
'/libguestfs-gobject-1\.0\.so.*' => "gobject/.libs",
|
||||
|
||||
'/ocaml/.*\.cmi$' => "IGNORE",
|
||||
'/ocaml/.*\.cmo$' => "ocaml",
|
||||
'/ocaml/.*\.cmx$' => "ocaml",
|
||||
'/ocaml/.*\.cma$' => "ocaml",
|
||||
'/ocaml/.*\.cmxa$' => "ocaml",
|
||||
'/ocaml/.*\.a$' => "ocaml",
|
||||
'/ocaml/.*\.so$' => "ocaml",
|
||||
'/ocaml/.*\.so.owner$' => "IGNORE",
|
||||
'/ocaml/.*META$' => "IGNORE",
|
||||
'/ocaml/.*/guestfs\.mli$' => "IGNORE",
|
||||
'/ocaml/.*/guestfs\.ml$' => "IGNORE",
|
||||
|
||||
'/perl5/.*/Guestfs\.so$' => "perl/blib/arch/auto/Sys/Guestfs",
|
||||
'/perl5/.*/Guestfs.pm$' => "perl/blib/lib/Sys/Guestfs.pm",
|
||||
'/perl5/.*/Lib.pm$' => "perl/blib/lib/Sys/Guestfs/Lib.pm",
|
||||
|
||||
'/php/modules/guestfs_php\.so$' => "php/extension/modules",
|
||||
'/php/modules/guestfs_php\.so$' => "php/extension/.libs",
|
||||
|
||||
'/python.*/libguestfsmod\.so$' => "python/.libs",
|
||||
'/python.*/guestfs\.py' => "IGNORE",
|
||||
'/python.*/guestfs\.pyc$' => "python/guestfs.pyc",
|
||||
'/python.*/guestfs\.pyo$' => "python/guestfs.pyo",
|
||||
|
||||
'/ruby/.*/_guestfs\.so$' => "ruby/ext/guestfs",
|
||||
'/ruby/.*/guestfs\.rb$' => "IGNORE",
|
||||
|
||||
'/share/doc/' => "IGNORE",
|
||||
'/share/javadoc/' => "IGNORE",
|
||||
'/share/locale/' => "IGNORE",
|
||||
'/share/man/' => "IGNORE",
|
||||
|
||||
'^/etc/' => "IGNORE",
|
||||
'/systemd/' => "IGNORE",
|
||||
'/include/guestfs\.h$' => "IGNORE",
|
||||
'/include/guestfs-gobject\.h$' => "IGNORE",
|
||||
'/libguestfs\.pc$' => "IGNORE",
|
||||
);
|
||||
|
||||
# Get list of installed files.
|
||||
$cmd = 'rpm -ql $(rpm -qa | grep -i guestf | grep -v debug) | sort';
|
||||
my @files;
|
||||
open CMD, "$cmd |" or die "$cmd: $!";
|
||||
while (<CMD>) {
|
||||
chomp;
|
||||
push @files, $_;
|
||||
}
|
||||
close CMD;
|
||||
|
||||
# Now try to map (copy) installed files to the local equivalents.
|
||||
foreach my $file (@files) {
|
||||
my $match = 0;
|
||||
foreach my $regexp (keys %mapping) {
|
||||
if ($file =~ m/$regexp/) {
|
||||
my $dest = $mapping{$regexp};
|
||||
if ($dest ne "IGNORE") {
|
||||
# Make destination writable if it's a file.
|
||||
chmod 0644, "$dest" if -f "$dest" && ! -w "$dest";
|
||||
|
||||
# Copy file to destination.
|
||||
$cmd = "cp '$file' '$dest'";
|
||||
system ($cmd) == 0 or die "$cmd: failed\n";
|
||||
print "$file => $dest\n";
|
||||
}
|
||||
$match++;
|
||||
}
|
||||
}
|
||||
if ($match == 0) {
|
||||
if (! -d $file) {
|
||||
warn "WARNING: file '$file' is unmatched\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
31
daemon/9p.c
31
daemon/9p.c
@@ -33,6 +33,7 @@
|
||||
#include "actions.h"
|
||||
|
||||
#define BUS_PATH "/sys/bus/virtio/drivers/9pnet_virtio"
|
||||
GUESTFSD_EXT_CMD(str_mount, mount);
|
||||
|
||||
static char *read_whole_file (const char *filename);
|
||||
|
||||
@@ -40,11 +41,9 @@ static char *read_whole_file (const char *filename);
|
||||
char **
|
||||
do_list_9p (void)
|
||||
{
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (r);
|
||||
|
||||
DIR *dir;
|
||||
int err = 0;
|
||||
|
||||
dir = opendir (BUS_PATH);
|
||||
if (!dir) {
|
||||
@@ -56,10 +55,10 @@ do_list_9p (void)
|
||||
* the virtio driver isn't loaded. Don't return an error
|
||||
* in this case, but return an empty list.
|
||||
*/
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&r) == -1)
|
||||
return NULL;
|
||||
|
||||
return r;
|
||||
return r.argv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
@@ -80,7 +79,7 @@ do_list_9p (void)
|
||||
if (mount_tag == 0)
|
||||
continue;
|
||||
|
||||
if (add_string (&r, &size, &alloc, mount_tag) == -1) {
|
||||
if (add_string (&r, mount_tag) == -1) {
|
||||
free (mount_tag);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
@@ -93,7 +92,7 @@ do_list_9p (void)
|
||||
/* Check readdir didn't fail */
|
||||
if (errno != 0) {
|
||||
reply_with_perror ("readdir: /sys/block");
|
||||
free_stringslen (r, size);
|
||||
free_stringslen (r.argv, r.size);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
@@ -101,19 +100,19 @@ do_list_9p (void)
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: /sys/block");
|
||||
free_stringslen (r, size);
|
||||
free_stringslen (r.argv, r.size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sort the tags. Note that r might be NULL if there are no tags. */
|
||||
if (r != NULL)
|
||||
sort_strings (r, size);
|
||||
/* Sort the tags. */
|
||||
if (r.size > 0)
|
||||
sort_strings (r.argv, r.size);
|
||||
|
||||
/* NULL terminate the list */
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&r) == -1)
|
||||
return NULL;
|
||||
|
||||
return r;
|
||||
return r.argv;
|
||||
}
|
||||
|
||||
/* Read whole file into dynamically allocated array. If there is an
|
||||
@@ -127,7 +126,7 @@ read_whole_file (const char *filename)
|
||||
size_t alloc = 0, size = 0;
|
||||
int fd;
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
fd = open (filename, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
perror (filename);
|
||||
return NULL;
|
||||
@@ -139,6 +138,7 @@ read_whole_file (const char *filename)
|
||||
if (r2 == NULL) {
|
||||
perror ("realloc");
|
||||
free (r);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
r = r2;
|
||||
@@ -150,6 +150,7 @@ read_whole_file (const char *filename)
|
||||
if (n == -1) {
|
||||
perror (filename);
|
||||
free (r);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
if (n == 0)
|
||||
@@ -211,7 +212,7 @@ do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options)
|
||||
}
|
||||
|
||||
r = command (NULL, &err,
|
||||
"mount", "-o", opts, "-t", "9p", mount_tag, mp, NULL);
|
||||
str_mount, "-o", opts, "-t", "9p", mount_tag, mp, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s on %s: %s", mount_tag, mountpoint, err);
|
||||
goto out;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
CLEANFILES = stamp-guestfsd.pod
|
||||
|
||||
libsrcdir = $(top_builddir)/src
|
||||
|
||||
generator_built = \
|
||||
@@ -28,12 +30,14 @@ 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
|
||||
|
||||
EXTRA_DIST = $(BUILT_SOURCES)
|
||||
EXTRA_DIST = \
|
||||
$(BUILT_SOURCES) \
|
||||
guestfsd.pod
|
||||
|
||||
noinst_LIBRARIES = libprotocol.a
|
||||
|
||||
@@ -57,16 +61,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 +110,7 @@ guestfsd_SOURCES = \
|
||||
dmesg.c \
|
||||
dropcaches.c \
|
||||
du.c \
|
||||
echo_daemon.c \
|
||||
echo-daemon.c \
|
||||
ext2.c \
|
||||
fallocate.c \
|
||||
file.c \
|
||||
@@ -114,17 +118,22 @@ guestfsd_SOURCES = \
|
||||
fill.c \
|
||||
find.c \
|
||||
fsck.c \
|
||||
fstrim.c \
|
||||
glob.c \
|
||||
grep.c \
|
||||
grub.c \
|
||||
guestfsd.c \
|
||||
headtail.c \
|
||||
hexdump.c \
|
||||
hotplug.c \
|
||||
hivex.c \
|
||||
htonl.c \
|
||||
initrd.c \
|
||||
inotify.c \
|
||||
internal.c \
|
||||
is.c \
|
||||
isoinfo.c \
|
||||
labels.c \
|
||||
link.c \
|
||||
ls.c \
|
||||
luks.c \
|
||||
@@ -133,10 +142,12 @@ guestfsd_SOURCES = \
|
||||
md.c \
|
||||
mkfs.c \
|
||||
mknod.c \
|
||||
mktemp.c \
|
||||
modprobe.c \
|
||||
mount.c \
|
||||
names.c \
|
||||
ntfs.c \
|
||||
ntfsclone.c \
|
||||
optgroups.c \
|
||||
optgroups.h \
|
||||
parted.c \
|
||||
@@ -144,6 +155,7 @@ guestfsd_SOURCES = \
|
||||
proto.c \
|
||||
readdir.c \
|
||||
realpath.c \
|
||||
rsync.c \
|
||||
scrub.c \
|
||||
selinux.c \
|
||||
sfdisk.c \
|
||||
@@ -159,15 +171,19 @@ 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 \
|
||||
$(SELINUX_LIB) \
|
||||
$(AUGEAS_LIBS) \
|
||||
$(HIVEX_LIBS) \
|
||||
$(top_builddir)/gnulib/lib/.libs/libgnu.a \
|
||||
$(GETADDRINFO_LIB) \
|
||||
$(HOSTENT_LIB) \
|
||||
@@ -178,6 +194,24 @@ guestfsd_LDADD = \
|
||||
$(SERVENT_LIB)
|
||||
|
||||
guestfsd_CPPFLAGS = -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
|
||||
guestfsd_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) $(AUGEAS_CFLAGS)
|
||||
guestfsd_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(AUGEAS_CFLAGS) \
|
||||
$(HIVEX_CFLAGS)
|
||||
|
||||
# Manual pages and HTML files for the website.
|
||||
man_MANS = guestfsd.8
|
||||
noinst_DATA = $(top_builddir)/html/guestfsd.8.html
|
||||
|
||||
guestfsd.8 $(top_builddir)/html/guestfsd.8.html: stamp-guestfsd.pod
|
||||
|
||||
stamp-guestfsd.pod: guestfsd.pod
|
||||
$(PODWRAPPER) \
|
||||
--section 8 \
|
||||
--man guestfsd.8 \
|
||||
--html $(top_builddir)/html/guestfsd.8.html \
|
||||
--license GPLv2+ \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
.PHONY: force
|
||||
|
||||
192
daemon/augeas.c
192
daemon/augeas.c
@@ -38,6 +38,17 @@
|
||||
*/
|
||||
static augeas *aug = NULL;
|
||||
|
||||
/* Clean up the augeas handle on daemon exit. */
|
||||
static void aug_finalize (void) __attribute__((destructor));
|
||||
static void
|
||||
aug_finalize (void)
|
||||
{
|
||||
if (aug) {
|
||||
aug_close (aug);
|
||||
aug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define NEED_AUG(errcode) \
|
||||
do { \
|
||||
if (!aug) { \
|
||||
@@ -52,19 +63,11 @@ optgroup_augeas_available (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#else /* !HAVE_AUGEAS */
|
||||
int
|
||||
optgroup_augeas_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We need to rewrite the root path so it is based at /sysroot. */
|
||||
int
|
||||
do_aug_init (const char *root, int flags)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
char *buf;
|
||||
|
||||
if (aug) {
|
||||
@@ -87,24 +90,17 @@ do_aug_init (const char *root, int flags)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_close (void)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
NEED_AUG(-1);
|
||||
|
||||
aug_close (aug);
|
||||
aug = NULL;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@@ -122,7 +118,8 @@ do_aug_defvar (const char *name, const char *expr)
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
reply_with_error ("function not available");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -130,27 +127,36 @@ guestfs_int_int_bool *
|
||||
do_aug_defnode (const char *name, const char *expr, const char *val)
|
||||
{
|
||||
#ifdef HAVE_AUG_DEFNODE
|
||||
static guestfs_int_int_bool r;
|
||||
int created;
|
||||
guestfs_int_int_bool *r;
|
||||
int i, created;
|
||||
|
||||
NEED_AUG (NULL);
|
||||
|
||||
r.i = aug_defnode (aug, name, expr, val, &created);
|
||||
if (r.i == -1) {
|
||||
i = aug_defnode (aug, name, expr, val, &created);
|
||||
if (i == -1) {
|
||||
reply_with_error ("Augeas defnode failed");
|
||||
return NULL;
|
||||
}
|
||||
r.b = created;
|
||||
return &r;
|
||||
|
||||
r = malloc (sizeof *r);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r->i = i;
|
||||
r->b = created;
|
||||
|
||||
return r;
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
reply_with_error ("function not available");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
char *
|
||||
do_aug_get (const char *path)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
const char *value = NULL;
|
||||
char *v;
|
||||
int r;
|
||||
@@ -184,15 +190,11 @@ do_aug_get (const char *path)
|
||||
}
|
||||
|
||||
return v; /* Caller frees. */
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_set (const char *path, const char *val)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
int r;
|
||||
|
||||
NEED_AUG (-1);
|
||||
@@ -204,15 +206,11 @@ do_aug_set (const char *path, const char *val)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_clear (const char *path)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
int r;
|
||||
|
||||
NEED_AUG (-1);
|
||||
@@ -224,15 +222,11 @@ do_aug_clear (const char *path)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_insert (const char *path, const char *label, int before)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
int r;
|
||||
|
||||
NEED_AUG (-1);
|
||||
@@ -244,15 +238,11 @@ do_aug_insert (const char *path, const char *label, int before)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_rm (const char *path)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
int r;
|
||||
|
||||
NEED_AUG (-1);
|
||||
@@ -264,15 +254,11 @@ do_aug_rm (const char *path)
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_mv (const char *src, const char *dest)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
int r;
|
||||
|
||||
NEED_AUG (-1);
|
||||
@@ -284,15 +270,11 @@ do_aug_mv (const char *src, const char *dest)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
char **
|
||||
do_aug_match (const char *path)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
char **matches = NULL;
|
||||
void *vp;
|
||||
int r;
|
||||
@@ -318,15 +300,11 @@ do_aug_match (const char *path)
|
||||
matches[r] = NULL;
|
||||
|
||||
return matches; /* Caller frees. */
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_aug_save (void)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
NEED_AUG (-1);
|
||||
|
||||
if (aug_save (aug) == -1) {
|
||||
@@ -335,9 +313,6 @@ do_aug_save (void)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@@ -353,7 +328,8 @@ do_aug_load (void)
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
reply_with_error ("function not available");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -361,10 +337,9 @@ do_aug_load (void)
|
||||
char **
|
||||
do_aug_ls (const char *path)
|
||||
{
|
||||
#ifdef HAVE_AUGEAS
|
||||
char **matches;
|
||||
char *buf;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
NEED_AUG (NULL);
|
||||
|
||||
@@ -400,7 +375,102 @@ do_aug_ls (const char *path)
|
||||
|
||||
sort_strings (matches, count_strings ((void *) matches));
|
||||
return matches; /* Caller frees. */
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* !HAVE_AUGEAS */
|
||||
|
||||
/* Note that the wrapper code (daemon/stubs.c) ensures that the
|
||||
* functions below are never called because optgroup_augeas_available
|
||||
* returns false.
|
||||
*/
|
||||
int
|
||||
optgroup_augeas_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_init (const char *root, int flags)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_close (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_defvar (const char *name, const char *expr)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
guestfs_int_int_bool * __attribute__((noreturn))
|
||||
do_aug_defnode (const char *name, const char *expr, const char *val)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char * __attribute__((noreturn))
|
||||
do_aug_get (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_set (const char *path, const char *val)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_clear (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_insert (const char *path, const char *label, int before)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_rm (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_mv (const char *src, const char *dest)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char ** __attribute__((noreturn))
|
||||
do_aug_match (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_save (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_aug_load (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char ** __attribute__((noreturn))
|
||||
do_aug_ls (const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,9 +22,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_grep, grep);
|
||||
GUESTFSD_EXT_CMD(str_modprobe, modprobe);
|
||||
|
||||
int
|
||||
do_available (char *const *groups)
|
||||
@@ -58,16 +64,91 @@ char **
|
||||
do_available_all_groups (void)
|
||||
{
|
||||
size_t i;
|
||||
char **groups = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (groups);
|
||||
|
||||
for (i = 0; optgroups[i].group != NULL; ++i) {
|
||||
if (add_string (&groups, &size, &alloc, optgroups[i].group) == -1)
|
||||
if (add_string (&groups, optgroups[i].group) == -1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_string (&groups, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&groups) == -1)
|
||||
return NULL;
|
||||
|
||||
return groups; /* caller frees */
|
||||
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, str_grep, regex, "/proc/filesystems", NULL);
|
||||
if (r == -1 || r >= 2) {
|
||||
fprintf (stderr, "grep /proc/filesystems: %s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
/* Do modprobe, ignore any errors. */
|
||||
static void
|
||||
modprobe (const char *module)
|
||||
{
|
||||
command (NULL, NULL, str_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;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_base64, base64);
|
||||
|
||||
static int
|
||||
write_cb (void *fd_ptr, const void *buf, size_t len)
|
||||
{
|
||||
@@ -42,7 +44,7 @@ do_base64_in (const char *file)
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
|
||||
if (asprintf_nowarn (&cmd, "base64 -d -i > %R", file) == -1) {
|
||||
if (asprintf_nowarn (&cmd, "%s -d -i > %R", str_base64, file) == -1) {
|
||||
err = errno;
|
||||
cancel_receive ();
|
||||
errno = err;
|
||||
@@ -102,7 +104,7 @@ do_base64_out (const char *file)
|
||||
char *cmd;
|
||||
char buf[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
if (asprintf_nowarn (&cmd, "base64 %R", file) == -1) {
|
||||
if (asprintf_nowarn (&cmd, "%s %R", str_base64, file) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_blkid, blkid);
|
||||
|
||||
static char *
|
||||
get_blkid_tag (const char *device, const char *tag)
|
||||
{
|
||||
@@ -34,7 +36,7 @@ get_blkid_tag (const char *device, const char *tag)
|
||||
int r;
|
||||
|
||||
r = commandr (&out, &err,
|
||||
"blkid",
|
||||
str_blkid,
|
||||
/* Adding -c option kills all caching, even on RHEL 5. */
|
||||
"-c", "/dev/null",
|
||||
"-o", "value", "-s", tag, device, NULL);
|
||||
@@ -94,10 +96,9 @@ static int
|
||||
test_blkid_p_i_opt (void)
|
||||
{
|
||||
int r;
|
||||
int result;
|
||||
char *err;
|
||||
|
||||
r = commandr (NULL, &err, "blkid", "-p", "/dev/null", NULL);
|
||||
r = commandr (NULL, &err, str_blkid, "-p", "/dev/null", NULL);
|
||||
if (r == -1) {
|
||||
/* This means we couldn't run the blkid command at all. */
|
||||
command_failed:
|
||||
@@ -112,7 +113,7 @@ test_blkid_p_i_opt (void)
|
||||
}
|
||||
free (err);
|
||||
|
||||
r = commandr (NULL, &err, "blkid", "-i", NULL);
|
||||
r = commandr (NULL, &err, str_blkid, "-i", NULL);
|
||||
if (r == -1)
|
||||
goto command_failed;
|
||||
|
||||
@@ -129,25 +130,23 @@ test_blkid_p_i_opt (void)
|
||||
static char **
|
||||
blkid_with_p_i_opt (const char *device)
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
r = command(&out, &err, "blkid", "-c", "/dev/null",
|
||||
r = command (&out, &err, str_blkid, "-c", "/dev/null",
|
||||
"-p", "-i", "-o", "export", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error("%s", err);
|
||||
reply_with_error ("%s", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Split the command output into lines */
|
||||
lines = split_lines(out);
|
||||
if (lines == NULL) {
|
||||
reply_with_perror("malloc");
|
||||
lines = split_lines (out);
|
||||
if (lines == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Parse the output of blkid -p -i -o export:
|
||||
* UUID=b6d83437-c6b4-4bf0-8381-ef3fc3578590
|
||||
@@ -164,38 +163,40 @@ blkid_with_p_i_opt (const char *device)
|
||||
* PART_ENTRY_SIZE=104857600
|
||||
* PART_ENTRY_DISK=8:0
|
||||
*/
|
||||
for (char **i = lines; *i != NULL; i++) {
|
||||
char *line = *i;
|
||||
for (i = 0; lines[i] != NULL; ++i) {
|
||||
char *line = lines[i];
|
||||
|
||||
/* Skip blank lines (shouldn't happen) */
|
||||
if (line[0] == '\0') continue;
|
||||
|
||||
/* Split the line in 2 at the equals sign */
|
||||
char *eq = strchr(line, '=');
|
||||
char *eq = strchr (line, '=');
|
||||
if (eq) {
|
||||
*eq = '\0'; eq++;
|
||||
|
||||
/* Add the key/value pair to the output */
|
||||
if (add_string(&ret, &size, &alloc, line) == -1 ||
|
||||
add_string(&ret, &size, &alloc, eq) == -1) goto error;
|
||||
if (add_string (&ret, line) == -1 ||
|
||||
add_string (&ret, eq) == -1) goto error;
|
||||
} else {
|
||||
fprintf(stderr, "blkid: unexpected blkid output ignored: %s", line);
|
||||
fprintf (stderr, "blkid: unexpected blkid output ignored: %s", line);
|
||||
}
|
||||
}
|
||||
|
||||
if (add_string(&ret, &size, &alloc, NULL) == -1) goto error;
|
||||
if (end_stringsbuf (&ret) == -1) goto error;
|
||||
|
||||
free(out);
|
||||
free(err);
|
||||
free(lines);
|
||||
free (out);
|
||||
free (err);
|
||||
free_strings (lines);
|
||||
|
||||
return ret;
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
free(out);
|
||||
free(err);
|
||||
if (lines) free(lines);
|
||||
if (ret) free_strings(ret);
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
if (ret.argv)
|
||||
free_strings (ret.argv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -204,33 +205,32 @@ static char **
|
||||
blkid_without_p_i_opt(const char *device)
|
||||
{
|
||||
char *s;
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
if (add_string (&ret, &size, &alloc, "TYPE") == -1) goto error;
|
||||
if (add_string (&ret, "TYPE") == -1) goto error;
|
||||
s = get_blkid_tag (device, "TYPE");
|
||||
if (s == NULL) goto error;
|
||||
if (add_string (&ret, &size, &alloc, s) == -1)
|
||||
if (add_string (&ret, s) == -1)
|
||||
goto error;
|
||||
|
||||
if (add_string (&ret, &size, &alloc, "LABEL") == -1) goto error;
|
||||
if (add_string (&ret, "LABEL") == -1) goto error;
|
||||
s = get_blkid_tag (device, "LABEL");
|
||||
if (s == NULL) goto error;
|
||||
if (add_string (&ret, &size, &alloc, s) == -1)
|
||||
if (add_string (&ret, s) == -1)
|
||||
goto error;
|
||||
|
||||
if (add_string (&ret, &size, &alloc, "UUID") == -1) goto error;
|
||||
if (add_string (&ret, "UUID") == -1) goto error;
|
||||
s = get_blkid_tag (device, "UUID");
|
||||
if (s == NULL) goto error;
|
||||
if (add_string (&ret, &size, &alloc, s) == -1)
|
||||
if (add_string (&ret, s) == -1)
|
||||
goto error;
|
||||
|
||||
if (add_string (&ret, &size, &alloc, NULL) == -1) goto error;
|
||||
if (end_stringsbuf (&ret) == -1) goto error;
|
||||
|
||||
return ret;
|
||||
return ret.argv;
|
||||
error:
|
||||
if (ret)
|
||||
free_strings (ret);
|
||||
if (ret.argv)
|
||||
free_strings (ret.argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -238,12 +238,6 @@ char **
|
||||
do_blkid (const char *device)
|
||||
{
|
||||
static int blkid_has_p_i_opt = -1;
|
||||
int r;
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
|
||||
if (blkid_has_p_i_opt == -1) {
|
||||
blkid_has_p_i_opt = test_blkid_p_i_opt ();
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_blockdev, blockdev);
|
||||
|
||||
/* These functions are all about using the blockdev command, so
|
||||
* we centralize it in one call.
|
||||
*/
|
||||
@@ -38,7 +40,7 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
|
||||
int64_t rv;
|
||||
char *out, *err;
|
||||
const char *argv[] = {
|
||||
"blockdev",
|
||||
str_blockdev,
|
||||
switc,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -46,6 +48,20 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
|
||||
};
|
||||
char buf[64];
|
||||
|
||||
/* When you call close on any block device, udev kicks off a rule
|
||||
* which runs blkid to reexamine the device. We need to wait for
|
||||
* this rule to finish running (from a previous operation) since it
|
||||
* holds the device open and can cause other operations to fail,
|
||||
* notably BLKRRPART.
|
||||
*
|
||||
* This is particularly a problem where we have just written to a
|
||||
* device (eg. zeroing it) and immediately call blockdev --rereadpt.
|
||||
*
|
||||
* Therefore, wait for udev to finish all outstanding events before
|
||||
* performing any blockdev command.
|
||||
*/
|
||||
udev_settle ();
|
||||
|
||||
if (extraarg > 0) {
|
||||
snprintf (buf, sizeof buf, "%d", extraarg);
|
||||
argv[2] = buf;
|
||||
|
||||
592
daemon/btrfs.c
592
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,22 @@
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
#define MAX_ARGS 64
|
||||
GUESTFSD_EXT_CMD(str_btrfs, btrfs);
|
||||
GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
|
||||
GUESTFSD_EXT_CMD(str_btrfsck, btrfsck);
|
||||
GUESTFSD_EXT_CMD(str_mkfs_btrfs, mkfs.btrfs);
|
||||
|
||||
int
|
||||
optgroup_btrfs_available (void)
|
||||
{
|
||||
return prog_exists ("btrfs");
|
||||
return prog_exists (str_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;
|
||||
@@ -47,7 +51,7 @@ do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
size_t i = 0;
|
||||
char size_str[32];
|
||||
|
||||
ADD_ARG (argv, i, "btrfs");
|
||||
ADD_ARG (argv, i, str_btrfs);
|
||||
ADD_ARG (argv, i, "filesystem");
|
||||
ADD_ARG (argv, i, "resize");
|
||||
|
||||
@@ -84,3 +88,583 @@ do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
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, j;
|
||||
int r;
|
||||
char *err;
|
||||
char allocstart_s[64];
|
||||
char bytecount_s[64];
|
||||
char leafsize_s[64];
|
||||
char nodesize_s[64];
|
||||
char sectorsize_s[64];
|
||||
|
||||
ADD_ARG (argv, i, str_mkfs_btrfs);
|
||||
|
||||
/* Optional arguments. */
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_ALLOCSTART_BITMASK) {
|
||||
if (allocstart < 0) {
|
||||
reply_with_error ("allocstart must be >= 0");
|
||||
return -1;
|
||||
}
|
||||
snprintf (allocstart_s, sizeof allocstart_s, "%" PRIi64, allocstart);
|
||||
ADD_ARG (argv, i, "--alloc-start");
|
||||
ADD_ARG (argv, i, allocstart_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_BYTECOUNT_BITMASK) {
|
||||
if (bytecount <= 0) { /* actually the minimum is 256MB */
|
||||
reply_with_error ("bytecount must be > 0");
|
||||
return -1;
|
||||
}
|
||||
snprintf (bytecount_s, sizeof bytecount_s, "%" PRIi64, bytecount);
|
||||
ADD_ARG (argv, i, "--byte-count");
|
||||
ADD_ARG (argv, i, bytecount_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_DATATYPE_BITMASK) {
|
||||
if (STRNEQ (datatype, "raid0") && STRNEQ (datatype, "raid1") &&
|
||||
STRNEQ (datatype, "raid10") && STRNEQ (datatype, "single")) {
|
||||
reply_with_error ("datatype not one of the allowed values");
|
||||
return -1;
|
||||
}
|
||||
ADD_ARG (argv, i, "--data");
|
||||
ADD_ARG (argv, i, datatype);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_LEAFSIZE_BITMASK) {
|
||||
if (!is_power_of_2 (leafsize) || leafsize <= 0) {
|
||||
reply_with_error ("leafsize must be > 0 and a power of two");
|
||||
return -1;
|
||||
}
|
||||
snprintf (leafsize_s, sizeof leafsize_s, "%d", leafsize);
|
||||
ADD_ARG (argv, i, "--leafsize");
|
||||
ADD_ARG (argv, i, leafsize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_LABEL_BITMASK) {
|
||||
ADD_ARG (argv, i, "--label");
|
||||
ADD_ARG (argv, i, label);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_METADATA_BITMASK) {
|
||||
if (STRNEQ (metadata, "raid0") && STRNEQ (metadata, "raid1") &&
|
||||
STRNEQ (metadata, "raid10") && STRNEQ (metadata, "single")) {
|
||||
reply_with_error ("metadata not one of the allowed values");
|
||||
return -1;
|
||||
}
|
||||
ADD_ARG (argv, i, "--metadata");
|
||||
ADD_ARG (argv, i, metadata);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_NODESIZE_BITMASK) {
|
||||
if (!is_power_of_2 (nodesize) || nodesize <= 0) {
|
||||
reply_with_error ("nodesize must be > 0 and a power of two");
|
||||
return -1;
|
||||
}
|
||||
snprintf (nodesize_s, sizeof nodesize_s, "%d", nodesize);
|
||||
ADD_ARG (argv, i, "--nodesize");
|
||||
ADD_ARG (argv, i, nodesize_s);
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKFS_BTRFS_SECTORSIZE_BITMASK) {
|
||||
if (!is_power_of_2 (sectorsize) || sectorsize <= 0) {
|
||||
reply_with_error ("sectorsize must be > 0 and a power of two");
|
||||
return -1;
|
||||
}
|
||||
snprintf (sectorsize_s, sizeof sectorsize_s, "%d", sectorsize);
|
||||
ADD_ARG (argv, i, "--sectorsize");
|
||||
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, str_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, str_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, str_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, str_btrfs);
|
||||
ADD_ARG (argv, i, "subvolume");
|
||||
ADD_ARG (argv, i, "list");
|
||||
ADD_ARG (argv, i, fs_buf);
|
||||
ADD_ARG (argv, i, NULL);
|
||||
|
||||
r = commandv (&out, &err, argv);
|
||||
free (fs_buf);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", fs, err);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
lines = split_lines (out);
|
||||
free (out);
|
||||
if (!lines)
|
||||
return NULL;
|
||||
|
||||
/* Output is:
|
||||
*
|
||||
* ID 256 top level 5 path test1
|
||||
* ID 257 top level 5 path dir/test2
|
||||
* ID 258 top level 5 path test3
|
||||
*
|
||||
* "ID <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, str_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, str_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, str_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, str_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, str_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, str_btrfstune, "-S", s_value, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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, str_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);
|
||||
|
||||
r = commandv (NULL, &err, argv);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,23 +29,33 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_find, find);
|
||||
GUESTFSD_EXT_CMD(str_xargs, xargs);
|
||||
GUESTFSD_EXT_CMD(str_cksum, cksum);
|
||||
GUESTFSD_EXT_CMD(str_md5sum, md5sum);
|
||||
GUESTFSD_EXT_CMD(str_sha1sum, sha1sum);
|
||||
GUESTFSD_EXT_CMD(str_sha224sum, sha224sum);
|
||||
GUESTFSD_EXT_CMD(str_sha256sum, sha256sum);
|
||||
GUESTFSD_EXT_CMD(str_sha384sum, sha384sum);
|
||||
GUESTFSD_EXT_CMD(str_sha512sum, sha512sum);
|
||||
|
||||
static const char *
|
||||
program_of_csum (const char *csumtype)
|
||||
{
|
||||
if (STRCASEEQ (csumtype, "crc"))
|
||||
return "cksum";
|
||||
return str_cksum;
|
||||
else if (STRCASEEQ (csumtype, "md5"))
|
||||
return "md5sum";
|
||||
return str_md5sum;
|
||||
else if (STRCASEEQ (csumtype, "sha1"))
|
||||
return "sha1sum";
|
||||
return str_sha1sum;
|
||||
else if (STRCASEEQ (csumtype, "sha224"))
|
||||
return "sha224sum";
|
||||
return str_sha224sum;
|
||||
else if (STRCASEEQ (csumtype, "sha256"))
|
||||
return "sha256sum";
|
||||
return str_sha256sum;
|
||||
else if (STRCASEEQ (csumtype, "sha384"))
|
||||
return "sha384sum";
|
||||
return str_sha384sum;
|
||||
else if (STRCASEEQ (csumtype, "sha512"))
|
||||
return "sha512sum";
|
||||
return str_sha512sum;
|
||||
else {
|
||||
reply_with_error ("unknown checksum type, expecting crc|md5|sha1|sha224|sha256|sha384|sha512");
|
||||
return NULL;
|
||||
@@ -58,7 +68,7 @@ checksum (const char *csumtype, int fd)
|
||||
const char *program;
|
||||
char *out, *err;
|
||||
int flags, r;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
program = program_of_csum (csumtype);
|
||||
if (program == NULL) {
|
||||
@@ -95,7 +105,7 @@ do_checksum (const char *csumtype, const char *path)
|
||||
int fd;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -111,7 +121,7 @@ do_checksum_device (const char *csumtype, const char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (device, O_RDONLY);
|
||||
fd = open (device, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("%s", device);
|
||||
return NULL;
|
||||
@@ -150,7 +160,8 @@ do_checksums_out (const char *csumtype, const char *dir)
|
||||
}
|
||||
|
||||
char *cmd;
|
||||
if (asprintf_nowarn (&cmd, "cd %Q && find -type f -print0 | xargs -0 %s",
|
||||
if (asprintf_nowarn (&cmd, "cd %Q && %s -type f -print0 | %s -0 %s",
|
||||
str_find, str_xargs,
|
||||
sysrootdir, program) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free (sysrootdir);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_cmp, cmp);
|
||||
|
||||
int
|
||||
do_equal (const char *file1, const char *file2)
|
||||
{
|
||||
@@ -47,7 +49,7 @@ do_equal (const char *file1, const char *file2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = commandr (NULL, &err, "cmp", "-s", file1buf, file2buf, NULL);
|
||||
r = commandr (NULL, &err, str_cmp, "-s", file1buf, file2buf, NULL);
|
||||
|
||||
free (file1buf);
|
||||
free (file2buf);
|
||||
|
||||
@@ -28,10 +28,13 @@
|
||||
|
||||
#include "ignore-value.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_mount, mount);
|
||||
GUESTFSD_EXT_CMD(str_umount, umount);
|
||||
|
||||
static inline void
|
||||
umount_ignore_fail (const char *path)
|
||||
{
|
||||
ignore_value (command (NULL, NULL, "umount", path, NULL));
|
||||
ignore_value (command (NULL, NULL, str_umount, path, NULL));
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -81,15 +84,15 @@ do_command (char *const *argv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = command (NULL, NULL, "mount", "--bind", "/dev", sysroot_dev, NULL);
|
||||
r = command (NULL, NULL, str_mount, "--bind", "/dev", sysroot_dev, NULL);
|
||||
dev_ok = r != -1;
|
||||
r = command (NULL, NULL, "mount", "--bind", "/dev/pts", sysroot_dev_pts, NULL);
|
||||
r = command (NULL, NULL, str_mount, "--bind", "/dev/pts", sysroot_dev_pts, NULL);
|
||||
dev_pts_ok = r != -1;
|
||||
r = command (NULL, NULL, "mount", "--bind", "/proc", sysroot_proc, NULL);
|
||||
r = command (NULL, NULL, str_mount, "--bind", "/proc", sysroot_proc, NULL);
|
||||
proc_ok = r != -1;
|
||||
r = command (NULL, NULL, "mount", "--bind", "/selinux", sysroot_selinux, NULL);
|
||||
r = command (NULL, NULL, str_mount, "--bind", "/selinux", sysroot_selinux, NULL);
|
||||
selinux_ok = r != -1;
|
||||
r = command (NULL, NULL, "mount", "--bind", "/sys", sysroot_sys, NULL);
|
||||
r = command (NULL, NULL, str_mount, "--bind", "/sys", sysroot_sys, NULL);
|
||||
sys_ok = r != -1;
|
||||
|
||||
CHROOT_IN;
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_compress, compress);
|
||||
GUESTFSD_EXT_CMD(str_gzip, gzip);
|
||||
GUESTFSD_EXT_CMD(str_bzip2, bzip2);
|
||||
GUESTFSD_EXT_CMD(str_xz, xz);
|
||||
GUESTFSD_EXT_CMD(str_lzop, lzop);
|
||||
|
||||
/* Has one FileOut parameter. */
|
||||
static int
|
||||
do_compressX_out (const char *file, const char *filter, int is_device)
|
||||
@@ -118,15 +124,15 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
|
||||
reply_with_error ("compress: cannot use optional level parameter with this compression type");
|
||||
return -1;
|
||||
}
|
||||
snprintf (ret, n, "compress -c");
|
||||
snprintf (ret, n, "%s -c", str_compress);
|
||||
return 0;
|
||||
}
|
||||
else if (STREQ (ctype, "gzip")) {
|
||||
CHECK_SUPPORTED ("gzip");
|
||||
if (level == -1)
|
||||
snprintf (ret, n, "gzip -c");
|
||||
snprintf (ret, n, "%s -c", str_gzip);
|
||||
else if (level >= 1 && level <= 9)
|
||||
snprintf (ret, n, "gzip -c -%d", level);
|
||||
snprintf (ret, n, "%s -c -%d", str_gzip, level);
|
||||
else {
|
||||
reply_with_error ("gzip: incorrect value for level parameter");
|
||||
return -1;
|
||||
@@ -136,9 +142,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
|
||||
else if (STREQ (ctype, "bzip2")) {
|
||||
CHECK_SUPPORTED ("bzip2");
|
||||
if (level == -1)
|
||||
snprintf (ret, n, "bzip2 -c");
|
||||
snprintf (ret, n, "%s -c", str_bzip2);
|
||||
else if (level >= 1 && level <= 9)
|
||||
snprintf (ret, n, "bzip2 -c -%d", level);
|
||||
snprintf (ret, n, "%s -c -%d", str_bzip2, level);
|
||||
else {
|
||||
reply_with_error ("bzip2: incorrect value for level parameter");
|
||||
return -1;
|
||||
@@ -148,9 +154,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
|
||||
else if (STREQ (ctype, "xz")) {
|
||||
CHECK_SUPPORTED ("xz");
|
||||
if (level == -1)
|
||||
snprintf (ret, n, "xz -c");
|
||||
snprintf (ret, n, "%s -c", str_xz);
|
||||
else if (level >= 0 && level <= 9)
|
||||
snprintf (ret, n, "xz -c -%d", level);
|
||||
snprintf (ret, n, "%s -c -%d", str_xz, level);
|
||||
else {
|
||||
reply_with_error ("xz: incorrect value for level parameter");
|
||||
return -1;
|
||||
@@ -160,9 +166,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
|
||||
else if (STREQ (ctype, "lzop")) {
|
||||
CHECK_SUPPORTED ("lzop");
|
||||
if (level == -1)
|
||||
snprintf (ret, n, "lzop -c");
|
||||
snprintf (ret, n, "%s -c", str_lzop);
|
||||
else if (level >= 1 && level <= 9)
|
||||
snprintf (ret, n, "lzop -c -%d", level);
|
||||
snprintf (ret, n, "%s -c -%d", str_lzop, level);
|
||||
else {
|
||||
reply_with_error ("lzop: incorrect value for level parameter");
|
||||
return -1;
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
#define DEST_FILE_FLAGS O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666
|
||||
#define DEST_DEVICE_FLAGS O_WRONLY, 0
|
||||
#define DEST_FILE_FLAGS O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0666
|
||||
#define DEST_DEVICE_FLAGS O_WRONLY|O_CLOEXEC, 0
|
||||
|
||||
/* NB: We cheat slightly by assuming that optargs_bitmask is
|
||||
* compatible for all four of the calls. This is true provided they
|
||||
@@ -78,7 +78,7 @@ copy (const char *src, const char *src_display,
|
||||
size = -1;
|
||||
|
||||
/* Open source and destination. */
|
||||
src_fd = open (src, O_RDONLY);
|
||||
src_fd = open (src, O_RDONLY|O_CLOEXEC);
|
||||
if (src_fd == -1) {
|
||||
reply_with_perror ("%s", src_display);
|
||||
return -1;
|
||||
|
||||
@@ -25,24 +25,27 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_cp, cp);
|
||||
GUESTFSD_EXT_CMD(str_mv, mv);
|
||||
|
||||
static int cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest);
|
||||
|
||||
int
|
||||
do_cp (const char *src, const char *dest)
|
||||
{
|
||||
return cpmv_cmd ("cp", NULL, src, dest);
|
||||
return cpmv_cmd (str_cp, NULL, src, dest);
|
||||
}
|
||||
|
||||
int
|
||||
do_cp_a (const char *src, const char *dest)
|
||||
{
|
||||
return cpmv_cmd ("cp", "-a", src, dest);
|
||||
return cpmv_cmd (str_cp, "-a", src, dest);
|
||||
}
|
||||
|
||||
int
|
||||
do_mv (const char *src, const char *dest)
|
||||
{
|
||||
return cpmv_cmd ("mv", NULL, src, dest);
|
||||
return cpmv_cmd (str_mv, NULL, src, dest);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -47,20 +47,54 @@ extern int xwrite (int sock, const void *buf, size_t len)
|
||||
extern int xread (int sock, void *buf, size_t len)
|
||||
__attribute__((__warn_unused_result__));
|
||||
|
||||
extern int add_string_nodup (char ***argv, int *size, int *alloc, char *str);
|
||||
extern int add_string (char ***argv, int *size, int *alloc, const char *str);
|
||||
extern size_t count_strings (char *const *argv);
|
||||
extern void sort_strings (char **argv, int len);
|
||||
extern void free_strings (char **argv);
|
||||
extern void free_stringslen (char **argv, int len);
|
||||
/* Growable strings buffer. */
|
||||
struct stringsbuf {
|
||||
char **argv;
|
||||
size_t size;
|
||||
size_t alloc;
|
||||
};
|
||||
#define DECLARE_STRINGSBUF(v) \
|
||||
struct stringsbuf (v) = { .argv = NULL, .size = 0, .alloc = 0 }
|
||||
|
||||
extern int is_power_of_2 (unsigned long v);
|
||||
/* Append a string to the strings buffer.
|
||||
*
|
||||
* add_string_nodup: don't copy the string.
|
||||
* add_string: copy the string.
|
||||
* end_stringsbuf: NULL-terminate the buffer.
|
||||
*
|
||||
* All functions may fail. If these functions return -1, then
|
||||
* reply_with_* has been called, the strings have been freed and the
|
||||
* buffer should no longer be used.
|
||||
*/
|
||||
extern int add_string_nodup (struct stringsbuf *sb, char *str);
|
||||
extern int add_string (struct stringsbuf *sb, const char *str);
|
||||
extern int end_stringsbuf (struct stringsbuf *sb);
|
||||
|
||||
extern size_t count_strings (char *const *argv);
|
||||
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);
|
||||
|
||||
/* Concatenate strings, optionally with a separator string between
|
||||
* each. On error, these return NULL but do NOT call reply_with_* nor
|
||||
* free anything.
|
||||
*/
|
||||
extern char *concat_strings (char *const *argv);
|
||||
extern char *join_strings (const char *separator, char *const *argv);
|
||||
|
||||
extern char **split_lines (char *str);
|
||||
|
||||
#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
|
||||
#define commandr(out,err,name,...) commandrf((out),(err),0,(name),__VA_ARGS__)
|
||||
#define commandv(out,err,argv) commandvf((out),(err),0,(argv))
|
||||
#define commandrv(out,err,argv) commandrvf((out),(err),0,(argv))
|
||||
|
||||
#define __external_command __attribute__((__section__(".guestfsd_ext_cmds")))
|
||||
#define GUESTFSD_EXT_CMD(___ext_cmd_var, ___ext_cmd_str) static const char ___ext_cmd_var[] __external_command = #___ext_cmd_str
|
||||
|
||||
#define COMMAND_FLAG_FD_MASK (1024-1)
|
||||
#define COMMAND_FLAG_FOLD_STDOUT_ON_STDERR 1024
|
||||
#define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
|
||||
@@ -74,7 +108,7 @@ extern int commandvf (char **stdoutput, char **stderror, int flags,
|
||||
extern int commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
char const* const *argv);
|
||||
|
||||
extern char **split_lines (char *str);
|
||||
extern int is_power_of_2 (unsigned long v);
|
||||
|
||||
extern void trim (char *str);
|
||||
|
||||
@@ -84,6 +118,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.
|
||||
@@ -111,6 +147,7 @@ extern uint64_t optargs_bitmask;
|
||||
|
||||
/*-- in mount.c --*/
|
||||
extern int is_root_mounted (void);
|
||||
extern int is_device_mounted (const char *device);
|
||||
|
||||
/*-- in stubs.c (auto-generated) --*/
|
||||
extern void dispatch_incoming_message (XDR *);
|
||||
@@ -125,12 +162,16 @@ 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);
|
||||
|
||||
/*-- in ext2.c --*/
|
||||
extern int e2prog (char *name); /* Massive hack for RHEL 5. */
|
||||
/* Confirmed this is true up to ext4 from the Linux sources. */
|
||||
#define EXT2_LABEL_MAX 16
|
||||
|
||||
/*-- in lvm.c --*/
|
||||
extern int lv_canonical (const char *device, char **ret);
|
||||
@@ -145,10 +186,11 @@ extern void main_loop (int sock) __attribute__((noreturn));
|
||||
* NB: you don't need to prefix the string with the current command,
|
||||
* it is added automatically by the client-side RPC stubs.
|
||||
*/
|
||||
extern void reply_with_error (const char *fs, ...)
|
||||
__attribute__((format (printf,1,2)));
|
||||
extern void reply_with_error_errno (int err, const char *fs, ...)
|
||||
__attribute__((format (printf,2,3)));
|
||||
extern void reply_with_perror_errno (int err, const char *fs, ...)
|
||||
__attribute__((format (printf,2,3)));
|
||||
#define reply_with_error(...) reply_with_error_errno(0, __VA_ARGS__)
|
||||
#define reply_with_perror(...) reply_with_perror_errno(errno, __VA_ARGS__)
|
||||
|
||||
/* daemon functions that receive files (FileIn) should call
|
||||
@@ -166,7 +208,7 @@ extern int cancel_receive (void);
|
||||
* reply, then send_file_* for each FileOut parameter.
|
||||
* Note max write size if GUESTFS_MAX_CHUNK_SIZE.
|
||||
*/
|
||||
extern int send_file_write (const void *buf, int len);
|
||||
extern int send_file_write (const void *buf, size_t len);
|
||||
extern int send_file_end (int cancel);
|
||||
|
||||
/* only call this if there is a FileOut parameter */
|
||||
@@ -264,8 +306,11 @@ is_zero (const char *buffer, size_t size)
|
||||
reply_with_error ("%s: %s: expecting a device name", __func__, (path)); \
|
||||
fail_stmt; \
|
||||
} \
|
||||
if (is_root_device (path)) \
|
||||
if (is_root_device (path)) { \
|
||||
cancel_stmt; \
|
||||
reply_with_error ("%s: %s: device not found", __func__, path); \
|
||||
fail_stmt; \
|
||||
} \
|
||||
if (device_name_translation ((path)) == -1) { \
|
||||
int err = errno; \
|
||||
cancel_stmt; \
|
||||
@@ -331,16 +376,6 @@ is_zero (const char *buffer, size_t size)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Marks functions which are not available.
|
||||
* NB. Cannot be used for FileIn functions.
|
||||
*/
|
||||
#define NOT_AVAILABLE(errcode) \
|
||||
do { \
|
||||
reply_with_error ("%s: function not available", __func__); \
|
||||
return (errcode); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#ifndef __attribute__
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
|
||||
# define __attribute__(x) /* empty */
|
||||
|
||||
12
daemon/dd.c
12
daemon/dd.c
@@ -27,6 +27,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_dd, dd);
|
||||
|
||||
int
|
||||
do_dd (const char *src, const char *dest)
|
||||
{
|
||||
@@ -58,7 +60,7 @@ do_dd (const char *src, const char *dest)
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &err, "dd", "bs=1024K", if_arg, of_arg, NULL);
|
||||
r = command (NULL, &err, str_dd, "bs=1024K", if_arg, of_arg, NULL);
|
||||
free (if_arg);
|
||||
free (of_arg);
|
||||
|
||||
@@ -79,14 +81,14 @@ do_copy_size (const char *src, const char *dest, int64_t ssize)
|
||||
int src_fd, dest_fd;
|
||||
|
||||
if (STRPREFIX (src, "/dev/"))
|
||||
src_fd = open (src, O_RDONLY);
|
||||
src_fd = open (src, O_RDONLY | O_CLOEXEC);
|
||||
else {
|
||||
buf = sysroot_path (src);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
src_fd = open (buf, O_RDONLY);
|
||||
src_fd = open (buf, O_RDONLY | O_CLOEXEC);
|
||||
free (buf);
|
||||
}
|
||||
if (src_fd == -1) {
|
||||
@@ -95,7 +97,7 @@ do_copy_size (const char *src, const char *dest, int64_t ssize)
|
||||
}
|
||||
|
||||
if (STRPREFIX (dest, "/dev/"))
|
||||
dest_fd = open (dest, O_WRONLY);
|
||||
dest_fd = open (dest, O_WRONLY | O_CLOEXEC);
|
||||
else {
|
||||
buf = sysroot_path (dest);
|
||||
if (!buf) {
|
||||
@@ -103,7 +105,7 @@ do_copy_size (const char *src, const char *dest, int64_t ssize)
|
||||
close (src_fd);
|
||||
return -1;
|
||||
}
|
||||
dest_fd = open (buf, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
|
||||
dest_fd = open (buf, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
free (buf);
|
||||
}
|
||||
if (dest_fd == -1) {
|
||||
|
||||
134
daemon/debug.c
134
daemon/debug.c
@@ -32,6 +32,15 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_printenv, printenv);
|
||||
GUESTFSD_EXT_CMD(str_ldd, ldd);
|
||||
GUESTFSD_EXT_CMD(str_ls, ls);
|
||||
GUESTFSD_EXT_CMD(str_find, find);
|
||||
GUESTFSD_EXT_CMD(str_xargs, xargs);
|
||||
GUESTFSD_EXT_CMD(str_file, file);
|
||||
GUESTFSD_EXT_CMD(str_grep, grep);
|
||||
GUESTFSD_EXT_CMD(str_gawk, gawk);
|
||||
|
||||
/* This command exposes debugging information, internals and
|
||||
* status. There is no comprehensive documentation for this
|
||||
* command. You have to look at the source code in this file
|
||||
@@ -47,21 +56,22 @@
|
||||
|
||||
struct cmd {
|
||||
const char *cmd;
|
||||
char * (*f) (const char *subcmd, int argc, char *const *const argv);
|
||||
char * (*f) (const char *subcmd, size_t argc, char *const *const argv);
|
||||
};
|
||||
|
||||
static char *debug_help (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_binaries (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_core_pattern (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_env (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_fds (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_ldd (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_ls (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_ll (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_progress (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_qtrace (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_segv (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_sh (const char *subcmd, int argc, char *const *const argv);
|
||||
static char *debug_help (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_binaries (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_core_pattern (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_env (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_fds (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_ldd (const char *subcmd, size_t argc, char *const *const argv);
|
||||
static char *debug_ls (const char *subcmd, size_t argc, char *const *const argv);
|
||||
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[] = {
|
||||
{ "help", debug_help },
|
||||
@@ -75,6 +85,7 @@ static struct cmd cmds[] = {
|
||||
{ "progress", debug_progress },
|
||||
{ "qtrace", debug_qtrace },
|
||||
{ "segv", debug_segv },
|
||||
{ "setenv", debug_setenv },
|
||||
{ "sh", debug_sh },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@@ -82,7 +93,7 @@ static struct cmd cmds[] = {
|
||||
char *
|
||||
do_debug (const char *subcmd, char *const *argv)
|
||||
{
|
||||
int argc, i;
|
||||
size_t argc, i;
|
||||
|
||||
for (i = argc = 0; argv[i] != NULL; ++i)
|
||||
argc++;
|
||||
@@ -97,9 +108,9 @@ do_debug (const char *subcmd, char *const *argv)
|
||||
}
|
||||
|
||||
static char *
|
||||
debug_help (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_help (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
char *r, *p;
|
||||
|
||||
r = strdup ("Commands supported:");
|
||||
@@ -128,7 +139,7 @@ debug_help (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* Show open FDs. */
|
||||
static char *
|
||||
debug_fds (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_fds (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out;
|
||||
@@ -196,7 +207,7 @@ debug_fds (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* Force a segfault in the daemon. */
|
||||
static char *
|
||||
debug_segv (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_segv (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
/* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
|
||||
* "Dereferencing a NULL Pointer: contrary to popular belief,
|
||||
@@ -214,16 +225,16 @@ debug_segv (const char *subcmd, int argc, char *const *const argv)
|
||||
* because it's not using the guest shell, and is not chrooted.
|
||||
*/
|
||||
static char *
|
||||
debug_sh (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_sh (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
char *cmd;
|
||||
size_t len, i, j;
|
||||
|
||||
if (argc < 1) {
|
||||
reply_with_error ("sh: expecting a command to run");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *cmd;
|
||||
int len, i, j;
|
||||
|
||||
/* guestfish splits the parameter(s) into a list of strings,
|
||||
* and we have to reassemble them here. Not ideal. XXX
|
||||
*/
|
||||
@@ -268,12 +279,12 @@ debug_sh (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* Print the environment that commands get (by running external printenv). */
|
||||
static char *
|
||||
debug_env (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_env (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
|
||||
r = command (&out, &err, "printenv", NULL);
|
||||
r = command (&out, &err, str_printenv, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("printenv: %s", err);
|
||||
free (out);
|
||||
@@ -286,20 +297,44 @@ debug_env (const char *subcmd, int 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
|
||||
*/
|
||||
static char *
|
||||
debug_binaries (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_binaries (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char cmd[256];
|
||||
|
||||
const char cmd[] =
|
||||
"find / -xdev -type f -executable "
|
||||
"| xargs file -i "
|
||||
"| grep application/x-executable "
|
||||
"| gawk -F: '{print $1}'";
|
||||
snprintf (cmd, sizeof (cmd),
|
||||
"%s / -xdev -type f -executable "
|
||||
"| %s %s -i "
|
||||
"| %s application/x-executable "
|
||||
"| %s -F: '{print $1}'",
|
||||
str_find, str_xargs, str_file, str_grep, str_gawk);
|
||||
|
||||
r = command (&out, &err, "sh", "-c", cmd, NULL);
|
||||
if (r == -1) {
|
||||
@@ -318,7 +353,7 @@ debug_binaries (const char *subcmd, int argc, char *const *const argv)
|
||||
* See tests/regressions/rhbz727178.sh
|
||||
*/
|
||||
static char *
|
||||
debug_ldd (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_ldd (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int r;
|
||||
char *out, *err, *ret;
|
||||
@@ -334,7 +369,7 @@ debug_ldd (const char *subcmd, int argc, char *const *const argv)
|
||||
* Also 'ldd' randomly sends messages to stderr and errors to stdout
|
||||
* depending on the phase of the moon.
|
||||
*/
|
||||
r = command (&out, &err, "ldd", "-r", argv[0], NULL);
|
||||
r = command (&out, &err, str_ldd, "-r", argv[0], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("ldd: %s: %s", argv[0], err);
|
||||
free (out);
|
||||
@@ -359,13 +394,13 @@ debug_ldd (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* List files in the appliance. */
|
||||
static char *
|
||||
debug_ls (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_ls (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int len = count_strings (argv);
|
||||
size_t len = count_strings (argv);
|
||||
const char *cargv[len+3];
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
cargv[0] = "ls";
|
||||
cargv[0] = str_ls;
|
||||
cargv[1] = "-a";
|
||||
for (i = 0; i < len; ++i)
|
||||
cargv[2+i] = argv[i];
|
||||
@@ -389,13 +424,13 @@ debug_ls (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* List files in the appliance. */
|
||||
static char *
|
||||
debug_ll (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_ll (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int len = count_strings (argv);
|
||||
size_t len = count_strings (argv);
|
||||
const char *cargv[len+3];
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
cargv[0] = "ls";
|
||||
cargv[0] = str_ls;
|
||||
cargv[1] = "-la";
|
||||
for (i = 0; i < len; ++i)
|
||||
cargv[2+i] = argv[i];
|
||||
@@ -419,7 +454,7 @@ debug_ll (const char *subcmd, int argc, char *const *const argv)
|
||||
|
||||
/* Generate progress notification messages in order to test progress bars. */
|
||||
static char *
|
||||
debug_progress (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_progress (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
if (argc < 1) {
|
||||
error:
|
||||
@@ -429,8 +464,12 @@ debug_progress (const char *subcmd, int 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 */
|
||||
@@ -455,7 +494,7 @@ debug_progress (const char *subcmd, int argc, char *const *const argv)
|
||||
* crashes doesn't chroot.
|
||||
*/
|
||||
static char *
|
||||
debug_core_pattern (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_core_pattern (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
if (argc < 1) {
|
||||
reply_with_error ("core_pattern: expecting a core pattern");
|
||||
@@ -466,13 +505,14 @@ debug_core_pattern (const char *subcmd, int argc, char *const *const argv)
|
||||
const size_t pattern_len = strlen(pattern);
|
||||
|
||||
#define CORE_PATTERN "/proc/sys/kernel/core_pattern"
|
||||
int fd = open (CORE_PATTERN, O_WRONLY);
|
||||
int fd = open (CORE_PATTERN, O_WRONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: " CORE_PATTERN);
|
||||
return NULL;
|
||||
}
|
||||
if (write (fd, pattern, pattern_len) < (ssize_t) pattern_len) {
|
||||
reply_with_perror ("write: " CORE_PATTERN);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
if (close (fd) == -1) {
|
||||
@@ -509,7 +549,7 @@ write_cb (void *fd_ptr, const void *buf, size_t len)
|
||||
* directory in the libguestfs source tree.
|
||||
*/
|
||||
static char *
|
||||
debug_qtrace (const char *subcmd, int argc, char *const *const argv)
|
||||
debug_qtrace (const char *subcmd, size_t argc, char *const *const argv)
|
||||
{
|
||||
int enable;
|
||||
|
||||
@@ -531,7 +571,7 @@ debug_qtrace (const char *subcmd, int argc, char *const *const argv)
|
||||
return NULL;
|
||||
|
||||
/* Note this doesn't do device name translation or check this is a device. */
|
||||
int fd = open (argv[0], O_RDONLY | O_DIRECT);
|
||||
int fd = open (argv[0], O_RDONLY|O_DIRECT|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("qtrace: %s: open", argv[0]);
|
||||
return NULL;
|
||||
@@ -601,7 +641,7 @@ do_debug_upload (const char *filename, int mode)
|
||||
/* Not chrooted - this command lets you upload a file to anywhere
|
||||
* in the appliance.
|
||||
*/
|
||||
int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, mode);
|
||||
int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, mode);
|
||||
|
||||
if (fd == -1) {
|
||||
int err = errno;
|
||||
|
||||
@@ -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
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
@@ -31,18 +32,18 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
typedef int (*block_dev_func_t)(const char *dev,
|
||||
char ***r, int *size, int *alloc);
|
||||
typedef int (*block_dev_func_t) (const char *dev, struct stringsbuf *r);
|
||||
|
||||
/* Execute a given function for each discovered block device */
|
||||
static char**
|
||||
static char **
|
||||
foreach_block_device (block_dev_func_t func)
|
||||
{
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
|
||||
DECLARE_STRINGSBUF (r);
|
||||
DIR *dir;
|
||||
int err = 0;
|
||||
struct dirent *d;
|
||||
char dev_path[256];
|
||||
int fd;
|
||||
|
||||
dir = opendir ("/sys/block");
|
||||
if (!dir) {
|
||||
@@ -50,16 +51,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. */
|
||||
@@ -70,7 +70,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);
|
||||
fd = open (dev_path, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
perror (dev_path);
|
||||
continue;
|
||||
@@ -78,7 +78,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
close (fd);
|
||||
|
||||
/* Call the map function for this device */
|
||||
if((*func)(d->d_name, &r, &size, &alloc) != 0) {
|
||||
if ((*func)(d->d_name, &r) != 0) {
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
@@ -86,9 +86,9 @@ 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, size);
|
||||
free_stringslen (r.argv, r.size);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
@@ -96,37 +96,36 @@ foreach_block_device (block_dev_func_t func)
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: /sys/block");
|
||||
free_stringslen(r, size);
|
||||
free_stringslen (r.argv, r.size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free the result list on error */
|
||||
if(err) {
|
||||
free_stringslen(r, size);
|
||||
if (err) {
|
||||
free_stringslen (r.argv, r.size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sort the devices. Note that r might be NULL if there are no devices. */
|
||||
if (r != NULL)
|
||||
sort_strings (r, size);
|
||||
/* Sort the devices. */
|
||||
if (r.size > 0)
|
||||
sort_device_names (r.argv, r.size);
|
||||
|
||||
/* NULL terminate the list */
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1) {
|
||||
if (end_stringsbuf (&r) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
return r.argv;
|
||||
}
|
||||
|
||||
/* Add a device to the list of devices */
|
||||
static int
|
||||
add_device(const char *device,
|
||||
char ***const r, int *const size, int *const alloc)
|
||||
add_device (const char *device, struct stringsbuf *r)
|
||||
{
|
||||
char dev_path[256];
|
||||
snprintf (dev_path, sizeof dev_path, "/dev/%s", device);
|
||||
|
||||
if (add_string (r, size, alloc, dev_path) == -1) {
|
||||
if (add_string (r, dev_path) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -136,12 +135,11 @@ add_device(const char *device,
|
||||
char **
|
||||
do_list_devices (void)
|
||||
{
|
||||
return foreach_block_device(add_device);
|
||||
return foreach_block_device (add_device);
|
||||
}
|
||||
|
||||
static int
|
||||
add_partitions(const char *device,
|
||||
char ***const r, int *const size, int *const alloc)
|
||||
add_partitions (const char *device, struct stringsbuf *r)
|
||||
{
|
||||
char devdir[256];
|
||||
|
||||
@@ -151,7 +149,7 @@ add_partitions(const char *device,
|
||||
DIR *dir = opendir (devdir);
|
||||
if (!dir) {
|
||||
reply_with_perror ("opendir: %s", devdir);
|
||||
free_stringslen (*r, *size);
|
||||
free_stringslen (r->argv, r->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -165,7 +163,7 @@ add_partitions(const char *device,
|
||||
char part[256];
|
||||
snprintf (part, sizeof part, "/dev/%s", d->d_name);
|
||||
|
||||
if (add_string (r, size, alloc, part) == -1) {
|
||||
if (add_string (r, part) == -1) {
|
||||
closedir (dir);
|
||||
return -1;
|
||||
}
|
||||
@@ -173,9 +171,9 @@ add_partitions(const char *device,
|
||||
}
|
||||
|
||||
/* Check if readdir failed */
|
||||
if(0 != errno) {
|
||||
if (0 != errno) {
|
||||
reply_with_perror ("readdir: %s", devdir);
|
||||
free_stringslen(*r, *size);
|
||||
free_stringslen (r->argv, r->size);
|
||||
closedir (dir);
|
||||
return -1;
|
||||
}
|
||||
@@ -183,7 +181,7 @@ add_partitions(const char *device,
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: /sys/block/%s", device);
|
||||
free_stringslen (*r, *size);
|
||||
free_stringslen (r->argv, r->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -193,7 +191,7 @@ add_partitions(const char *device,
|
||||
char **
|
||||
do_list_partitions (void)
|
||||
{
|
||||
return foreach_block_device(add_partitions);
|
||||
return foreach_block_device (add_partitions);
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -245,3 +243,118 @@ 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;
|
||||
}
|
||||
|
||||
#define GUESTFSDIR "/dev/disk/guestfs"
|
||||
|
||||
char **
|
||||
do_list_disk_labels (void)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
struct dirent *d;
|
||||
char *path = NULL, *rawdev = NULL;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
dir = opendir (GUESTFSDIR);
|
||||
if (!dir) {
|
||||
reply_with_perror ("opendir: %s", GUESTFSDIR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
while ((d = readdir (dir)) != NULL) {
|
||||
if (d->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (asprintf (&path, "%s/%s", GUESTFSDIR, d->d_name) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rawdev = realpath (path, NULL);
|
||||
if (rawdev == NULL) {
|
||||
reply_with_perror ("realpath: %s", path);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
free (path);
|
||||
path = NULL;
|
||||
|
||||
if (add_string (&ret, d->d_name) == -1)
|
||||
goto error;
|
||||
|
||||
if (add_string_nodup (&ret, rawdev) == -1)
|
||||
goto error;
|
||||
rawdev = NULL; /* buffer now owned by the stringsbuf */
|
||||
}
|
||||
|
||||
/* Check readdir didn't fail */
|
||||
if (errno != 0) {
|
||||
reply_with_perror ("readdir: %s", GUESTFSDIR);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: %s", GUESTFSDIR);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
dir = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dir = NULL;
|
||||
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
goto error;
|
||||
|
||||
return ret.argv; /* caller frees */
|
||||
|
||||
error:
|
||||
if (dir)
|
||||
closedir (dir);
|
||||
free (path);
|
||||
free (rawdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_df, df);
|
||||
|
||||
char *
|
||||
do_df (void)
|
||||
{
|
||||
@@ -35,7 +37,7 @@ do_df (void)
|
||||
|
||||
NEED_ROOT (, return NULL);
|
||||
|
||||
r = command (&out, &err, "df", NULL);
|
||||
r = command (&out, &err, str_df, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
@@ -56,7 +58,7 @@ do_df_h (void)
|
||||
|
||||
NEED_ROOT (, return NULL);
|
||||
|
||||
r = command (&out, &err, "df", "-h", NULL);
|
||||
r = command (&out, &err, str_df, "-h", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
|
||||
25
daemon/dir.c
25
daemon/dir.c
@@ -29,6 +29,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_rm, rm);
|
||||
|
||||
int
|
||||
do_rmdir (const char *path)
|
||||
{
|
||||
@@ -67,7 +69,7 @@ do_rm_rf (const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &err, "rm", "-rf", buf, NULL);
|
||||
r = command (NULL, &err, str_rm, "-rf", buf, NULL);
|
||||
free (buf);
|
||||
|
||||
/* rm -rf is never supposed to fail. I/O errors perhaps? */
|
||||
@@ -189,24 +191,3 @@ do_mkdir_p (const char *path)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
do_mkdtemp (const char *template)
|
||||
{
|
||||
char *writable = strdup (template);
|
||||
if (writable == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
char *r = mkdtemp (writable);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("%s", template);
|
||||
free (writable);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_dmesg, dmesg);
|
||||
|
||||
char *
|
||||
do_dmesg (void)
|
||||
{
|
||||
char *out, *err;
|
||||
int r;
|
||||
|
||||
r = command (&out, &err, "dmesg", NULL);
|
||||
r = command (&out, &err, str_dmesg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_du, du);
|
||||
|
||||
int64_t
|
||||
do_du (const char *path)
|
||||
{
|
||||
@@ -45,7 +47,7 @@ do_du (const char *path)
|
||||
|
||||
pulse_mode_start ();
|
||||
|
||||
r = command (&out, &err, "du", "-s", buf, NULL);
|
||||
r = command (&out, &err, str_du, "-s", buf, NULL);
|
||||
free (buf);
|
||||
if (r == -1) {
|
||||
pulse_mode_cancel ();
|
||||
|
||||
798
daemon/ext2.c
798
daemon/ext2.c
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ do_fallocate64 (const char *path, int64_t len)
|
||||
int fd;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0666);
|
||||
fd = open (path, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s", path);
|
||||
|
||||
250
daemon/file.c
250
daemon/file.c
@@ -29,6 +29,10 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_file, file);
|
||||
GUESTFSD_EXT_CMD(str_zcat, zcat);
|
||||
GUESTFSD_EXT_CMD(str_bzcat, bzcat);
|
||||
|
||||
int
|
||||
do_touch (const char *path)
|
||||
{
|
||||
@@ -38,6 +42,12 @@ do_touch (const char *path)
|
||||
|
||||
/* RHBZ#582484: Restrict touch to regular files. It's also OK
|
||||
* here if the file does not exist, since we will create it.
|
||||
*
|
||||
* XXX Coverity flags this as a time-of-check to time-of-use race
|
||||
* condition, particularly in the libguestfs live case. Not clear
|
||||
* how to fix this yet, since unconditionally opening the file can
|
||||
* cause a hang, so you have to somehow check it first before you
|
||||
* open it.
|
||||
*/
|
||||
CHROOT_IN;
|
||||
r = lstat (path, &buf);
|
||||
@@ -56,7 +66,7 @@ do_touch (const char *path)
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY, 0666);
|
||||
fd = open (path, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -79,123 +89,6 @@ do_touch (const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
do_cat (const char *path)
|
||||
{
|
||||
int fd;
|
||||
int alloc, size, r, max;
|
||||
char *buf, *buf2;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read up to GUESTFS_MESSAGE_MAX - <overhead> bytes. If it's
|
||||
* larger than that, we need to return an error instead (for
|
||||
* correctness).
|
||||
*/
|
||||
max = GUESTFS_MESSAGE_MAX - 1000;
|
||||
buf = NULL;
|
||||
size = alloc = 0;
|
||||
|
||||
for (;;) {
|
||||
if (size >= alloc) {
|
||||
alloc += 8192;
|
||||
if (alloc > max) {
|
||||
reply_with_error ("%s: file is too large for message buffer",
|
||||
path);
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
buf2 = realloc (buf, alloc);
|
||||
if (buf2 == NULL) {
|
||||
reply_with_perror ("realloc");
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
r = read (fd, buf + size, alloc - size);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("read: %s", path);
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
if (r == 0) {
|
||||
buf[size] = '\0';
|
||||
break;
|
||||
}
|
||||
if (r > 0)
|
||||
size += r;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close: %s", path);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf; /* caller will free */
|
||||
}
|
||||
|
||||
char **
|
||||
do_read_lines (const char *path)
|
||||
{
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
|
||||
CHROOT_IN;
|
||||
fp = fopen (path, "r");
|
||||
CHROOT_OUT;
|
||||
|
||||
if (!fp) {
|
||||
reply_with_perror ("fopen: %s", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((n = getline (&line, &len, fp)) != -1) {
|
||||
/* Remove either LF or CRLF. */
|
||||
if (n >= 2 && line[n-2] == '\r' && line[n-1] == '\n')
|
||||
line[n-2] = '\0';
|
||||
else if (n >= 1 && line[n-1] == '\n')
|
||||
line[n-1] = '\0';
|
||||
|
||||
if (add_string (&r, &size, &alloc, line) == -1) {
|
||||
free (line);
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free (line);
|
||||
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1) {
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fclose (fp) == EOF) {
|
||||
reply_with_perror ("fclose: %s", path);
|
||||
free_strings (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_rm (const char *path)
|
||||
{
|
||||
@@ -213,6 +106,24 @@ do_rm (const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_rm_f (const char *path)
|
||||
{
|
||||
int r;
|
||||
|
||||
CHROOT_IN;
|
||||
r = unlink (path);
|
||||
CHROOT_OUT;
|
||||
|
||||
/* Ignore ENOENT. */
|
||||
if (r == -1 && errno != ENOENT) {
|
||||
reply_with_perror ("%s", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_chmod (int mode, const char *path)
|
||||
{
|
||||
@@ -299,7 +210,7 @@ do_write_file (const char *path, const char *content, int size)
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666);
|
||||
fd = open (path, O_WRONLY|O_TRUNC|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -322,12 +233,12 @@ do_write_file (const char *path, const char *content, int size)
|
||||
}
|
||||
|
||||
int
|
||||
do_write (const char *path, const char *content, size_t size)
|
||||
do_internal_write (const char *path, const char *content, size_t size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666);
|
||||
fd = open (path, O_WRONLY|O_TRUNC|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -350,12 +261,12 @@ do_write (const char *path, const char *content, size_t size)
|
||||
}
|
||||
|
||||
int
|
||||
do_write_append (const char *path, const char *content, size_t size)
|
||||
do_internal_write_append (const char *path, const char *content, size_t size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0666);
|
||||
fd = open (path, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -377,65 +288,6 @@ do_write_append (const char *path, const char *content, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
do_read_file (const char *path, size_t *size_r)
|
||||
{
|
||||
int fd;
|
||||
struct stat statbuf;
|
||||
char *r;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat (fd, &statbuf) == -1) {
|
||||
reply_with_perror ("fstat: %s", path);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The actual limit on messages is smaller than this. This
|
||||
* check just limits the amount of memory we'll try and allocate
|
||||
* here. If the message is larger than the real limit, that will
|
||||
* be caught later when we try to serialize the message.
|
||||
*/
|
||||
if (statbuf.st_size >= GUESTFS_MESSAGE_MAX) {
|
||||
reply_with_error ("%s: file is too large for the protocol, use guestfs_download instead", path);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
r = malloc (statbuf.st_size);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (xread (fd, r, statbuf.st_size) == -1) {
|
||||
reply_with_perror ("read: %s", path);
|
||||
close (fd);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close: %s", path);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mustn't touch *size_r until we are sure that we won't return any
|
||||
* error (RHBZ#589039).
|
||||
*/
|
||||
*size_r = statbuf.st_size;
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *
|
||||
pread_fd (int fd, int count, int64_t offset, size_t *size_r,
|
||||
const char *display_path)
|
||||
@@ -500,7 +352,7 @@ do_pread (const char *path, int count, int64_t offset, size_t *size_r)
|
||||
int fd;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -514,7 +366,7 @@ do_pread (const char *path, int count, int64_t offset, size_t *size_r)
|
||||
char *
|
||||
do_pread_device (const char *device, int count, int64_t offset, size_t *size_r)
|
||||
{
|
||||
int fd = open (device, O_RDONLY);
|
||||
int fd = open (device, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s", device);
|
||||
return NULL;
|
||||
@@ -525,7 +377,7 @@ do_pread_device (const char *device, int count, int64_t offset, size_t *size_r)
|
||||
|
||||
static int
|
||||
pwrite_fd (int fd, const char *content, size_t size, int64_t offset,
|
||||
const char *display_path, int settle)
|
||||
const char *display_path)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
@@ -541,18 +393,6 @@ pwrite_fd (int fd, const char *content, size_t size, int64_t offset,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* When you call close on any block device, udev kicks off a rule
|
||||
* which runs blkid to reexamine the device. We need to wait for
|
||||
* this rule to finish running since it holds the device open and
|
||||
* can cause other operations to fail, notably BLKRRPART. 'settle'
|
||||
* flag is only set on block devices.
|
||||
*
|
||||
* XXX We should be smarter about when we do this or should get rid
|
||||
* of the udev rules since we don't use blkid in cached mode.
|
||||
*/
|
||||
if (settle)
|
||||
udev_settle ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -567,7 +407,7 @@ do_pwrite (const char *path, const char *content, size_t size, int64_t offset)
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_WRONLY);
|
||||
fd = open (path, O_WRONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -575,7 +415,7 @@ do_pwrite (const char *path, const char *content, size_t size, int64_t offset)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pwrite_fd (fd, content, size, offset, path, 0);
|
||||
return pwrite_fd (fd, content, size, offset, path);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -587,13 +427,13 @@ do_pwrite_device (const char *device, const char *content, size_t size,
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = open (device, O_WRONLY);
|
||||
int fd = open (device, O_WRONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pwrite_fd (fd, content, size, offset, device, 1);
|
||||
return pwrite_fd (fd, content, size, offset, device);
|
||||
}
|
||||
|
||||
/* This runs the 'file' command. */
|
||||
@@ -655,7 +495,7 @@ do_file (const char *path)
|
||||
const char *flags = is_dev ? "-zbsL" : "-zb";
|
||||
|
||||
char *out, *err;
|
||||
int r = command (&out, &err, "file", flags, path, NULL);
|
||||
int r = command (&out, &err, str_file, flags, path, NULL);
|
||||
free (buf);
|
||||
|
||||
if (r == -1) {
|
||||
@@ -678,16 +518,16 @@ do_file (const char *path)
|
||||
char *
|
||||
do_zfile (const char *method, const char *path)
|
||||
{
|
||||
int len;
|
||||
size_t len;
|
||||
const char *zcat;
|
||||
char *cmd;
|
||||
FILE *fp;
|
||||
char line[256];
|
||||
|
||||
if (STREQ (method, "gzip") || STREQ (method, "compress"))
|
||||
zcat = "zcat";
|
||||
zcat = str_zcat;
|
||||
else if (STREQ (method, "bzip2"))
|
||||
zcat = "bzcat";
|
||||
zcat = str_bzcat;
|
||||
else {
|
||||
reply_with_error ("unknown method");
|
||||
return NULL;
|
||||
|
||||
@@ -123,3 +123,31 @@ do_fill_pattern (const char *pattern, int len, const char *path)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_fill_dir (const char *dir, int n)
|
||||
{
|
||||
size_t len = strlen (dir);
|
||||
char filename[len+10];
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
snprintf (filename, len+10, "%s/%08d", dir, i);
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("create: %s", filename);
|
||||
return -1;
|
||||
}
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close: %s", filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,10 +30,13 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_find, find);
|
||||
|
||||
static int
|
||||
input_to_nul (FILE *fp, char *buf, int maxlen)
|
||||
input_to_nul (FILE *fp, char *buf, size_t maxlen)
|
||||
{
|
||||
int i = 0, c;
|
||||
size_t i = 0;
|
||||
int c;
|
||||
|
||||
while (i < maxlen) {
|
||||
c = fgetc (fp);
|
||||
@@ -48,87 +51,6 @@ input_to_nul (FILE *fp, char *buf, int maxlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char **
|
||||
do_find (const char *dir)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int r, len, sysrootdirlen;
|
||||
char *cmd;
|
||||
FILE *fp;
|
||||
char **res = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
char *sysrootdir;
|
||||
char str[PATH_MAX];
|
||||
|
||||
sysrootdir = sysroot_path (dir);
|
||||
if (!sysrootdir) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = stat (sysrootdir, &statbuf);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("%s", dir);
|
||||
free (sysrootdir);
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISDIR (statbuf.st_mode)) {
|
||||
reply_with_error ("%s: not a directory", dir);
|
||||
free (sysrootdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sysrootdirlen = strlen (sysrootdir);
|
||||
|
||||
/* Assemble the external find command. */
|
||||
if (asprintf_nowarn (&cmd, "find %Q -print0", sysrootdir) == -1) {
|
||||
reply_with_perror ("malloc");
|
||||
free (sysrootdir);
|
||||
return NULL;
|
||||
}
|
||||
free (sysrootdir);
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("%s", cmd);
|
||||
free (cmd);
|
||||
return NULL;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
while ((r = input_to_nul (fp, str, PATH_MAX)) > 0) {
|
||||
len = strlen (str);
|
||||
if (len <= sysrootdirlen)
|
||||
continue;
|
||||
|
||||
/* Remove the directory part of the path when adding it. */
|
||||
if (add_string (&res, &size, &alloc, str + sysrootdirlen) == -1) {
|
||||
pclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (pclose (fp) != 0) {
|
||||
reply_with_perror ("pclose");
|
||||
free_stringslen (res, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r == -1) {
|
||||
free_stringslen (res, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_string (&res, &size, &alloc, NULL) == -1)
|
||||
return NULL;
|
||||
|
||||
sort_strings (res, size-1);
|
||||
|
||||
return res; /* caller frees */
|
||||
}
|
||||
|
||||
/* The code below assumes each path returned can fit into a protocol
|
||||
* chunk. If this turns out not to be true at some point in the
|
||||
* future then we'll need to modify the code a bit to handle it.
|
||||
@@ -169,7 +91,7 @@ do_find0 (const char *dir)
|
||||
|
||||
sysrootdirlen = strlen (sysrootdir);
|
||||
|
||||
if (asprintf_nowarn (&cmd, "find %Q -print0", sysrootdir) == -1) {
|
||||
if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
free (sysrootdir);
|
||||
return -1;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_findfs, findfs);
|
||||
|
||||
static char *
|
||||
findfs (const char *tag, const char *label_or_uuid)
|
||||
{
|
||||
@@ -35,13 +37,14 @@ findfs (const char *tag, const char *label_or_uuid)
|
||||
* is not supported in RHEL 5.
|
||||
*/
|
||||
unlink ("/etc/blkid/blkid.tab");
|
||||
unlink ("/run/blkid/blkid.tab");
|
||||
|
||||
size_t len = strlen (tag) + strlen (label_or_uuid) + 2;
|
||||
char arg[len];
|
||||
snprintf (arg, len, "%s=%s", tag, label_or_uuid);
|
||||
|
||||
char *out, *err;
|
||||
int r = command (&out, &err, "findfs", arg, NULL);
|
||||
int r = command (&out, &err, str_findfs, arg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
|
||||
@@ -26,13 +26,15 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_fsck, fsck);
|
||||
|
||||
int
|
||||
do_fsck (const char *fstype, const char *device)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = commandr (NULL, &err, "fsck", "-a", "-t", fstype, device, NULL);
|
||||
r = commandr (NULL, &err, str_fsck, "-a", "-t", fstype, device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
|
||||
99
daemon/fstrim.c
Normal file
99
daemon/fstrim.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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
|
||||
|
||||
GUESTFSD_EXT_CMD(str_fstrim, fstrim);
|
||||
|
||||
int
|
||||
optgroup_fstrim_available (void)
|
||||
{
|
||||
return prog_exists (str_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, str_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;
|
||||
}
|
||||
@@ -29,7 +29,7 @@ char **
|
||||
do_glob_expand (const char *pattern)
|
||||
{
|
||||
int r;
|
||||
glob_t buf;
|
||||
glob_t buf = { .gl_pathc = 0, .gl_pathv = NULL, .gl_offs = 0 };
|
||||
|
||||
/* glob(3) in glibc never calls chdir, so this seems to be safe: */
|
||||
CHROOT_IN;
|
||||
|
||||
@@ -28,15 +28,42 @@
|
||||
#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);
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_grub_install, grub-install);
|
||||
|
||||
int
|
||||
optgroup_grub_available (void)
|
||||
{
|
||||
return prog_exists ("grub-install");
|
||||
return prog_exists (str_grub_install);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -44,7 +46,7 @@ do_grub_install (const char *root, const char *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &err, "grub-install", buf, device, NULL);
|
||||
r = command (NULL, &err, str_grub_install, buf, device, NULL);
|
||||
free (buf);
|
||||
|
||||
if (r == -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>
|
||||
@@ -52,6 +53,8 @@
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_udevadm, udevadm);
|
||||
|
||||
static char *read_cmdline (void);
|
||||
|
||||
#ifndef MAX
|
||||
@@ -203,6 +206,8 @@ main (int argc, char *argv[])
|
||||
printf ("could not read linux command line\n");
|
||||
}
|
||||
|
||||
free (cmdline);
|
||||
|
||||
#ifndef WIN32
|
||||
/* Make sure SIGPIPE doesn't kill us. */
|
||||
struct sigaction sa;
|
||||
@@ -245,7 +250,7 @@ main (int argc, char *argv[])
|
||||
copy_lvm ();
|
||||
|
||||
/* Connect to virtio-serial channel. */
|
||||
int sock = open (VIRTIO_SERIAL_CHANNEL, O_RDWR | O_CLOEXEC);
|
||||
int sock = open (VIRTIO_SERIAL_CHANNEL, O_RDWR|O_CLOEXEC);
|
||||
if (sock == -1) {
|
||||
fprintf (stderr,
|
||||
"\n"
|
||||
@@ -264,6 +269,17 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Wait for udev devices to be created. If you start libguestfs,
|
||||
* especially with disks that contain complex (eg. mdadm) data
|
||||
* already, then it is possible for the 'mdadm' and LVM commands
|
||||
* that the init script runs to have not completed by the time the
|
||||
* daemon starts executing library commands. (This is very rare and
|
||||
* hard to test however, but we have seen it in 'brew'). Run
|
||||
* udev_settle, but do it as late as possible to minimize the chance
|
||||
* that we'll have to do any waiting here.
|
||||
*/
|
||||
udev_settle ();
|
||||
|
||||
/* Send the magic length message which indicates that
|
||||
* userspace is up inside the guest.
|
||||
*/
|
||||
@@ -290,7 +306,7 @@ main (int argc, char *argv[])
|
||||
static char *
|
||||
read_cmdline (void)
|
||||
{
|
||||
int fd = open ("/proc/cmdline", O_RDONLY);
|
||||
int fd = open ("/proc/cmdline", O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
perror ("/proc/cmdline");
|
||||
return NULL;
|
||||
@@ -362,7 +378,7 @@ char *
|
||||
sysroot_path (const char *path)
|
||||
{
|
||||
char *r;
|
||||
int len = strlen (path) + sysroot_len + 1;
|
||||
size_t len = strlen (path) + sysroot_len + 1;
|
||||
|
||||
r = malloc (len);
|
||||
if (r == NULL)
|
||||
@@ -375,7 +391,7 @@ sysroot_path (const char *path)
|
||||
int
|
||||
xwrite (int sock, const void *v_buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
ssize_t r;
|
||||
const char *buf = v_buf;
|
||||
|
||||
while (len > 0) {
|
||||
@@ -415,46 +431,50 @@ xread (int sock, void *v_buf, size_t len)
|
||||
}
|
||||
|
||||
int
|
||||
add_string_nodup (char ***argv, int *size, int *alloc, char *str)
|
||||
add_string_nodup (struct stringsbuf *sb, char *str)
|
||||
{
|
||||
char **new_argv;
|
||||
|
||||
if (*size >= *alloc) {
|
||||
*alloc += 64;
|
||||
new_argv = realloc (*argv, *alloc * sizeof (char *));
|
||||
if (sb->size >= sb->alloc) {
|
||||
sb->alloc += 64;
|
||||
new_argv = realloc (sb->argv, sb->alloc * sizeof (char *));
|
||||
if (new_argv == NULL) {
|
||||
reply_with_perror ("realloc");
|
||||
free_strings (*argv);
|
||||
*argv = NULL;
|
||||
free_stringslen (sb->argv, sb->size);
|
||||
sb->argv = NULL;
|
||||
return -1;
|
||||
}
|
||||
*argv = new_argv;
|
||||
sb->argv = new_argv;
|
||||
}
|
||||
|
||||
(*argv)[*size] = str;
|
||||
sb->argv[sb->size] = str;
|
||||
sb->size++;
|
||||
|
||||
(*size)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
add_string (char ***argv, int *size, int *alloc, const char *str)
|
||||
add_string (struct stringsbuf *sb, const char *str)
|
||||
{
|
||||
char *new_str;
|
||||
char *new_str = NULL;
|
||||
|
||||
if (str) {
|
||||
new_str = strdup (str);
|
||||
if (new_str == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
free_strings (*argv);
|
||||
*argv = NULL;
|
||||
free_stringslen (sb->argv, sb->size);
|
||||
sb->argv = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
new_str = NULL;
|
||||
}
|
||||
|
||||
return add_string_nodup (argv, size, alloc, new_str);
|
||||
return add_string_nodup (sb, new_str);
|
||||
}
|
||||
|
||||
int
|
||||
end_stringsbuf (struct stringsbuf *sb)
|
||||
{
|
||||
return add_string_nodup (sb, NULL);
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -483,7 +503,7 @@ compare (const void *vp1, const void *vp2)
|
||||
}
|
||||
|
||||
void
|
||||
sort_strings (char **argv, int len)
|
||||
sort_strings (char **argv, size_t len)
|
||||
{
|
||||
qsort (argv, len, sizeof (char *), compare);
|
||||
}
|
||||
@@ -491,7 +511,7 @@ sort_strings (char **argv, int len)
|
||||
void
|
||||
free_strings (char **argv)
|
||||
{
|
||||
int argc;
|
||||
size_t argc;
|
||||
|
||||
for (argc = 0; argv[argc] != NULL; ++argc)
|
||||
free (argv[argc]);
|
||||
@@ -499,15 +519,127 @@ free_strings (char **argv)
|
||||
}
|
||||
|
||||
void
|
||||
free_stringslen (char **argv, int len)
|
||||
free_stringslen (char **argv, size_t len)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
free (argv[i]);
|
||||
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;
|
||||
|
||||
/* If no partition numbers, bail -- the devices are the same. This
|
||||
* can happen in one peculiar case: where you have a mix of devices
|
||||
* with different interfaces (eg. /dev/sda and /dev/vda).
|
||||
* (RHBZ#858128).
|
||||
*/
|
||||
if (!*a && !*b)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
char *
|
||||
concat_strings (char *const *argv)
|
||||
{
|
||||
return join_strings ("", argv);
|
||||
}
|
||||
|
||||
char *
|
||||
join_strings (const char *separator, char *const *argv)
|
||||
{
|
||||
size_t i, len, seplen, rlen;
|
||||
char *r;
|
||||
|
||||
seplen = strlen (separator);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; argv[i] != NULL; ++i) {
|
||||
if (i > 0)
|
||||
len += seplen;
|
||||
len += strlen (argv[i]);
|
||||
}
|
||||
len++; /* for final \0 */
|
||||
|
||||
r = malloc (len);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
rlen = 0;
|
||||
for (i = 0; argv[i] != NULL; ++i) {
|
||||
if (i > 0) {
|
||||
memcpy (&r[rlen], separator, seplen);
|
||||
rlen += seplen;
|
||||
}
|
||||
len = strlen (argv[i]);
|
||||
memcpy (&r[rlen], argv[i], len);
|
||||
rlen += len;
|
||||
}
|
||||
r[rlen] = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Easy ways to run external commands. For full documentation, see
|
||||
* 'commandrvf' below.
|
||||
*/
|
||||
@@ -517,7 +649,8 @@ commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
|
||||
va_list args;
|
||||
const char **argv;
|
||||
char *s;
|
||||
int i, r;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
/* Collect the command line arguments into an array. */
|
||||
i = 2;
|
||||
@@ -649,7 +782,7 @@ int
|
||||
commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
char const* const *argv)
|
||||
{
|
||||
int so_size = 0, se_size = 0;
|
||||
size_t so_size = 0, se_size = 0;
|
||||
int so_fd[2], se_fd[2];
|
||||
int flag_copy_stdin = flags & COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN;
|
||||
int stdin_fd[2] = { -1, -1 };
|
||||
@@ -706,7 +839,7 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
close (stdin_fd[1]);
|
||||
} else {
|
||||
/* Set stdin to /dev/null (ignore failure) */
|
||||
ignore_value (open ("/dev/null", O_RDONLY));
|
||||
ignore_value (open ("/dev/null", O_RDONLY|O_CLOEXEC));
|
||||
}
|
||||
close (so_fd[0]);
|
||||
close (se_fd[0]);
|
||||
@@ -888,9 +1021,10 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
*stderror = q;
|
||||
if (*stderror) {
|
||||
(*stderror)[se_size] = '\0';
|
||||
se_size--;
|
||||
while (se_size >= 0 && (*stderror)[se_size] == '\n')
|
||||
(*stderror)[se_size--] = '\0';
|
||||
while (se_size > 0 && (*stderror)[se_size-1] == '\n') {
|
||||
se_size--;
|
||||
(*stderror)[se_size] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,7 +1038,7 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
}
|
||||
|
||||
if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
|
||||
fprintf (stderr, "failed copying from input file, see earlier messages\n");
|
||||
fprintf (stderr, "failed copying from input file, see earlier messages (r = %d)\n", r);
|
||||
kill (pid, 9);
|
||||
waitpid (pid, NULL, 0);
|
||||
return -1;
|
||||
@@ -944,8 +1078,7 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
char **
|
||||
split_lines (char *str)
|
||||
{
|
||||
char **lines = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (lines);
|
||||
char *p, *pend;
|
||||
|
||||
if (STREQ (str, ""))
|
||||
@@ -963,7 +1096,7 @@ split_lines (char *str)
|
||||
pend++;
|
||||
}
|
||||
|
||||
if (add_string (&lines, &size, &alloc, p) == -1) {
|
||||
if (add_string (&lines, p) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -971,10 +1104,10 @@ split_lines (char *str)
|
||||
}
|
||||
|
||||
empty_list:
|
||||
if (add_string (&lines, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&lines) == -1)
|
||||
return NULL;
|
||||
|
||||
return lines;
|
||||
return lines.argv;
|
||||
}
|
||||
|
||||
/* Skip leading and trailing whitespace, updating the original string
|
||||
@@ -1072,7 +1205,7 @@ device_name_translation (char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (device, O_RDONLY);
|
||||
fd = open (device, O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
close_ok:
|
||||
close (fd);
|
||||
@@ -1087,12 +1220,12 @@ device_name_translation (char *device)
|
||||
return -1;
|
||||
|
||||
device[5] = 'h'; /* /dev/hd (old IDE driver) */
|
||||
fd = open (device, O_RDONLY);
|
||||
fd = open (device, O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
goto close_ok;
|
||||
|
||||
device[5] = 'v'; /* /dev/vd (for virtio devices) */
|
||||
fd = open (device, O_RDONLY);
|
||||
fd = open (device, O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
goto close_ok;
|
||||
|
||||
@@ -1119,6 +1252,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
|
||||
@@ -1126,16 +1305,9 @@ prog_exists (const char *prog)
|
||||
*
|
||||
* Use 'udevadm settle' after certain commands, but don't be too
|
||||
* fussed if it fails.
|
||||
*
|
||||
* 'udevsettle' was the old name for this command (RHEL 5). This was
|
||||
* deprecated in favour of 'udevadm settle'. The old 'udevsettle'
|
||||
* command was left as a symlink. Then in Fedora 13 the old symlink
|
||||
* remained but it stopped working (RHBZ#548121), so we have to be
|
||||
* careful not to assume that we can use 'udevsettle' if it exists.
|
||||
*/
|
||||
void
|
||||
udev_settle (void)
|
||||
{
|
||||
(void) command (NULL, NULL, "udevadm", "settle", NULL);
|
||||
(void) command (NULL, NULL, "udevsettle", NULL);
|
||||
(void) command (NULL, NULL, str_udevadm, "settle", NULL);
|
||||
}
|
||||
|
||||
103
daemon/guestfsd.pod
Normal file
103
daemon/guestfsd.pod
Normal file
@@ -0,0 +1,103 @@
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
guestfsd - guestfs daemon
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
guestfsd [-r] [-v|--verbose]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<guestfsd> is the libguestfs daemon. Normal users never need to run
|
||||
this program explicitly. This man page discusses what C<guestfsd>
|
||||
does in both the libguestfs appliance and when using libguestfs live.
|
||||
|
||||
=head2 LIBGUESTFS APPLIANCE
|
||||
|
||||
For the architecture of the libguestfs appliance, see
|
||||
L<guestfs(3)/ARCHITECTURE>.
|
||||
|
||||
After the appliance boots, the C</init> script in the appliance starts
|
||||
C<guestfsd> with no arguments. C<guestfsd> opens the virtio-serial
|
||||
port on a known path (see L</FILES>). It initiates the protocol (see
|
||||
L<guestfs(3)/COMMUNICATION PROTOCOL>) and processes requests one at a
|
||||
time from the library until the appliance is destroyed.
|
||||
|
||||
Filesystems are mounted under C</sysroot> and all filesystem
|
||||
operations happen relative to this directory.
|
||||
|
||||
=head2 LIBGUESTFS LIVE
|
||||
|
||||
In the libguestfs live case, C<guestfsd -r> is started from the
|
||||
rc-scripts, systemd, etc.
|
||||
|
||||
The C<-r> option causes the daemon to operate on the root filesystem
|
||||
instead of C</sysroot>.
|
||||
|
||||
Currently (because of limitations in virtio-serial) only one client
|
||||
can connect at a time, and C<guestfsd> must be restarted after each
|
||||
client disconnects. If libguestfs live were changed to use a
|
||||
different transport such as TCP/IP then this limitation could be
|
||||
removed.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-?>
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display brief help.
|
||||
|
||||
=item B<-r>
|
||||
|
||||
Set the root filesystem to be C</> (instead of the default which is
|
||||
C</sysroot>). Also do not unmount filesystems when the daemon exits.
|
||||
|
||||
This option is used to enable libguestfs live.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
=item B<--verbose>
|
||||
|
||||
Enable verbose messages for debugging.
|
||||
|
||||
The verbose flag is also set if the Linux command line contains the
|
||||
substring C<guestfs_verbose=1>.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
|
||||
This program returns 0 if successful, or non-zero if there was an
|
||||
error.
|
||||
|
||||
=head1 FILES
|
||||
|
||||
=over 4
|
||||
|
||||
=item C</dev/virtio-ports/org.libguestfs.channel.0>
|
||||
|
||||
The virtio serial port which C<guestfsd> connects to.
|
||||
|
||||
=item C</proc/cmdline>
|
||||
|
||||
The Linux command line is parsed to discover C<guestfs_*> flags.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<guestfs(3)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2012 Red Hat Inc.
|
||||
@@ -36,7 +36,7 @@ headtail (const char *prog, const char *flag, const char *n, const char *path)
|
||||
char **lines;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
|
||||
@@ -34,7 +34,7 @@ do_hexdump (const char *path)
|
||||
char *out, *err;
|
||||
|
||||
CHROOT_IN;
|
||||
fd = open (path, O_RDONLY);
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
|
||||
509
daemon/hivex.c
Normal file
509
daemon/hivex.c
Normal file
@@ -0,0 +1,509 @@
|
||||
/* 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 <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
#ifdef HAVE_HIVEX
|
||||
|
||||
#include <hivex.h>
|
||||
|
||||
int
|
||||
optgroup_hivex_available (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The hivex handle. As with Augeas, there is one per guestfs handle /
|
||||
* daemon.
|
||||
*/
|
||||
static hive_h *h = NULL;
|
||||
|
||||
/* Clean up the hivex handle on daemon exit. */
|
||||
static void hivex_finalize (void) __attribute__((destructor));
|
||||
static void
|
||||
hivex_finalize (void)
|
||||
{
|
||||
if (h) {
|
||||
hivex_close (h);
|
||||
h = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define NEED_HANDLE(errcode) \
|
||||
do { \
|
||||
if (!h) { \
|
||||
reply_with_error ("%s: you must call 'hivex-open' first to initialize the hivex handle", __func__); \
|
||||
return (errcode); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_hivex_open (const char *filename, int verbose, int debug, int write)
|
||||
{
|
||||
char *buf;
|
||||
int flags = 0;
|
||||
|
||||
if (h) {
|
||||
hivex_close (h);
|
||||
h = NULL;
|
||||
}
|
||||
|
||||
buf = sysroot_path (filename);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_VERBOSE_BITMASK) {
|
||||
if (verbose)
|
||||
flags |= HIVEX_OPEN_VERBOSE;
|
||||
}
|
||||
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_DEBUG_BITMASK) {
|
||||
if (debug)
|
||||
flags |= HIVEX_OPEN_DEBUG;
|
||||
}
|
||||
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_WRITE_BITMASK) {
|
||||
if (write)
|
||||
flags |= HIVEX_OPEN_WRITE;
|
||||
}
|
||||
|
||||
h = hivex_open (buf, flags);
|
||||
if (!h) {
|
||||
reply_with_perror ("hivex failed to open %s", filename);
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_hivex_close (void)
|
||||
{
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
hivex_close (h);
|
||||
h = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_root (void)
|
||||
{
|
||||
int64_t r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
r = hivex_root (h);
|
||||
if (r == 0) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *
|
||||
do_hivex_node_name (int64_t nodeh)
|
||||
{
|
||||
char *r;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
|
||||
r = hivex_node_name (h, nodeh);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
guestfs_int_hivex_node_list *
|
||||
do_hivex_node_children (int64_t nodeh)
|
||||
{
|
||||
guestfs_int_hivex_node_list *ret;
|
||||
hive_node_h *r;
|
||||
size_t i, len;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
|
||||
r = hivex_node_children (h, nodeh);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (i = 0; r[i] != 0; ++i)
|
||||
len++;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->guestfs_int_hivex_node_list_len = len;
|
||||
ret->guestfs_int_hivex_node_list_val =
|
||||
malloc (len * sizeof (guestfs_int_hivex_node));
|
||||
if (ret->guestfs_int_hivex_node_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
ret->guestfs_int_hivex_node_list_val[i].hivex_node_h = r[i];
|
||||
|
||||
free (r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_node_get_child (int64_t nodeh, const char *name)
|
||||
{
|
||||
int64_t r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
errno = 0;
|
||||
r = hivex_node_get_child (h, nodeh, name);
|
||||
if (r == 0 && errno != 0) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_node_parent (int64_t nodeh)
|
||||
{
|
||||
int64_t r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
r = hivex_node_parent (h, nodeh);
|
||||
if (r == 0) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
guestfs_int_hivex_value_list *
|
||||
do_hivex_node_values (int64_t nodeh)
|
||||
{
|
||||
guestfs_int_hivex_value_list *ret;
|
||||
hive_value_h *r;
|
||||
size_t i, len;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
|
||||
r = hivex_node_values (h, nodeh);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (i = 0; r[i] != 0; ++i)
|
||||
len++;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->guestfs_int_hivex_value_list_len = len;
|
||||
ret->guestfs_int_hivex_value_list_val =
|
||||
malloc (len * sizeof (guestfs_int_hivex_value));
|
||||
if (ret->guestfs_int_hivex_value_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
ret->guestfs_int_hivex_value_list_val[i].hivex_value_h = (int64_t) r[i];
|
||||
|
||||
free (r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_node_get_value (int64_t nodeh, const char *key)
|
||||
{
|
||||
int64_t r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
errno = 0;
|
||||
r = hivex_node_get_value (h, nodeh, key);
|
||||
if (r == 0 && errno != 0) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *
|
||||
do_hivex_value_key (int64_t valueh)
|
||||
{
|
||||
char *r;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
|
||||
r = hivex_value_key (h, valueh);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_value_type (int64_t valueh)
|
||||
{
|
||||
hive_type r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
if (hivex_value_type (h, valueh, &r, NULL) == -1) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *
|
||||
do_hivex_value_value (int64_t valueh, size_t *size_r)
|
||||
{
|
||||
char *r;
|
||||
size_t size;
|
||||
|
||||
NEED_HANDLE (NULL);
|
||||
|
||||
r = hivex_value_value (h, valueh, NULL, &size);
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size_r = size;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_hivex_commit (const char *filename)
|
||||
{
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
if (hivex_commit (h, filename, 0) == -1) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_hivex_node_add_child (int64_t parent, const char *name)
|
||||
{
|
||||
int64_t r;
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
r = hivex_node_add_child (h, parent, name);
|
||||
if (r == 0) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
do_hivex_node_delete_child (int64_t nodeh)
|
||||
{
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
if (hivex_node_delete_child (h, nodeh) == -1) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_hivex_node_set_value (int64_t nodeh,
|
||||
const char *key, int64_t t,
|
||||
const char *val, size_t val_size)
|
||||
{
|
||||
const hive_set_value v =
|
||||
{ .key = (char *) key, .t = t, .len = val_size, .value = (char *) val };
|
||||
|
||||
NEED_HANDLE (-1);
|
||||
|
||||
if (hivex_node_set_value (h, nodeh, &v, 0) == -1) {
|
||||
reply_with_perror ("failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !HAVE_HIVEX */
|
||||
|
||||
/* Note that the wrapper code (daemon/stubs.c) ensures that the
|
||||
* functions below are never called because optgroup_hivex_available
|
||||
* returns false.
|
||||
*/
|
||||
int
|
||||
optgroup_hivex_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_hivex_open (const char *filename, int verbose, int debug, int write)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_hivex_close (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_root (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char * __attribute__((noreturn))
|
||||
do_hivex_node_name (int64_t nodeh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
guestfs_int_hivex_node_list * __attribute__((noreturn))
|
||||
do_hivex_node_children (int64_t nodeh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_node_get_child (int64_t nodeh, const char *name)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_node_parent (int64_t nodeh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
guestfs_int_hivex_value_list * __attribute__((noreturn))
|
||||
do_hivex_node_values (int64_t nodeh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_node_get_value (int64_t nodeh, const char *key)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char * __attribute__((noreturn))
|
||||
do_hivex_value_key (int64_t valueh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_value_type (int64_t valueh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char * __attribute__((noreturn))
|
||||
do_hivex_value_value (int64_t valueh, size_t *size_r)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_hivex_commit (const char *filename)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t __attribute__((noreturn))
|
||||
do_hivex_node_add_child (int64_t parent, const char *name)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_hivex_node_delete_child (int64_t nodeh)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int __attribute__((noreturn))
|
||||
do_hivex_node_set_value (int64_t nodeh, const char *key, int64_t t, const char *val, size_t val_size)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
#endif /* !HAVE_HIVEX */
|
||||
160
daemon/hotplug.c
Normal file
160
daemon/hotplug.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
#define HOT_ADD_TIMEOUT 30 /* seconds */
|
||||
#define HOT_REMOVE_TIMEOUT HOT_ADD_TIMEOUT
|
||||
|
||||
static void
|
||||
hotplug_error (const char *op, const char *path, const char *verb,
|
||||
int timeout)
|
||||
{
|
||||
reply_with_error ("%s drive: '%s' did not %s after %d seconds: "
|
||||
"this could mean that virtio-scsi (in qemu or kernel) "
|
||||
"or udev is not working",
|
||||
op, path, verb, timeout);
|
||||
}
|
||||
|
||||
/* Wait for /dev/disk/guestfs/<label> to appear. Timeout (and error)
|
||||
* if it doesn't appear after a reasonable length of time.
|
||||
*/
|
||||
int
|
||||
do_internal_hot_add_drive (const char *label)
|
||||
{
|
||||
time_t start_t, now_t;
|
||||
size_t len = strlen (label);
|
||||
char path[len+64];
|
||||
int r;
|
||||
|
||||
snprintf (path, len+64, "/dev/disk/guestfs/%s", label);
|
||||
|
||||
time (&start_t);
|
||||
|
||||
while (time (&now_t) - start_t <= HOT_ADD_TIMEOUT) {
|
||||
udev_settle ();
|
||||
|
||||
r = access (path, F_OK);
|
||||
if (r == -1 && errno != ENOENT) {
|
||||
reply_with_perror ("%s", path);
|
||||
return -1;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
hotplug_error ("hot-add", path, "appear", HOT_ADD_TIMEOUT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GUESTFSD_EXT_CMD(str_fuser, fuser);
|
||||
|
||||
/* This function is called before a drive is hot-unplugged. */
|
||||
int
|
||||
do_internal_hot_remove_drive_precheck (const char *label)
|
||||
{
|
||||
size_t len = strlen (label);
|
||||
char path[len+64];
|
||||
int r;
|
||||
char *out, *err;
|
||||
|
||||
/* Ensure there are no requests in flight (thanks Paolo Bonzini). */
|
||||
udev_settle ();
|
||||
sync_disks ();
|
||||
|
||||
snprintf (path, len+64, "/dev/disk/guestfs/%s", label);
|
||||
|
||||
r = commandr (&out, &err, str_fuser, "-v", "-m", path, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("fuser: %s: %s", path, err);
|
||||
free (out);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* "fuser returns a non-zero return code if none of the specified
|
||||
* files is accessed or in case of a fatal error. If at least one
|
||||
* access has been found, fuser returns zero."
|
||||
*/
|
||||
if (r == 0) {
|
||||
reply_with_error ("disk with label '%s' is in use "
|
||||
"(eg. mounted or belongs to a volume group)", label);
|
||||
|
||||
/* Useful for debugging when a drive cannot be unplugged. */
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", out);
|
||||
|
||||
free (out);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called after a drive is hot-unplugged. It checks
|
||||
* that it has really gone and udev has finished processing the
|
||||
* events, in case the user immediately hotplugs a drive with an
|
||||
* identical label.
|
||||
*/
|
||||
int
|
||||
do_internal_hot_remove_drive (const char *label)
|
||||
{
|
||||
time_t start_t, now_t;
|
||||
size_t len = strlen (label);
|
||||
char path[len+64];
|
||||
int r;
|
||||
|
||||
snprintf (path, len+64, "/dev/disk/guestfs/%s", label);
|
||||
|
||||
time (&start_t);
|
||||
|
||||
while (time (&now_t) - start_t <= HOT_REMOVE_TIMEOUT) {
|
||||
udev_settle ();
|
||||
|
||||
r = access (path, F_OK);
|
||||
if (r == -1) {
|
||||
if (errno != ENOENT) {
|
||||
reply_with_perror ("%s", path);
|
||||
return -1;
|
||||
}
|
||||
/* else udev has removed the file, so we can return */
|
||||
return 0;
|
||||
}
|
||||
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
hotplug_error ("hot-remove", path, "disappear", HOT_REMOVE_TIMEOUT);
|
||||
return -1;
|
||||
}
|
||||
@@ -30,18 +30,20 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_zcat, zcat);
|
||||
GUESTFSD_EXT_CMD(str_cpio, cpio);
|
||||
|
||||
char **
|
||||
do_initrd_list (const char *path)
|
||||
{
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char filename[PATH_MAX];
|
||||
char **filenames = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (filenames);
|
||||
size_t len;
|
||||
|
||||
/* "zcat /sysroot/<path> | cpio --quiet -it", but path must be quoted. */
|
||||
if (asprintf_nowarn (&cmd, "zcat %R | cpio --quiet -it", path) == -1) {
|
||||
if (asprintf_nowarn (&cmd, "%s %R | %s --quiet -it", str_zcat, path, str_cpio) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return NULL;
|
||||
}
|
||||
@@ -62,24 +64,24 @@ do_initrd_list (const char *path)
|
||||
if (len > 0 && filename[len-1] == '\n')
|
||||
filename[len-1] = '\0';
|
||||
|
||||
if (add_string (&filenames, &size, &alloc, filename) == -1) {
|
||||
if (add_string (&filenames, filename) == -1) {
|
||||
pclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_string (&filenames, &size, &alloc, NULL) == -1) {
|
||||
if (end_stringsbuf (&filenames) == -1) {
|
||||
pclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
reply_with_perror ("pclose");
|
||||
free_strings (filenames);
|
||||
free_stringslen (filenames.argv, filenames.size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return filenames;
|
||||
return filenames.argv;
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -108,9 +110,11 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
int r = system (cmd);
|
||||
if (r == -1) {
|
||||
reply_with_perror ("command failed: %s", cmd);
|
||||
free (cmd);
|
||||
rmdir (tmpdir);
|
||||
return NULL;
|
||||
}
|
||||
free (cmd);
|
||||
if (WEXITSTATUS (r) != 0) {
|
||||
reply_with_perror ("command failed with return code %d",
|
||||
WEXITSTATUS (r));
|
||||
@@ -125,7 +129,7 @@ do_initrd_cat (const char *path, const char *filename, size_t *size_r)
|
||||
struct stat statbuf;
|
||||
int fd;
|
||||
|
||||
fd = open (fullpath, O_RDONLY);
|
||||
fd = open (fullpath, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("open: %s:%s", path, filename);
|
||||
rmdir (tmpdir);
|
||||
|
||||
114
daemon/inotify.c
114
daemon/inotify.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -34,24 +35,30 @@
|
||||
#include "optgroups.h"
|
||||
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
GUESTFSD_EXT_CMD(str_sort, sort);
|
||||
|
||||
/* Currently open inotify handle, or -1 if not opened. */
|
||||
static int inotify_fd = -1;
|
||||
|
||||
static char inotify_buf[64*1024*1024]; /* Event buffer, [0..posn-1] is valid */
|
||||
static size_t inotify_posn = 0;
|
||||
|
||||
/* Clean up the inotify handle on daemon exit. */
|
||||
static void inotify_finalize (void) __attribute__((destructor));
|
||||
static void
|
||||
inotify_finalize (void)
|
||||
{
|
||||
if (inotify_fd >= 0) {
|
||||
close (inotify_fd);
|
||||
inotify_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
optgroup_inotify_available (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#else /* !HAVE_SYS_INOTIFY_H */
|
||||
int
|
||||
optgroup_inotify_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Because inotify_init does NEED_ROOT, NEED_INOTIFY implies NEED_ROOT. */
|
||||
#define NEED_INOTIFY(errcode) \
|
||||
@@ -67,7 +74,6 @@ optgroup_inotify_available (void)
|
||||
int
|
||||
do_inotify_init (int max_events)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
FILE *fp;
|
||||
|
||||
NEED_ROOT (, return -1);
|
||||
@@ -118,15 +124,11 @@ do_inotify_init (int max_events)
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_inotify_close (void)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
NEED_INOTIFY (-1);
|
||||
|
||||
if (inotify_fd == -1) {
|
||||
@@ -143,15 +145,11 @@ do_inotify_close (void)
|
||||
inotify_posn = 0;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_inotify_add_watch (const char *path, int mask)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
int64_t r;
|
||||
char *buf;
|
||||
|
||||
@@ -171,15 +169,11 @@ do_inotify_add_watch (const char *path, int mask)
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
do_inotify_rm_watch (int wd)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
NEED_INOTIFY (-1);
|
||||
|
||||
if (inotify_rm_watch (inotify_fd, wd) == -1) {
|
||||
@@ -188,15 +182,11 @@ do_inotify_rm_watch (int wd)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
guestfs_int_inotify_event_list *
|
||||
do_inotify_read (void)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
int space;
|
||||
guestfs_int_inotify_event_list *ret;
|
||||
|
||||
@@ -253,6 +243,12 @@ do_inotify_read (void)
|
||||
#error "this code needs fixing so it works on non-GCC compilers"
|
||||
#endif
|
||||
|
||||
/* Check event->len is reasonable (note the field is uint32_t). */
|
||||
if (event->len > PATH_MAX) {
|
||||
reply_with_error ("event->len = %" PRIu32 " > PATH_MAX", event->len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
np = realloc (ret->guestfs_int_inotify_event_list_val,
|
||||
(ret->guestfs_int_inotify_event_list_len + 1) *
|
||||
sizeof (guestfs_int_inotify_event));
|
||||
@@ -302,17 +298,12 @@ do_inotify_read (void)
|
||||
xdr_free ((xdrproc_t) xdr_guestfs_int_inotify_event_list, (char *) ret);
|
||||
free (ret);
|
||||
return NULL;
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
char **
|
||||
do_inotify_files (void)
|
||||
{
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
unsigned int i;
|
||||
FILE *fp = NULL;
|
||||
guestfs_int_inotify_event_list *events;
|
||||
@@ -329,7 +320,7 @@ do_inotify_files (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf (cmd, sizeof cmd, "sort -u > %s", tempfile);
|
||||
snprintf (cmd, sizeof cmd, "%s -u > %s", str_sort, tempfile);
|
||||
|
||||
fp = popen (cmd, "w");
|
||||
if (fp == NULL) {
|
||||
@@ -369,23 +360,23 @@ do_inotify_files (void)
|
||||
}
|
||||
|
||||
while (fgets (buf, sizeof buf, fp) != NULL) {
|
||||
int len = strlen (buf);
|
||||
size_t len = strlen (buf);
|
||||
|
||||
if (len > 0 && buf[len-1] == '\n')
|
||||
buf[len-1] = '\0';
|
||||
|
||||
if (add_string (&ret, &size, &alloc, buf) == -1)
|
||||
if (add_string (&ret, buf) == -1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
fclose (fp); /* implicitly closes fd */
|
||||
fp = NULL;
|
||||
|
||||
if (add_string (&ret, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
goto error;
|
||||
|
||||
unlink (tempfile);
|
||||
return ret;
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
if (fp != NULL)
|
||||
@@ -393,7 +384,54 @@ do_inotify_files (void)
|
||||
|
||||
unlink (tempfile);
|
||||
return NULL;
|
||||
#else
|
||||
NOT_AVAILABLE (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* !HAVE_SYS_INOTIFY_H */
|
||||
|
||||
/* Note that the wrapper code (daemon/stubs.c) ensures that the
|
||||
* functions below are never called because optgroup_inotify_available
|
||||
* returns false.
|
||||
*/
|
||||
int
|
||||
optgroup_inotify_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_inotify_init (int max_events)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
do_inotify_close (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int64_t
|
||||
do_inotify_add_watch (const char *path, int mask)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
do_inotify_rm_watch (int wd)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
guestfs_int_inotify_event_list *
|
||||
do_inotify_read (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
char **
|
||||
do_inotify_files (void)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
294
daemon/isoinfo.c
Normal file
294
daemon/isoinfo.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/* 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 <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_isoinfo, isoinfo);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* This is always in a fixed format:
|
||||
* "2012 03 16 11:05:46.00"
|
||||
* or if the field is not present, then:
|
||||
* "0000 00 00 00:00:00.00"
|
||||
*/
|
||||
static int
|
||||
parse_time_t (int64_t *ret, const char *str)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t r;
|
||||
|
||||
if (STREQ (str, "0000 00 00 00:00:00.00")) {
|
||||
*ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf (str, "%04d %02d %02d %02d:%02d:%02d",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
|
||||
reply_with_error ("cannot parse date from isoinfo: %s", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adjust fields. */
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon--;
|
||||
tm.tm_isdst = -1;
|
||||
|
||||
/* Convert to time_t. */
|
||||
r = timegm (&tm);
|
||||
if (r == -1) {
|
||||
reply_with_error ("invalid date or time: %s", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static guestfs_int_isoinfo *
|
||||
parse_isoinfo (char **lines)
|
||||
{
|
||||
guestfs_int_isoinfo *ret;
|
||||
size_t i;
|
||||
|
||||
ret = calloc (1, sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("calloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Default each int field in the struct to -1. */
|
||||
ret->iso_volume_space_size = (uint32_t) -1;
|
||||
ret->iso_volume_set_size = (uint32_t) -1;
|
||||
ret->iso_volume_sequence_number = (uint32_t) -1;
|
||||
ret->iso_logical_block_size = (uint32_t) -1;
|
||||
ret->iso_volume_creation_t = -1;
|
||||
ret->iso_volume_modification_t = -1;
|
||||
ret->iso_volume_expiration_t = -1;
|
||||
ret->iso_volume_effective_t = -1;
|
||||
|
||||
for (i = 0; lines[i] != NULL; ++i) {
|
||||
if (STRPREFIX (lines[i], "System id: ")) {
|
||||
ret->iso_system_id = strdup (&lines[i][11]);
|
||||
if (ret->iso_system_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Volume id: ")) {
|
||||
ret->iso_volume_id = strdup (&lines[i][11]);
|
||||
if (ret->iso_volume_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Volume set id: ")) {
|
||||
ret->iso_volume_set_id = strdup (&lines[i][15]);
|
||||
if (ret->iso_volume_set_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Publisher id: ")) {
|
||||
ret->iso_publisher_id = strdup (&lines[i][14]);
|
||||
if (ret->iso_publisher_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Data preparer id: ")) {
|
||||
ret->iso_data_preparer_id = strdup (&lines[i][18]);
|
||||
if (ret->iso_data_preparer_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Application id: ")) {
|
||||
ret->iso_application_id = strdup (&lines[i][16]);
|
||||
if (ret->iso_application_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Copyright File id: ")) {
|
||||
ret->iso_copyright_file_id = strdup (&lines[i][19]);
|
||||
if (ret->iso_copyright_file_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Abstract File id: ")) {
|
||||
ret->iso_abstract_file_id = strdup (&lines[i][18]);
|
||||
if (ret->iso_abstract_file_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Bibliographic File id: ")) {
|
||||
ret->iso_bibliographic_file_id = strdup (&lines[i][23]);
|
||||
if (ret->iso_bibliographic_file_id == NULL) goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Volume size is: ")) {
|
||||
if (parse_uint32 (&ret->iso_volume_space_size, &lines[i][16]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Volume set size is: ")) {
|
||||
if (parse_uint32 (&ret->iso_volume_set_size, &lines[i][20]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Volume set sequence number is: ")) {
|
||||
if (parse_uint32 (&ret->iso_volume_sequence_number, &lines[i][31]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Logical block size is: ")) {
|
||||
if (parse_uint32 (&ret->iso_logical_block_size, &lines[i][23]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Creation Date: ")) {
|
||||
if (parse_time_t (&ret->iso_volume_creation_t, &lines[i][19]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Modification Date: ")) {
|
||||
if (parse_time_t (&ret->iso_volume_modification_t, &lines[i][19]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Expiration Date: ")) {
|
||||
if (parse_time_t (&ret->iso_volume_expiration_t, &lines[i][19]) == -1)
|
||||
goto error;
|
||||
}
|
||||
else if (STRPREFIX (lines[i], "Effective Date: ")) {
|
||||
if (parse_time_t (&ret->iso_volume_effective_t, &lines[i][19]) == -1)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Any string fields which were not set above will be NULL. However
|
||||
* we cannot return NULL fields in structs, so we convert these to
|
||||
* empty strings here.
|
||||
*/
|
||||
if (ret->iso_system_id == NULL) {
|
||||
ret->iso_system_id = strdup ("");
|
||||
if (ret->iso_system_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_volume_id == NULL) {
|
||||
ret->iso_volume_id = strdup ("");
|
||||
if (ret->iso_volume_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_volume_set_id == NULL) {
|
||||
ret->iso_volume_set_id = strdup ("");
|
||||
if (ret->iso_volume_set_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_publisher_id == NULL) {
|
||||
ret->iso_publisher_id = strdup ("");
|
||||
if (ret->iso_publisher_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_data_preparer_id == NULL) {
|
||||
ret->iso_data_preparer_id = strdup ("");
|
||||
if (ret->iso_data_preparer_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_application_id == NULL) {
|
||||
ret->iso_application_id = strdup ("");
|
||||
if (ret->iso_application_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_copyright_file_id == NULL) {
|
||||
ret->iso_copyright_file_id = strdup ("");
|
||||
if (ret->iso_copyright_file_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_abstract_file_id == NULL) {
|
||||
ret->iso_abstract_file_id = strdup ("");
|
||||
if (ret->iso_abstract_file_id == NULL) goto error;
|
||||
}
|
||||
if (ret->iso_bibliographic_file_id == NULL) {
|
||||
ret->iso_bibliographic_file_id = strdup ("");
|
||||
if (ret->iso_bibliographic_file_id == NULL) goto error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
free (ret->iso_system_id);
|
||||
free (ret->iso_volume_id);
|
||||
free (ret->iso_volume_set_id);
|
||||
free (ret->iso_publisher_id);
|
||||
free (ret->iso_data_preparer_id);
|
||||
free (ret->iso_application_id);
|
||||
free (ret->iso_copyright_file_id);
|
||||
free (ret->iso_abstract_file_id);
|
||||
free (ret->iso_bibliographic_file_id);
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guestfs_int_isoinfo *
|
||||
isoinfo (const char *path)
|
||||
{
|
||||
char *out = NULL, *err = NULL;
|
||||
int r;
|
||||
char **lines = NULL;
|
||||
guestfs_int_isoinfo *ret = NULL;
|
||||
|
||||
/* --debug is necessary to get additional fields, in particular
|
||||
* the date & time fields.
|
||||
*/
|
||||
r = command (&out, &err, str_isoinfo, "--debug", "-d", "-i", path, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
lines = split_lines (out);
|
||||
if (lines == NULL)
|
||||
goto done;
|
||||
|
||||
ret = parse_isoinfo (lines);
|
||||
if (ret == NULL)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
guestfs_int_isoinfo *
|
||||
do_isoinfo_device (const char *device)
|
||||
{
|
||||
return isoinfo (device);
|
||||
}
|
||||
|
||||
guestfs_int_isoinfo *
|
||||
do_isoinfo (const char *path)
|
||||
{
|
||||
char *buf;
|
||||
guestfs_int_isoinfo *ret;
|
||||
|
||||
buf = sysroot_path (path);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = isoinfo (buf);
|
||||
free (buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
103
daemon/labels.c
Normal file
103
daemon/labels.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_e2label, e2label);
|
||||
GUESTFSD_EXT_CMD(str_ntfslabel, ntfslabel);
|
||||
|
||||
static int
|
||||
e2label (const char *device, const char *label)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
|
||||
if (strlen (label) > EXT2_LABEL_MAX) {
|
||||
reply_with_error ("%s: ext2 labels are limited to %d bytes",
|
||||
label, EXT2_LABEL_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = command (NULL, &err, str_e2label, device, label, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ntfslabel (const char *device, const char *label)
|
||||
{
|
||||
int r;
|
||||
char *err;
|
||||
|
||||
/* XXX We should check if the label is longer than 128 unicode
|
||||
* characters and return an error. This is not so easy since we
|
||||
* don't have the required libraries.
|
||||
*/
|
||||
r = command (NULL, &err, str_ntfslabel, device, label, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_set_label (const char *device, const char *label)
|
||||
{
|
||||
char *vfs_type;
|
||||
int r;
|
||||
|
||||
/* How we set the label depends on the filesystem type. */
|
||||
vfs_type = do_vfs_type (device);
|
||||
if (vfs_type == NULL)
|
||||
return -1;
|
||||
|
||||
if (STREQ (vfs_type, "ext2") || STREQ (vfs_type, "ext3")
|
||||
|| STREQ (vfs_type, "ext4"))
|
||||
r = e2label (device, label);
|
||||
|
||||
else if (STREQ (vfs_type, "ntfs"))
|
||||
r = ntfslabel (device, label);
|
||||
|
||||
else {
|
||||
reply_with_error ("don't know how to set the label for '%s' filesystems",
|
||||
vfs_type);
|
||||
r = -1;
|
||||
}
|
||||
|
||||
free (vfs_type);
|
||||
return r;
|
||||
}
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_ln, ln);
|
||||
|
||||
char *
|
||||
do_readlink (const char *path)
|
||||
{
|
||||
@@ -53,18 +55,17 @@ do_readlink (const char *path)
|
||||
}
|
||||
|
||||
char **
|
||||
do_readlinklist (const char *path, char *const *names)
|
||||
do_internal_readlinklist (const char *path, char *const *names)
|
||||
{
|
||||
int fd_cwd;
|
||||
size_t i;
|
||||
ssize_t r;
|
||||
char link[PATH_MAX];
|
||||
const char *str;
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
CHROOT_IN;
|
||||
fd_cwd = open (path, O_RDONLY | O_DIRECTORY);
|
||||
fd_cwd = open (path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd_cwd == -1) {
|
||||
@@ -87,7 +88,7 @@ do_readlinklist (const char *path, char *const *names)
|
||||
str = link;
|
||||
} else
|
||||
str = "";
|
||||
if (add_string (&ret, &size, &alloc, str) == -1) {
|
||||
if (add_string (&ret, str) == -1) {
|
||||
close (fd_cwd);
|
||||
return NULL;
|
||||
}
|
||||
@@ -95,10 +96,10 @@ do_readlinklist (const char *path, char *const *names)
|
||||
|
||||
close (fd_cwd);
|
||||
|
||||
if (add_string (&ret, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
return ret.argv;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -133,11 +134,11 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
|
||||
|
||||
if (flag)
|
||||
r = command (NULL, &err,
|
||||
"ln", flag, "--", /* target could begin with '-' */
|
||||
str_ln, flag, "--", /* target could begin with '-' */
|
||||
buf_target ? : target, buf_linkname, NULL);
|
||||
else
|
||||
r = command (NULL, &err,
|
||||
"ln", "--",
|
||||
str_ln, "--",
|
||||
buf_target ? : target, buf_linkname, NULL);
|
||||
free (buf_linkname);
|
||||
free (buf_target);
|
||||
|
||||
84
daemon/ls.c
84
daemon/ls.c
@@ -25,50 +25,74 @@
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
char **
|
||||
do_ls (const char *path)
|
||||
GUESTFSD_EXT_CMD(str_ls, ls);
|
||||
|
||||
/* Has one FileOut parameter. */
|
||||
int
|
||||
do_ls0 (const char *path)
|
||||
{
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
size_t len;
|
||||
|
||||
CHROOT_IN;
|
||||
dir = opendir (path);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (!dir) {
|
||||
if (dir == NULL) {
|
||||
reply_with_perror ("opendir: %s", path);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((d = readdir (dir)) != NULL) {
|
||||
/* Now we must send the reply message, before the filenames. After
|
||||
* this there is no opportunity in the protocol to send any error
|
||||
* message back. Instead we can only cancel the transfer.
|
||||
*/
|
||||
reply (NULL, NULL);
|
||||
|
||||
while (1) {
|
||||
errno = 0;
|
||||
d = readdir (dir);
|
||||
if (d == NULL) break;
|
||||
|
||||
/* Ignore . and .. */
|
||||
if (STREQ (d->d_name, ".") || STREQ (d->d_name, ".."))
|
||||
continue;
|
||||
|
||||
if (add_string (&r, &size, &alloc, d->d_name) == -1) {
|
||||
/* Send the name in a single chunk. XXX Needs to be fixed if
|
||||
* names can be longer than the chunk size. Note we use 'len+1'
|
||||
* because we want to include the \0 terminating character in the
|
||||
* output.
|
||||
*/
|
||||
len = strlen (d->d_name);
|
||||
if (send_file_write (d->d_name, len+1) < 0) {
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1) {
|
||||
if (errno != 0) {
|
||||
perror (path);
|
||||
send_file_end (1); /* Cancel. */
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: %s", path);
|
||||
free_strings (r);
|
||||
return NULL;
|
||||
perror (path);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
sort_strings (r, size-1);
|
||||
return r;
|
||||
if (send_file_end (0)) /* Normal end of file. */
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Because we can't chroot and run the ls command (since 'ls' won't
|
||||
@@ -90,7 +114,33 @@ do_ll (const char *path)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = command (&out, &err, "ls", "-la", spath, NULL);
|
||||
r = command (&out, &err, str_ls, "-la", spath, NULL);
|
||||
free (spath);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free (err);
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
char *
|
||||
do_llz (const char *path)
|
||||
{
|
||||
int r;
|
||||
char *out, *err;
|
||||
char *spath;
|
||||
|
||||
spath = sysroot_path (path);
|
||||
if (!spath) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = command (&out, &err, str_ls, "-laZ", spath, NULL);
|
||||
free (spath);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
|
||||
@@ -28,29 +28,35 @@
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
GUESTFSD_EXT_CMD(str_cryptsetup, cryptsetup);
|
||||
|
||||
int
|
||||
optgroup_luks_available (void)
|
||||
{
|
||||
return prog_exists ("cryptsetup");
|
||||
return prog_exists (str_cryptsetup);
|
||||
}
|
||||
|
||||
/* Callers must also call remove_temp (tempfile). */
|
||||
static char *
|
||||
write_key_to_temp (const char *key)
|
||||
{
|
||||
char *tempfile = strdup ("/tmp/luksXXXXXX");
|
||||
char *tempfile;
|
||||
int fd;
|
||||
size_t len;
|
||||
|
||||
tempfile = strdup ("/tmp/luksXXXXXX");
|
||||
if (!tempfile) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fd = mkstemp (tempfile);
|
||||
fd = mkstemp (tempfile);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("mkstemp");
|
||||
goto error;
|
||||
}
|
||||
|
||||
size_t len = strlen (key);
|
||||
len = strlen (key);
|
||||
if (xwrite (fd, key, len) == -1) {
|
||||
reply_with_perror ("write");
|
||||
close (fd);
|
||||
@@ -100,7 +106,7 @@ luks_open (const char *device, const char *key, const char *mapname,
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "cryptsetup");
|
||||
ADD_ARG (argv, i, str_cryptsetup);
|
||||
ADD_ARG (argv, i, "-d");
|
||||
ADD_ARG (argv, i, tempfile);
|
||||
if (readonly) ADD_ARG (argv, i, "--readonly");
|
||||
@@ -150,7 +156,7 @@ do_luks_close (const char *device)
|
||||
const char *mapname = &device[12];
|
||||
|
||||
char *err;
|
||||
int r = command (NULL, &err, "cryptsetup", "luksClose", mapname, NULL);
|
||||
int r = command (NULL, &err, str_cryptsetup, "luksClose", mapname, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -176,7 +182,7 @@ luks_format (const char *device, const char *key, int keyslot,
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "cryptsetup");
|
||||
ADD_ARG (argv, i, str_cryptsetup);
|
||||
ADD_ARG (argv, i, "-q");
|
||||
if (cipher) {
|
||||
ADD_ARG (argv, i, "--cipher");
|
||||
@@ -238,7 +244,7 @@ do_luks_add_key (const char *device, const char *key, const char *newkey,
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "cryptsetup");
|
||||
ADD_ARG (argv, i, str_cryptsetup);
|
||||
ADD_ARG (argv, i, "-q");
|
||||
ADD_ARG (argv, i, "-d");
|
||||
ADD_ARG (argv, i, keyfile);
|
||||
@@ -277,7 +283,7 @@ do_luks_kill_slot (const char *device, const char *key, int keyslot)
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "cryptsetup");
|
||||
ADD_ARG (argv, i, str_cryptsetup);
|
||||
ADD_ARG (argv, i, "-q");
|
||||
ADD_ARG (argv, i, "-d");
|
||||
ADD_ARG (argv, i, tempfile);
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_lvm, lvm);
|
||||
GUESTFSD_EXT_CMD(str_cp, cp);
|
||||
GUESTFSD_EXT_CMD(str_rm, rm);
|
||||
|
||||
/* This runs during daemon start up and creates a complete copy of
|
||||
* /etc/lvm so that we can modify it as we desire. We set
|
||||
* LVM_SYSTEM_DIR to point to the copy.
|
||||
@@ -65,7 +69,7 @@ copy_lvm (void)
|
||||
}
|
||||
|
||||
/* Hopefully no dotfiles in there ... XXX */
|
||||
snprintf (cmd, sizeof cmd, "cp -a /etc/lvm/* %s", lvm_system_dir);
|
||||
snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/* %s", str_cp, lvm_system_dir);
|
||||
r = system (cmd);
|
||||
if (r == -1) {
|
||||
perror (cmd);
|
||||
@@ -92,7 +96,7 @@ rm_lvm_system_dir (void)
|
||||
{
|
||||
char cmd[64];
|
||||
|
||||
snprintf (cmd, sizeof cmd, "rm -rf %s", lvm_system_dir);
|
||||
snprintf (cmd, sizeof cmd, "%s -rf %s", str_rm, lvm_system_dir);
|
||||
ignore_value (system (cmd));
|
||||
}
|
||||
|
||||
@@ -189,7 +193,7 @@ static int
|
||||
vgchange (const char *vgchange_flag)
|
||||
{
|
||||
char *err;
|
||||
int r = command (NULL, &err, "lvm", "vgchange", vgchange_flag, NULL);
|
||||
int r = command (NULL, &err, str_lvm, "vgchange", vgchange_flag, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgchange: %s", err);
|
||||
free (err);
|
||||
@@ -224,7 +228,7 @@ rescan (void)
|
||||
unlink (lvm_cache);
|
||||
|
||||
char *err;
|
||||
int r = command (NULL, &err, "lvm", "vgscan", NULL);
|
||||
int r = command (NULL, &err, str_lvm, "vgscan", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgscan: %s", err);
|
||||
free (err);
|
||||
@@ -245,7 +249,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 +259,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);
|
||||
|
||||
291
daemon/lvm.c
291
daemon/lvm.c
@@ -23,6 +23,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
@@ -31,10 +32,12 @@
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_lvm, lvm);
|
||||
|
||||
int
|
||||
optgroup_lvm2_available (void)
|
||||
{
|
||||
return prog_exists ("lvm");
|
||||
return prog_exists (str_lvm);
|
||||
}
|
||||
|
||||
/* LVM actions. Keep an eye on liblvm, although at the time
|
||||
@@ -45,9 +48,8 @@ static char **
|
||||
convert_lvm_output (char *out, const char *prefix)
|
||||
{
|
||||
char *p, *pend;
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
int len;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
size_t len;
|
||||
char buf[256];
|
||||
char *str;
|
||||
|
||||
@@ -79,7 +81,7 @@ convert_lvm_output (char *out, const char *prefix)
|
||||
} else
|
||||
str = p;
|
||||
|
||||
if (add_string (&r, &size, &alloc, str) == -1) {
|
||||
if (add_string (&ret, str) == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
@@ -89,11 +91,13 @@ convert_lvm_output (char *out, const char *prefix)
|
||||
|
||||
free (out);
|
||||
|
||||
if (add_string (&r, &size, &alloc, NULL) == -1)
|
||||
if (ret.size > 0)
|
||||
sort_strings (ret.argv, ret.size);
|
||||
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
sort_strings (r, size-1);
|
||||
return r;
|
||||
return ret.argv;
|
||||
}
|
||||
|
||||
char **
|
||||
@@ -103,7 +107,7 @@ do_pvs (void)
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
"lvm", "pvs", "-o", "pv_name", "--noheadings", NULL);
|
||||
str_lvm, "pvs", "-o", "pv_name", "--noheadings", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
@@ -123,7 +127,7 @@ do_vgs (void)
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
"lvm", "vgs", "-o", "vg_name", "--noheadings", NULL);
|
||||
str_lvm, "vgs", "-o", "vg_name", "--noheadings", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
@@ -143,7 +147,7 @@ do_lvs (void)
|
||||
int r;
|
||||
|
||||
r = command (&out, &err,
|
||||
"lvm", "lvs",
|
||||
str_lvm, "lvs",
|
||||
"-o", "vg_name,lv_name", "--noheadings",
|
||||
"--separator", "/", NULL);
|
||||
if (r == -1) {
|
||||
@@ -187,7 +191,7 @@ do_pvcreate (const char *device)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "pvcreate", device, NULL);
|
||||
str_lvm, "pvcreate", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -214,7 +218,7 @@ do_vgcreate (const char *volgroup, char *const *physvols)
|
||||
reply_with_perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
argv[0] = "lvm";
|
||||
argv[0] = str_lvm;
|
||||
argv[1] = "vgcreate";
|
||||
argv[2] = volgroup;
|
||||
for (i = 3; i <= argc; ++i)
|
||||
@@ -246,7 +250,7 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
|
||||
snprintf (size, sizeof size, "%d", mbytes);
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "lvcreate",
|
||||
str_lvm, "lvcreate",
|
||||
"-L", size, "-n", logvol, volgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -261,6 +265,36 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_lvcreate_free (const char *logvol, const char *volgroup, int percent)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
if (percent < 0 || percent > 100) {
|
||||
reply_with_error ("percentage must be [0..100] (was %d)", percent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char size[64];
|
||||
snprintf (size, sizeof size, "%d%%FREE", percent);
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "lvcreate",
|
||||
"-l", size, "-n", logvol, volgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_lvresize (const char *logvol, int mbytes)
|
||||
{
|
||||
@@ -271,7 +305,7 @@ do_lvresize (const char *logvol, int mbytes)
|
||||
snprintf (size, sizeof size, "%d", mbytes);
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "lvresize",
|
||||
str_lvm, "lvresize",
|
||||
"--force", "-L", size, logvol, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -298,7 +332,7 @@ do_lvresize_free (const char *logvol, int percent)
|
||||
snprintf (size, sizeof size, "+%d%%FREE", percent);
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "lvresize", "-l", size, logvol, NULL);
|
||||
str_lvm, "lvresize", "-l", size, logvol, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -316,7 +350,8 @@ int
|
||||
do_lvm_remove_all (void)
|
||||
{
|
||||
char **xs;
|
||||
int i, r;
|
||||
size_t i;
|
||||
int r;
|
||||
char *err;
|
||||
|
||||
/* Remove LVs. */
|
||||
@@ -328,10 +363,10 @@ do_lvm_remove_all (void)
|
||||
/* Deactivate the LV first. On Ubuntu, lvremove '-f' option
|
||||
* does not remove active LVs reliably.
|
||||
*/
|
||||
(void) command (NULL, NULL, "lvm", "lvchange", "-an", xs[i], NULL);
|
||||
(void) command (NULL, NULL, str_lvm, "lvchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, "lvm", "lvremove", "-f", xs[i], NULL);
|
||||
r = command (NULL, &err, str_lvm, "lvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("lvremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
@@ -349,10 +384,10 @@ do_lvm_remove_all (void)
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
/* Deactivate the VG first, see note above. */
|
||||
(void) command (NULL, NULL, "lvm", "vgchange", "-an", xs[i], NULL);
|
||||
(void) command (NULL, NULL, str_lvm, "vgchange", "-an", xs[i], NULL);
|
||||
udev_settle ();
|
||||
|
||||
r = command (NULL, &err, "lvm", "vgremove", "-f", xs[i], NULL);
|
||||
r = command (NULL, &err, str_lvm, "vgremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
@@ -369,7 +404,7 @@ do_lvm_remove_all (void)
|
||||
return -1;
|
||||
|
||||
for (i = 0; xs[i] != NULL; ++i) {
|
||||
r = command (NULL, &err, "lvm", "pvremove", "-f", xs[i], NULL);
|
||||
r = command (NULL, &err, str_lvm, "pvremove", "-f", xs[i], NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("pvremove: %s: %s", xs[i], err);
|
||||
free (err);
|
||||
@@ -393,7 +428,7 @@ do_lvremove (const char *device)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "lvremove", "-f", device, NULL);
|
||||
str_lvm, "lvremove", "-f", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -414,7 +449,7 @@ do_vgremove (const char *device)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "vgremove", "-f", device, NULL);
|
||||
str_lvm, "vgremove", "-f", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -435,7 +470,7 @@ do_pvremove (const char *device)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "pvremove", "-ff", device, NULL);
|
||||
str_lvm, "pvremove", "-ff", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -456,7 +491,7 @@ do_pvresize (const char *device)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "pvresize", device, NULL);
|
||||
str_lvm, "pvresize", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
@@ -477,7 +512,7 @@ do_pvresize_size (const char *device, int64_t size)
|
||||
snprintf (buf, sizeof buf, "%" PRIi64 "b", size);
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "pvresize",
|
||||
str_lvm, "pvresize",
|
||||
"--setphysicalvolumesize", buf,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
@@ -504,7 +539,7 @@ do_vg_activate (int activate, char *const *volgroups)
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[0] = "lvm";
|
||||
argv[0] = str_lvm;
|
||||
argv[1] = "vgchange";
|
||||
argv[2] = "-a";
|
||||
argv[3] = activate ? "y" : "n";
|
||||
@@ -541,7 +576,7 @@ do_lvrename (const char *logvol, const char *newlogvol)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "lvrename",
|
||||
str_lvm, "lvrename",
|
||||
logvol, newlogvol, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s -> %s: %s", logvol, newlogvol, err);
|
||||
@@ -563,7 +598,7 @@ do_vgrename (const char *volgroup, const char *newvolgroup)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "vgrename",
|
||||
str_lvm, "vgrename",
|
||||
volgroup, newvolgroup, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s -> %s: %s", volgroup, newvolgroup, err);
|
||||
@@ -584,7 +619,7 @@ get_lvm_field (const char *cmd, const char *field, const char *device)
|
||||
char *out;
|
||||
char *err;
|
||||
int r = command (&out, &err,
|
||||
"lvm", cmd,
|
||||
str_lvm, cmd,
|
||||
"--unbuffered", "--noheadings", "-o", field,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
@@ -624,7 +659,7 @@ get_lvm_fields (const char *cmd, const char *field, const char *device)
|
||||
char *out;
|
||||
char *err;
|
||||
int r = command (&out, &err,
|
||||
"lvm", cmd,
|
||||
str_lvm, cmd,
|
||||
"--unbuffered", "--noheadings", "-o", field,
|
||||
device, NULL);
|
||||
if (r == -1) {
|
||||
@@ -668,7 +703,7 @@ do_vgscan (void)
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
"lvm", "vgscan", NULL);
|
||||
str_lvm, "vgscan", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
@@ -769,8 +804,7 @@ do_lvm_canonical_lv_name (const char *device)
|
||||
char **
|
||||
do_list_dm_devices (void)
|
||||
{
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
struct dirent *d;
|
||||
DIR *dir;
|
||||
int r;
|
||||
@@ -802,7 +836,7 @@ do_list_dm_devices (void)
|
||||
/* Ignore dm devices which are LVs. */
|
||||
r = lv_canonical (devname, NULL);
|
||||
if (r == -1) {
|
||||
free_stringslen (ret, size);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
@@ -810,7 +844,7 @@ do_list_dm_devices (void)
|
||||
continue;
|
||||
|
||||
/* Not an LV, so add it. */
|
||||
if (add_string (&ret, &size, &alloc, devname) == -1) {
|
||||
if (add_string (&ret, devname) == -1) {
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
@@ -819,7 +853,7 @@ do_list_dm_devices (void)
|
||||
/* Did readdir fail? */
|
||||
if (errno != 0) {
|
||||
reply_with_perror ("readdir: /dev/mapper");
|
||||
free_stringslen (ret, size);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
closedir (dir);
|
||||
return NULL;
|
||||
}
|
||||
@@ -827,17 +861,188 @@ do_list_dm_devices (void)
|
||||
/* Close the directory handle. */
|
||||
if (closedir (dir) == -1) {
|
||||
reply_with_perror ("closedir: /dev/mapper");
|
||||
free_stringslen (ret, size);
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sort the output (may be empty). */
|
||||
if (ret != NULL)
|
||||
sort_strings (ret, size);
|
||||
if (ret.size > 0)
|
||||
sort_strings (ret.argv, ret.size);
|
||||
|
||||
/* NULL-terminate the list. */
|
||||
if (add_string (&ret, &size, &alloc, NULL) == -1)
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
return ret.argv;
|
||||
}
|
||||
|
||||
char *
|
||||
do_vgmeta (const char *vg, size_t *size_r)
|
||||
{
|
||||
char *err;
|
||||
int fd, r;
|
||||
char tmp[] = "/tmp/vgmetaXXXXXX";
|
||||
size_t alloc, size, max;
|
||||
ssize_t rs;
|
||||
char *buf, *buf2;
|
||||
|
||||
/* Make a temporary file. */
|
||||
fd = mkstemp (tmp);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("mkstemp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
r = command (NULL, &err, str_lvm, "vgcfgbackup", "-f", tmp, vg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("vgcfgbackup: %s", err);
|
||||
free (err);
|
||||
return NULL;
|
||||
}
|
||||
free (err);
|
||||
|
||||
/* Now read back the temporary file. */
|
||||
fd = open (tmp, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
reply_with_error ("%s", tmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read up to GUESTFS_MESSAGE_MAX - <overhead> bytes. If it's
|
||||
* larger than that, we need to return an error instead (for
|
||||
* correctness).
|
||||
*/
|
||||
max = GUESTFS_MESSAGE_MAX - 1000;
|
||||
buf = NULL;
|
||||
size = alloc = 0;
|
||||
|
||||
for (;;) {
|
||||
if (size >= alloc) {
|
||||
alloc += 8192;
|
||||
if (alloc > max) {
|
||||
reply_with_error ("metadata is too large for message buffer");
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
buf2 = realloc (buf, alloc);
|
||||
if (buf2 == NULL) {
|
||||
reply_with_perror ("realloc");
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
rs = read (fd, buf + size, alloc - size);
|
||||
if (rs == -1) {
|
||||
reply_with_perror ("read: %s", tmp);
|
||||
free (buf);
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
if (rs == 0)
|
||||
break;
|
||||
if (rs > 0)
|
||||
size += rs;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close: %s", tmp);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unlink (tmp);
|
||||
|
||||
*size_r = size;
|
||||
|
||||
return buf; /* caller will free */
|
||||
}
|
||||
|
||||
int
|
||||
do_pvchange_uuid (const char *device)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvchange", "-u", device, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", device, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_pvchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "pvchange", "-u", "-a", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_vgchange_uuid (const char *vg)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgchange", "-u", vg, NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s: %s", vg, err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_vgchange_uuid_all (void)
|
||||
{
|
||||
char *err;
|
||||
int r;
|
||||
|
||||
r = command (NULL, &err,
|
||||
str_lvm, "vgchange", "-u", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
247
daemon/md.c
247
daemon/md.c
@@ -29,10 +29,12 @@
|
||||
#include "optgroups.h"
|
||||
#include "c-ctype.h"
|
||||
|
||||
GUESTFSD_EXT_CMD(str_mdadm, mdadm);
|
||||
|
||||
int
|
||||
optgroup_mdadm_available (void)
|
||||
{
|
||||
return prog_exists ("mdadm");
|
||||
return prog_exists (str_mdadm);
|
||||
}
|
||||
|
||||
static size_t
|
||||
@@ -121,7 +123,7 @@ do_md_create (const char *name, char *const *devices,
|
||||
const char *argv[MAX_ARGS];
|
||||
size_t i = 0;
|
||||
|
||||
ADD_ARG (argv, i, "mdadm");
|
||||
ADD_ARG (argv, i, str_mdadm);
|
||||
ADD_ARG (argv, i, "--create");
|
||||
/* --run suppresses "Continue creating array" question */
|
||||
ADD_ARG (argv, i, "--run");
|
||||
@@ -180,8 +182,7 @@ glob_errfunc (const char *epath, int eerrno)
|
||||
char **
|
||||
do_list_md_devices (void)
|
||||
{
|
||||
char **r = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
glob_t mds;
|
||||
|
||||
memset(&mds, 0, sizeof(mds));
|
||||
@@ -218,44 +219,44 @@ do_list_md_devices (void)
|
||||
n = mempcpy(n, &mds.gl_pathv[i][strlen(PREFIX)], len);
|
||||
*n = '\0';
|
||||
|
||||
if (add_string_nodup (&r, &size, &alloc, dev) == -1) goto error;
|
||||
if (add_string_nodup (&ret, dev) == -1) goto error;
|
||||
}
|
||||
|
||||
if (add_string_nodup (&r, &size, &alloc, NULL) == -1) goto error;
|
||||
if (end_stringsbuf (&ret) == -1) goto error;
|
||||
globfree (&mds);
|
||||
|
||||
return r;
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
globfree (&mds);
|
||||
if (r != NULL) free_strings (r);
|
||||
if (ret.argv != NULL)
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **
|
||||
do_md_detail(const char *md)
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
char *out = NULL, *err = NULL;
|
||||
char **lines = NULL;
|
||||
|
||||
char **ret = NULL;
|
||||
int size = 0, alloc = 0;
|
||||
DECLARE_STRINGSBUF (ret);
|
||||
|
||||
const char *mdadm[] = { "mdadm", "-D", "--export", md, NULL };
|
||||
r = commandv(&out, &err, mdadm);
|
||||
const char *mdadm[] = { str_mdadm, "-D", "--export", md, NULL };
|
||||
r = commandv (&out, &err, mdadm);
|
||||
if (r == -1) {
|
||||
reply_with_error("%s", err);
|
||||
reply_with_error ("%s", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Split the command output into lines */
|
||||
lines = split_lines(out);
|
||||
if (lines == NULL) {
|
||||
reply_with_perror("malloc");
|
||||
lines = split_lines (out);
|
||||
if (lines == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Parse the output of mdadm -D --export:
|
||||
* MD_LEVEL=raid1
|
||||
@@ -264,49 +265,52 @@ do_md_detail(const char *md)
|
||||
* MD_UUID=cfa81b59:b6cfbd53:3f02085b:58f4a2e1
|
||||
* MD_NAME=localhost.localdomain:0
|
||||
*/
|
||||
for (char **i = lines; *i != NULL; i++) {
|
||||
char *line = *i;
|
||||
for (i = 0; lines[i] != NULL; ++i) {
|
||||
char *line = lines[i];
|
||||
|
||||
/* Skip blank lines (shouldn't happen) */
|
||||
if (line[0] == '\0') continue;
|
||||
|
||||
/* Split the line in 2 at the equals sign */
|
||||
char *eq = strchr(line, '=');
|
||||
char *eq = strchr (line, '=');
|
||||
if (eq) {
|
||||
*eq = '\0'; eq++;
|
||||
|
||||
/* Remove the MD_ prefix from the key and translate the remainder to lower
|
||||
* case */
|
||||
if (STRPREFIX(line, "MD_")) {
|
||||
if (STRPREFIX (line, "MD_")) {
|
||||
line += 3;
|
||||
for (char *j = line; *j != '\0'; j++) {
|
||||
*j = c_tolower(*j);
|
||||
*j = c_tolower (*j);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the key/value pair to the output */
|
||||
if (add_string(&ret, &size, &alloc, line) == -1 ||
|
||||
add_string(&ret, &size, &alloc, eq) == -1) goto error;
|
||||
if (add_string (&ret, line) == -1 ||
|
||||
add_string (&ret, eq) == -1) goto error;
|
||||
} else {
|
||||
/* Ignore lines with no equals sign (shouldn't happen). Log to stderr so
|
||||
* it will show up in LIBGUESTFS_DEBUG. */
|
||||
fprintf(stderr, "md-detail: unexpected mdadm output ignored: %s", line);
|
||||
fprintf (stderr, "md-detail: unexpected mdadm output ignored: %s", line);
|
||||
}
|
||||
}
|
||||
|
||||
free(out);
|
||||
free(err);
|
||||
free(lines); /* We freed the contained strings when we freed out */
|
||||
free (out);
|
||||
free (err);
|
||||
free_strings (lines);
|
||||
|
||||
if (add_string(&ret, &size, &alloc, NULL) == -1) return NULL;
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
return ret.argv;
|
||||
|
||||
error:
|
||||
free(out);
|
||||
free(err);
|
||||
if (lines) free(lines);
|
||||
if (ret) free_strings(ret);
|
||||
free (out);
|
||||
free (err);
|
||||
if (lines)
|
||||
free_strings (lines);
|
||||
if (ret.argv != NULL)
|
||||
free_stringslen (ret.argv, ret.size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -317,12 +321,185 @@ do_md_stop(const char *md)
|
||||
int r;
|
||||
char *err = NULL;
|
||||
|
||||
const char *mdadm[] = { "mdadm", "--stop", md, NULL};
|
||||
const char *mdadm[] = { str_mdadm, "--stop", md, NULL};
|
||||
r = commandv(NULL, &err, mdadm);
|
||||
if (r == -1) {
|
||||
reply_with_error("%s", err);
|
||||
free(err);
|
||||
return -1;
|
||||
}
|
||||
free (err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_spaces (const char *line)
|
||||
{
|
||||
size_t r = 0;
|
||||
while (*line) {
|
||||
if (*line == ' ')
|
||||
r++;
|
||||
line++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Parse a line like: "active raid1 sdb1[0] sdc1[1](F)" */
|
||||
static guestfs_int_mdstat_list *
|
||||
parse_md_stat_line (char *line)
|
||||
{
|
||||
guestfs_int_mdstat_list *ret;
|
||||
guestfs_int_mdstat *t;
|
||||
size_t spaces, n, i, len;
|
||||
char *next;
|
||||
char *p, *q;
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (!ret) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We don't know exactly how many entries we will need yet, but we
|
||||
* can estimate it, and this will always be an over-estimate.
|
||||
*/
|
||||
spaces = count_spaces (line);
|
||||
ret->guestfs_int_mdstat_list_val =
|
||||
calloc (spaces+1, sizeof (struct guestfs_int_mdstat));
|
||||
if (ret->guestfs_int_mdstat_list_val == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (n = 0; *line; line = next) {
|
||||
len = strcspn (line, " ");
|
||||
if (line[len] == '\0')
|
||||
next = &line[len];
|
||||
else {
|
||||
line[len] = '\0';
|
||||
next = &line[len+1];
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf ("mdstat: %s\n", line);
|
||||
|
||||
/* Looking for entries that contain "[..]", skip ones which don't. */
|
||||
p = strchr (line, '[');
|
||||
if (p == NULL)
|
||||
continue;
|
||||
q = strchr (line, ']');
|
||||
if (q == NULL)
|
||||
continue;
|
||||
if (p > q)
|
||||
continue;
|
||||
|
||||
ret->guestfs_int_mdstat_list_len = n+1;
|
||||
t = &ret->guestfs_int_mdstat_list_val[n];
|
||||
|
||||
/* Device name is everything before the '[' character, but we
|
||||
* need to prefix with /dev/.
|
||||
*/
|
||||
if (p == line) {
|
||||
reply_with_error ("device entry is too short: %s", line);
|
||||
goto error;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
if (asprintf (&t->mdstat_device, "/dev/%s", line) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Device index is the number after '['. */
|
||||
line = p+1;
|
||||
*q = '\0';
|
||||
if (sscanf (line, "%" SCNi32, &t->mdstat_index) != 1) {
|
||||
reply_with_error ("not a device number: %s", line);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Looking for flags "(F)(S)...". */
|
||||
line = q+1;
|
||||
len = strlen (line);
|
||||
t->mdstat_flags = malloc (len+1);
|
||||
if (!t->mdstat_flags) {
|
||||
reply_with_error ("malloc");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; *line; line++) {
|
||||
if (c_isalpha (*line))
|
||||
t->mdstat_flags[i++] = *line;
|
||||
}
|
||||
t->mdstat_flags[i] = '\0';
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
for (i = 0; i <= spaces; ++i) {
|
||||
free (ret->guestfs_int_mdstat_list_val[i].mdstat_device);
|
||||
free (ret->guestfs_int_mdstat_list_val[i].mdstat_flags);
|
||||
}
|
||||
free (ret->guestfs_int_mdstat_list_val);
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern guestfs_int_mdstat_list *
|
||||
do_md_stat (const char *md)
|
||||
{
|
||||
size_t mdlen;
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
guestfs_int_mdstat_list *ret = NULL;
|
||||
|
||||
if (STRPREFIX (md, "/dev/"))
|
||||
md += 5;
|
||||
mdlen = strlen (md);
|
||||
|
||||
fp = fopen ("/proc/mdstat", "r");
|
||||
if (fp == NULL) {
|
||||
reply_with_perror ("fopen: %s", "/proc/mdstat");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for a line which begins with "<md> : ". */
|
||||
while ((n = getline (&line, &len, fp)) != -1) {
|
||||
if (STRPREFIX (line, md) &&
|
||||
line[mdlen] == ' ' && line[mdlen+1] == ':' && line[mdlen+2] == ' ') {
|
||||
/* Found it. */
|
||||
ret = parse_md_stat_line (&line[mdlen+3]);
|
||||
if (!ret) {
|
||||
free (line);
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Stop parsing the mdstat file after we've found the line
|
||||
* we are interested in.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (line);
|
||||
|
||||
if (fclose (fp) == EOF) {
|
||||
reply_with_perror ("fclose: %s", "/proc/mdstat");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Did we find the line? */
|
||||
if (!ret) {
|
||||
reply_with_error ("%s: MD device not found", md);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "daemon.h"
|
||||
@@ -31,10 +30,13 @@
|
||||
|
||||
#define MAX_ARGS 64
|
||||
|
||||
GUESTFSD_EXT_CMD(str_mke2fs, mke2fs);
|
||||
GUESTFSD_EXT_CMD(str_mkfs, mkfs);
|
||||
|
||||
/* 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;
|
||||
@@ -43,7 +45,6 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
char sectorsize_str[32];
|
||||
int r;
|
||||
char *err;
|
||||
char mke2fs[] = "mke2fs";
|
||||
int extfs = 0;
|
||||
|
||||
if (STREQ (fstype, "ext2") || STREQ (fstype, "ext3") ||
|
||||
@@ -54,13 +55,10 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
* the mkfs program "eats" some options, in particular the -F
|
||||
* option.
|
||||
*/
|
||||
if (extfs) {
|
||||
if (e2prog (mke2fs) == -1)
|
||||
return -1;
|
||||
ADD_ARG (argv, i, mke2fs);
|
||||
}
|
||||
if (extfs)
|
||||
ADD_ARG (argv, i, str_mke2fs);
|
||||
else
|
||||
ADD_ARG (argv, i, "mkfs");
|
||||
ADD_ARG (argv, i, str_mkfs);
|
||||
|
||||
ADD_ARG (argv, i, "-t");
|
||||
ADD_ARG (argv, i, fstype);
|
||||
@@ -100,7 +98,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;
|
||||
@@ -133,6 +131,11 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize,
|
||||
ADD_ARG (argv, i, "-c");
|
||||
ADD_ARG (argv, i, blocksize_str);
|
||||
}
|
||||
else if (STREQ (fstype, "btrfs")) {
|
||||
/* For btrfs, blocksize cannot be specified (RHBZ#807905). */
|
||||
reply_with_error ("blocksize cannot be set on btrfs filesystems, use 'mkfs-btrfs'");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
/* For all other filesystem types, try the -b option. */
|
||||
snprintf (blocksize_str, sizeof blocksize_str, "%d", blocksize);
|
||||
@@ -141,12 +144,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;
|
||||
@@ -162,7 +165,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;
|
||||
@@ -192,16 +195,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);
|
||||
}
|
||||
|
||||
@@ -37,18 +37,10 @@ optgroup_mknod_available (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int
|
||||
optgroup_mknod_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
do_mknod (int mode, int devmajor, int devminor, const char *path)
|
||||
{
|
||||
#ifdef HAVE_MKNOD
|
||||
int r;
|
||||
|
||||
if (mode < 0) {
|
||||
@@ -66,9 +58,6 @@ do_mknod (int mode, int devmajor, int devminor, const char *path)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
NOT_AVAILABLE (-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@@ -88,3 +77,37 @@ do_mknod_c (int mode, int devmajor, int devminor, const char *path)
|
||||
{
|
||||
return do_mknod (mode | S_IFCHR, devmajor, devminor, path);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
optgroup_mknod_available (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_mknod (int mode, int devmajor, int devminor, const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
do_mkfifo (int mode, const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
do_mknod_b (int mode, int devmajor, int devminor, const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
do_mknod_c (int mode, int devmajor, int devminor, const char *path)
|
||||
{
|
||||
abort ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
97
daemon/mktemp.c
Normal file
97
daemon/mktemp.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2012 FUJITSU LTD.
|
||||
* Copyright (C) 2009 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
char *
|
||||
do_mkdtemp (const char *template)
|
||||
{
|
||||
char *writable = strdup (template);
|
||||
if (writable == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
char *r = mkdtemp (writable);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == NULL) {
|
||||
reply_with_perror ("%s", template);
|
||||
free (writable);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *
|
||||
do_mktemp (const char *template,
|
||||
const char *suffix)
|
||||
{
|
||||
char *dest_name = NULL;
|
||||
size_t suffix_len = 0;
|
||||
int fd;
|
||||
size_t len;
|
||||
|
||||
if (optargs_bitmask & GUESTFS_MKTEMP_SUFFIX_BITMASK) {
|
||||
if (suffix) {
|
||||
len = strlen (template);
|
||||
if (len == 0 || template[len - 1] != 'X') {
|
||||
reply_with_error ("template %s must end in X", template);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append suffix to template. */
|
||||
suffix_len = strlen (suffix);
|
||||
if (asprintf (&dest_name, "%s%s", template, suffix) == -1) {
|
||||
reply_with_perror ("asprintf");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_name == NULL) {
|
||||
dest_name = strdup (template);
|
||||
if (dest_name == NULL) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CHROOT_IN;
|
||||
fd = mkstemps (dest_name, (int) suffix_len);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("%s", dest_name);
|
||||
free (dest_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
return dest_name;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user