mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-27 11:33:19 +03:00 
			
		
		
		
	Compare commits
	
		
			3056 Commits
		
	
	
		
			dev-dct-fi
			...
			v2_02_43
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9fbe96fd7c | ||
|  | 98cd400443 | ||
|  | 873e699f6d | ||
|  | 9a8f6c824f | ||
|  | a98888ad07 | ||
|  | db98500b72 | ||
|  | 3feee09cfe | ||
|  | 4a1cd0d391 | ||
|  | edb5071d3b | ||
|  | e9509aa5e6 | ||
|  | 5e6ca1b72d | ||
|  | 543bf2ffbd | ||
|  | 15a7a4c38b | ||
|  | 640d07bf35 | ||
|  | e5ecc2b942 | ||
|  | cfd8fe40f4 | ||
|  | abba6e0642 | ||
|  | ec94fb89a2 | ||
|  | bb167efa7b | ||
|  | 2a550ef96d | ||
|  | 03ed7d73fc | ||
|  | 446852db3b | ||
|  | 7c90b57e87 | ||
|  | 6339e2588b | ||
|  | af6687405b | ||
|  | a2bfad1c29 | ||
|  | 645aa55abc | ||
|  | 05329c885a | ||
|  | b3fed93a74 | ||
|  | 2c6fad0ea7 | ||
|  | 57854c2231 | ||
|  | a8cf4293e0 | ||
|  | ba70dce803 | ||
|  | 5b4c3ace56 | ||
|  | 2ade7a15e2 | ||
|  | e83f71d678 | ||
|  | 412c91cb6b | ||
|  | aa44167319 | ||
|  | dd5700e8b3 | ||
|  | ef7fc430d7 | ||
|  | f1bcb6c634 | ||
|  | 4a4eb17d08 | ||
|  | 8afc267c68 | ||
|  | 6457ab31b6 | ||
|  | 306dfa2043 | ||
|  | 424bdade0b | ||
|  | 10857e3321 | ||
|  | 85a4e47879 | ||
|  | 759e49f025 | ||
|  | 43924e31b8 | ||
|  | 3b34fcf59f | ||
|  | ba7253eaf7 | ||
|  | be23682a30 | ||
|  | 3a5dce4c92 | ||
|  | 22d7e60d0e | ||
|  | 5752156c9e | ||
|  | a30215a530 | ||
|  | f9c8c1b964 | ||
|  | 5650f67ef5 | ||
|  | 5ec25dfb94 | ||
|  | ef16682725 | ||
|  | 883486cc67 | ||
|  | f367f9b747 | ||
|  | a3d987fa73 | ||
|  | 2d48685673 | ||
|  | 9b21ace1e9 | ||
|  | be2c03fa96 | ||
|  | f5585e9252 | ||
|  | 4d534dd7e4 | ||
|  | c8584e1cce | ||
|  | 84a1de464c | ||
|  | 3966f3d319 | ||
|  | e6166cf711 | ||
|  | 2285712834 | ||
|  | 53cb6128e8 | ||
|  | 8c317baf19 | ||
|  | 8cac933c71 | ||
|  | 03e61a4bf8 | ||
|  | 71446a76b2 | ||
|  | 28db8d6c7c | ||
|  | 786e33d7d5 | ||
|  | b140d6c50e | ||
|  | 64a95abdee | ||
|  | 57f926be17 | ||
|  | 4933b67959 | ||
|  | 370b4f1b9e | ||
|  | f3b7baa84e | ||
|  | eafdb2c807 | ||
|  | a91fa821ab | ||
|  | 37ef162cda | ||
|  | 770928acfc | ||
|  | d0f3570219 | ||
|  | 3d07c2605f | ||
|  | c350798528 | ||
|  | 6bc3cc0bec | ||
|  | 2e3e5fcc81 | ||
|  | dfdb10f6de | ||
|  | 5cbe5909eb | ||
|  | 04d52b450b | ||
|  | a586a89547 | ||
|  | 1905eacf15 | ||
|  | 858ec0d740 | ||
|  | 76cfd406ca | ||
|  | 9dbaad859d | ||
|  | 95d43e17b3 | ||
|  | 09a2dff8de | ||
|  | 57208f879a | ||
|  | 149638431d | ||
|  | 30d2940c67 | ||
|  | 5ee86fc5d0 | ||
|  | a03d0e2c3f | ||
|  | 8bd367d58d | ||
|  | bc633e03aa | ||
|  | 797d0f1ef1 | ||
|  | 1be3e86aa0 | ||
|  | e56dd38021 | ||
|  | 410904bef1 | ||
|  | 026cc120e7 | ||
|  | ef2fda05cf | ||
|  | 92277e3ae2 | ||
|  | fbc34d70b0 | ||
|  | 91dcddbdf7 | ||
|  | 874f42ad6c | ||
|  | 1989ef4ebc | ||
|  | 4f4c72c065 | ||
|  | 666cc72661 | ||
|  | 4524e8f5c9 | ||
|  | bd07a29886 | ||
|  | a0d865492e | ||
|  | de27790de8 | ||
|  | 9c910b7be2 | ||
|  | 7f23ab94e2 | ||
|  | 77dc036c8f | ||
|  | aa6e8d82ce | ||
|  | 3010285bb3 | ||
|  | aaad3252f8 | ||
|  | 9065f534d8 | ||
|  | 52361c94e5 | ||
|  | 798be60fef | ||
|  | 6294154b15 | ||
|  | 6594fe077d | ||
|  | 582706cde6 | ||
|  | 6537cbdc17 | ||
|  | 53959459bb | ||
|  | 22d6121099 | ||
|  | 48d7f6f2f4 | ||
|  | 9fd4ddc490 | ||
|  | a4d2fddbb2 | ||
|  | c54a3f2721 | ||
|  | 04c0dba697 | ||
|  | 5406e3b7c5 | ||
|  | 6b624b7d00 | ||
|  | 2d364d4d80 | ||
|  | 1f27bf3774 | ||
|  | d30a2653b5 | ||
|  | 3086822cd2 | ||
|  | 2c08336490 | ||
|  | 5936ac58c2 | ||
|  | ded77e3f5c | ||
|  | 8a29df0a6c | ||
|  | 9db22babaf | ||
|  | c318c5ed61 | ||
|  | 61243c65cd | ||
|  | 4a5d5cb462 | ||
|  | cbf1447ebd | ||
|  | 30104441bf | ||
|  | b4a70804f0 | ||
|  | 74f6707bde | ||
|  | 223eb8c84d | ||
|  | 107d000606 | ||
|  | 43e05607af | ||
|  | 55793452d5 | ||
|  | 686ba37255 | ||
|  | 03ed19dad5 | ||
|  | ad2b6e5de1 | ||
|  | 767676d6ff | ||
|  | bc7a54c615 | ||
|  | 1bda393678 | ||
|  | bb5495c6bd | ||
|  | 484f905749 | ||
|  | e0d61a4336 | ||
|  | e643a16ba5 | ||
|  | 98fadec2b6 | ||
|  | 14f464ecb0 | ||
|  | 2ecdaf9bd4 | ||
|  | 707c898f66 | ||
|  | 69e4400774 | ||
|  | 695efde68d | ||
|  | 0c4b769011 | ||
|  | e53eff0634 | ||
|  | 6c75243a06 | ||
|  | efde37880b | ||
|  | 7d8f6381be | ||
|  | 3c361e3393 | ||
|  | 8440ecef5e | ||
|  | 6401f1b1c9 | ||
|  | 7487a7c988 | ||
|  | f44584fa10 | ||
|  | 7b32165614 | ||
|  | b0dc94d187 | ||
|  | 0383c4e1d8 | ||
|  | a8c5758222 | ||
|  | a7fabfd8cb | ||
|  | 5d5b575d16 | ||
|  | ac1373653c | ||
|  | b097aa787b | ||
|  | 723be0fe69 | ||
|  | f0597a03de | ||
|  | 65f0656f54 | ||
|  | 507ece15a5 | ||
|  | 30be4d1613 | ||
|  | 366e89bda0 | ||
|  | f159c3f768 | ||
|  | 8506d1d567 | ||
|  | 111829da46 | ||
|  | 605798073e | ||
|  | 8320f2b094 | ||
|  | df0d8d809b | ||
|  | 062886df64 | ||
|  | 148ea3aaa8 | ||
|  | ab5f66c13a | ||
|  | e65ffb8e68 | ||
|  | 949c1ab517 | ||
|  | 946d8ee046 | ||
|  | c54a8a2e10 | ||
|  | 31177e4f85 | ||
|  | 750f81b4b5 | ||
|  | 987ff02a45 | ||
|  | f5adaf813c | ||
|  | 78ff7dc7f0 | ||
|  | d1fced3324 | ||
|  | e7df9c289b | ||
|  | a78d7231a9 | ||
|  | ba7ae0002e | ||
|  | a090f7b839 | ||
|  | 34ed15a987 | ||
|  | cacec4c910 | ||
|  | 3e47d4e65b | ||
|  | 8b42fa150b | ||
|  | 60e660b9c7 | ||
|  | fe74f013e3 | ||
|  | 24c0c70f90 | ||
|  | 757f91ca89 | ||
|  | 5c34f7847e | ||
|  | de456f014e | ||
|  | d29565066d | ||
|  | 4d52c9233b | ||
|  | 6da1ca0cb9 | ||
|  | 2f02f1518a | ||
|  | e8863707de | ||
|  | 6a336dfc69 | ||
|  | 35dec1b9e4 | ||
|  | f148280c99 | ||
|  | 599fe39749 | ||
|  | 44f3fcb238 | ||
|  | af40fdb285 | ||
|  | 9daf8b825c | ||
|  | ef5d8ce367 | ||
|  | 4a199ab23b | ||
|  | 6f0f5a569d | ||
|  | 3172fbfde6 | ||
|  | e97a07a505 | ||
|  | 6579ad92da | ||
|  | ec2fad0cfa | ||
|  | 6196ac7995 | ||
|  | 095a861018 | ||
|  | 2449ed7765 | ||
|  | 117a0408d6 | ||
|  | a54b0223a3 | ||
|  | 44ee708ba5 | ||
|  | 58a20d0fb6 | ||
|  | 063078a02d | ||
|  | 01402fea50 | ||
|  | b7fc2d1147 | ||
|  | 43eeb7011c | ||
|  | d7901a4220 | ||
|  | 0c6271dabc | ||
|  | 2d4cf0c9f5 | ||
|  | 0646d0dd91 | ||
|  | 83e54b45a5 | ||
|  | 5cd87d3d27 | ||
|  | 689d8a80b5 | ||
|  | b1d82a92e7 | ||
|  | 4d65627a50 | ||
|  | ce3a68d817 | ||
|  | 409725be24 | ||
|  | b74f74a0d7 | ||
|  | 719d554430 | ||
|  | 13f54f4521 | ||
|  | 57dfc9cf42 | ||
|  | 57244a6823 | ||
|  | 8bdde01bef | ||
|  | 09bbd5a472 | ||
|  | 9154a74400 | ||
|  | 1399b84b32 | ||
|  | 2ddbb3a8fa | ||
|  | e46a6d1cc1 | ||
|  | b698ab9011 | ||
|  | 0a2572a5eb | ||
|  | 77d049cc3d | ||
|  | 7b8f053be2 | ||
|  | 2c850d5293 | ||
|  | 4056bbf10b | ||
|  | 896b04a846 | ||
|  | 93cda8b6ec | ||
|  | bb5e930684 | ||
|  | 43761fed2a | ||
|  | a636299680 | ||
|  | 08e5bd5b72 | ||
|  | 2f057bef5e | ||
|  | 5ab4f21444 | ||
|  | 9ec26ed481 | ||
|  | 29c9df1389 | ||
|  | 867e9c51d4 | ||
|  | 0170f7b42a | ||
|  | 74bb6ead95 | ||
|  | 303388e5cb | ||
|  | 8388779937 | ||
|  | fc7dfca452 | ||
|  | e5a1db2392 | ||
|  | 6790656af6 | ||
|  | b7477bdc15 | ||
|  | ffc61f31de | ||
|  | e612871ea7 | ||
|  | 7f40f09f10 | ||
|  | 456e42257c | ||
|  | 8618c271cf | ||
|  | 72ca1ccc23 | ||
|  | 075b4bef3f | ||
|  | b59fce4393 | ||
|  | 8674a25eb8 | ||
|  | 10bf8fd2cd | ||
|  | 57cb22ff3c | ||
|  | 0162abdcae | ||
|  | 5801171518 | ||
|  | bf1edbd1e2 | ||
|  | a8484d987d | ||
|  | 9b2147f608 | ||
|  | 32530b378e | ||
|  | a42905efa6 | ||
|  | c59745f9dd | ||
|  | b4ad9a5d08 | ||
|  | 3ead7a38b1 | ||
|  | bf90435200 | ||
|  | 9c181fa3d3 | ||
|  | 3af0b1eb90 | ||
|  | 7110c318ee | ||
|  | 49a552ccdc | ||
|  | 57685f17a9 | ||
|  | a1c09a463f | ||
|  | 194121760a | ||
|  | 6a987d46bf | ||
|  | e3db0b39b9 | ||
|  | 4d4f0ee188 | ||
|  | ac7334c167 | ||
|  | e7bdd69af0 | ||
|  | fefc655969 | ||
|  | 4dceaef60e | ||
|  | 6fc10dd3ae | ||
|  | 1ecd05a584 | ||
|  | 976acaca31 | ||
|  | b4e5131d59 | ||
|  | 49f7cfefd7 | ||
|  | fc365092f6 | ||
|  | 7f26240442 | ||
|  | db559bb20a | ||
|  | 52850faa15 | ||
|  | 57d9a6c836 | ||
|  | 752c880bfc | ||
|  | d83a354781 | ||
|  | 17dd81336d | ||
|  | eaa46a2575 | ||
|  | fc0ec1e71e | ||
|  | fb2f92df1d | ||
|  | 74adbb77b7 | ||
|  | 788e544e1d | ||
|  | 368a0d4d2d | ||
|  | 962b7222d0 | ||
|  | 17c1f54369 | ||
|  | 33ae38e71b | ||
|  | ef58af4bf1 | ||
|  | 3fad2db2f8 | ||
|  | 9feaeb28ca | ||
|  | 0075364715 | ||
|  | 99c5da5da5 | ||
|  | 22c957bc20 | ||
|  | 3316d59910 | ||
|  | a109ce1eca | ||
|  | e581a78d65 | ||
|  | 3c78f9900c | ||
|  | bd606943e6 | ||
|  | 6381666df4 | ||
|  | 736f1aa301 | ||
|  | b1a4eac7a8 | ||
|  | 8226a5276b | ||
|  | 77ad0bb12e | ||
|  | 9412b42206 | ||
|  | 2a91d87074 | ||
|  | 4a23617d79 | ||
|  | 0e2ceed74d | ||
|  | ed56aed8eb | ||
|  | 8d909cbdc0 | ||
|  | bf98943cbb | ||
|  | 6ff4552be2 | ||
|  | 1c7eb79370 | ||
|  | f095a75f1e | ||
|  | f70af6018c | ||
|  | 71b3b1ff4c | ||
|  | d9fefa0c6c | ||
|  | 3bfe922381 | ||
|  | a85cf17bf1 | ||
|  | dbb5a09918 | ||
|  | 93e5097f20 | ||
|  | dd53f2dc83 | ||
|  | 2b83c80593 | ||
|  | 6930f60c06 | ||
|  | 376b76e75c | ||
|  | 1ddd4509dc | ||
|  | 6af3f4f4cf | ||
|  | 6726c5f958 | ||
|  | d5a9c43cb2 | ||
|  | 19a5a6a4eb | ||
|  | 617a599ee9 | ||
|  | 25e2d4da44 | ||
|  | ad2e7218cb | ||
|  | 917637fa9b | ||
|  | b595ee1c0b | ||
|  | c8260a4a56 | ||
|  | d2eaff3204 | ||
|  | b65f5a844f | ||
|  | 95a69f99ba | ||
|  | 71d609895a | ||
|  | 9229630447 | ||
|  | eb18a0b7dc | ||
|  | 05ed5c0d74 | ||
|  | 41330ecc5e | ||
|  | 16fbcc6e36 | ||
|  | d87da9c7de | ||
|  | 94563b6017 | ||
|  | 34d22f7047 | ||
|  | e24d996fbe | ||
|  | 9b52617919 | ||
|  | efc1d46c89 | ||
|  | 9397833ceb | ||
|  | e9433e83cd | ||
|  | f3c58100a0 | ||
|  | 8900231d99 | ||
|  | c7a63b8a2b | ||
|  | 90e90672a4 | ||
|  | fa51e5c762 | ||
|  | 911f55d005 | ||
|  | d30eb4e570 | ||
|  | 67bcfb6947 | ||
|  | 3915a61b1e | ||
|  | c170d321e8 | ||
|  | 2802c476ee | ||
|  | 1050cebf7f | ||
|  | dad73465fc | ||
|  | 8e2ac98fe2 | ||
|  | 9aaf0c36d5 | ||
|  | 1cb07e9cfd | ||
|  | f1ccdf25b1 | ||
|  | 6dca497b27 | ||
|  | 42a83262a1 | ||
|  | 63ee9cbee6 | ||
|  | 3862f8ca7c | ||
|  | 4ada7cffd0 | ||
|  | a664ce4298 | ||
|  | 8d7b6c6905 | ||
|  | 16d22d404a | ||
|  | ccb24d5779 | ||
|  | 8795b45cb4 | ||
|  | 628d3bff45 | ||
|  | 0336bc9de9 | ||
|  | 033cb21797 | ||
|  | 09b98a45df | ||
|  | 38857ba29e | ||
|  | 1c7520ec8f | ||
|  | 362b9769b2 | ||
|  | b2d68bd3d2 | ||
|  | 0dc7e635d4 | ||
|  | 80e070a857 | ||
|  | cc203245e4 | ||
|  | 2f9a65fc93 | ||
|  | 62738e8001 | ||
|  | 5ecacf0c7f | ||
|  | 06b103c8d4 | ||
|  | d473b7bca8 | ||
|  | 50a1e81ba7 | ||
|  | d9885b1b64 | ||
|  | 0a9c8cada2 | ||
|  | 60f55f8461 | ||
|  | 7bedaea38f | ||
|  | 9e4b87e798 | ||
|  | 95bf59095c | ||
|  | e0f34a9720 | ||
|  | f3797c2a8e | ||
|  | 30cbcccc80 | ||
|  | f49c0d696f | ||
|  | 71f564ee5b | ||
|  | 4b0950aba5 | ||
|  | 8c3af822ec | ||
|  | 878a207d19 | ||
|  | 0537ad860a | ||
|  | 2cdbbb1aea | ||
|  | 7af977d36b | ||
|  | 9afff4cf30 | ||
|  | 48ba9734aa | ||
|  | 897fc59f72 | ||
|  | 947e44ae67 | ||
|  | e44843beba | ||
|  | 147482ea69 | ||
|  | 09091c5cf8 | ||
|  | 50827a5f69 | ||
|  | 2d6444c924 | ||
|  | 1d2675d9aa | ||
|  | ad98990a8e | ||
|  | 8e58c143f2 | ||
|  | 556a4a2395 | ||
|  | 5be987b40f | ||
|  | 066bc35e69 | ||
|  | 403779437c | ||
|  | fb806f61d4 | ||
|  | 6ce306661c | ||
|  | 3c08ff94d4 | ||
|  | a6afae2356 | ||
|  | 0eea7070a7 | ||
|  | 105c2b1eea | ||
|  | 82bb0e8dda | ||
|  | 8c01179075 | ||
|  | c9d9a96630 | ||
|  | 8f21c9a920 | ||
|  | 0ba7d05ea7 | ||
|  | 5a4c5b4155 | ||
|  | 55323fb497 | ||
|  | 7c082d2471 | ||
|  | f3cafcf983 | ||
|  | 75073e4aa6 | ||
|  | a3c23f650c | ||
|  | 0545cd5879 | ||
|  | c96506f22c | ||
|  | 49b2006824 | ||
|  | 8c6f96faab | ||
|  | a0e648abfd | ||
|  | 6350cd12fc | ||
|  | f2fab0677b | ||
|  | edffc52927 | ||
|  | d6e5e3d103 | ||
|  | 5be7a0ebf7 | ||
|  | 7f722fe7d3 | ||
|  | a01732ee9b | ||
|  | 85ac11b69b | ||
|  | 590cfb77a5 | ||
|  | f01dd16a27 | ||
|  | df49287e5f | ||
|  | c8ec8391ee | ||
|  | 3499e48064 | ||
|  | 2e379cb8a5 | ||
|  | f8ee3c2369 | ||
|  | c74fa11518 | ||
|  | ceec4455df | ||
|  | 17c9975c0b | ||
|  | 6c1cdff912 | ||
|  | 79f53f569d | ||
|  | ccb85cc719 | ||
|  | c0eff8a07f | ||
|  | 954626f157 | ||
|  | 17e7dfa4bd | ||
|  | 971f233fb7 | ||
|  | b12bc692af | ||
|  | 730301b34d | ||
|  | c443bcf43c | ||
|  | b77e7eeddc | ||
|  | 031b7b57a1 | ||
|  | 5123fab525 | ||
|  | 705b96c6f9 | ||
|  | 9ec582002b | ||
|  | ee79277774 | ||
|  | db02dc218e | ||
|  | b66ce1089e | ||
|  | ec0e70b599 | ||
|  | a273482f9d | ||
|  | 76cf8c4cf7 | ||
|  | 9691ecc839 | ||
|  | 59b2a86359 | ||
|  | fe7cd72cff | ||
|  | f0761fc570 | ||
|  | 90990aa19d | ||
|  | a3d3ce82e4 | ||
|  | b8e48113a3 | ||
|  | d4b1003a97 | ||
|  | efd83567c9 | ||
|  | 5563f373f7 | ||
|  | 15a36619fe | ||
|  | 38e54b626e | ||
|  | 8aa30fb56a | ||
|  | b764becd1b | ||
|  | 219370932e | ||
|  | 90afae186c | ||
|  | 84e49a809d | ||
|  | 1cfb9ff46a | ||
|  | f35026c74f | ||
|  | 5f2d3da8c5 | ||
|  | 4e61f32a28 | ||
|  | d7814c7011 | ||
|  | aa40668e84 | ||
|  | 3767e6e96f | ||
|  | 44976cef6c | ||
|  | eba4417947 | ||
|  | c99204d370 | ||
|  | 1bfc4335bb | ||
|  | 6b9c7485f1 | ||
|  | 737f3d78f2 | ||
|  | b1d5e1b5e3 | ||
|  | 8d92a5cc14 | ||
|  | fc455df92c | ||
|  | c0076ebfa1 | ||
|  | 5d607aa3cd | ||
|  | fa1b9a4098 | ||
|  | c8c4dbb409 | ||
|  | 16628e6cea | ||
|  | 7067c12991 | ||
|  | 7b47e241e0 | ||
|  | d1e46207a5 | ||
|  | 2a04b97cbd | ||
|  | e6c8ef59e0 | ||
|  | d3380f41de | ||
|  | 4ef1633969 | ||
|  | 57e593aab2 | ||
|  | 6461caacbb | ||
|  | e5531e2a93 | ||
|  | 329402a614 | ||
|  | 4656ed462e | ||
|  | 96ddad91a9 | ||
|  | 5eb40588d2 | ||
|  | 58def149aa | ||
|  | 0ee5743d75 | ||
|  | 7c266f3e81 | ||
|  | d7ce981cd1 | ||
|  | eadadf6299 | ||
|  | 8ac9fabd07 | ||
|  | 44c2b4b281 | ||
|  | 4cd97611e5 | ||
|  | da27380ab5 | ||
|  | 756e539661 | ||
|  | cde44e3172 | ||
|  | e79a4b34b0 | ||
|  | e9f0bdd72c | ||
|  | d080291150 | ||
|  | 06c69c56ba | ||
|  | d79710ba9d | ||
|  | c9bc7dd0b6 | ||
|  | ebc26c7421 | ||
|  | 3769425f6b | ||
|  | a50957443e | ||
|  | 63fa007af0 | ||
|  | a6a52a128b | ||
|  | 1ad58e1121 | ||
|  | 3f507a26fb | ||
|  | bfc368764a | ||
|  | 53fbce932b | ||
|  | a94195c6cd | ||
|  | 626c6d1124 | ||
|  | 471ab92bbb | ||
|  | fbccd12924 | ||
|  | e5928bbaea | ||
|  | 3c1597bc67 | ||
|  | 295019815e | ||
|  | 654a391250 | ||
|  | 9ee1465d3c | ||
|  | 52197cf4d2 | ||
|  | cfbb2afac5 | ||
|  | 8f154f65f9 | ||
|  | 7454664997 | ||
|  | 3393b7aedd | ||
|  | 133ccc95b5 | ||
|  | c392ff1cd3 | ||
|  | 30a0f831a5 | ||
|  | 541ea4dc63 | ||
|  | afc5e0e3e5 | ||
|  | bcb31df10d | ||
|  | 2192c4e269 | ||
|  | eec17858c4 | ||
|  | 6d696706be | ||
|  | 8cd88b6051 | ||
|  | 9dbf53fdb9 | ||
|  | 38b6963c8b | ||
|  | 7b6248983d | ||
|  | 4d418dee0e | ||
|  | 06fe319347 | ||
|  | 9dd7e3fb24 | ||
|  | d5a46396b0 | ||
|  | 5e84cb560d | ||
|  | 756c6f8560 | ||
|  | 6fa6ce35da | ||
|  | b14b97599d | ||
|  | db6f60d6fc | ||
|  | 25c348d7c8 | ||
|  | 2e4bf8b034 | ||
|  | c1490e2f7b | ||
|  | b004fe9556 | ||
|  | 67142ad046 | ||
|  | 3c3ec06b12 | ||
|  | 5b5caa8a16 | ||
|  | b2cba098bb | ||
|  | 1ec0d47f10 | ||
|  | f232606ec7 | ||
|  | fa28cea152 | ||
|  | c8da1647a1 | ||
|  | 505a0a8718 | ||
|  | 10d3496a17 | ||
|  | a13c755370 | ||
|  | 62f9996fd7 | ||
|  | edbcd8a1b2 | ||
|  | a5308d1689 | ||
|  | cbfe6e8fcc | ||
|  | 5571ff35d8 | ||
|  | 2a4819f3c8 | ||
|  | 7121866b13 | ||
|  | d6e05ad9e2 | ||
|  | 993e30a7de | ||
|  | 49cae61254 | ||
|  | 1ea4b2ea91 | ||
|  | bc1d6e1f90 | ||
|  | 9ec6e68d0c | ||
|  | 341bdc93e2 | ||
|  | 6fb3e1aa15 | ||
|  | f1f92eb2e2 | ||
|  | 8c2369d40f | ||
|  | a6d9fc58eb | ||
|  | f7cd471548 | ||
|  | 5f951faf32 | ||
|  | b228dfaf2c | ||
|  | 764858fa12 | ||
|  | 5ee976d276 | ||
|  | 8b28b6f2d3 | ||
|  | fe16df2e6f | ||
|  | 779047f8c9 | ||
|  | 094e9fb45d | ||
|  | 1458bd0e74 | ||
|  | d2cb05988d | ||
|  | 6e056767b4 | ||
|  | a10afb1b98 | ||
|  | bb6d3b6cfd | ||
|  | c75d4af4bc | ||
|  | 972dc39d00 | ||
|  | 9daac5c178 | ||
|  | dd2a3f40e1 | ||
|  | 78f76c1690 | ||
|  | 4788066a5f | ||
|  | 10e4254e7d | ||
|  | 0106e4df9d | ||
|  | 8ac718a3a2 | ||
|  | 46d45273a1 | ||
|  | 8da9ec3599 | ||
|  | 01fdf84d69 | ||
|  | cc78386e75 | ||
|  | 3755157c61 | ||
|  | 80f8436f0a | ||
|  | f88a4b7760 | ||
|  | de229b8ab0 | ||
|  | a3ba37e45e | ||
|  | 50c779b3c6 | ||
|  | 192372e1c3 | ||
|  | f88fd88c38 | ||
|  | 6e15145af1 | ||
|  | 4b5fad4e48 | ||
|  | 7a13e71c80 | ||
|  | 3c10943900 | ||
|  | 696b8811c2 | ||
|  | 9fd2c8602a | ||
|  | a3636a5af4 | ||
|  | f2e5f07718 | ||
|  | 16c6fdde60 | ||
|  | 2155c93426 | ||
|  | c394631e4c | ||
|  | 8b370b7cc1 | ||
|  | 607db9971c | ||
|  | 6768f64e2f | ||
|  | f1813b1cc6 | ||
|  | fb665bd0dd | ||
|  | 65dda2ef3d | ||
|  | b162b992af | ||
|  | 67a3a3d130 | ||
|  | 92cd9bf7d2 | ||
|  | bf97034485 | ||
|  | 1ded1fc509 | ||
|  | e0592c58b3 | ||
|  | 5ead2706b4 | ||
|  | 52ada4853c | ||
|  | c2b27a8298 | ||
|  | 3934c1d437 | ||
|  | e366b68ad3 | ||
|  | fb94fb980a | ||
|  | b10cc18f53 | ||
|  | a249de3b72 | ||
|  | d04e972d65 | ||
|  | b9f5a18a76 | ||
|  | d3f157f08a | ||
|  | 2294fdb496 | ||
|  | d7ba0e01a5 | ||
|  | b6172b53fd | ||
|  | 477ec611d5 | ||
|  | b6194edd67 | ||
|  | dcdbbb3ecb | ||
|  | 7ef99ee4e6 | ||
|  | 1ac1418286 | ||
|  | 8fc854f38e | ||
|  | 1c2360b335 | ||
|  | dd4477406b | ||
|  | 9d67bbb104 | ||
|  | d6c8e1df61 | ||
|  | 5ec7c8fece | ||
|  | 86b21eaf83 | ||
|  | 228486a971 | ||
|  | 88c0caab26 | ||
|  | 5cd4679419 | ||
|  | eeed5e0d19 | ||
|  | 369ab1e0b2 | ||
|  | 2e21519a10 | ||
|  | ecc001ed08 | ||
|  | cd96852696 | ||
|  | b9f7f30158 | ||
|  | ca5e423331 | ||
|  | fa9407089c | ||
|  | 66f28e193a | ||
|  | 0d93f89f5c | ||
|  | 154e9a2c47 | ||
|  | 84574a1257 | ||
|  | bf83527b64 | ||
|  | 12c53622a0 | ||
|  | d8f54cf891 | ||
|  | 625a671189 | ||
|  | 6ebdad3102 | ||
|  | 9a8f21aa03 | ||
|  | 291dd8edc2 | ||
|  | de4c1daf29 | ||
|  | 0b55d7d0d8 | ||
|  | 5d86fd8fdb | ||
|  | 1b76eb1f59 | ||
|  | b05678d8bf | ||
|  | 781f4971c6 | ||
|  | d02ac7b99a | ||
|  | b1b6c97f7c | ||
|  | baee28ab5c | ||
|  | 83edf68ff9 | ||
|  | c7588f91dd | ||
|  | 30b432adc5 | ||
|  | 7c9733eb5d | ||
|  | a223c3fea3 | ||
|  | d5250f4901 | ||
|  | 25f29f4712 | ||
|  | 382af5563d | ||
|  | 8cf3d165d3 | ||
|  | 0fd6ce546f | ||
|  | b881c372bc | ||
|  | 94c5e7deb0 | ||
|  | c344766f3c | ||
|  | 67895de0bc | ||
|  | ff00cb6990 | ||
|  | 2cc75c11ed | ||
|  | cd79e58eda | ||
|  | 6fa801f3d8 | ||
|  | 684eecba1d | ||
|  | da9cf7e5de | ||
|  | f57e7445fd | ||
|  | fba1388719 | ||
|  | 80ed029c17 | ||
|  | 34a74e81e3 | ||
|  | cb120ddb15 | ||
|  | f9ee4395b0 | ||
|  | 71f06d51ed | ||
|  | 217f70952f | ||
|  | f813d41a76 | ||
|  | d851289d8a | ||
|  | b115b8a2ea | ||
|  | d0f7067471 | ||
|  | be5b4c38a7 | ||
|  | d6d597e3dd | ||
|  | 84e348fade | ||
|  | 910054657e | ||
|  | 8357a11249 | ||
|  | 9b021ba057 | ||
|  | 317e588efd | ||
|  | b1d32a03c7 | ||
|  | ee6e6529ee | ||
|  | 9d944d6cf9 | ||
|  | 13635d281a | ||
|  | 2493c46970 | ||
|  | 63e4217271 | ||
|  | f4bd12e8e9 | ||
|  | df15f46900 | ||
|  | fb3a732361 | ||
|  | 2d74110feb | ||
|  | 19d102082d | ||
|  | d2af2c9487 | ||
|  | 82980149fa | ||
|  | a19bb7b909 | ||
|  | 9d98c3278d | ||
|  | 26376ac1c9 | ||
|  | 8459f99341 | ||
|  | e5bdb0e0b5 | ||
|  | 1106b7775a | ||
|  | ae2852156d | ||
|  | 44c6c36c43 | ||
|  | a81926503d | ||
|  | af13ccddda | ||
|  | 392e1bc2e8 | ||
|  | 9268d92c70 | ||
|  | bb3366c07d | ||
|  | d24d563ebc | ||
|  | 954bd9257b | ||
|  | 5d51a56c02 | ||
|  | f48648552e | ||
|  | edb9c3cc9f | ||
|  | 01dc83b936 | ||
|  | 3a8dff3a62 | ||
|  | 13b234ccba | ||
|  | e451e93664 | ||
|  | b4f9531475 | ||
|  | 3184ff75c4 | ||
|  | 43243f4d30 | ||
|  | c975a100b1 | ||
|  | 02bf389425 | ||
|  | bcb9a3dd04 | ||
|  | cce3baa275 | ||
|  | 2b48fad426 | ||
|  | d554b2bc94 | ||
|  | f66943de43 | ||
|  | 9d1e9bc2fb | ||
|  | 2d6a014920 | ||
|  | c1952bf257 | ||
|  | a10227eb03 | ||
|  | 475ae29b85 | ||
|  | 0b9cfc278b | ||
|  | b57b6b4fba | ||
|  | 7d948f7bc5 | ||
|  | 459023d171 | ||
|  | fd6570720a | ||
|  | 7831665417 | ||
|  | 7c9920d982 | ||
|  | cbdccf0a9c | ||
|  | 64fa83ec3f | ||
|  | faff865cfd | ||
|  | 742ab55a9a | ||
|  | 66e623fb2a | ||
|  | 4ab17ee965 | ||
|  | 7f48ca5132 | ||
|  | da983848b4 | ||
|  | bc03f7bad3 | ||
|  | a1c8bd3846 | ||
|  | 404bc284e0 | ||
|  | 9dee30ff0e | ||
|  | f91aadbea8 | ||
|  | aa15a10c91 | ||
|  | 5b03e36351 | ||
|  | b9ba9ffad2 | ||
|  | 642be5d16c | ||
|  | ee68d715bf | ||
|  | 224084f056 | ||
|  | 1cd8c849b8 | ||
|  | 169f68bfcd | ||
|  | d2b7cfa2d1 | ||
|  | a40c7dff5d | ||
|  | e8e00630d3 | ||
|  | e33720c854 | ||
|  | bd8a4e0d17 | ||
|  | 586a2aef76 | ||
|  | ce1d8f6754 | ||
|  | 7b0f401065 | ||
|  | 8387016eef | ||
|  | 4e1342b641 | ||
|  | e45a184d90 | ||
|  | 979e1012d2 | ||
|  | fe10a50e23 | ||
|  | 8ab6d72519 | ||
|  | 3aada6dd1d | ||
|  | 0933036366 | ||
|  | 05f5abdc06 | ||
|  | fb875e0709 | ||
|  | 9acdc2f6bf | ||
|  | 028ce4bff6 | ||
|  | 3f245ad6db | ||
|  | 23115f4116 | ||
|  | cf5f48e6cc | ||
|  | 997fa756ad | ||
|  | e23f75b1cc | ||
|  | 6531e88761 | ||
|  | e76a9c2618 | ||
|  | 45be8a836b | ||
|  | 954b6032e7 | ||
|  | bd95416f27 | ||
|  | df2577ace2 | ||
|  | 720e6558c9 | ||
|  | c239f15d8a | ||
|  | dfa1f80a57 | ||
|  | 15dfb93b17 | ||
|  | 0ec8488c2b | ||
|  | 94b2e29cb1 | ||
|  | fefa8e9b4d | ||
|  | 32c4c44812 | ||
|  | 05195e2b1d | ||
|  | 4c2ff675b8 | ||
|  | e5692a4721 | ||
|  | 312e6a0d31 | ||
|  | 5bb8efa41f | ||
|  | 949a835f4a | ||
|  | 85e6042941 | ||
|  | 3cd2f28975 | ||
|  | 2179a72c3a | ||
|  | a5f282f156 | ||
|  | 40e8631f63 | ||
|  | 9ded05bb97 | ||
|  | ec8efa35a1 | ||
|  | f72bf20482 | ||
|  | ebde2002e8 | ||
|  | 352a66f46f | ||
|  | d84c5391f7 | ||
|  | f4c582472b | ||
|  | 1485586f7e | ||
|  | d5c9024335 | ||
|  | 860cf80703 | ||
|  | 897ff3161f | ||
|  | b356b2e501 | ||
|  | 1d2733c893 | ||
|  | 32d9126094 | ||
|  | db43314e50 | ||
|  | 68d2baeb65 | ||
|  | 1fd5f562d3 | ||
|  | 48e02f2086 | ||
|  | eab7b2b581 | ||
|  | 45abade7fc | ||
|  | 5372fc4b43 | ||
|  | 4e2f240c98 | ||
|  | bb3605518d | ||
|  | 3ef6d37f27 | ||
|  | 88e9f2f7f4 | ||
|  | 704a447df9 | ||
|  | a5fcb26a33 | ||
|  | 2491a61481 | ||
|  | 91831d51ed | ||
|  | 174f0c19f7 | ||
|  | de6fadfb4f | ||
|  | f946db3e00 | ||
|  | 8d05e5bc31 | ||
|  | cfb46820e4 | ||
|  | 081f1cbcc2 | ||
|  | 7bc6da326f | ||
|  | cd95a0df7b | ||
|  | 82fa497c16 | ||
|  | 44fd345206 | ||
|  | 088e1c9db4 | ||
|  | d4f16e666e | ||
|  | 8233cfd371 | ||
|  | ff05e2e30d | ||
|  | a8ea7dd3fb | ||
|  | 96f70a5303 | ||
|  | f1604c3e69 | ||
|  | c42c8c5192 | ||
|  | 5facb53a41 | ||
|  | d039ce89af | ||
|  | bc7605103f | ||
|  | d305d655d4 | ||
|  | 4ef1220b16 | ||
|  | a4fef143cd | ||
|  | 74ecb724a9 | ||
|  | af235897ab | ||
|  | 5ec4e458b5 | ||
|  | 2dae63ce21 | ||
|  | be748fe33b | ||
|  | 7408340b6a | ||
|  | 29eb92446e | ||
|  | ae6918742e | ||
|  | 863484bb65 | ||
|  | 1cd7ebce4c | ||
|  | eef8c7862e | ||
|  | b52375d446 | ||
|  | 6e2babc2ce | ||
|  | 08e253bed1 | ||
|  | c6661477a2 | ||
|  | 415cfd99a0 | ||
|  | 8c2e37381a | ||
|  | 45df79feba | ||
|  | 5824f992b7 | ||
|  | b0b60fafd5 | ||
|  | 8d98b02ba2 | ||
|  | a93fe79bc4 | ||
|  | 4aebd7be37 | ||
|  | 3170a5db32 | ||
|  | 3605b9eef6 | ||
|  | a945f1fde2 | ||
|  | 461a997b5b | ||
|  | a80afd7b4e | ||
|  | aad2b51d85 | ||
|  | 36a9a81ff1 | ||
|  | 42c88546ae | ||
|  | 0f0e86ef9b | ||
|  | 98efd9a857 | ||
|  | a0c27d95b7 | ||
|  | 984651d99d | ||
|  | c6f7370b30 | ||
|  | 3e4b8e8985 | ||
|  | 73f08b98d2 | ||
|  | 8607a74206 | ||
|  | 8339f3ceb3 | ||
|  | c0c9f3cc19 | ||
|  | 81f4813c29 | ||
|  | 94f57745b9 | ||
|  | 54fb2ebbe0 | ||
|  | 02d122b65b | ||
|  | df0a5561a1 | ||
|  | f7c55da7d0 | ||
|  | b385f701ce | ||
|  | 05dd42f443 | ||
|  | 36d816d5cb | ||
|  | 92a6746e70 | ||
|  | 1728848a39 | ||
|  | f9eb4e7487 | ||
|  | d0b9f33aeb | ||
|  | 718583b241 | ||
|  | 6737127e9a | ||
|  | 19a7b4479b | ||
|  | c340647502 | ||
|  | 0f987d2982 | ||
|  | 52bcaed169 | ||
|  | 177bd565ac | ||
|  | c801c32fc5 | ||
|  | d090cf3058 | ||
|  | 1e4b82cc94 | ||
|  | 3426f31184 | ||
|  | b4fb7af1df | ||
|  | b36647598b | ||
|  | fd6b94f20e | ||
|  | 296dc0ed8a | ||
|  | 4f869e14d6 | ||
|  | 5704270e9d | ||
|  | 505b381e85 | ||
|  | da6cb15393 | ||
|  | 16843f6cc8 | ||
|  | 64f3ad1fd4 | ||
|  | ff4c4f99b3 | ||
|  | f5d2e09569 | ||
|  | f2bdbe0d4d | ||
|  | c51a13caa6 | ||
|  | 7840c78a23 | ||
|  | c706f3246b | ||
|  | 608eedf88d | ||
|  | a564ca82be | ||
|  | c868b1fee2 | ||
|  | 22374f718f | ||
|  | abe3cfcf41 | ||
|  | 59db4b50cd | ||
|  | bdae38765d | ||
|  | 66d3ceeb61 | ||
|  | 445dd17db3 | ||
|  | cff78a2577 | ||
|  | 6a09e64195 | ||
|  | 22eabe5eab | ||
|  | b69ba36c2d | ||
|  | 5240aad22b | ||
|  | 2897eb3cb3 | ||
|  | d3f2f00c25 | ||
|  | bacfb913a0 | ||
|  | c99d0236a0 | ||
|  | aac2b655f7 | ||
|  | 126c41e73a | ||
|  | 359ee54f0d | ||
|  | 28ab560907 | ||
|  | ead252fee4 | ||
|  | abf67914c4 | ||
|  | 127884e9dd | ||
|  | 654f5049eb | ||
|  | 979ca34259 | ||
|  | 4dd1086805 | ||
|  | 3503d4b72c | ||
|  | b8d32a0d33 | ||
|  | 45dca55fc8 | ||
|  | 445d8ecd9f | ||
|  | c980add503 | ||
|  | 133842392a | ||
|  | 8baf2ef155 | ||
|  | 20b71340bc | ||
|  | 61d8baf8b1 | ||
|  | 56a9645aa5 | ||
|  | 85877000a6 | ||
|  | 2f7d2477b6 | ||
|  | 21ea3f05f4 | ||
|  | 79d3492e90 | ||
|  | 5972777abe | ||
|  | 8e373ff868 | ||
|  | a4db92da3a | ||
|  | 9b777eb281 | ||
|  | bd3c652184 | ||
|  | 800f747570 | ||
|  | 2b8423437e | ||
|  | 8b4b6945f8 | ||
|  | e5ecfec5c4 | ||
|  | f95dbff71f | ||
|  | 098f6830a6 | ||
|  | d1ecebdb52 | ||
|  | 590b654251 | ||
|  | 3bf190c8ab | ||
|  | dcca7638e0 | ||
|  | 70e45ad37b | ||
|  | db88210289 | ||
|  | d2e0d96cc3 | ||
|  | 3feba82ccc | ||
|  | db924da231 | ||
|  | fc55ae7e6d | ||
|  | 86e757a6ad | ||
|  | 4790715cd3 | ||
|  | e7e9c60042 | ||
|  | 1c3bc52cc4 | ||
|  | 5227dff0e1 | ||
|  | 33f0b5b7c2 | ||
|  | 0a02968303 | ||
|  | f7bf658c07 | ||
|  | 8d16a0abad | ||
|  | c974b97ca3 | ||
|  | b8025bfebd | ||
|  | 30323b253f | ||
|  | 535c3ede96 | ||
|  | 89fed8ca33 | ||
|  | f43c77aaed | ||
|  | 96c676b371 | ||
|  | 113047e1a2 | ||
|  | abed57cb53 | ||
|  | c01a800a6b | ||
|  | d648832a2d | ||
|  | f06833fbd2 | ||
|  | c561addc94 | ||
|  | 702f5f1f4c | ||
|  | 1273f179e8 | ||
|  | 5d02f60bde | ||
|  | 4cf7a108e8 | ||
|  | 42635c3938 | ||
|  | ed43dc842b | ||
|  | 49d4db6cd2 | ||
|  | ea80ab2cae | ||
|  | 382e808b8d | ||
|  | 846befa7e0 | ||
|  | 74dd29f843 | ||
|  | b0473bffcb | ||
|  | 24dd9ab1a7 | ||
|  | 49d3037e87 | ||
|  | 37ad2bd4e8 | ||
|  | 7d7b332b02 | ||
|  | ac033b8612 | ||
|  | a7b98dfe25 | ||
|  | 7fb7c86c46 | ||
|  | ed036598a9 | ||
|  | 160bb70cdf | ||
|  | c2e61f3c21 | ||
|  | 18218467f3 | ||
|  | 17e298ad2a | ||
|  | d031a374f9 | ||
|  | 55f69c98cb | ||
|  | 71f2e4306d | ||
|  | f8af23a025 | ||
|  | 4ef55a6cd3 | ||
|  | 312f866723 | ||
|  | 0ebe1f6dec | ||
|  | 2ad92e0e6e | ||
|  | ac8823cdcf | ||
|  | 77565f7ee4 | ||
|  | d656d90fa8 | ||
|  | 175b3b0834 | ||
|  | 7477e6b714 | ||
|  | cd6568db69 | ||
|  | 6aff325fb2 | ||
|  | 0d603cfe9c | ||
|  | 34a1f14a17 | ||
|  | efe1c8a070 | ||
|  | 1575844344 | ||
|  | 221ac1c208 | ||
|  | 57442db759 | ||
|  | 5fdb3e7cd6 | ||
|  | 96f259726c | ||
|  | 4936efba5e | ||
|  | d5a3559a2f | ||
|  | 114a1c7f52 | ||
|  | ce5265c203 | ||
|  | 1a575d926f | ||
|  | 85c818a39e | ||
|  | 4ffa2defe4 | ||
|  | 8825157fbb | ||
|  | 966d608dc5 | ||
|  | b808c89471 | ||
|  | 75d4e6490f | ||
|  | a82775f544 | ||
|  | 6a22ad0171 | ||
|  | c854e88186 | ||
|  | d02203060c | ||
|  | cf703b0433 | ||
|  | c0197a72d3 | ||
|  | e5a543e283 | ||
|  | b8b029b7d3 | ||
|  | 370f368b1a | ||
|  | 8288b45b4f | ||
|  | fe529faf8e | ||
|  | ab931b177d | ||
|  | 9aa3465513 | ||
|  | 6c70fc1a6c | ||
|  | 1ccc39962a | ||
|  | 99c941fc85 | ||
|  | 19729fdcc2 | ||
|  | 02e17998ce | ||
|  | 459e00c67a | ||
|  | 292f665650 | ||
|  | 93bbb79569 | ||
|  | 273e724f2b | ||
|  | 5d2615c56f | ||
|  | bfaaf21330 | ||
|  | dcb8415b7a | ||
|  | 699e1c75ce | ||
|  | 465b6e613e | ||
|  | 05fa105855 | ||
|  | d7a0cdebe5 | ||
|  | b049ab31eb | ||
|  | 6db4dcff7a | ||
|  | 3eeaef00ec | ||
|  | 8bf4c38a00 | ||
|  | 3a32b09ad1 | ||
|  | 6315982752 | ||
|  | 374a171e82 | ||
|  | fc5d801f91 | ||
|  | 5146641848 | ||
|  | cdd0ac42cf | ||
|  | e5895500a2 | ||
|  | 9cb4dde3fa | ||
|  | 3c2a4370a5 | ||
|  | e7a360dd6f | ||
|  | c814c2fd35 | ||
|  | fefa7fe262 | ||
|  | 26f01a29d1 | ||
|  | 169d4090ab | ||
|  | 0b43754d60 | ||
|  | 8b3b26b813 | ||
|  | 5426af4f81 | ||
|  | 4e2c3a579d | ||
|  | 5ae2693241 | ||
|  | 41c86b0d19 | ||
|  | 40788e8c3d | ||
|  | 0d29120033 | ||
|  | 4be598f865 | ||
|  | 558a6d509e | ||
|  | 75cd02aad2 | ||
|  | e4c4451482 | ||
|  | 0671632477 | ||
|  | 54c230c264 | ||
|  | 64ba878eda | ||
|  | 01acd6dd76 | ||
|  | 9d819b52d3 | ||
|  | 37bac5cdc9 | ||
|  | 78c718c591 | ||
|  | 284b8bf6ca | ||
|  | 5a5084b837 | ||
|  | 3b8058e1f1 | ||
|  | 2a3168e0d6 | ||
|  | a8ac6e4a15 | ||
|  | 6172cf9fba | ||
|  | b728ec3909 | ||
|  | 61a53bbcff | ||
|  | 17d13dd084 | ||
|  | edcb28d591 | ||
|  | ad101119a7 | ||
|  | bc36676d31 | ||
|  | d76fe120ab | ||
|  | 2e95949b80 | ||
|  | ae14d85e24 | ||
|  | fad6304c60 | ||
|  | a4dd3c8ce9 | ||
|  | 6d1a5d45e2 | ||
|  | a6c7043e03 | ||
|  | bcc400dafa | ||
|  | 8fbedf3441 | ||
|  | 2e8a9c9874 | ||
|  | 44fc41b3e5 | ||
|  | 7212c20a1b | ||
|  | 7ff142de1c | ||
|  | e67efb199d | ||
|  | 20128bd04b | ||
|  | c0fefdde28 | ||
|  | f6ee160e66 | ||
|  | 06acc2004f | ||
|  | 43ac2ce4c8 | ||
|  | b32bf72b5f | ||
|  | c6880c957e | ||
|  | 095b71ed96 | ||
|  | 9160e496bc | ||
|  | 2a7ac78f02 | ||
|  | 64efa4627d | ||
|  | f7e35569ce | ||
|  | e8af32ec2b | ||
|  | e092ce51f6 | ||
|  | 7b78edb1b7 | ||
|  | b332e7090e | ||
|  | 67eb7723d6 | ||
|  | 251d138474 | ||
|  | 1170dfac05 | ||
|  | 4157f141c7 | ||
|  | f569abd28a | ||
|  | 088f9687c0 | ||
|  | e23df1f07a | ||
|  | c818540dfd | ||
|  | 21365cbe1a | ||
|  | 5471a80a96 | ||
|  | d7b6fa9cd0 | ||
|  | dfdc2e02ef | ||
|  | 893ec9a302 | ||
|  | 05f65c38e6 | ||
|  | 2e9d062ec0 | ||
|  | 6b0b394e61 | ||
|  | 25621396c9 | ||
|  | 82aa0271f3 | ||
|  | 653cab13f8 | ||
|  | b526f86b49 | ||
|  | 53c0f00888 | ||
|  | f0c4d9de40 | ||
|  | 03ef8cec83 | ||
|  | 85f2a2e8c2 | ||
|  | 584b3e6642 | ||
|  | 39b7ef841d | ||
|  | aa16a9098d | ||
|  | 7b8c2707bc | ||
|  | 60e26a31a7 | ||
|  | 3473c25c14 | ||
|  | e52f022026 | ||
|  | b1a7df8e43 | ||
|  | 0fd2479b7c | ||
|  | 273857f914 | ||
|  | a08b85dbc8 | ||
|  | a0aedf299a | ||
|  | 3c61426844 | ||
|  | 786f228076 | ||
|  | 004da28792 | ||
|  | 6e2be6efb6 | ||
|  | a994dfcfbc | ||
|  | 7a8ea2ac93 | ||
|  | 0da3965d19 | ||
|  | 885fd7bb46 | ||
|  | 08771f9c89 | ||
|  | 8be48195a5 | ||
|  | 98ce2d650e | ||
|  | 3af327116a | ||
|  | b75434db93 | ||
|  | 04e912aacd | ||
|  | d7be352f87 | ||
|  | 96be3ec22c | ||
|  | 32e7e0d790 | ||
|  | becc320e62 | ||
|  | 7666ed57d1 | ||
|  | 5e61d0955e | ||
|  | e8a4662ae7 | ||
|  | a48da3bd3b | ||
|  | 5f1a5d7b99 | ||
|  | 3e28a9db8f | ||
|  | ebf6071d77 | ||
|  | 47a35fb9fb | ||
|  | 48e88aba44 | ||
|  | b85f99c140 | ||
|  | 0a5e0e1f71 | ||
|  | 85dc22ebb7 | ||
|  | 5c21526009 | ||
|  | 14dff1cefc | ||
|  | 39fbb844f9 | ||
|  | ca4e0c973a | ||
|  | ecb42bee80 | ||
|  | 674ed2a9f3 | ||
|  | 252daf9717 | ||
|  | 196b8eaad3 | ||
|  | 8e526ba1bf | ||
|  | 19225828d9 | ||
|  | 7e594126be | ||
|  | d2529e6334 | ||
|  | 97344f18e2 | ||
|  | 33934db629 | ||
|  | 6c6165c9f5 | ||
|  | 853460b20d | ||
|  | cc4d9676c5 | ||
|  | 1cf1b819f4 | ||
|  | f916c66d2b | ||
|  | 550aa86b45 | ||
|  | 014e764758 | ||
|  | d1fc28432b | ||
|  | 879576f0a2 | ||
|  | 69098210be | ||
|  | 99df4f892d | ||
|  | 7bc04fbad3 | ||
|  | 8a74ce578d | ||
|  | 0805e4e5de | ||
|  | f1060fc88e | ||
|  | 7d3d3d0a3a | ||
|  | 40377032e3 | ||
|  | b2971edd7d | ||
|  | c37d723692 | ||
|  | 30f9026e1d | ||
|  | 332286072e | ||
|  | d6da172a2a | ||
|  | ebfe584afc | ||
|  | 6250023583 | ||
|  | 6b4f3d63b8 | ||
|  | 56db773a09 | ||
|  | fc6c472401 | ||
|  | 2cd42a6866 | ||
|  | 36a90c345c | ||
|  | ef1e82c72c | ||
|  | 88f9534685 | ||
|  | 68254a052a | ||
|  | 2425b3a166 | ||
|  | 5524ed753b | ||
|  | 89711723da | ||
|  | bed2740ffd | ||
|  | 751d633c3d | ||
|  | 45952cbdf2 | ||
|  | b355dd7b23 | ||
|  | 48a186f172 | ||
|  | 39dc7ec2ab | ||
|  | 2fedabd3b9 | ||
|  | 6d719e9480 | ||
|  | 05e278afda | ||
|  | 87dbf462cb | ||
|  | 40e896bc5b | ||
|  | 3e940f80c7 | ||
|  | dbf2888d43 | ||
|  | d412355324 | ||
|  | 178732217f | ||
|  | de17b95c3d | ||
|  | d14e774525 | ||
|  | ca5402a7fa | ||
|  | 7a6fa7c5b4 | ||
|  | da36c286a6 | ||
|  | d3901bcf2e | ||
|  | 94c8d4fdfb | ||
|  | ab8bdc18bb | ||
|  | c9dcd7442a | ||
|  | 34c8f13346 | ||
|  | 7a8ccda95c | ||
|  | 44a1448542 | ||
|  | c87d89ffaf | ||
|  | 0868749d42 | ||
|  | 1d40ee23f0 | ||
|  | 8893f32603 | ||
|  | adcf7e8dc3 | ||
|  | 901f7c5c36 | ||
|  | 775bb413b3 | ||
|  | 64cd5b5a46 | ||
|  | ae356609b1 | ||
|  | 6102a5d2b0 | ||
|  | f8782ee2d7 | ||
|  | 6181ec4c77 | ||
|  | e0e7a685ef | ||
|  | ae1f8cdad2 | ||
|  | a4cf792e6d | ||
|  | 89109ded53 | ||
|  | e20e52a4b2 | ||
|  | 20c4b1cbec | ||
|  | 5238b0241d | ||
|  | 9cdf6c203d | ||
|  | 839335cae6 | ||
|  | a99b2ce167 | ||
|  | b695141d87 | ||
|  | 92d5c9f866 | ||
|  | 7f18a1ffe0 | ||
|  | 8c3fdaaa62 | ||
|  | 5ac1c69710 | ||
|  | de2d5fba63 | ||
|  | 33d516748f | ||
|  | de17f6f0fd | ||
|  | 756731fc02 | ||
|  | e46be0415f | ||
|  | aa02fb50bf | ||
|  | 8b6cd9c772 | ||
|  | cdd0d3351a | ||
|  | 8b6d584529 | ||
|  | f49fdd4141 | ||
|  | b26e1be81a | ||
|  | bacab38d7f | ||
|  | 701c05ce96 | ||
|  | 438c452585 | ||
|  | 0a7a1eff3f | ||
|  | 87e743e381 | ||
|  | a03f1b3d55 | ||
|  | 2d8dc3d243 | ||
|  | b982232cc5 | ||
|  | 61c8d728ac | ||
|  | 851a2bf855 | ||
|  | e0bdde3630 | ||
|  | 6a0dcd7f0e | ||
|  | 75f0b4c879 | ||
|  | db536a9504 | ||
|  | 0fb114dede | ||
|  | e703342179 | ||
|  | 35c8f4a611 | ||
|  | 7c89ae44a9 | ||
|  | 84fe06da22 | ||
|  | 806318c8b3 | ||
|  | 3aac2e1822 | ||
|  | 168baef433 | ||
|  | 6dba6cd78d | ||
|  | 502250d08f | ||
|  | 7395f0e680 | ||
|  | 494d3fdaca | ||
|  | 7b86a157de | ||
|  | 0988c41785 | ||
|  | 522db1bf01 | ||
|  | 06f066f90d | ||
|  | f37b20677b | ||
|  | cd2eac1032 | ||
|  | 8ac38d58d7 | ||
|  | 4c80cc313a | ||
|  | 1c65fee9b4 | ||
|  | 90dda7edc1 | ||
|  | da054fae20 | ||
|  | bdb6611e30 | ||
|  | 9284f973f1 | ||
|  | 2bfd64c3c9 | ||
|  | 939d24cce5 | ||
|  | 27b0183c46 | ||
|  | d14efacac7 | ||
|  | 150a002c40 | ||
|  | ce0def3bd8 | ||
|  | ee20fa97c2 | ||
|  | 7403b7d700 | ||
|  | 87ef173e0a | ||
|  | 52a3fb6bc7 | ||
|  | 92e2a257a6 | ||
|  | 32e175752c | ||
|  | d43f7180dc | ||
|  | 0129c2b0fc | ||
|  | 4ed1990001 | ||
|  | 5bd6ab27ae | ||
|  | f3593b89fa | ||
|  | 23d84b2310 | ||
|  | fdc49402ec | ||
|  | 5457c133e1 | ||
|  | 292e588ee3 | ||
|  | 243494c25e | ||
|  | e4365f3706 | ||
|  | 310f3038d3 | ||
|  | 4e6033273d | ||
|  | 73718586d3 | ||
|  | 011abe61e8 | ||
|  | fe3a37f89d | ||
|  | 8aea44e77b | ||
|  | 5529aec0d6 | ||
|  | 369549d23f | ||
|  | 181ea9a381 | ||
|  | 76b8f2854e | ||
|  | 320e5198f9 | ||
|  | e522539e2d | ||
|  | 7c996b83d2 | ||
|  | 3dd354d7aa | ||
|  | f4ad6e2157 | ||
|  | 8b170dc2bf | ||
|  | dcb9d779bf | ||
|  | 80f736d670 | ||
|  | 8502c6da3c | ||
|  | b131449422 | ||
|  | 6eebc4a620 | ||
|  | 4661ab1179 | ||
|  | 86046445ed | ||
|  | baea9bf944 | ||
|  | 0951ee9e63 | ||
|  | 5492528287 | ||
|  | 14dbd220c2 | ||
|  | babc890c59 | ||
|  | 6f7b47ff40 | ||
|  | 3991f03202 | ||
|  | 27271d5da7 | ||
|  | 627312e1de | ||
|  | bfc9550e4e | ||
|  | 2b9c21268b | ||
|  | 3dce4ed6f1 | ||
|  | 0f16c2ea87 | ||
|  | 9a635f0686 | ||
|  | 6a0d4b2baa | ||
|  | ac017098ad | ||
|  | 98fef2640d | ||
|  | 8bb66e133a | ||
|  | 68a582901d | ||
|  | c094f4c06e | ||
|  | f7ca545544 | ||
|  | 69b4716894 | ||
|  | 7e44dcc5bf | ||
|  | ab9843e183 | ||
|  | 01af706ade | ||
|  | 9ebdb08e99 | ||
|  | a74ffe25d9 | ||
|  | 7f95e27707 | ||
|  | 1facf5bba3 | ||
|  | 03d77009eb | ||
|  | 8afd6812b5 | ||
|  | ec9ad78fcf | ||
|  | 6f4e93dc90 | ||
|  | a38e43862d | ||
|  | 39294bb037 | ||
|  | edc5e59b78 | ||
|  | c00fd9fd37 | ||
|  | b3e621dd9f | ||
|  | 6e8c49b978 | ||
|  | 398d57133d | ||
|  | 16521a6feb | ||
|  | 3ca0b37a3e | ||
|  | cf2ec1229d | ||
|  | fe9b1e5f9b | ||
|  | f5b96ddf01 | ||
|  | 2fe076fb27 | ||
|  | 99249cff04 | ||
|  | 0cdf7b0613 | ||
|  | 90bcf4f157 | ||
|  | 03c3ec4e12 | ||
|  | ca9bb20d64 | ||
|  | c6bc078fd9 | ||
|  | 2f4bd6e52c | ||
|  | 2affe53727 | ||
|  | 09654d7dd8 | ||
|  | 90a4e37815 | ||
|  | 60889c0c79 | ||
|  | 20f3408d96 | ||
|  | e9d86789db | ||
|  | 5152b7c66c | ||
|  | c494c4e12c | ||
|  | 54d58ccb7e | ||
|  | 714a77bfbe | ||
|  | d48f8bf5cc | ||
|  | 99d97754a6 | ||
|  | b9d437de2a | ||
|  | 11403f2019 | ||
|  | 1ca102d639 | ||
|  | 339ba55111 | ||
|  | 14ae59885a | ||
|  | e3ef54f99b | ||
|  | 001901f9a9 | ||
|  | 6a98f60e2e | ||
|  | 6f2e24c47d | ||
|  | aafa368923 | ||
|  | eb783cab4c | ||
|  | 6533aa865a | ||
|  | f1a1e1bc07 | ||
|  | 953f4838dd | ||
|  | 130b892d34 | ||
|  | 6ad525c77e | ||
|  | d0ca74ad27 | ||
|  | 9806f69b4d | ||
|  | 34d9b5e3d7 | ||
|  | 3bf5189d86 | ||
|  | 12e5b0681b | ||
|  | 8c0285d608 | ||
|  | 36558fa3b8 | ||
|  | 235f940cde | ||
|  | 803d61fcbc | ||
|  | ffbd7d8de4 | ||
|  | 4ed924d7c7 | ||
|  | 798dc9948b | ||
|  | 13515f7ee4 | ||
|  | ef80824c26 | ||
|  | c8503fd65e | ||
|  | b3c454fb1c | ||
|  | 1d7723e873 | ||
|  | 77100b2365 | ||
|  | 259a788134 | ||
|  | 39511455cb | ||
|  | b04c16178e | ||
|  | 49a959c06e | ||
|  | 096a8932b4 | ||
|  | e39e66df93 | ||
|  | 513633f49a | ||
|  | eb3740daaf | ||
|  | f7947b148a | ||
|  | 9a2a702f3f | ||
|  | c65d95bf29 | ||
|  | 753a5edc4f | ||
|  | 0b3f853c2d | ||
|  | 3527fcf1d5 | ||
|  | 4544a89c7a | ||
|  | ffeae9005e | ||
|  | 47217bcfb7 | ||
|  | 80ff58b57a | ||
|  | d15dd368f1 | ||
|  | 8a2ec32bd8 | ||
|  | 410496ed52 | ||
|  | b7b07552e5 | ||
|  | 44486e80d9 | ||
|  | 7890c527d8 | ||
|  | 2c82ab79a7 | ||
|  | e3ebe5fc53 | ||
|  | 0ac430892e | ||
|  | a7739c942c | ||
|  | 24581482d0 | ||
|  | 0571c3b453 | ||
|  | 73e7f5a0b0 | ||
|  | 20c0adb961 | ||
|  | a01e03562f | ||
|  | d184ed0130 | ||
|  | 089e1c2aee | ||
|  | ebab0e91ee | ||
|  | 858a2b1b88 | ||
|  | 02bd59827c | ||
|  | 4991428510 | ||
|  | 3b245f5dc1 | ||
|  | c9c81da901 | ||
|  | 4919cdc3fb | ||
|  | e90e1f577d | ||
|  | afd4284403 | ||
|  | 150b350d31 | ||
|  | 2818520bd1 | ||
|  | 2819952292 | ||
|  | 5af71af51c | ||
|  | 07a55b51df | ||
|  | 66dd68b49d | ||
|  | 9812657777 | ||
|  | 0b09312fc6 | ||
|  | d0a7ac6b74 | ||
|  | ff9a238fbd | ||
|  | 359fffa5f1 | ||
|  | 5bf92ced1a | ||
|  | 340bcc7b45 | ||
|  | ef03742bd4 | ||
|  | 20431ec16d | ||
|  | becba8157b | ||
|  | 51fd3bb0eb | ||
|  | 4bbd3acb4e | ||
|  | 3bc930ea7b | ||
|  | d1b26f8e86 | ||
|  | fdf15caaff | ||
|  | c7b4a53c0b | ||
|  | af78dc0308 | ||
|  | 5ad39493c4 | ||
|  | 61f597b408 | ||
|  | 2162825240 | ||
|  | 2b780e70d1 | ||
|  | a3823f818e | ||
|  | 1f7c47bcaf | ||
|  | ec53c365a2 | ||
|  | 793ad1f2d4 | ||
|  | 9bc733b76c | ||
|  | 21b28f0217 | ||
|  | d3e23caa52 | ||
|  | 9e7518de67 | ||
|  | 679f0047aa | ||
|  | d77d5ce14b | ||
|  | 33ec22a2af | ||
|  | 353053225f | ||
|  | b7f3d6f7f7 | ||
|  | e34577499d | ||
|  | 4cf8960c0c | ||
|  | 1f93ea0675 | ||
|  | 25b705c3a8 | ||
|  | 0725588731 | ||
|  | fc5c61cc8b | ||
|  | ac282e63c6 | ||
|  | c3941941ce | ||
|  | 46cdd53323 | ||
|  | 3ff3e302c3 | ||
|  | f2ceecf95c | ||
|  | 9314c7c881 | ||
|  | 54abb2c572 | ||
|  | 8fa3bdd025 | ||
|  | 5e7a308528 | ||
|  | 7952177786 | ||
|  | 9afbe49c84 | ||
|  | 9f06ba2db3 | ||
|  | fe55bfddcf | ||
|  | c0842e6444 | ||
|  | 3fed20d06a | ||
|  | 5e8f2e2c04 | ||
|  | e4df99ea84 | ||
|  | b3276f5f11 | ||
|  | 32667ca256 | ||
|  | bed122a170 | ||
|  | 14adc9b875 | ||
|  | a8778bbc5a | ||
|  | a54e641f44 | ||
|  | 5c99efe87a | ||
|  | 7da1d731ff | ||
|  | af9828e819 | ||
|  | 7a27136142 | ||
|  | 012ad2d423 | ||
|  | ef3bdbf4da | ||
|  | b3bb698f7b | ||
|  | 1ed5d1e4c1 | ||
|  | bdee01a03d | ||
|  | 458f7376d7 | ||
|  | cb3a00e027 | ||
|  | 482eb1f3fb | ||
|  | 6e0f638f5e | ||
|  | bab349047d | ||
|  | 28ea6b8de8 | ||
|  | 9d51bbdae8 | ||
|  | d622f79533 | ||
|  | 04c8515ad1 | ||
|  | 53bc4251d1 | ||
|  | a5a751f02f | ||
|  | 66ed5f82c4 | ||
|  | c802a9e6aa | ||
|  | 880f210946 | ||
|  | 4f9f7eb6a6 | ||
|  | f910c4a8e7 | ||
|  | 529686d965 | ||
|  | 84dfd1536f | ||
|  | 85dedc324c | ||
|  | d639237411 | ||
|  | 449aaf75f1 | ||
|  | b1fda66caa | ||
|  | 66a8e90fd9 | ||
|  | 37b487d191 | ||
|  | 6c59fe3577 | ||
|  | 1cbb70c992 | ||
|  | e06b39f882 | ||
|  | 2602b1493e | ||
|  | 989d14502d | ||
|  | f78a550282 | ||
|  | 54a1abb284 | ||
|  | 97b492a8e2 | ||
|  | 0873bd14a9 | ||
|  | eff6ba429a | ||
|  | 8c18064be4 | ||
|  | 44a1ac0cf3 | ||
|  | 28dc8d88dd | ||
|  | 2c0c2b64ba | ||
|  | bd3e0f5248 | ||
|  | cd52d98938 | ||
|  | 894c70e7f8 | ||
|  | 51d70c2edd | ||
|  | 7d4b355240 | ||
|  | 3b56193b98 | ||
|  | b16045b57d | ||
|  | 9e8b0fca5b | ||
|  | 35cf1b3b5b | ||
|  | 83f788af57 | ||
|  | 2ffe378d3f | ||
|  | 38b33a4a5e | ||
|  | 60bf9ed0a0 | ||
|  | 16adf4de1b | ||
|  | 80de983023 | ||
|  | 8703ca623f | ||
|  | 286253a73f | ||
|  | bd806a41df | ||
|  | b89c4e9002 | ||
|  | 6dbf31c0c3 | ||
|  | 060c45d8a1 | ||
|  | 33d3e82e4d | ||
|  | 4bb074514d | ||
|  | e3f8892003 | ||
|  | 9d00ad5f18 | ||
|  | dae4344850 | ||
|  | aa7f3fabe2 | ||
|  | f93434a8ce | ||
|  | 25dee56be9 | ||
|  | ce9a3f3797 | ||
|  | 11e384920a | ||
|  | a0a1f1e536 | ||
|  | 3b3d0ea9eb | ||
|  | 2f4d78286d | ||
|  | 677dc6f985 | ||
|  | d52057e732 | ||
|  | fa2a1cb1fb | ||
|  | 19a0fb04ad | ||
|  | 947352f2fe | ||
|  | adcbedb686 | ||
|  | 7732f92acd | ||
|  | ad8a001688 | ||
|  | 9121eada08 | ||
|  | 49bd4d25a2 | ||
|  | d80b4129c6 | ||
|  | 7edb4172d5 | ||
|  | c3a4677990 | ||
|  | 5cbb893a3b | ||
|  | f28a2a432b | ||
|  | 03b75a2d27 | ||
|  | 859fe69083 | ||
|  | f6f2205ddb | ||
|  | 0f9a03ef61 | ||
|  | 9aa417c084 | ||
|  | 7b70952f5d | ||
|  | edd3d07b49 | ||
|  | 5293d0a4ec | ||
|  | 3c8c7beae1 | ||
|  | 9c3ba9fdcd | ||
|  | fb1748fb0f | ||
|  | 0a109fbd03 | ||
|  | 5cf64db74e | ||
|  | 488cc94f36 | ||
|  | e15846bf79 | ||
|  | 752bd00674 | ||
|  | 7fadfcbe32 | ||
|  | 41141e75bb | ||
|  | 50f641e627 | ||
|  | c7883fd093 | ||
|  | 4fcb24b2b1 | ||
|  | 5003557935 | ||
|  | bdf1ba84da | ||
|  | b0b4def983 | ||
|  | cc184bbe9e | ||
|  | ad30c830aa | ||
|  | 1d791a8af4 | ||
|  | e63c51cd97 | ||
|  | f202e32908 | ||
|  | 26e1a08e82 | ||
|  | 4d5119d435 | ||
|  | 75e34ea62e | ||
|  | 0a183d6274 | ||
|  | 21d8060aea | ||
|  | 9cbe906f60 | ||
|  | 8ce4137399 | ||
|  | 5f8a139347 | ||
|  | 9bb009a3fe | ||
|  | 726d65923f | ||
|  | 8a6be4cb2d | ||
|  | 10b06beb8e | ||
|  | 81318c7968 | ||
|  | 47a2c1c6e5 | ||
|  | 39cee65c6b | ||
|  | 8582ec724e | ||
|  | b0139682e8 | ||
|  | d39c475a6d | ||
|  | 48f38354c6 | ||
|  | cd5a920ed5 | ||
|  | 71bc1f378d | ||
|  | 0ee6c31cff | ||
|  | af89a9971e | ||
|  | c718a8ef72 | ||
|  | 8c8ad0faf0 | ||
|  | 314d5bbb7f | ||
|  | 102255757a | ||
|  | 914067a0d0 | ||
|  | 06e3ae2536 | ||
|  | 7f9b252556 | ||
|  | 3d700e243f | ||
|  | bcfc78ce11 | ||
|  | 09241765d5 | ||
|  | 671c83c265 | ||
|  | 772d28b766 | ||
|  | c26fcea58d | ||
|  | 1e5e26dbff | ||
|  | 742fc54864 | ||
|  | 49738f43c0 | ||
|  | 9f85f61010 | ||
|  | 239f422039 | ||
|  | 67af3c37be | ||
|  | a9442385c4 | ||
|  | 8c9cd10b8b | ||
|  | 72542059dd | ||
|  | a843fc6d40 | ||
|  | 4beed60c08 | ||
|  | 4049c1e480 | ||
|  | 8449314da2 | ||
|  | 63ad057028 | ||
|  | e720464330 | ||
|  | 24036afef9 | ||
|  | c78fa1a1bc | ||
|  | faa8b9022c | ||
|  | 729bafef7a | ||
|  | 590b028632 | ||
|  | 8150d00f36 | ||
|  | 060065926f | ||
|  | 70babe8a28 | ||
|  | c36e09664f | ||
|  | a9672246f3 | ||
|  | ff571884e9 | ||
|  | 475138bceb | ||
|  | 4a8af199c2 | ||
|  | bdabf5db72 | ||
|  | 6a5f21b34e | ||
|  | d608be103c | ||
|  | 374bb5d18a | ||
|  | 031d6c25ff | ||
|  | 223fb7b075 | ||
|  | a746741971 | ||
|  | 120faf2a58 | ||
|  | 990bca0dc6 | ||
|  | 3406472db7 | ||
|  | 1bd733c9f6 | ||
|  | 238c7f982e | ||
|  | fcb81147cb | ||
|  | 1915b73783 | ||
|  | ee79e621fb | ||
|  | d203275a3b | ||
|  | 9e8a996222 | ||
|  | 0126b0b3ed | ||
|  | 458928612c | ||
|  | e33f88e28d | ||
|  | be570bbf9e | ||
|  | f59b4be110 | ||
|  | 37336e41be | ||
|  | d24a1a3f0a | ||
|  | f7258955bd | ||
|  | 2a1eae5d6f | ||
|  | 50ee0a4adb | ||
|  | 955a26584e | ||
|  | 1d3e407c8f | ||
|  | cb809c4596 | ||
|  | 53bbe2888e | ||
|  | 7246f476a5 | ||
|  | 0785d1c390 | ||
|  | 85d2c49d14 | ||
|  | 8b77d62b7f | ||
|  | 373058a32a | ||
|  | e6293c2c8c | ||
|  | eff181c959 | ||
|  | 54752c2305 | ||
|  | b4753c044f | ||
|  | 26493424ae | ||
|  | 0282fd1332 | ||
|  | b9a019a08b | ||
|  | 66f6a0e687 | ||
|  | 2dd1b9f97d | ||
|  | 89615f3045 | ||
|  | 7e46192f67 | ||
|  | e78d985cdf | ||
|  | e8c4bf56fe | ||
|  | e6aa7d323d | ||
|  | fca8e25929 | ||
|  | 8e8ac286b4 | ||
|  | 7d9770b9a2 | ||
|  | 1996230460 | ||
|  | de7897a864 | ||
|  | e2884dcdb7 | ||
|  | 544a53a42b | ||
|  | 2e4787bfc8 | ||
|  | 1829eeb171 | ||
|  | c7488e3c4a | ||
|  | 3bf9606383 | ||
|  | 4f43f18f0a | ||
|  | 5b7f197397 | ||
|  | 018141c97f | ||
|  | 4d7813e57c | ||
|  | 605c60208f | ||
|  | 884fafcc30 | ||
|  | 56baa90320 | ||
|  | 6bb20ee09e | ||
|  | 541356430c | ||
|  | 2f4d91fd69 | ||
|  | f58c5e6b30 | ||
|  | 0311d0132c | ||
|  | c946c97402 | ||
|  | 84a6f51318 | ||
|  | 24a1501b0d | ||
|  | 383b6f5fcc | ||
|  | 633dd7ff9b | ||
|  | 580624fad6 | ||
|  | a8190f7efa | ||
|  | dd2157534b | ||
|  | 38a90e7669 | ||
|  | 6bfc526dcd | ||
|  | aadb8a7405 | ||
|  | 27082bf77e | ||
|  | a2903c80cd | ||
|  | 9a77c5369c | ||
|  | 3c30741a19 | ||
|  | 7028ad4ec0 | ||
|  | 8de750c6aa | ||
|  | 04f98de9ee | ||
|  | a1a019784b | ||
|  | 4aeeae77bd | ||
|  | 651cfc2b78 | ||
|  | 2ef8af25e2 | ||
|  | 0b13852a5b | ||
|  | 13427578c9 | ||
|  | d89ca2087e | ||
|  | 8b0ea9fba6 | ||
|  | 9f0b653d5a | ||
|  | 659a339233 | ||
|  | 4c29f177a0 | ||
|  | d664e63d55 | ||
|  | 2493509dbe | ||
|  | 1c8b27f554 | ||
|  | 68297b7186 | ||
|  | 34dd8d0a91 | ||
|  | 81c44790d5 | ||
|  | d557b335cf | ||
|  | e2adc28cff | ||
|  | 0fef6a6ecc | ||
|  | f2fd4b8a1f | ||
|  | 95bd5605a8 | ||
|  | 497cca7eca | ||
|  | 54f78feedd | ||
|  | 76408e53ae | ||
|  | be19e74d30 | ||
|  | dac578a775 | ||
|  | 04732ce74b | ||
|  | a6c95a2374 | ||
|  | f68622abe9 | ||
|  | 83a9a7bdb2 | ||
|  | 6500afc0ca | ||
|  | c69b7ecc96 | ||
|  | 615ef1e2d2 | ||
|  | cf69a0cd7f | ||
|  | 06e892fb33 | ||
|  | e6c5dd6865 | ||
|  | 247efdebdb | ||
|  | 76f3792287 | ||
|  | 64d8e2c727 | ||
|  | ead0bd9cb0 | ||
|  | 66fc13b2ec | ||
|  | f3af4128b0 | ||
|  | 0e43107c87 | ||
|  | 1ee3e7997e | ||
|  | 50fd61d91f | ||
|  | e4cdc051a9 | ||
|  | 778e846e96 | ||
|  | a27759b647 | ||
|  | b75eceab41 | ||
|  | e748a5d5f4 | ||
|  | 99c5a3ae46 | ||
|  | 51da710f5a | ||
|  | 569d69b3d2 | ||
|  | 059a6b1d90 | ||
|  | 990af7548a | ||
|  | a38aefdfc8 | ||
|  | 3bcb12e7d1 | ||
|  | 7904ecb462 | ||
|  | 9ba4d45109 | ||
|  | 56b8afe19d | ||
|  | f7aed9a94c | ||
|  | e12a7e881d | ||
|  | 5afb65325d | ||
|  | 135f520f32 | ||
|  | bc251f4ff6 | ||
|  | b8769751f6 | ||
|  | eff96d839e | ||
|  | aa34c23807 | ||
|  | 195acdac8c | ||
|  | 903e03c56c | ||
|  | 0892767b8a | ||
|  | 83ebfa772c | ||
|  | 1583641322 | ||
|  | 9510e2c256 | ||
|  | a9dbabe07e | ||
|  | 12884008fa | ||
|  | 02543bad1c | ||
|  | a8c56a5251 | ||
|  | 4e5a855f3f | ||
|  | 7e497a951e | ||
|  | cd08eabbfa | ||
|  | f7e62d9f81 | ||
|  | 9a3761e86e | ||
|  | 3619a68693 | ||
|  | efaf3c3bf9 | ||
|  | 0e4e6a6f67 | ||
|  | 42458e6278 | ||
|  | 41ec995377 | ||
|  | 4f37599326 | ||
|  | 4144520e5c | ||
|  | 6c4800546c | ||
|  | 733733c8a7 | ||
|  | 2aa67cc946 | ||
|  | 9385981a9d | ||
|  | fff780035d | ||
|  | 46127e673d | ||
|  | 70df59b224 | ||
|  | 0fdbaa803f | ||
|  | 6af1830eff | ||
|  | 6f860e2bd5 | ||
|  | 20a492f7ee | ||
|  | 63875e7591 | ||
|  | 0ad98cabde | ||
|  | 668879d2e1 | ||
|  | 2e09783302 | ||
|  | 49734114b3 | ||
|  | 950d9d6ee7 | ||
|  | f7974aee2e | ||
|  | c870a82621 | ||
|  | 984929a001 | ||
|  | 7f9e2c1db8 | ||
|  | 324e8389dc | ||
|  | 6f448c5a38 | ||
|  | ec43efbb20 | ||
|  | 3ed065de37 | ||
|  | 8152f0d72c | ||
|  | f8047f4736 | ||
|  | b93c66dc2d | ||
|  | ac877b3065 | ||
|  | dee8abfdde | ||
|  | cef3841d73 | ||
|  | 3cd5e8a041 | ||
|  | 515b5f866e | ||
|  | 321f62bf92 | ||
|  | f94fa47b52 | ||
|  | c502f8a722 | ||
|  | 59b4868ac3 | ||
|  | 3634e12cce | ||
|  | 6d45445391 | ||
|  | 4f47e268cc | ||
|  | 0035b31cdb | ||
|  | f2565aee03 | ||
|  | 5bd85668dd | ||
|  | 20f990b6ce | ||
|  | 6821379586 | ||
|  | 73b040eb49 | ||
|  | 49aa4b2e1e | ||
|  | 972241c74c | ||
|  | 680750e3c2 | ||
|  | 5e7d4d9d15 | ||
|  | 1e57e60613 | ||
|  | 3ac7ce605a | ||
|  | b720dea9f0 | ||
|  | c80722aefe | ||
|  | a84fa69f28 | ||
|  | e33781e59f | ||
|  | 8824bc7ece | ||
|  | c2e3b0e448 | ||
|  | f61a38e85a | ||
|  | d23e948216 | ||
|  | 58bdaa31f0 | ||
|  | b6491d88a6 | ||
|  | f6061ba62e | ||
|  | 427899ddce | ||
|  | c4ab7d2dbd | ||
|  | 0fd2ba033f | ||
|  | ed38939a93 | ||
|  | c7ee26ce5a | ||
|  | 909b8cb303 | ||
|  | b0277370cf | ||
|  | 2ec8656bea | ||
|  | b2ef256910 | ||
|  | 63d6ce95db | ||
|  | a9532b189c | ||
|  | 844545411f | ||
|  | 4e23a2b9b8 | ||
|  | 5deba027eb | ||
|  | fc8b7efc6f | ||
|  | a1c2d9c0f3 | ||
|  | 4ca49a0501 | ||
|  | 493c53d090 | ||
|  | b27e956d35 | ||
|  | 35ebed75c6 | ||
|  | 7bfdb5f77f | ||
|  | 8d8c02317f | ||
|  | a34482feab | ||
|  | cbdc8fd4a6 | ||
|  | 8d3afaa53c | ||
|  | 7ced9ef3df | ||
|  | e8a9ae7e80 | ||
|  | 73a88ab3d3 | ||
|  | aaed82738a | ||
|  | de7f7b96db | ||
|  | 1a669b3e68 | ||
|  | 333af9b13a | ||
|  | a5bca5e240 | ||
|  | c885633e02 | ||
|  | ca7e20b7ca | ||
|  | 545e11a3d7 | ||
|  | 44f5287664 | ||
|  | cf510897f1 | ||
|  | 1d171345f8 | ||
|  | 4fa7e1cd49 | ||
|  | acd008298e | ||
|  | 83a8021515 | ||
|  | cf88dfb1db | ||
|  | 8937c4b481 | ||
|  | cc6af10a4d | ||
|  | 6d94578955 | ||
|  | 08442ab71e | ||
|  | 10d91d213f | ||
|  | b7a3b06994 | ||
|  | 5f12c37f23 | ||
|  | 585edebccd | ||
|  | 9921c62234 | ||
|  | 1ac76d2e16 | ||
|  | 6e983bf400 | ||
|  | 6a8fd4fa6e | ||
|  | 3698eaa2d2 | ||
|  | 8d97ca433c | ||
|  | 23cc65e537 | ||
|  | 2f5a3c2bbe | ||
|  | f6485616cd | ||
|  | 6544fb43d9 | ||
|  | a954b32dcc | ||
|  | 426dc7836c | ||
|  | ff941ffc16 | ||
|  | a063c201df | ||
|  | e2be3fa0aa | ||
|  | 609da6fb50 | ||
|  | fc9f3ccec3 | ||
|  | f7baa67a0a | ||
|  | e8d78c2cdb | ||
|  | 9d33366092 | ||
|  | f5d61515c2 | ||
|  | 711a04a972 | ||
|  | e5b470a3f1 | ||
|  | 31820e1e22 | ||
|  | 4849e8cd6d | ||
|  | 77e3b460aa | ||
|  | b5321001f8 | ||
|  | 38eba9f5ea | ||
|  | ea6f399454 | ||
|  | f8bf2d7b7d | ||
|  | c4856caebb | ||
|  | fc1030bb22 | ||
|  | 9eb6cad8dc | ||
|  | 0fa2a78dce | ||
|  | a56fa1558b | ||
|  | 261c73a997 | ||
|  | 929c1333ca | ||
|  | 286a79d94d | ||
|  | 8b951f99da | ||
|  | abb449bca0 | ||
|  | bd084028d1 | ||
|  | 138a27570b | ||
|  | c2ed40a74f | ||
|  | a7e7a00cab | ||
|  | 64a31ab3cd | ||
|  | 71958bc0f1 | ||
|  | 366ec35612 | ||
|  | 3738f6e8ae | ||
|  | 051a8e2af1 | ||
|  | 2f43f28d5e | ||
|  | b64769754b | ||
|  | a97daa18d1 | ||
|  | b6556dce8b | ||
|  | aa8d8bc8b5 | ||
|  | 0800dcfdc4 | ||
|  | 12b0101e94 | ||
|  | 021b391a02 | ||
|  | d11e2b6057 | ||
|  | 264d90e7e5 | ||
|  | f9f3da9e78 | ||
|  | 6435b49153 | ||
|  | f9aa2941cf | ||
|  | 5a933d4bee | ||
|  | 5536aea0df | ||
|  | 976666d216 | ||
|  | 9a5bcd4392 | ||
|  | 812060a118 | ||
|  | 089b5052e6 | ||
|  | 874e5d72f4 | ||
|  | 6b11de1329 | ||
|  | 2245a7ad8d | ||
|  | ee5ec1b870 | ||
|  | 74ccfe851b | ||
|  | e1c24bd5a2 | ||
|  | 1349b79728 | ||
|  | d294d7604c | ||
|  | 01df2cf464 | ||
|  | 45b7322488 | ||
|  | b3055e992f | ||
|  | 3da548565c | ||
|  | a975e85548 | ||
|  | c4b5ade752 | ||
|  | a4b61b0794 | ||
|  | f6011184b8 | ||
|  | 74de118c6e | ||
|  | 9c25e77c17 | ||
|  | 440113e67e | ||
|  | a11b60c445 | ||
|  | a6052681ad | ||
|  | 482d50536a | ||
|  | 25c79a4fcd | ||
|  | 02946144ac | ||
|  | 71a360e9a3 | ||
|  | f7912d88b1 | ||
|  | 975101d7d2 | ||
|  | ef58c5ff55 | ||
|  | e10221804a | ||
|  | 284ed9ee0e | ||
|  | 5d7b961997 | ||
|  | c699a5c4b4 | ||
|  | 1f4ceb89cf | ||
|  | 0934ca0040 | ||
|  | 4738f892c2 | ||
|  | 33004fcf33 | ||
|  | 34d214c166 | ||
|  | a56cd92a1e | ||
|  | 7251348507 | ||
|  | 01cd5c84d6 | ||
|  | e210599fa6 | ||
|  | dbe7cee7e9 | ||
|  | 7370d88ceb | ||
|  | 34458e0c57 | ||
|  | 05c8c3abf2 | ||
|  | e9d464b4d3 | ||
|  | 6968c3ab9b | ||
|  | 131a8a9650 | ||
|  | 379ecbf9a9 | ||
|  | 7b9dfa9a28 | ||
|  | fbd0f5eed2 | ||
|  | 5970f904ae | ||
|  | 8cbcb2868d | ||
|  | 8ff2a4b026 | ||
|  | ae14d205a5 | ||
|  | ec5d560ec5 | ||
|  | fb543b53c0 | ||
|  | 39c16422e2 | ||
|  | 4d5b273ebe | ||
|  | ed6a860fad | ||
|  | 423e579292 | ||
|  | ee11aa9e75 | ||
|  | c46d20fa92 | ||
|  | dc8d17574c | ||
|  | 5c17cd04c8 | ||
|  | 67ada02076 | ||
|  | 32d94c2eaf | ||
|  | 687b39a12a | ||
|  | 705af407bf | ||
|  | 080052da2e | ||
|  | ef735fd92a | ||
|  | 17c16dcafc | ||
|  | a89b3018fb | ||
|  | 851e2ebd32 | ||
|  | 1225ce7fe8 | ||
|  | 7e77a31b96 | ||
|  | d146b9002f | ||
|  | 1f9d567b23 | ||
|  | ed1b3a023c | ||
|  | 1ca18f501a | ||
|  | 49588ccd98 | ||
|  | 098dedc092 | ||
|  | b06f6b9545 | ||
|  | ba3cb94999 | ||
|  | 74c67fbf4b | ||
|  | 32b46e4910 | ||
|  | ecf5539ed2 | ||
|  | ac9db4e4d5 | ||
|  | 0eb96094b0 | ||
|  | 30b3ac7dc5 | ||
|  | 0092790c7d | ||
|  | 28909d8a51 | ||
|  | b20cfbb7b6 | ||
|  | 97639bd0a8 | ||
|  | 161ec73c96 | ||
|  | 957d6bea15 | ||
|  | f8b6e5b414 | ||
|  | 1ab450870e | ||
|  | de45f4884c | ||
|  | 5da1f3e7c8 | ||
|  | 983014952b | ||
|  | 55298019a3 | ||
|  | a1ffc3f271 | ||
|  | 2fb60aa997 | ||
|  | f5ec76537a | ||
|  | 728491fd2b | ||
|  | d9d3f2b9e4 | ||
|  | 3fe4864f65 | ||
|  | 0b156f22a4 | ||
|  | 35b1d93813 | ||
|  | d770851ac0 | ||
|  | 989e7b1033 | ||
|  | c4e0eb7b49 | ||
|  | 71f5d0dac7 | ||
|  | 561b0c4381 | ||
|  | 995fbc7330 | ||
|  | 10ab8949c4 | ||
|  | c441202fea | ||
|  | ca261b0bee | ||
|  | 52f3709f67 | ||
|  | c2ca6187fe | ||
|  | 671a13d295 | ||
|  | 14c3e2eccf | ||
|  | 08e5b852c2 | ||
|  | 1c9606c824 | ||
|  | 3cd47b5c9b | ||
|  | aedc729087 | ||
|  | 5f7cfa3fa9 | ||
|  | 0083f30af5 | ||
|  | 4a06f05ef5 | ||
|  | 8f37cadce8 | ||
|  | a11603ca6c | ||
|  | 86274842e9 | ||
|  | cf9c955a44 | ||
|  | 55d828c35f | ||
|  | cdff28aca6 | ||
|  | b9da39274f | ||
|  | c379aa5782 | ||
|  | 9dcabac9dd | ||
|  | 794f3a2b9f | ||
|  | 2066121b7c | ||
|  | 0c4067f143 | ||
|  | 8aa69243b7 | ||
|  | 8697263bde | ||
|  | ea25c4f65c | ||
|  | 82ac3ebd7e | ||
|  | 13cb94909c | ||
|  | b57ca2a763 | ||
|  | 83c49e9745 | ||
|  | e15771d78d | ||
|  | 6edc4920ba | ||
|  | 302bb1bd93 | ||
|  | 529b1bceee | ||
|  | 42cd47d32e | ||
|  | 711d884c2e | ||
|  | 183d1c4674 | ||
|  | faed63a0bb | ||
|  | 53bff262f8 | ||
|  | 3251a708e4 | ||
|  | b5dbdbf7b2 | ||
|  | a9649e92c9 | ||
|  | b561f1fa8b | ||
|  | cecd7491b5 | ||
|  | 55a66322b5 | ||
|  | 155c31a2d7 | ||
|  | a89ce91089 | ||
|  | b897fe6700 | ||
|  | 548a351b06 | ||
|  | 4b1da57ca1 | ||
|  | 529aec7f25 | ||
|  | 1661e545cb | ||
|  | ec71d08878 | ||
|  | ac258b7dd7 | ||
|  | 0f57876233 | ||
|  | 1d25a3693d | ||
|  | 45fa428bf1 | ||
|  | 177fa80f1a | ||
|  | 3261261bfe | ||
|  | d4de7934f8 | ||
|  | c3475af809 | ||
|  | b12f707812 | ||
|  | 22c0c34d60 | ||
|  | a60b66f230 | ||
|  | 83f6e93628 | ||
|  | 222b5f0229 | ||
|  | 30aa383e26 | ||
|  | 676b401294 | ||
|  | ebf57159de | ||
|  | 199d2aafec | ||
|  | 81952f56fd | ||
|  | c5bac82b43 | ||
|  | 081b86109c | ||
|  | 8ac2028a75 | ||
|  | 264fed1c9f | ||
|  | dd59f7b2c7 | ||
|  | 9245a760db | ||
|  | b61b32bbc3 | ||
|  | 09b3914f5d | ||
|  | fe644e4c9e | ||
|  | 7b09bf2156 | ||
|  | 987d0aae66 | ||
|  | 9cbcbc1c22 | ||
|  | cfc4e2bc60 | ||
|  | a03405fa81 | ||
|  | d5c9ccbe6e | ||
|  | e52772d65f | ||
|  | 1e3259e728 | ||
|  | e905a20a60 | ||
|  | 88e2be7a33 | ||
|  | 8939131600 | ||
|  | ba37ebff8b | ||
|  | 28f4cb7e07 | ||
|  | db1e7102cd | ||
|  | 07eb7a5830 | ||
|  | b7c6c685fa | ||
|  | 212134df70 | ||
|  | 6eeb5528f5 | ||
|  | 54fad845c9 | ||
|  | d6c0de6fc7 | ||
|  | 649c8649f7 | ||
|  | da2f53d1b1 | ||
|  | 405139e3b8 | ||
|  | 4f8d347171 | ||
|  | bf0db4876c | ||
|  | 47a14884d6 | ||
|  | 3a7bbc8b08 | ||
|  | 1b1d65372c | ||
|  | fd2faaa16e | ||
|  | 0609cdb9ea | ||
|  | d3bb140f89 | ||
|  | b31dc66628 | ||
|  | 09476171a6 | ||
|  | 33dee813b5 | ||
|  | bb4e73c40b | ||
|  | b1f23ffa94 | ||
|  | b0e8cec1e7 | ||
|  | 5077ae19bc | ||
|  | 0d8447bf59 | ||
|  | c6cf08a274 | ||
|  | dc49ae519e | ||
|  | 904539476a | ||
|  | 3fbf02dc82 | ||
|  | c9392a840d | ||
|  | d164e8ab72 | ||
|  | 6dc62c9fb6 | ||
|  | 87a9684d66 | ||
|  | 94525e2f44 | ||
|  | b408b1b3b9 | ||
|  | 27c2f09e32 | ||
|  | 19bc4d3349 | ||
|  | f2b6c424d6 | ||
|  | a49d4453e9 | ||
|  | 65e50087b9 | ||
|  | 2d90f759d9 | ||
|  | 4230ac7674 | ||
|  | d96e9182e9 | ||
|  | 68c87b9616 | ||
|  | 7f8e9a0b6d | ||
|  | 81a229f2a5 | ||
|  | 8be7ae2733 | ||
|  | 846bca4cb1 | ||
|  | f36f353789 | ||
|  | 939a2731ed | ||
|  | 835dab97ff | ||
|  | fa904b53be | ||
|  | 0ec52dddce | ||
|  | c289355a3a | ||
|  | 02a13a5a18 | ||
|  | 6cf2a0281b | ||
|  | 120d35f9af | ||
|  | 2b15d5e7b3 | ||
|  | fc167bd3f0 | ||
|  | 91b04abf05 | ||
|  | 77faac8740 | ||
|  | 43b3d54855 | ||
|  | 69e9b85700 | ||
|  | 0b6d132759 | ||
|  | 7c233c6c0c | ||
|  | c35b290fa4 | ||
|  | 3d95cfb367 | ||
|  | b90fc3a56e | ||
|  | 1ef3fdccf5 | ||
|  | 02b7f77bd8 | ||
|  | 0ac7ead922 | ||
|  | da9d0e03ce | ||
|  | 120f65f672 | ||
|  | 200a14caa4 | ||
|  | 35bf6da8e2 | ||
|  | f08f70276c | ||
|  | 1ae50fd95b | ||
|  | 40512beb47 | ||
|  | 0d7f9b2c94 | ||
|  | 52f42140a7 | ||
|  | 3f6c50297f | ||
|  | f72d80afc5 | ||
|  | 7c5cb13b22 | ||
|  | d728750eb2 | ||
|  | 02a70e5667 | ||
|  | 44e51ea5fa | ||
|  | 87e201460a | ||
|  | 039bd945e2 | ||
|  | e9e52d2b4b | ||
|  | 2bf92e7399 | ||
|  | 5b0df241f0 | ||
|  | 76f5b05eff | ||
|  | 40fb6c998f | ||
|  | 33f50a342d | ||
|  | 81523ab68a | ||
|  | 2bf8cc62cf | ||
|  | 1ae8247af3 | ||
|  | 5ef32227ec | ||
|  | 6456e773bd | ||
|  | 234fe53ca3 | ||
|  | 7c93e7a7b3 | ||
|  | 8afc6c7f4b | ||
|  | 4609d0fa3a | ||
|  | d452c035c6 | ||
|  | 45113c8f5a | ||
|  | 0acdd3c62b | ||
|  | 96d7d0a33e | ||
|  | b6b280267b | ||
|  | 6e6d253b1a | ||
|  | d92c105db2 | ||
|  | 906db728d6 | ||
|  | c4b7411565 | ||
|  | de06396046 | ||
|  | ee6bfeb8e3 | ||
|  | 058347321f | ||
|  | feefe49324 | ||
|  | 187381a9a2 | ||
|  | 993dfa4368 | ||
|  | 7e35a16440 | ||
|  | e4eeb15926 | ||
|  | 634e0db26d | ||
|  | 56855c23e1 | ||
|  | 0b00f742e3 | ||
|  | b7ab3f673c | ||
|  | be04ea1e35 | ||
|  | 1f8e695802 | ||
|  | 2d82b2c64f | ||
|  | d076caf473 | ||
|  | c7abdefa31 | ||
|  | ba772c0bca | ||
|  | 5bad234119 | ||
|  | c7e7baaf23 | ||
|  | 36658a671b | ||
|  | 045f2e10ba | ||
|  | fb5a7db66d | ||
|  | ba7d33982e | ||
|  | c62279a755 | ||
|  | 17fa1a7ffb | ||
|  | e89ceac351 | ||
|  | 0b8c30c109 | ||
|  | 9ab0f463cc | ||
|  | 6433dda7b8 | ||
|  | fa7a2f4be4 | ||
|  | ba90e16505 | ||
|  | 008f710203 | ||
|  | df2740f126 | ||
|  | 2db89d143e | ||
|  | 0525d49da3 | ||
|  | e2b0745882 | ||
|  | 92e804fc50 | ||
|  | 67abf45576 | ||
|  | d2c9c814e7 | ||
|  | 22f8881a64 | ||
|  | 4ab20322fe | ||
|  | 5370eeecea | ||
|  | ba71cb5dd7 | ||
|  | 9aad6c2c52 | ||
|  | 4d9627f20c | ||
|  | c142492e91 | ||
|  | 6bf8d9e207 | ||
|  | 4f9a6168c1 | ||
|  | 38397f99aa | ||
|  | f8686d0e75 | ||
|  | 549e3c8f9d | ||
|  | bb56225b95 | ||
|  | f00be261ba | ||
|  | 9cd94f26d0 | ||
|  | 4d8f5c80a7 | ||
|  | 24a23acc3d | ||
|  | ca8703cfd8 | ||
|  | 6dcbb5b2f8 | ||
|  | a84fdddb2a | ||
|  | 38bb2f8ceb | ||
|  | 23f5ef4345 | ||
|  | ef8a2a9054 | ||
|  | 96103d0e36 | ||
|  | ff5f6748df | ||
|  | 1c1fd6c366 | ||
|  | 32d37d00cb | ||
|  | 82f6cda966 | ||
|  | f1ff8ff0d0 | ||
|  | 756c72902f | ||
|  | 73f8f0bbd0 | ||
|  | 18ed528f5d | ||
|  | 8fd2f136bc | ||
|  | 0524b1bf67 | ||
|  | 15716f65ce | ||
|  | d46bdba332 | ||
|  | 760728110a | ||
|  | 12d0a194ca | ||
|  | 4104543508 | ||
|  | 5c211db015 | ||
|  | 2dc6180f8d | ||
|  | e222a34b69 | ||
|  | ef17d95063 | ||
|  | 853502e5d7 | ||
|  | c18e297e77 | ||
|  | c5a49599ba | ||
|  | df9da9edf5 | ||
|  | e2200fd050 | ||
|  | c6207f5d9c | ||
|  | 4302b7ff6b | ||
|  | 50a7923438 | ||
|  | ab416445c8 | ||
|  | a54698d43c | ||
|  | c5a77cc1c0 | ||
|  | a9ffa811fc | ||
|  | 080a2608e0 | ||
|  | 57f2e83d6a | ||
|  | 5b030139d3 | ||
|  | 0da1ff42d1 | ||
|  | 2c599b7baa | ||
|  | 5c8af8d21a | ||
|  | 026f3cfde2 | ||
|  | f6349180e8 | ||
|  | aa6421921c | ||
|  | 7d41d2dab2 | ||
|  | f0b4d18f93 | ||
|  | 6750f06e10 | ||
|  | b2bd38fa9e | ||
|  | 3482a01e22 | ||
|  | 6335467552 | ||
|  | 4a39e65b62 | ||
|  | c50a23e918 | ||
|  | 1e76b72b98 | ||
|  | b94cf39eef | ||
|  | fef254ffff | ||
|  | e5495863a2 | ||
|  | 3b4df2abf0 | ||
|  | aef2aee6a4 | ||
|  | d0d9519149 | ||
|  | 685df1d2c5 | ||
|  | 08e6b6f2e7 | ||
|  | 66c887d0f3 | ||
|  | 22e9960697 | ||
|  | 64aa6e1f2d | ||
|  | 7a93ed9d04 | ||
|  | a905e922e9 | ||
|  | f9f08fc720 | ||
|  | 8d402d76d0 | ||
|  | 46fda6281c | ||
|  | a14dbe1ea6 | ||
|  | 18810a4c16 | ||
|  | 147bc80dba | ||
|  | c7a484195a | ||
|  | 4968eb6503 | ||
|  | a6f2d698a9 | ||
|  | ea5ed93ea5 | ||
|  | e1140134c6 | ||
|  | 5ed11e012e | ||
|  | 5380bd39ca | ||
|  | 2ee2685688 | ||
|  | 782002245b | ||
|  | 7fc0905843 | ||
|  | 72ecb99e54 | ||
|  | c863507d08 | ||
|  | cff86c9093 | ||
|  | 0479dfcc54 | ||
|  | 68dd67f21c | ||
|  | 540f6858b5 | ||
|  | b61e791a4f | ||
|  | d0986f9482 | ||
|  | 112cb0dc28 | ||
|  | 0d3d7fdcf2 | ||
|  | 5d6b89ef3b | ||
|  | ed0b26c09e | ||
|  | ae292bd920 | ||
|  | 6c85a90723 | ||
|  | 852592066c | ||
|  | 96e1bc9b44 | ||
|  | b41d81ed31 | ||
|  | e241ec2244 | ||
|  | 16e1f1a94c | ||
|  | 7a68c42b26 | ||
|  | 37ccc2e118 | ||
|  | 4192fe1ab2 | ||
|  | d5c743d7bb | ||
|  | 11814d63e8 | ||
|  | b753656d50 | ||
|  | f7e87611fc | ||
|  | 1fb0e1900e | ||
|  | 954a9731e0 | ||
|  | 65c3364ad8 | ||
|  | 3d72b7dccc | ||
|  | 13ee569f06 | ||
|  | d79ef23a75 | ||
|  | 5d0797d4ba | ||
|  | 47a8d7475f | ||
|  | 4939053121 | ||
|  | b525bf554e | ||
|  | f00285d2b2 | ||
|  | 040f8d6eda | ||
|  | 66d905325c | ||
|  | 8b0cd95e73 | ||
|  | d867cca6d9 | ||
|  | a28f736369 | ||
|  | 5c3a71cc59 | ||
|  | cef6dadb08 | ||
|  | 36be817a3e | ||
|  | 02f571f081 | ||
|  | 157159e487 | ||
|  | 02ada9f800 | ||
|  | 6fcf9a97bb | ||
|  | 17a5d8799f | ||
|  | 31f3fe7a22 | ||
|  | 89e46d3d83 | ||
|  | 885795e67d | ||
|  | 92bfb53dd4 | ||
|  | 4cecbeb115 | ||
|  | 5971480f55 | ||
|  | 05bebea511 | ||
|  | 76fa6c5cfb | ||
|  | 633b68b518 | ||
|  | 6913d8e995 | ||
|  | f3654e6f8d | ||
|  | d685dbcf22 | ||
|  | 6a57fa079e | ||
|  | 0a91d145ba | ||
|  | c2866e799d | ||
|  | d8cffcaae7 | ||
|  | 30abca7be2 | ||
|  | edce87f3fb | ||
|  | 66bac98fc2 | ||
|  | 59156de92b | ||
|  | e0d7d10600 | ||
|  | daaf862257 | ||
|  | 9de53d4b59 | ||
|  | f1571e2d46 | ||
|  | bd28d06298 | ||
|  | a24e4655eb | ||
|  | 20a6c8d8e5 | ||
|  | 98d264faf4 | ||
|  | 321902a9b5 | ||
|  | 8df5d06f9a | ||
|  | e69ea529cc | ||
|  | 15405b1119 | ||
|  | d2f97ce2da | ||
|  | 543ca631e9 | ||
|  | f184886db1 | ||
|  | 8432ab4324 | ||
|  | 6c05b37ca3 | ||
|  | 35f4beeb47 | ||
|  | cbad7caa68 | ||
|  | b0388a4012 | ||
|  | df3fab4d55 | ||
|  | da49f88a03 | ||
|  | e28feceb06 | ||
|  | 50496a164d | ||
|  | 6f1dce1572 | ||
|  | 6847776ae7 | ||
|  | 67bd53bdd8 | ||
|  | e735abfdfd | ||
|  | 1de93a2d6d | ||
|  | 36f9e7c742 | ||
|  | 9462763bbb | ||
|  | 4ae0880ea6 | ||
|  | 6ae2b6c835 | ||
|  | a0f180fd48 | ||
|  | bf1cf89914 | ||
|  | 297a047fb4 | ||
|  | 52ffc15ffc | ||
|  | e478c9c693 | ||
|  | d004f28074 | ||
|  | bc68ed8b1d | ||
|  | 04555ae650 | ||
|  | e8f62085be | ||
|  | f430bffe2a | ||
|  | 1f0520634f | ||
|  | 902d4c31fb | ||
|  | 17364ac09f | ||
|  | 0b889f8f81 | ||
|  | 40e349ff35 | ||
|  | c943b1b1df | ||
|  | 912bc1d4e1 | ||
|  | cacb1533a3 | ||
|  | f0feaca9d7 | ||
|  | b6656f171b | ||
|  | 6206ab3931 | ||
|  | c35fc58b1f | ||
|  | deed8abed7 | ||
|  | 7151ad23f0 | ||
|  | 0166d938af | ||
|  | 6194aeddb0 | ||
|  | 903dbf2c30 | ||
|  | 9380f9ff57 | ||
|  | 259ed95486 | ||
|  | 2ebc92681e | ||
|  | 195a1ffe13 | ||
|  | a8c2978185 | ||
|  | 140f97a457 | ||
|  | 7f94445a1e | ||
|  | 82a89aec65 | ||
|  | 7e95110232 | ||
|  | ec4aaaad89 | ||
|  | 1b790fde24 | ||
|  | aaccea731e | ||
|  | 29e31d7610 | ||
|  | aa51f4a98f | ||
|  | e6ccd12f00 | ||
|  | b134315df1 | ||
|  | 7f34dffa13 | ||
|  | fa239e78c9 | ||
|  | 707a6c4d6a | ||
|  | e5da303b43 | ||
|  | 84ccd66331 | ||
|  | ad8cc2baea | ||
|  | 7c4cf70309 | ||
|  | c3211e9b4f | ||
|  | 268d94c983 | ||
|  | 0bcacbba58 | ||
|  | 8cdc26add9 | ||
|  | e0b2238886 | ||
|  | 369a2e4029 | ||
|  | c4089e3b51 | ||
|  | 9e2e9bc5b8 | ||
|  | a9e44426ed | 
							
								
								
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Library General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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 software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| 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 | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  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 components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program 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 | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the 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. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| 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 | ||||
|  | ||||
|   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 | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| 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 | ||||
|  | ||||
| 	    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 | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year  name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Library General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										504
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,504 @@ | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		       Version 2.1, February 1999 | ||||
|  | ||||
|  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 Lesser GPL.  It also counts | ||||
|  as the successor of the GNU Library Public License, version 2, hence | ||||
|  the version number 2.1.] | ||||
|  | ||||
| 			    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 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 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 | ||||
| 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 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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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, 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.  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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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, whereas the latter must | ||||
| be combined with the library in order to run. | ||||
|  | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   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 | ||||
| (which use some of those functions and data) to form executables. | ||||
|  | ||||
|   The "Library", below, refers to any such software library or work | ||||
| which has been distributed under these terms.  A "work based on the | ||||
| Library" means either the Library or any derivative work under | ||||
| copyright law: that is to say, a work containing the Library or a | ||||
| portion of it, either verbatim or with modifications and/or translated | ||||
| straightforwardly into another language.  (Hereinafter, translation is | ||||
| included without limitation in the term "modification".) | ||||
|  | ||||
|   "Source code" for a work means the preferred form of the work for | ||||
| making modifications to it.  For a library, complete source code means | ||||
| all the source code for all modules it contains, plus any associated | ||||
| interface definition files, plus the scripts used to control compilation | ||||
| and installation of the library. | ||||
|  | ||||
|   Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running a program using the Library is not restricted, and output from | ||||
| such a program is covered only if its contents constitute a work based | ||||
| on the Library (independent of the use of the Library in a tool for | ||||
| writing it).  Whether that is true depends on what the Library does | ||||
| and what the program that uses the Library does. | ||||
|    | ||||
|   1. You may copy and distribute verbatim copies of the Library's | ||||
| complete source code as you receive it, in any medium, provided that | ||||
| you conspicuously and appropriately publish on each copy an | ||||
| appropriate copyright notice and disclaimer of warranty; keep intact | ||||
| all the notices that refer to this License and to the absence of any | ||||
| warranty; and distribute a copy of this License along with the | ||||
| Library. | ||||
|  | ||||
|   You may charge a fee for the physical act of transferring a copy, | ||||
| and you may at your option offer warranty protection in exchange for a | ||||
| fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Library or any portion | ||||
| of it, thus forming a work based on the Library, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) The modified work must itself be a software library. | ||||
|  | ||||
|     b) You must cause the files modified to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     c) You must cause the whole of the work to be licensed at no | ||||
|     charge to all third parties under the terms of this License. | ||||
|  | ||||
|     d) If a facility in the modified Library refers to a function or a | ||||
|     table of data to be supplied by an application program that uses | ||||
|     the facility, other than as an argument passed when the facility | ||||
|     is invoked, then you must make a good faith effort to ensure that, | ||||
|     in the event an application does not supply such function or | ||||
|     table, the facility still operates, and performs whatever part of | ||||
|     its purpose remains meaningful. | ||||
|  | ||||
|     (For example, a function in a library to compute square roots has | ||||
|     a purpose that is entirely well-defined independent of the | ||||
|     application.  Therefore, Subsection 2d requires that any | ||||
|     application-supplied function or table used by this function must | ||||
|     be optional: if the application does not supply it, the square | ||||
|     root function must still compute square roots.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Library, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Library, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote | ||||
| it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Library. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Library | ||||
| with the Library (or with a work based on the Library) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may opt to apply the terms of the ordinary GNU General Public | ||||
| License instead of this License to a given copy of the Library.  To do | ||||
| this, you must alter all the notices that refer to this License, so | ||||
| that they refer to the ordinary GNU General Public License, version 2, | ||||
| instead of to this License.  (If a newer version than version 2 of the | ||||
| ordinary GNU General Public License has appeared, then you can specify | ||||
| that version instead if you wish.)  Do not make any other change in | ||||
| these notices. | ||||
|  | ||||
|   Once this change is made in a given copy, it is irreversible for | ||||
| that copy, so the ordinary GNU General Public License applies to all | ||||
| subsequent copies and derivative works made from that copy. | ||||
|  | ||||
|   This option is useful when you wish to copy part of the code of | ||||
| the Library into a program that is not a library. | ||||
|  | ||||
|   4. You may copy and distribute the Library (or a portion or | ||||
| derivative of it, under Section 2) in object code or executable form | ||||
| under the terms of Sections 1 and 2 above provided that you accompany | ||||
| it with the complete corresponding machine-readable source code, which | ||||
| must be distributed under the terms of Sections 1 and 2 above on a | ||||
| medium customarily used for software interchange. | ||||
|  | ||||
|   If distribution of object code is made by offering access to copy | ||||
| from a designated place, then offering equivalent access to copy the | ||||
| source code from the same place satisfies the requirement to | ||||
| distribute the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   5. A program that contains no derivative of any portion of the | ||||
| Library, but is designed to work with the Library by being compiled or | ||||
| linked with it, is called a "work that uses the Library".  Such a | ||||
| work, in isolation, is not a derivative work of the Library, and | ||||
| therefore falls outside the scope of this License. | ||||
|  | ||||
|   However, linking a "work that uses the Library" with the Library | ||||
| creates an executable that is a derivative of the Library (because it | ||||
| contains portions of the Library), rather than a "work that uses the | ||||
| library".  The executable is therefore covered by this License. | ||||
| Section 6 states terms for distribution of such executables. | ||||
|  | ||||
|   When a "work that uses the Library" uses material from a header file | ||||
| that is part of the Library, the object code for the work may be a | ||||
| derivative work of the Library even though the source code is not. | ||||
| Whether this is true is especially significant if the work can be | ||||
| linked without the Library, or if the work is itself a library.  The | ||||
| threshold for this to be true is not precisely defined by law. | ||||
|  | ||||
|   If such an object file uses only numerical parameters, data | ||||
| structure layouts and accessors, and small macros and small inline | ||||
| functions (ten lines or less in length), then the use of the object | ||||
| file is unrestricted, regardless of whether it is legally a derivative | ||||
| work.  (Executables containing this object code plus portions of the | ||||
| Library will still fall under Section 6.) | ||||
|  | ||||
|   Otherwise, if the work is a derivative of the Library, you may | ||||
| 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 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 | ||||
| modification of the work for the customer's own use and reverse | ||||
| engineering for debugging such modifications. | ||||
|  | ||||
|   You must give prominent notice with each copy of the work that the | ||||
| Library is used in it and that the Library and its use are covered by | ||||
| this License.  You must supply a copy of this License.  If the work | ||||
| during execution displays copyright notices, you must include the | ||||
| copyright notice for the Library among them, as well as a reference | ||||
| directing the user to the copy of this License.  Also, you must do one | ||||
| of these things: | ||||
|  | ||||
|     a) Accompany the work with the complete corresponding | ||||
|     machine-readable source code for the Library including whatever | ||||
|     changes were used in the work (which must be distributed under | ||||
|     Sections 1 and 2 above); and, if the work is an executable linked | ||||
|     with the Library, with the complete machine-readable "work that | ||||
|     uses the Library", as object code and/or source code, so that the | ||||
|     user can modify the Library and then relink to produce a modified | ||||
|     executable containing the modified Library.  (It is understood | ||||
|     that the user who changes the contents of definitions files in the | ||||
|     Library will not necessarily be able to recompile the application | ||||
|     to use the modified definitions.) | ||||
|  | ||||
|     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. | ||||
|  | ||||
|     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. | ||||
|  | ||||
|     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 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. | ||||
|  | ||||
|   It may happen that this requirement contradicts the license | ||||
| restrictions of other proprietary libraries that do not normally | ||||
| accompany the operating system.  Such a contradiction means you cannot | ||||
| use both them and the Library together in an executable that you | ||||
| distribute. | ||||
|  | ||||
|   7. You may place library facilities that are a work based on the | ||||
| Library side-by-side in a single library together with other library | ||||
| facilities not covered by this License, and distribute such a combined | ||||
| library, provided that the separate distribution of the work based on | ||||
| the Library and of the other library facilities is otherwise | ||||
| permitted, and provided that you do these two things: | ||||
|  | ||||
|     a) Accompany the combined library with a copy of the same work | ||||
|     based on the Library, uncombined with any other library | ||||
|     facilities.  This must be distributed under the terms of the | ||||
|     Sections above. | ||||
|  | ||||
|     b) Give prominent notice with the combined library of the fact | ||||
|     that part of it is a work based on the Library, and explaining | ||||
|     where to find the accompanying uncombined form of the same work. | ||||
|  | ||||
|   8. You may not copy, modify, sublicense, link with, or distribute | ||||
| the Library except as expressly provided under this License.  Any | ||||
| attempt otherwise to copy, modify, sublicense, link with, or | ||||
| distribute the Library is void, and will automatically terminate your | ||||
| rights under this License.  However, parties who have received copies, | ||||
| or rights, from you under this License will not have their licenses | ||||
| terminated so long as such parties remain in full compliance. | ||||
|  | ||||
|   9. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Library or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Library (or any work based on the | ||||
| Library), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Library or works based on it. | ||||
|  | ||||
|   10. Each time you redistribute the Library (or any work based on the | ||||
| 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 with | ||||
| this License. | ||||
|  | ||||
|   11. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Library at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Library by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Library. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under any | ||||
| particular circumstance, the balance of the section is intended to apply, | ||||
| and the section as a whole is intended to apply in other circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   12. If the distribution and/or use of the Library is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Library under this License may add | ||||
| an explicit geographical distribution limitation excluding those countries, | ||||
| so that distribution is permitted only in or among countries not thus | ||||
| 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 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. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Library | ||||
| specifies a version number of this License which applies to it and | ||||
| "any later version", you have the option of following the terms and | ||||
| conditions either of that version or of any later version published by | ||||
| the Free Software Foundation.  If the Library does not specify a | ||||
| license version number, you may choose any version ever published by | ||||
| the Free Software Foundation. | ||||
|  | ||||
|   14. If you wish to incorporate parts of the Library into other free | ||||
| programs whose distribution conditions are incompatible with these, | ||||
| write to the author to ask for permission.  For software which is | ||||
| copyrighted by the Free Software Foundation, write to the Free | ||||
| Software Foundation; we sometimes 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 | ||||
|  | ||||
|   15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | ||||
| WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | ||||
| EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | ||||
| OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | ||||
| KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
| PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | ||||
| LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | ||||
| THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||
|  | ||||
|   16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | ||||
| WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | ||||
| AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | ||||
| FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | ||||
| CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | ||||
| LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | ||||
| RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | ||||
| 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 | ||||
|  | ||||
|            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 | ||||
| everyone can redistribute and change.  You can do so by permitting | ||||
| redistribution under these terms (or, alternatively, under the terms of the | ||||
| ordinary General Public License). | ||||
|  | ||||
|   To apply these terms, attach the following notices to the library.  It is | ||||
| safest to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least the | ||||
| "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the library's name and a brief idea of what it does.> | ||||
|     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 Lesser General Public | ||||
|     License as published by the Free Software Foundation; either | ||||
|     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 | ||||
|     Lesser General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Lesser General Public | ||||
|     License along with this library; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the library, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the | ||||
|   library `Frob' (a library for tweaking knobs) written by James Random Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1990 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| That's all there is to it! | ||||
|  | ||||
|  | ||||
							
								
								
									
										31
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| Installation | ||||
| ============ | ||||
|  | ||||
| 1) Generate custom makefiles. | ||||
|  | ||||
|    Run the 'configure' script from the top directory. | ||||
|  | ||||
|    If you don't want to include the LVM1 backwards-compatibility code use: | ||||
|      ./configure --with-lvm1=none  | ||||
|  | ||||
|    To separate the LVM1 support into a shared library loaded by lvm.conf use: | ||||
|      ./configure --with-lvm1=shared | ||||
|  | ||||
|    Use ./configure --help to see other options. | ||||
|  | ||||
| 2) Build and install. | ||||
|  | ||||
|    Run 'make' from the top directory to build everything you configured. | ||||
|    Run 'make install' to build and install everything you configured. | ||||
|  | ||||
|    If you only want the device-mapper libraries and tools use | ||||
|    'make device-mapper' or 'make install_device-mapper'. | ||||
|  | ||||
| 3) If using LVM2, create a configuration file. | ||||
|  | ||||
|    The tools will work fine without a configuration file being | ||||
|    present, but you ought to review the example file in doc/example.conf. | ||||
|  | ||||
| Please also refer to the WHATS_NEW file and the manual pages for the  | ||||
| individual commands. | ||||
|  | ||||
							
								
								
									
										110
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS = doc include man scripts | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| SUBDIRS += lib tools daemons libdm | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS += daemons/clvmd \ | ||||
| 	     daemons/dmeventd/plugins \ | ||||
| 	     lib/format1 \ | ||||
| 	     lib/format_pool \ | ||||
| 	     lib/locking \ | ||||
| 	     lib/mirror \ | ||||
| 	     lib/snapshot \ | ||||
| 	     test \ | ||||
| 	     po | ||||
|   DISTCLEAN_TARGETS += lib/misc/configure.h | ||||
|   DISTCLEAN_DIRS += lcov_reports* | ||||
| endif | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| libdm: include | ||||
| lib: libdm | ||||
| daemons: lib | ||||
| tools: lib device-mapper | ||||
| po: tools daemons | ||||
|  | ||||
| libdm.device-mapper: include.device-mapper | ||||
| daemons.device-mapper: libdm.device-mapper | ||||
| tools.device-mapper: libdm.device-mapper | ||||
| device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| daemons.pofile: lib.pofile | ||||
| po.pofile: tools.pofile daemons.pofile | ||||
| pofile: po.pofile | ||||
| endif | ||||
|  | ||||
| ifneq ("@CFLOW_CMD@", "") | ||||
| tools.cflow: lib.cflow | ||||
| cflow: tools.cflow | ||||
| endif | ||||
|  | ||||
| ifneq ("@CSCOPE_CMD@", "") | ||||
| cscope.out: tools | ||||
| 	@CSCOPE_CMD@ -b -R | ||||
| all: cscope.out | ||||
| endif | ||||
|  | ||||
| check: all | ||||
| 	$(MAKE) -C test all | ||||
|  | ||||
| ifneq ("@LCOV@", "") | ||||
| .PHONY: lcov-reset lcov lcov-dated | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),lcov-dated) | ||||
| LCOV_REPORTS_DIR=$(top_srcdir)/lcov_reports-$(shell date +%Y%m%d%k%M%S) | ||||
| else | ||||
| LCOV_REPORTS_DIR=$(top_srcdir)/lcov_reports | ||||
| endif | ||||
|  | ||||
| lcov-reset: | ||||
| 	$(LCOV) -d $(top_srcdir)/dmeventd --zerocounters | ||||
| 	$(LCOV) -d $(top_srcdir)/libdm --zerocounters | ||||
| 	$(LCOV) -d $(top_srcdir)/lib --zerocounters | ||||
| 	$(LCOV) -d $(top_srcdir)/tools --zerocounters | ||||
|  | ||||
| lcov: all | ||||
| 	$(RM) -rf $(LCOV_REPORTS_DIR) | ||||
| 	$(MKDIR_P) $(LCOV_REPORTS_DIR) | ||||
| 	$(LCOV) -b ${top_srcdir}/libdm -d $(top_srcdir)/libdm -c -o $(LCOV_REPORTS_DIR)/libdm.info | ||||
| 	$(LCOV) -b $(top_srcdir)/lib -d $(top_srcdir)/lib -c -o $(LCOV_REPORTS_DIR)/lib.info | ||||
| 	$(LCOV) -b $(top_srcdir)/tools -d $(top_srcdir)/tools -c -o $(LCOV_REPORTS_DIR)/tools.info | ||||
| 	DMEVENTD_INFO="$(LCOV_REPORTS_DIR)/dmeventd.info" ;\ | ||||
| 	DMEVENTD_INFO_A="-a $$DMEVENTDINFO" ;\ | ||||
| 	$(LCOV) -b $(top_srcdir)/dmeventd -d $(top_srcdir)/dmeventd -c -o $$DMEVENTD_INFO || DMEVENTD_INFO_A="" ;\ | ||||
| 	$(LCOV) $$DMEVENTD_INFO_A -a $(LCOV_REPORTS_DIR)/lib.info \ | ||||
| 		-a $(LCOV_REPORTS_DIR)/libdm.info \ | ||||
| 		-a $(LCOV_REPORTS_DIR)/tools.info \ | ||||
| 		-o $(LCOV_REPORTS_DIR)/lvm.info | ||||
| ifneq ("@GENHTML@", "") | ||||
| 	$(GENHTML) -o $(LCOV_REPORTS_DIR) -p $(top_srcdir) $(LCOV_REPORTS_DIR)/lvm.info | ||||
| endif | ||||
|  | ||||
| lcov-dated: lcov | ||||
|  | ||||
| endif | ||||
							
								
								
									
										29
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README
									
									
									
									
									
								
							| @@ -1,2 +1,27 @@ | ||||
| This is pretty much empty so far...if you can't see subdirectories, | ||||
| try 'cvs -f update' | ||||
| This tree contains the LVM2 and device-mapper tools and libraries. | ||||
|  | ||||
| For more information about LVM2 read the changelog in the WHATS_NEW file. | ||||
| Installation instructions are in INSTALL. | ||||
|  | ||||
| There is no warranty - see COPYING and COPYING.LIB. | ||||
|  | ||||
| Tarballs are available from: | ||||
|   ftp://sources.redhat.com/pub/lvm2/ | ||||
|  | ||||
| To access the CVS tree use: | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login | ||||
|   CVS password: cvs | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2 | ||||
|  | ||||
| Mailing list for general discussion related to LVM2: | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| Mailing list for LVM2 development, patches and commits: | ||||
|   lvm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| Mailing list for device-mapper development, including kernel patches | ||||
| and multipath-tools: | ||||
|   dm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel | ||||
|   | ||||
							
								
								
									
										1
									
								
								VERSION_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								VERSION_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 1.02.29-cvs (2008-11-10) | ||||
							
								
								
									
										360
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,360 @@ | ||||
| Version 1.02.29 - 10th November 2008 | ||||
| ==================================== | ||||
|   Merge device-mapper into the LVM2 tree. | ||||
|   Split out dm-logging.h from log.h. | ||||
|   Use lvm-types.h. | ||||
|   Add usrsbindir to configure. | ||||
|  | ||||
| Version 1.02.28 - 18th September 2008 | ||||
| ===================================== | ||||
|   Only resume devices in dm_tree_preload_children if size changes. | ||||
|   Extend deptree buffers so the largest possible device numbers fit. | ||||
|   Generate versioned libdevmapper-event.so. | ||||
|   Underline longer report help text headings. | ||||
|  | ||||
| Version 1.02.27 - 25th June 2008 | ||||
| ================================ | ||||
|   Align struct memblock in dbg_malloc for sparc. | ||||
|   Add --unquoted and --rows to dmsetup. | ||||
|   Avoid compiler warning about cast in dmsetup.c's OFFSET_OF macro. | ||||
|   Fix inverted no_flush debug message. | ||||
|   Remove --enable-jobs from configure. (Set at runtime instead.) | ||||
|   Bring configure.in and list.h into line with the lvm2 versions. | ||||
|  | ||||
| Version 1.02.26 - 6th June 2008 | ||||
| =============================== | ||||
|   Initialise params buffer to empty string in _emit_segment. | ||||
|   Skip add_dev_node when ioctls disabled. | ||||
|   Make dm_hash_iter safe against deletion. | ||||
|   Accept a NULL pointer to dm_free silently. | ||||
|   Add tables_loaded, readonly and suspended columns to reports. | ||||
|   Add --nameprefixes to dmsetup. | ||||
|   Add field name prefix option to reporting functions. | ||||
|   Calculate string size within dm_pool_grow_object. | ||||
|  | ||||
| Version 1.02.25 - 10th April 2008 | ||||
| ================================= | ||||
|   Remove redundant if-before-free tests. | ||||
|   Use log_warn for reporting field help text instead of log_print. | ||||
|   Change cluster mirror log type name (s/clustered_/clustered-/) | ||||
|  | ||||
| Version 1.02.24 - 20th December 2007 | ||||
| ==================================== | ||||
|   Fix deptree to pass new name to _resume_node after a rename. | ||||
|   Suppress other node operations if node is deleted. | ||||
|   Add node operation stack debug messages. | ||||
|   Report error when empty device name passed to readahead functions. | ||||
|   Fix minimum readahead debug message. | ||||
|  | ||||
| Version 1.02.23 - 5th December 2007 | ||||
| =================================== | ||||
|   Update dm-ioctl.h after removal of compat code. | ||||
|   Add readahead support to libdevmapper and dmsetup. | ||||
|   Fix double free in a libdevmapper-event error path. | ||||
|   Fix configure --with-dmeventd-path substitution. | ||||
|   Allow a DM_DEV_DIR environment variable to override /dev in dmsetup. | ||||
|   Create a libdevmapper.so.$LIB_VERSION symlink within the build tree. | ||||
|   Avoid static link failure with some SELinux libraries that require libpthread. | ||||
|   Remove obsolete dmfs code from tree and update INSTALL. | ||||
|  | ||||
| Version 1.02.22 - 21st August 2007 | ||||
| ================================== | ||||
|   Fix inconsistent licence notices: executables are GPLv2; libraries LGPLv2.1. | ||||
|   Update to use autoconf 2.61, while still supporting 2.57. | ||||
|   Avoid repeated dm_task free on some dm_event_get_registered_device errors. | ||||
|   Introduce log_sys_* macros from LVM2. | ||||
|   Export dm_fclose and dm_create_dir; remove libdm-file.h. | ||||
|   Don't log EROFS mkdir failures in _create_dir_recursive (for LVM2). | ||||
|   Add fclose wrapper dm_fclose that catches write failures (using ferror). | ||||
|  | ||||
| Version 1.02.21 - 13th July 2007 | ||||
| ================================ | ||||
|   Introduce _LOG_STDERR to send log_warn() messages to stderr not stdout. | ||||
|   Fix dmsetup -o devno string termination. (1.02.20) | ||||
|  | ||||
| Version 1.02.20 - 15th June 2007 | ||||
| ================================ | ||||
|   Fix default dmsetup report buffering and add --unbuffered. | ||||
|   Add tree-based and dependency fields to dmsetup reports. | ||||
|  | ||||
| Version 1.02.19 - 27th April 2007 | ||||
| ================================= | ||||
|   Standardise protective include file #defines. | ||||
|   Add regex functions to library. | ||||
|   Avoid trailing separator in reports when there are hidden sort fields. | ||||
|   Fix segfault in 'dmsetup status' without --showkeys against crypt target. | ||||
|   Deal with some more compiler warnings. | ||||
|   Introduce _add_field() and _is_same_field() to libdm-report.c. | ||||
|   Fix some libdevmapper-event and dmeventd memory leaks. | ||||
|   Remove unnecessary memset() return value checks. | ||||
|   Fix a few leaks in reporting error paths. [1.02.15+] | ||||
|  | ||||
| Version 1.02.18 - 13th February 2007 | ||||
| ==================================== | ||||
|   Improve dmeventd messaging protocol: drain pipe and tag messages. | ||||
|  | ||||
| Version 1.02.17 - 29th January 2007 | ||||
| =================================== | ||||
|   Add recent reporting options to dmsetup man page. | ||||
|   Revise some report fields names. | ||||
|   Add dmsetup 'help' command and update usage text. | ||||
|   Use fixed-size fields in report interface and reorder. | ||||
|  | ||||
| Version 1.02.16 - 25th January 2007 | ||||
| =================================== | ||||
|   Add some missing close() and fclose() return value checks. | ||||
|   Migrate dmsetup column-based output over to new libdevmapper report framework. | ||||
|   Add descriptions to reporting field definitions. | ||||
|   Add a dso-private variable to dmeventd dso interface. | ||||
|   Add dm_event_handler_[gs]et_timeout functions. | ||||
|   Streamline dm_report_field_* interface. | ||||
|   Add cmdline debug & version options to dmeventd. | ||||
|   Add DM_LIB_VERSION definition to configure.h. | ||||
|   Suppress 'Unrecognised field' error if report field is 'help'. | ||||
|   Add --separator and --sort to dmsetup (unused). | ||||
|   Make alignment flag optional when specifying report fields. | ||||
|  | ||||
| Version 1.02.15 - 17th January 2007 | ||||
| =================================== | ||||
|   Add basic reporting functions to libdevmapper. | ||||
|   Fix a malloc error path in dmsetup message. | ||||
|   More libdevmapper-event interface changes and fixes. | ||||
|   Rename dm_saprintf() to dm_asprintf(). | ||||
|   Report error if NULL pointer is supplied to dm_strdup_aux(). | ||||
|   Reinstate dm_event_get_registered_device. | ||||
|  | ||||
| Version 1.02.14 - 11th January 2007 | ||||
| =================================== | ||||
|   Add dm_saprintf(). | ||||
|   Use CFLAGS when linking so mixed sparc builds can supply -m64. | ||||
|   Add dm_tree_use_no_flush_suspend(). | ||||
|   Lots of dmevent changes including revised interface. | ||||
|   Export dm_basename(). | ||||
|   Cope with a trailing space when comparing tables prior to possible reload. | ||||
|   Fix dmeventd to cope if monitored device disappears. | ||||
|  | ||||
| Version 1.02.13 - 28 Nov 2006 | ||||
| ============================= | ||||
|   Update dmsetup man page (setgeometry & message). | ||||
|   Fix dmsetup free after getline with debug. | ||||
|   Suppress encryption key in 'dmsetup table' output unless --showkeys supplied. | ||||
|  | ||||
| Version 1.02.12 - 13 Oct 2006 | ||||
| ============================= | ||||
|   Avoid deptree attempting to suspend a device that's already suspended. | ||||
|  | ||||
| Version 1.02.11 -  12 Oct 2006 | ||||
| ============================== | ||||
|   Add suspend noflush support. | ||||
|   Add basic dmsetup loop support. | ||||
|   Switch dmsetup to use dm_malloc and dm_free. | ||||
|  | ||||
| Version 1.02.10 - 19 Sep 2006 | ||||
| ============================= | ||||
|   Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper. | ||||
|   Reorder mm bounds_check code to reduce window for a dmeventd race. | ||||
|  | ||||
| Version 1.02.09 - 15 Aug 2006 | ||||
| ============================= | ||||
|   Add --table argument to dmsetup for a one-line table. | ||||
|   Abort if errors are found during cmdline option processing. | ||||
|   Add lockfs indicator to debug output. | ||||
|  | ||||
| Version 1.02.08 - 17 July 2006 | ||||
| ============================== | ||||
|   Append full patch to check in emails. | ||||
|   Avoid duplicate dmeventd subdir with 'make distclean'. | ||||
|   Update dmsetup man page. | ||||
|   Add --force to dmsetup remove* to load error target. | ||||
|   dmsetup remove_all also performs mknodes. | ||||
|   Don't suppress identical table reloads if permission changes. | ||||
|   Fix corelog segment line. | ||||
|   Suppress some compiler warnings. | ||||
|  | ||||
| Version 1.02.07 - 11 May 2006 | ||||
| ============================= | ||||
|   Add DM_CORELOG flag to dm_tree_node_add_mirror_target(). | ||||
|   Avoid a dmeventd compiler warning. | ||||
|  | ||||
| Version 1.02.06 - 10 May 2006 | ||||
| ============================= | ||||
|   Move DEFS into configure.h. | ||||
|   Fix leaks in error paths found by coverity. | ||||
|   Remove dmsetup line buffer limitation. | ||||
|  | ||||
| Version 1.02.05 - 19 Apr 2006 | ||||
| ============================= | ||||
|   Separate install_include target in makefiles. | ||||
|   Separate out DEFS from CFLAGS. | ||||
|   Support pkg-config. | ||||
|   Check for libsepol. | ||||
|  | ||||
| Version 1.02.04 - 14 Apr 2006 | ||||
| ============================= | ||||
|   Bring dmsetup man page up-to-date. | ||||
|   Use name-based device refs if kernel doesn't support device number refs. | ||||
|   Fix memory leak (struct dm_ioctl) when struct dm_task is reused. | ||||
|   If _create_and_load_v4 fails part way through, revert the creation. | ||||
|   dmeventd thread/fifo fixes. | ||||
|   Add file & line to dm_strdup_aux(). | ||||
|   Add setgeometry. | ||||
|  | ||||
| Version 1.02.03 - 7 Feb 2006 | ||||
| ============================ | ||||
|   Add exported functions to set uid, gid and mode. | ||||
|   Rename _log to dm_log and export. | ||||
|   Add dm_tree_skip_lockfs. | ||||
|   Fix dm_strdup debug definition. | ||||
|   Fix hash function to avoid using a negative array offset. | ||||
|   Don't inline _find in hash.c and tidy signed/unsigned etc. | ||||
|   Fix libdevmapper.h #endif. | ||||
|   Fix dmsetup version driver version. | ||||
|   Add sync, nosync and block_on_error mirror log parameters. | ||||
|   Add hweight32. | ||||
|   Fix dmeventd build. | ||||
|  | ||||
| Version 1.02.02 - 2 Dec 2005 | ||||
| ============================ | ||||
|   dmeventd added. | ||||
|   Export dm_task_update_nodes. | ||||
|   Use names instead of numbers in messages when ioctls fail. | ||||
|  | ||||
| Version 1.02.01 - 23 Nov 2005 | ||||
| ============================= | ||||
|   Resume snapshot-origins last. | ||||
|   Drop leading zeros from dm_format_dev. | ||||
|   Suppress attempt to reload identical table. | ||||
|   Additional LVM- prefix matching for transitional period. | ||||
|  | ||||
| Version 1.02.00 - 10 Nov 2005 | ||||
| ============================= | ||||
|   Added activation functions to library. | ||||
|   Added return macros. | ||||
|   Also suppress error if device doesn't exist with DM_DEVICE_STATUS. | ||||
|   Export dm_set_selinux_context(). | ||||
|   Add dm_driver_version(). | ||||
|   Added dependency tree functions to library. | ||||
|   Added hash, bitset, pool, dbg_malloc to library. | ||||
|   Added ls --tree to dmsetup. | ||||
|   Added dmsetup --nolockfs support for suspend/reload. | ||||
|  | ||||
| Version 1.01.05 - 26 Sep 2005 | ||||
| ============================= | ||||
|   Resync list.h with LVM2. | ||||
|   Remember increased buffer size and use for subsequent calls. | ||||
|   On 'buffer full' condition, double buffer size and repeat ioctl. | ||||
|   Fix termination of getopt_long() option array. | ||||
|   Report 'buffer full' condition with v4 ioctl as well as with v1. | ||||
|  | ||||
| Version 1.01.04 - 2 Aug 2005 | ||||
| ============================ | ||||
|   Fix dmsetup ls -j and status --target with empty table. | ||||
|  | ||||
| Version 1.01.03 - 13 Jun 2005 | ||||
| ============================= | ||||
|   Use matchpathcon mode parameter. | ||||
|   Fix configure script to re-enable selinux. | ||||
|  | ||||
| Version 1.01.02 - 17 May 2005 | ||||
| ============================= | ||||
|   Call dm_lib_exit() and dm_lib_release() automatically now. | ||||
|   Add --target <target_type> filter to dmsetup table/status/ls. | ||||
|   Add --exec <command> to dmsetup ls. | ||||
|   Fix dmsetup getopt_long usage. | ||||
|  | ||||
| Version 1.01.01 - 29 Mar 2005 | ||||
| ============================= | ||||
|   Update dmsetup man page. | ||||
|   Drop-in devmap_name replacement. | ||||
|   Add option to compile without ioctl for testing. | ||||
|   Fix DM_LIB_VERSION sed. | ||||
|  | ||||
| Version 1.01.00 - 17 Jan 2005 | ||||
| ============================= | ||||
|   Add dm_task_no_open_count() to skip getting open_count. | ||||
|  | ||||
| Version 1.00.21 - 7 Jan 2005 | ||||
| ============================ | ||||
|   Fix /proc/devices parsing. | ||||
|  | ||||
| Version 1.00.20 - 6 Jan 2005 | ||||
| ============================ | ||||
|   Attempt to fix /dev/mapper/control transparently if it's wrong. | ||||
|   Configuration-time option for setting uid/gid/mode for /dev/mapper nodes. | ||||
|   Update kernel patches for 2.4.27/2.4.28-pre-4 (includes minor fixes). | ||||
|   Add --noheadings columns option for colon-separated dmsetup output. | ||||
|   Support device referencing by uuid or major/minor. | ||||
|   Warn if kernel data didn't fit in buffer. | ||||
|   Fix a printf. | ||||
|  | ||||
| Version 1.00.19 - 3 July 2004 | ||||
| ============================= | ||||
|   More autoconf fixes. | ||||
|   Fix a dmsetup newline. | ||||
|   Fix device number handling for 2.6 kernels. | ||||
|  | ||||
| Version 1.00.18 - 20 Jun 2004 | ||||
| ============================= | ||||
|   Fix a uuid free in libdm-iface. | ||||
|   Fix a targets string size calc in driver. | ||||
|   Add -c to dmsetup for column-based output. | ||||
|   Add target message-passing ioctl. | ||||
|  | ||||
| Version 1.00.17 - 17 Apr 2004 | ||||
| ============================= | ||||
|   configure --with-owner= --with-group= to avoid -o and -g args to 'install' | ||||
|   Fix library selinux linking. | ||||
|  | ||||
| Version 1.00.16 - 16 Apr 2004 | ||||
| ============================= | ||||
|   Ignore error setting selinux file context if fs doesn't support it. | ||||
|  | ||||
| Version 1.00.15 - 7 Apr 2004 | ||||
| ============================ | ||||
|   Fix status overflow check in kernel patches. | ||||
|  | ||||
| Version 1.00.14 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Fix static selinux build. | ||||
|  | ||||
| Version 1.00.13 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Add some basic selinux support. | ||||
|  | ||||
| Version 1.00.12 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Fix dmsetup.static install. | ||||
|  | ||||
| Version 1.00.11 - 5 Apr 2004 | ||||
| ============================ | ||||
|   configure --enable-static_link does static build in addition to dynamic. | ||||
|   Moved Makefile library targets definition into template. | ||||
|  | ||||
| Version 1.00.10 - 2 Apr 2004 | ||||
| ============================ | ||||
|   Fix DESTDIR handling. | ||||
|   Static build installs to dmsetup.static. | ||||
|   Basic support for internationalisation. | ||||
|   Minor Makefile tidy-ups/fixes. | ||||
|  | ||||
| Version 1.00.09 - 31 Mar 2004 | ||||
| ============================= | ||||
|   Update copyright notices to Red Hat. | ||||
|   Move full mknodes functionality from dmsetup into libdevmapper. | ||||
|   Avoid sscanf %as for uClibc compatibility. | ||||
|   Cope if DM_LIST_VERSIONS is not defined. | ||||
|   Add DM_LIST_VERSIONS functionality to kernel patches. | ||||
|   Generate new kernel patches for 2.4.26-rc1. | ||||
|  | ||||
| Version 1.00.08 - 27 Feb 2004 | ||||
| ============================= | ||||
|   Added 'dmsetup targets'. | ||||
|   Added event_nr support to 'dmsetup wait'. | ||||
|   Updated dmsetup man page. | ||||
|   Allow logging function to be reset to use internal one. | ||||
|   Bring log macros in line with LVM2 ones. | ||||
|   Added 'make install_static_lib' which installs libdevmapper.a. | ||||
|   Made configure/makefiles closer to LVM2 versions. | ||||
|   Fixed DESTDIR for make install/install_static_lib. | ||||
|   Updated README/INSTALL to reflect move to sources.redhat.com. | ||||
|   Updated autoconf files to 2003-06-17. | ||||
							
								
								
									
										1466
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1466
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										722
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										722
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,36 +1,62 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # install - install a program, script, or datafile | ||||
| # This comes from X11R5 (mit/util/scripts/install.sh). | ||||
|  | ||||
| scriptversion=2006-10-14.15 | ||||
|  | ||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||
| # later released in X11R6 (xc/config/util/install.sh) with the | ||||
| # following copyright and license. | ||||
| # | ||||
| # Copyright 1991 by the Massachusetts Institute of Technology | ||||
| # Copyright (C) 1994 X Consortium | ||||
| # | ||||
| # Permission to use, copy, modify, distribute, and sell this software and its | ||||
| # documentation for any purpose is hereby granted without fee, provided that | ||||
| # the above copyright notice appear in all copies and that both that | ||||
| # copyright notice and this permission notice appear in supporting | ||||
| # documentation, and that the name of M.I.T. not be used in advertising or | ||||
| # publicity pertaining to distribution of the software without specific, | ||||
| # written prior permission.  M.I.T. makes no representations about the | ||||
| # suitability of this software for any purpose.  It is provided "as is" | ||||
| # without express or implied warranty. | ||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| # of this software and associated documentation files (the "Software"), to | ||||
| # deal in the Software without restriction, including without limitation the | ||||
| # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| # sell copies of the Software, and to permit persons to whom the Software is | ||||
| # furnished to do so, subject to the following conditions: | ||||
| # | ||||
| # The above copyright notice and this permission notice shall be included in | ||||
| # all copies or substantial portions of the Software. | ||||
| # | ||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | ||||
| # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||||
| # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- | ||||
| # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| # | ||||
| # Except as contained in this notice, the name of the X Consortium shall not | ||||
| # be used in advertising or otherwise to promote the sale, use or other deal- | ||||
| # ings in this Software without prior written authorization from the X Consor- | ||||
| # tium. | ||||
| # | ||||
| # | ||||
| # FSF changes to this file are in the public domain. | ||||
| # | ||||
| # Calling this script install-sh is preferred over install.sh, to prevent | ||||
| # `make' implicit rules from creating a file called install from it | ||||
| # when there is no Makefile. | ||||
| # | ||||
| # This script is compatible with the BSD install script, but was written | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
| # from scratch. | ||||
|  | ||||
| nl=' | ||||
| ' | ||||
| IFS=" ""	$nl" | ||||
|  | ||||
| # set DOITPROG to echo to test this script | ||||
|  | ||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||
| doit="${DOITPROG-}" | ||||
| if test -z "$doit"; then | ||||
|   doit_exec=exec | ||||
| else | ||||
|   doit_exec=$doit | ||||
| fi | ||||
|  | ||||
|  | ||||
| # put in absolute paths if you don't have them in your path; or use env. vars. | ||||
| # Put in absolute file names if you don't have them in your path; | ||||
| # or use environment vars. | ||||
|  | ||||
| mvprog="${MVPROG-mv}" | ||||
| cpprog="${CPPROG-cp}" | ||||
| @@ -41,211 +67,441 @@ stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| transformbasename="" | ||||
| transform_arg="" | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd="" | ||||
| chgrpcmd="" | ||||
| stripcmd="" | ||||
| posix_glob= | ||||
| posix_mkdir= | ||||
|  | ||||
| # Desired mode of installed file. | ||||
| mode=0755 | ||||
|  | ||||
| chmodcmd=$chmodprog | ||||
| chowncmd= | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
| rmcmd="$rmprog -f" | ||||
| mvcmd="$mvprog" | ||||
| src="" | ||||
| dst="" | ||||
| dir_arg="" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
| dstarg= | ||||
| no_target_directory= | ||||
|  | ||||
| while [ x"$1" != x ]; do | ||||
|     case $1 in | ||||
| 	-c) instcmd="$cpprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||
|    or: $0 [OPTION]... -d DIRECTORIES... | ||||
|  | ||||
| 	-d) dir_arg=true | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| In the 1st form, copy SRCFILE to DSTFILE. | ||||
| In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | ||||
| In the 4th, create DIRECTORIES. | ||||
|  | ||||
| 	-m) chmodcmd="$chmodprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| Options: | ||||
| -c         (ignored) | ||||
| -d         create directories instead of installing files. | ||||
| -g GROUP   $chgrpprog installed files to GROUP. | ||||
| -m MODE    $chmodprog installed files to MODE. | ||||
| -o USER    $chownprog installed files to USER. | ||||
| -s         $stripprog installed files. | ||||
| -t DIRECTORY  install into DIRECTORY. | ||||
| -T         report an error if DSTFILE is a directory. | ||||
| --help     display this help and exit. | ||||
| --version  display version info and exit. | ||||
|  | ||||
| 	-o) chowncmd="$chownprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| Environment variables override the default commands: | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG | ||||
| " | ||||
|  | ||||
| 	-g) chgrpcmd="$chgrpprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| while test $# -ne 0; do | ||||
|   case $1 in | ||||
|     -c) shift | ||||
|         continue;; | ||||
|  | ||||
| 	-s) stripcmd="$stripprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -d) dir_arg=true | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -g) chgrpcmd="$chgrpprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     --help) echo "$usage"; exit $?;; | ||||
|  | ||||
| 	*)  if [ x"$src" = x ] | ||||
| 	    then | ||||
| 		src=$1 | ||||
| 	    else | ||||
| 		# this colon is to work around a 386BSD /bin/sh bug | ||||
| 		: | ||||
| 		dst=$1 | ||||
| 	    fi | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     esac | ||||
| done | ||||
|     -m) mode=$2 | ||||
|         shift | ||||
|         shift | ||||
| 	case $mode in | ||||
| 	  *' '* | *'	'* | *' | ||||
| '*	  | *'*'* | *'?'* | *'['*) | ||||
| 	    echo "$0: invalid mode: $mode" >&2 | ||||
| 	    exit 1;; | ||||
| 	esac | ||||
|         continue;; | ||||
|  | ||||
| if [ x"$src" = x ] | ||||
| then | ||||
| 	echo "install:	no input file specified" | ||||
| 	exit 1 | ||||
| else | ||||
| 	true | ||||
| fi | ||||
|     -o) chowncmd="$chownprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| if [ x"$dir_arg" != x ]; then | ||||
| 	dst=$src | ||||
| 	src="" | ||||
| 	 | ||||
| 	if [ -d $dst ]; then | ||||
| 		instcmd=: | ||||
| 		chmodcmd="" | ||||
| 	else | ||||
| 		instcmd=mkdir | ||||
| 	fi | ||||
| else | ||||
|     -s) stripcmd=$stripprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| # Waiting for this to be detected by the "$instcmd $src $dsttmp" command | ||||
| # might cause directories to be created, which would be especially bad  | ||||
| # if $src (and thus $dsttmp) contains '*'. | ||||
|  | ||||
| 	if [ -f $src -o -d $src ] | ||||
| 	then | ||||
| 		true | ||||
| 	else | ||||
| 		echo "install:  $src does not exist" | ||||
| 		exit 1 | ||||
| 	fi | ||||
| 	 | ||||
| 	if [ x"$dst" = x ] | ||||
| 	then | ||||
| 		echo "install:	no destination specified" | ||||
| 		exit 1 | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| # If destination is a directory, append the input filename; if your system | ||||
| # does not like double slashes in filenames, you may need to add some logic | ||||
|  | ||||
| 	if [ -d $dst ] | ||||
| 	then | ||||
| 		dst="$dst"/`basename $src` | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ## this sed command emulates the dirname command | ||||
| dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | ||||
|  | ||||
| # Make sure that the destination directory exists. | ||||
| #  this part is taken from Noah Friedman's mkinstalldirs script | ||||
|  | ||||
| # Skip lots of stat calls in the usual case. | ||||
| if [ ! -d "$dstdir" ]; then | ||||
| defaultIFS='	 | ||||
| ' | ||||
| IFS="${IFS-${defaultIFS}}" | ||||
|  | ||||
| oIFS="${IFS}" | ||||
| # Some sh's can't handle IFS=/ for some reason. | ||||
| IFS='%' | ||||
| set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` | ||||
| IFS="${oIFS}" | ||||
|  | ||||
| pathcomp='' | ||||
|  | ||||
| while [ $# -ne 0 ] ; do | ||||
| 	pathcomp="${pathcomp}${1}" | ||||
|     -t) dstarg=$2 | ||||
| 	shift | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
| 	if [ ! -d "${pathcomp}" ] ; | ||||
|         then | ||||
| 		$mkdirprog "${pathcomp}" | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|     -T) no_target_directory=true | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
| 	pathcomp="${pathcomp}/" | ||||
|     --version) echo "$0 $scriptversion"; exit $?;; | ||||
|  | ||||
|     --)	shift | ||||
| 	break;; | ||||
|  | ||||
|     -*)	echo "$0: invalid option: $1" >&2 | ||||
| 	exit 1;; | ||||
|  | ||||
|     *)  break;; | ||||
|   esac | ||||
| done | ||||
|  | ||||
| if test $# -ne 0 && test -z "$dir_arg$dstarg"; then | ||||
|   # When -d is used, all remaining arguments are directories to create. | ||||
|   # When -t is used, the destination is already specified. | ||||
|   # Otherwise, the last argument is the destination.  Remove it from $@. | ||||
|   for arg | ||||
|   do | ||||
|     if test -n "$dstarg"; then | ||||
|       # $@ is not empty: it contains at least $arg. | ||||
|       set fnord "$@" "$dstarg" | ||||
|       shift # fnord | ||||
|     fi | ||||
|     shift # arg | ||||
|     dstarg=$arg | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ] | ||||
| then | ||||
| 	$doit $instcmd $dst && | ||||
| if test $# -eq 0; then | ||||
|   if test -z "$dir_arg"; then | ||||
|     echo "$0: no input file specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|   # It's OK to call `install-sh -d' without argument. | ||||
|   # This can happen when creating conditional directories. | ||||
|   exit 0 | ||||
| fi | ||||
|  | ||||
| 	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && | ||||
| 	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && | ||||
| 	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && | ||||
| 	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi | ||||
| else | ||||
| if test -z "$dir_arg"; then | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
| # If we're going to rename the final executable, determine the name now. | ||||
|   # Set umask so as not to create temps with too-generous modes. | ||||
|   # However, 'strip' requires both read and write access to temps. | ||||
|   case $mode in | ||||
|     # Optimize common cases. | ||||
|     *644) cp_umask=133;; | ||||
|     *755) cp_umask=22;; | ||||
|  | ||||
| 	if [ x"$transformarg" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
|     *[0-7]) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw='% 200' | ||||
|       fi | ||||
|       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; | ||||
|     *) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw=,u+rw | ||||
|       fi | ||||
|       cp_umask=$mode$u_plus_rw;; | ||||
|   esac | ||||
| fi | ||||
|  | ||||
| for src | ||||
| do | ||||
|   # Protect names starting with `-'. | ||||
|   case $src in | ||||
|     -*) src=./$src ;; | ||||
|   esac | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     dst=$src | ||||
|     dstdir=$dst | ||||
|     test -d "$dstdir" | ||||
|     dstdir_status=$? | ||||
|   else | ||||
|  | ||||
|     # Waiting for this to be detected by the "$cpprog $src $dsttmp" command | ||||
|     # might cause directories to be created, which would be especially bad | ||||
|     # if $src (and thus $dsttmp) contains '*'. | ||||
|     if test ! -f "$src" && test ! -d "$src"; then | ||||
|       echo "$0: $src does not exist." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     if test -z "$dstarg"; then | ||||
|       echo "$0: no destination specified." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     dst=$dstarg | ||||
|     # Protect names starting with `-'. | ||||
|     case $dst in | ||||
|       -*) dst=./$dst ;; | ||||
|     esac | ||||
|  | ||||
|     # If destination is a directory, append the input filename; won't work | ||||
|     # if double slashes aren't ignored. | ||||
|     if test -d "$dst"; then | ||||
|       if test -n "$no_target_directory"; then | ||||
| 	echo "$0: $dstarg: Is a directory" >&2 | ||||
| 	exit 1 | ||||
|       fi | ||||
|       dstdir=$dst | ||||
|       dst=$dstdir/`basename "$src"` | ||||
|       dstdir_status=0 | ||||
|     else | ||||
|       # Prefer dirname, but fall back on a substitute if dirname fails. | ||||
|       dstdir=` | ||||
| 	(dirname "$dst") 2>/dev/null || | ||||
| 	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | ||||
| 	     X"$dst" : 'X\(//\)[^/]' \| \ | ||||
| 	     X"$dst" : 'X\(//\)$' \| \ | ||||
| 	     X"$dst" : 'X\(/\)' \| . 2>/dev/null || | ||||
| 	echo X"$dst" | | ||||
| 	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)[^/].*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\).*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 s/.*/./; q' | ||||
|       ` | ||||
|  | ||||
|       test -d "$dstdir" | ||||
|       dstdir_status=$? | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   obsolete_mkdir_used=false | ||||
|  | ||||
|   if test $dstdir_status != 0; then | ||||
|     case $posix_mkdir in | ||||
|       '') | ||||
| 	# Create intermediate dirs using mode 755 as modified by the umask. | ||||
| 	# This is like FreeBSD 'install' as of 1997-10-28. | ||||
| 	umask=`umask` | ||||
| 	case $stripcmd.$umask in | ||||
| 	  # Optimize common cases. | ||||
| 	  *[2367][2367]) mkdir_umask=$umask;; | ||||
| 	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; | ||||
|  | ||||
| 	  *[0-7]) | ||||
| 	    mkdir_umask=`expr $umask + 22 \ | ||||
| 	      - $umask % 100 % 40 + $umask % 20 \ | ||||
| 	      - $umask % 10 % 4 + $umask % 2 | ||||
| 	    `;; | ||||
| 	  *) mkdir_umask=$umask,go-w;; | ||||
| 	esac | ||||
|  | ||||
| 	# With -d, create the new directory with the user-specified mode. | ||||
| 	# Otherwise, rely on $mkdir_umask. | ||||
| 	if test -n "$dir_arg"; then | ||||
| 	  mkdir_mode=-m$mode | ||||
| 	else | ||||
| 		dstfile=`basename $dst $transformbasename |  | ||||
| 			sed $transformarg`$transformbasename | ||||
| 	  mkdir_mode= | ||||
| 	fi | ||||
|  | ||||
| # don't allow the sed command to completely eliminate the filename | ||||
| 	posix_mkdir=false | ||||
| 	case $umask in | ||||
| 	  *[123567][0-7][0-7]) | ||||
| 	    # POSIX mkdir -p sets u+wx bits regardless of umask, which | ||||
| 	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0. | ||||
| 	    ;; | ||||
| 	  *) | ||||
| 	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ | ||||
| 	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 | ||||
|  | ||||
| 	if [ x"$dstfile" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	    if (umask $mkdir_umask && | ||||
| 		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 | ||||
| 	    then | ||||
| 	      if test -z "$dir_arg" || { | ||||
| 		   # Check for POSIX incompatibilities with -m. | ||||
| 		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | ||||
| 		   # other-writeable bit of parent directory when it shouldn't. | ||||
| 		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | ||||
| 		   ls_ld_tmpdir=`ls -ld "$tmpdir"` | ||||
| 		   case $ls_ld_tmpdir in | ||||
| 		     d????-?r-*) different_mode=700;; | ||||
| 		     d????-?--*) different_mode=755;; | ||||
| 		     *) false;; | ||||
| 		   esac && | ||||
| 		   $mkdirprog -m$different_mode -p -- "$tmpdir" && { | ||||
| 		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"` | ||||
| 		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" | ||||
| 		   } | ||||
| 		 } | ||||
| 	      then posix_mkdir=: | ||||
| 	      fi | ||||
| 	      rmdir "$tmpdir/d" "$tmpdir" | ||||
| 	    else | ||||
| 	      # Remove any dirs left behind by ancient mkdir implementations. | ||||
| 	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null | ||||
| 	    fi | ||||
| 	    trap '' 0;; | ||||
| 	esac;; | ||||
|     esac | ||||
|  | ||||
|     if | ||||
|       $posix_mkdir && ( | ||||
| 	umask $mkdir_umask && | ||||
| 	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" | ||||
|       ) | ||||
|     then : | ||||
|     else | ||||
|  | ||||
|       # The umask is ridiculous, or mkdir does not conform to POSIX, | ||||
|       # or it failed possibly due to a race condition.  Create the | ||||
|       # directory the slow way, step by step, checking for races as we go. | ||||
|  | ||||
|       case $dstdir in | ||||
| 	/*) prefix=/ ;; | ||||
| 	-*) prefix=./ ;; | ||||
| 	*)  prefix= ;; | ||||
|       esac | ||||
|  | ||||
|       case $posix_glob in | ||||
|         '') | ||||
| 	  if (set -f) 2>/dev/null; then | ||||
| 	    posix_glob=true | ||||
| 	  else | ||||
| 	    posix_glob=false | ||||
| 	  fi ;; | ||||
|       esac | ||||
|  | ||||
|       oIFS=$IFS | ||||
|       IFS=/ | ||||
|       $posix_glob && set -f | ||||
|       set fnord $dstdir | ||||
|       shift | ||||
|       $posix_glob && set +f | ||||
|       IFS=$oIFS | ||||
|  | ||||
|       prefixes= | ||||
|  | ||||
|       for d | ||||
|       do | ||||
| 	test -z "$d" && continue | ||||
|  | ||||
| 	prefix=$prefix$d | ||||
| 	if test -d "$prefix"; then | ||||
| 	  prefixes= | ||||
| 	else | ||||
| 		true | ||||
| 	  if $posix_mkdir; then | ||||
| 	    (umask=$mkdir_umask && | ||||
| 	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break | ||||
| 	    # Don't fail if two instances are running concurrently. | ||||
| 	    test -d "$prefix" || exit 1 | ||||
| 	  else | ||||
| 	    case $prefix in | ||||
| 	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; | ||||
| 	      *) qprefix=$prefix;; | ||||
| 	    esac | ||||
| 	    prefixes="$prefixes '$qprefix'" | ||||
| 	  fi | ||||
| 	fi | ||||
| 	prefix=$prefix/ | ||||
|       done | ||||
|  | ||||
| # Make a temp file name in the proper directory. | ||||
|       if test -n "$prefixes"; then | ||||
| 	# Don't fail if two instances are running concurrently. | ||||
| 	(umask $mkdir_umask && | ||||
| 	 eval "\$doit_exec \$mkdirprog $prefixes") || | ||||
| 	  test -d "$dstdir" || exit 1 | ||||
| 	obsolete_mkdir_used=true | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
| 	dsttmp=$dstdir/#inst.$$# | ||||
|   if test -n "$dir_arg"; then | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && | ||||
|     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && | ||||
|     { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || | ||||
|       test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 | ||||
|   else | ||||
|  | ||||
| # Move or copy the file name to the temp name | ||||
|     # Make a couple of temp file names in the proper directory. | ||||
|     dsttmp=$dstdir/_inst.$$_ | ||||
|     rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
| 	$doit $instcmd $src $dsttmp && | ||||
|     # Trap to clean up those temp files at exit. | ||||
|     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | ||||
|  | ||||
| 	trap "rm -f ${dsttmp}" 0 && | ||||
|     # Copy the file name to the temp name. | ||||
|     (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && | ||||
|  | ||||
| # and set any options; do chmod last to preserve setuid bits | ||||
|     # and set any options; do chmod last to preserve setuid bits. | ||||
|     # | ||||
|     # If any of these fail, we abort the whole thing.  If we want to | ||||
|     # ignore errors from any of these, just make sure not to ignore | ||||
|     # errors from the above "$doit $cpprog $src $dsttmp" command. | ||||
|     # | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ | ||||
|       && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ | ||||
|       && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ | ||||
|       && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | ||||
|  | ||||
| # If any of these fail, we abort the whole thing.  If we want to | ||||
| # ignore errors from any of these, just make sure not to ignore | ||||
| # errors from the above "$doit $instcmd $src $dsttmp" command. | ||||
|     # Now rename the file to the real destination. | ||||
|     { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ | ||||
|       || { | ||||
| 	   # The rename failed, perhaps because mv can't rename something else | ||||
| 	   # to itself, or perhaps because mv is so ancient that it does not | ||||
| 	   # support -f. | ||||
|  | ||||
| 	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && | ||||
| 	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && | ||||
| 	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && | ||||
| 	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && | ||||
| 	   # Now remove or move aside any old file at destination location. | ||||
| 	   # We try this two ways since rm can't unlink itself on some | ||||
| 	   # systems and the destination file might be busy for other | ||||
| 	   # reasons.  In this case, the final cleanup might fail but the new | ||||
| 	   # file should still install successfully. | ||||
| 	   { | ||||
| 	     if test -f "$dst"; then | ||||
| 	       $doit $rmcmd -f "$dst" 2>/dev/null \ | ||||
| 	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ | ||||
| 		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ | ||||
| 	       || { | ||||
| 		 echo "$0: cannot unlink or rename $dst" >&2 | ||||
| 		 (exit 1); exit 1 | ||||
| 	       } | ||||
| 	     else | ||||
| 	       : | ||||
| 	     fi | ||||
| 	   } && | ||||
|  | ||||
| # Now rename the file to the real destination. | ||||
| 	   # Now rename the file to the real destination. | ||||
| 	   $doit $mvcmd "$dsttmp" "$dst" | ||||
| 	 } | ||||
|     } || exit 1 | ||||
|  | ||||
| 	$doit $rmcmd -f $dstdir/$dstfile && | ||||
| 	$doit $mvcmd $dsttmp $dstdir/$dstfile  | ||||
|     trap '' 0 | ||||
|   fi | ||||
| done | ||||
|  | ||||
| fi && | ||||
|  | ||||
|  | ||||
| exit 0 | ||||
| # Local variables: | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
| # time-stamp-start: "scriptversion=" | ||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||
| # time-stamp-end: "$" | ||||
| # End: | ||||
|   | ||||
							
								
								
									
										815
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										815
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,815 @@ | ||||
| ############################################################################### | ||||
| ## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved. | ||||
| ## Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
| ## | ||||
| ## This copyrighted material is made available to anyone wishing to use, | ||||
| ## modify, copy, or redistribute it subject to the terms and conditions | ||||
| ## of the GNU General Public License v.2. | ||||
| ## | ||||
| ## 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| ################################################################################ | ||||
|  | ||||
| AC_PREREQ(2.57) | ||||
| ################################################################################ | ||||
| dnl -- Process this file with autoconf to produce a configure script. | ||||
| AC_INIT | ||||
| AC_CONFIG_SRCDIR([lib/device/dev-cache.h]) | ||||
| AC_CONFIG_HEADERS([lib/misc/configure.h]) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the directory where autoconf has auxilary files | ||||
| AC_CONFIG_AUX_DIR(autoconf) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Get system type | ||||
| AC_CANONICAL_TARGET([]) | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		COPTIMISE_FLAG="-O2" | ||||
| 		CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym" | ||||
| 		CLDWHOLEARCHIVE="-Wl,-whole-archive" | ||||
| 		CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" | ||||
| 		LDDEPS="$LDDEPS .export.sym" | ||||
| 		LDFLAGS="$LDFLAGS -Wl,--export-dynamic" | ||||
| 		LIB_SUFFIX=so | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=yes | ||||
| 		DM_IOCTLS=yes | ||||
| 		SELINUX=yes | ||||
| 		REALTIME=yes | ||||
| 		CLUSTER=internal | ||||
| 		FSADM=yes | ||||
| 		;; | ||||
| 	darwin*) | ||||
| 		CFLAGS="$CFLAGS -no-cpp-precomp -fno-common" | ||||
| 		COPTIMISE_FLAG="-O2" | ||||
| 		CLDFLAGS="$CLDFLAGS" | ||||
| 		CLDWHOLEARCHIVE="-all_load" | ||||
| 		CLDNOWHOLEARCHIVE= | ||||
| 		LIB_SUFFIX=dylib | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=no | ||||
| 		DM_IOCTLS=no | ||||
| 		SELINUX=no | ||||
| 		REALTIME=no | ||||
| 		CLUSTER=none | ||||
| 		FSADM=no | ||||
| 		;; | ||||
| esac | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for programs. | ||||
| AC_PROG_SED | ||||
| AC_PROG_AWK | ||||
| AC_PROG_CC | ||||
|  | ||||
| dnl probably no longer needed in 2008, but... | ||||
| AC_PROG_GCC_TRADITIONAL | ||||
| AC_PROG_INSTALL | ||||
| AC_PROG_LN_S | ||||
| AC_PROG_MAKE_SET | ||||
| AC_PROG_MKDIR_P | ||||
| AC_PROG_RANLIB | ||||
| AC_PATH_PROG(CFLOW_CMD, cflow) | ||||
| AC_PATH_PROG(CSCOPE_CMD, cscope) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for header files. | ||||
| AC_HEADER_DIRENT | ||||
| AC_HEADER_STDC | ||||
| AC_HEADER_SYS_WAIT | ||||
| AC_HEADER_TIME | ||||
|  | ||||
| AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \ | ||||
|   libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h sys/wait.h time.h], , | ||||
|   [AC_MSG_ERROR(bailing out)]) | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;; | ||||
| 	darwin*) | ||||
| 		AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;; | ||||
| esac | ||||
|  | ||||
| AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \ | ||||
|   stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \ | ||||
|   sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)]) | ||||
| AC_CHECK_HEADERS(termios.h sys/statvfs.h) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for typedefs, structures, and compiler characteristics. | ||||
| AC_C_CONST | ||||
| AC_C_INLINE | ||||
| AC_CHECK_MEMBERS([struct stat.st_rdev]) | ||||
| AC_TYPE_OFF_T | ||||
| AC_TYPE_PID_T | ||||
| AC_TYPE_SIGNAL | ||||
| AC_TYPE_SIZE_T | ||||
| AC_TYPE_MODE_T | ||||
| AC_CHECK_MEMBERS([struct stat.st_rdev]) | ||||
| AC_STRUCT_TM | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for functions | ||||
| AC_CHECK_FUNCS([gethostname getpagesize memset mkdir rmdir munmap setlocale \ | ||||
|   strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul \ | ||||
|   uname], , [AC_MSG_ERROR(bailing out)]) | ||||
| AC_FUNC_ALLOCA | ||||
| AC_FUNC_CLOSEDIR_VOID | ||||
| AC_FUNC_FORK | ||||
| AC_FUNC_LSTAT | ||||
| AC_FUNC_MALLOC | ||||
| AC_FUNC_MEMCMP | ||||
| AC_FUNC_MMAP | ||||
| AC_FUNC_STAT | ||||
| AC_FUNC_STRTOD | ||||
| AC_FUNC_VPRINTF | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Prefix is /usr by default, the exec_prefix default is setup later | ||||
| AC_PREFIX_DEFAULT(/usr) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the ownership of the files | ||||
| AC_MSG_CHECKING(file owner) | ||||
| OWNER="root" | ||||
|  | ||||
| AC_ARG_WITH(user, | ||||
|   [  --with-user=USER        Set the owner of installed files [[USER=root]] ], | ||||
|   [ OWNER="$withval" ]) | ||||
| AC_MSG_RESULT($OWNER) | ||||
|  | ||||
| if test x$OWNER != x; then | ||||
| 	OWNER="-o $OWNER" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the group ownership of the files | ||||
| AC_MSG_CHECKING(group owner) | ||||
| GROUP="root" | ||||
| AC_ARG_WITH(group, | ||||
|   [  --with-group=GROUP      Set the group owner of installed files [[GROUP=root]] ], | ||||
|   [ GROUP="$withval" ]) | ||||
| AC_MSG_RESULT($GROUP) | ||||
|  | ||||
| if test x$GROUP != x; then | ||||
| 	GROUP="-g $GROUP" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup device node ownership | ||||
| AC_MSG_CHECKING(device node uid) | ||||
|  | ||||
| AC_ARG_WITH(device-uid, | ||||
|   [  --with-device-uid=UID   Set the owner used for new device nodes [[UID=0]] ], | ||||
|   [ DM_DEVICE_UID="$withval" ], [ DM_DEVICE_UID="0" ] ) | ||||
| AC_MSG_RESULT($DM_DEVICE_UID) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup device group ownership | ||||
| AC_MSG_CHECKING(device node gid) | ||||
|  | ||||
| AC_ARG_WITH(device-gid, | ||||
|   [  --with-device-gid=UID   Set the group used for new device nodes [[GID=0]] ], | ||||
|   [ DM_DEVICE_GID="$withval" ], [ DM_DEVICE_GID="0" ] ) | ||||
| AC_MSG_RESULT($DM_DEVICE_GID) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup device mode | ||||
| AC_MSG_CHECKING(device node mode) | ||||
|  | ||||
| AC_ARG_WITH(device-mode, | ||||
|   [  --with-device-mode=MODE Set the mode used for new device nodes [[MODE=0600]] ], | ||||
|   [ DM_DEVICE_MODE="$withval" ], [ DM_DEVICE_MODE="0600" ] ) | ||||
| AC_MSG_RESULT($DM_DEVICE_MODE) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- LVM1 tool fallback option | ||||
| AC_MSG_CHECKING(whether to enable lvm1 fallback) | ||||
| AC_ARG_ENABLE(lvm1_fallback, [  --enable-lvm1_fallback  Use this to fall back and use LVM1 binaries if | ||||
|                           device-mapper is missing from the kernel],  LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no) | ||||
| AC_MSG_RESULT($LVM1_FALLBACK) | ||||
|  | ||||
| if test x$LVM1_FALLBACK = xyes; then | ||||
| 	AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- format1 inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for lvm1 metadata) | ||||
| AC_ARG_WITH(lvm1, | ||||
|   [  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ LVM1="$withval" ], | ||||
|   [ LVM1="internal" ]) | ||||
| AC_MSG_RESULT($LVM1) | ||||
|  | ||||
| if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-lvm1 parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$LVM1 = xinternal; then | ||||
| 	AC_DEFINE([LVM1_INTERNAL], 1, [Define to 1 to include built-in support for LVM1 metadata.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- format_pool inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for GFS pool metadata) | ||||
| AC_ARG_WITH(pool, | ||||
|   [  --with-pool=TYPE        GFS pool read-only support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ POOL="$withval" ], | ||||
|   [ POOL="internal" ]) | ||||
| AC_MSG_RESULT($POOL) | ||||
|  | ||||
| if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-pool parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$POOL = xinternal; then | ||||
| 	AC_DEFINE([POOL_INTERNAL], 1, [Define to 1 to include built-in support for GFS pool metadata.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- cluster_locking inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for cluster locking) | ||||
| AC_ARG_WITH(cluster, | ||||
|   [  --with-cluster=TYPE     Cluster LVM locking support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ CLUSTER="$withval" ]) | ||||
| AC_MSG_RESULT($CLUSTER) | ||||
|  | ||||
| if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-cluster parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$CLUSTER = xinternal; then | ||||
| 	AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1, [Define to 1 to include built-in support for clustered LVM locking.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- snapshots inclusion type | ||||
| AC_MSG_CHECKING(whether to include snapshots) | ||||
| AC_ARG_WITH(snapshots, | ||||
|   [  --with-snapshots=TYPE   Snapshot support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ SNAPSHOTS="$withval" ], | ||||
|   [ SNAPSHOTS="internal" ]) | ||||
| AC_MSG_RESULT($SNAPSHOTS) | ||||
|  | ||||
| if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-snapshots parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$SNAPSHOTS = xinternal; then | ||||
| 	AC_DEFINE([SNAPSHOT_INTERNAL], 1, [Define to 1 to include built-in support for snapshots.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- mirrors inclusion type | ||||
| AC_MSG_CHECKING(whether to include mirrors) | ||||
| AC_ARG_WITH(mirrors, | ||||
|   [  --with-mirrors=TYPE     Mirror support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ MIRRORS="$withval" ], | ||||
|   [ MIRRORS="internal" ]) | ||||
| AC_MSG_RESULT($MIRRORS) | ||||
|  | ||||
| if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-mirrors parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$MIRRORS = xinternal; then | ||||
| 	AC_DEFINE([MIRRORED_INTERNAL], 1, [Define to 1 to include built-in support for mirrors.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable readline | ||||
| AC_MSG_CHECKING(whether to enable readline) | ||||
| AC_ARG_ENABLE([readline], | ||||
|   [  --disable-readline      Disable readline support], | ||||
|   [READLINE=$enableval], [READLINE=maybe]) | ||||
| AC_MSG_RESULT($READLINE) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable realtime clock support | ||||
| AC_MSG_CHECKING(whether to enable realtime support) | ||||
| AC_ARG_ENABLE(realtime, [  --disable-realtime      Disable realtime clock support], | ||||
| REALTIME=$enableval) | ||||
| AC_MSG_RESULT($REALTIME) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Build cluster LVM daemon | ||||
| AC_MSG_CHECKING(whether to build cluster LVM daemon) | ||||
| AC_ARG_WITH(clvmd, | ||||
|   [  --with-clvmd=TYPE       Build cluster LVM Daemon: cman/gulm/none/all | ||||
|                           [TYPE=none] ], | ||||
|   [ CLVMD="$withval" ], | ||||
|   [ CLVMD="none" ]) | ||||
| if test x$CLVMD = xyes; then | ||||
| 	CLVMD=all | ||||
| fi | ||||
| AC_MSG_RESULT($CLVMD) | ||||
|  | ||||
| dnl -- If clvmd enabled without cluster locking, automagically include it | ||||
| if  test x$CLVMD != xnone && test x$CLUSTER = xnone; then | ||||
| 	CLUSTER=internal | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable debugging | ||||
| AC_MSG_CHECKING(whether to enable debugging) | ||||
| AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debugging], | ||||
|   DEBUG=$enableval, DEBUG=no) | ||||
| AC_MSG_RESULT($DEBUG) | ||||
|  | ||||
| dnl -- Normally turn off optimisation for debug builds | ||||
| if test x$DEBUG = xyes; then | ||||
| 	COPTIMISE_FLAG= | ||||
| else | ||||
| 	CSCOPE_CMD= | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Override optimisation | ||||
| AC_MSG_CHECKING(for C optimisation flag) | ||||
| AC_ARG_WITH(optimisation, | ||||
|   [  --with-optimisation=OPT C optimisation flag [[OPT=-O2]] ], | ||||
|   [ COPTIMISE_FLAG="$withval" ]) | ||||
| AC_MSG_RESULT($COPTIMISE_FLAG) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable profiling | ||||
| AC_MSG_CHECKING(whether to gather gcov profiling data) | ||||
| AC_ARG_ENABLE(profiling, | ||||
|   AC_HELP_STRING(--enable-profiling, [Gather gcov profiling data]), | ||||
|   PROFILING=$enableval, PROFILING=no) | ||||
| AC_MSG_RESULT($PROFILING) | ||||
|  | ||||
| if test "x$PROFILING" = xyes; then | ||||
|   COPTIMISE_FLAG="$COPTIMISE_FLAG -fprofile-arcs -ftest-coverage" | ||||
|   AC_PATH_PROG(LCOV, lcov, no) | ||||
|   AC_PATH_PROG(GENHTML, genhtml, no) | ||||
|   if test "$LCOV" = no -o "$GENHTML" = no ; then | ||||
|     AC_MSG_ERROR([lcov and genhtml are required for profiling]) | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable devmapper | ||||
| AC_MSG_CHECKING(whether to use device-mapper) | ||||
| AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable LVM2 device-mapper interaction], | ||||
| DEVMAPPER=$enableval) | ||||
| AC_MSG_RESULT($DEVMAPPER) | ||||
|  | ||||
| if test x$DEVMAPPER = xyes; then | ||||
| 	AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Compatibility mode | ||||
| AC_ARG_ENABLE(compat,   [  --enable-compat         Enable support for old device-mapper versions], | ||||
|   DM_COMPAT=$enableval, DM_COMPAT=no) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable ioctl | ||||
| AC_ARG_ENABLE(ioctl,   [  --disable-driver        Disable calls to device-mapper in the kernel], | ||||
|   DM_IOCTLS=$enableval) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable O_DIRECT | ||||
| AC_MSG_CHECKING(whether to enable O_DIRECT) | ||||
| AC_ARG_ENABLE(o_direct, [  --disable-o_direct      Disable O_DIRECT], | ||||
| ODIRECT=$enableval) | ||||
| AC_MSG_RESULT($ODIRECT) | ||||
|  | ||||
| if test x$ODIRECT = xyes; then | ||||
| 	AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable cmdlib | ||||
| AC_MSG_CHECKING(whether to compile liblvm2cmd.so) | ||||
| AC_ARG_ENABLE(cmdlib, [  --enable-cmdlib         Build shared command library], | ||||
| CMDLIB=$enableval, CMDLIB=no) | ||||
| AC_MSG_RESULT($CMDLIB) | ||||
| AC_SUBST([LVM2CMD_LIB]) | ||||
| test x$CMDLIB = xyes \ | ||||
|   && LVM2CMD_LIB=-llvm2cmd \ | ||||
|   || LVM2CMD_LIB= | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable pkg-config | ||||
| AC_ARG_ENABLE(pkgconfig,   [  --enable-pkgconfig      Install pkgconfig support], | ||||
|   PKGCONFIG=$enableval, PKGCONFIG=no) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable fsadm | ||||
| AC_MSG_CHECKING(whether to install fsadm) | ||||
| AC_ARG_ENABLE(fsadm, [  --enable-fsadm          Enable fsadm], | ||||
| FSADM=$enableval) | ||||
| AC_MSG_RESULT($FSADM) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- enable dmeventd handling | ||||
| AC_MSG_CHECKING(whether to use dmeventd) | ||||
| AC_ARG_ENABLE(dmeventd, [  --enable-dmeventd       Enable the device-mapper event daemon], | ||||
| DMEVENTD=$enableval) | ||||
| AC_MSG_RESULT($DMEVENTD) | ||||
|  | ||||
| BUILD_DMEVENTD=$DMEVENTD | ||||
|  | ||||
| dnl -- dmeventd currently requires internal mirror support | ||||
| if test x$DMEVENTD = xyes; then | ||||
|    if test x$MIRRORS != xinternal; then | ||||
|       AC_MSG_ERROR( | ||||
| 	--enable-dmeventd currently requires --with-mirrors=internal | ||||
|       ) | ||||
|    fi | ||||
|    if test x$CMDLIB = xno; then | ||||
|       AC_MSG_ERROR( | ||||
|         --enable-dmeventd requires --enable-cmdlib to be used as well | ||||
|       ) | ||||
|    fi | ||||
| fi | ||||
|  | ||||
| if test x$DMEVENTD = xyes; then | ||||
| 	AC_DEFINE([DMEVENTD], 1, [Define to 1 to enable the device-mapper event daemon.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- getline included in recent libc | ||||
|  | ||||
| AC_CHECK_LIB(c, getline, AC_DEFINE([HAVE_GETLINE], 1, | ||||
|   [Define to 1 if getline is available.])) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- canonicalize_file_name included in recent libc | ||||
|  | ||||
| AC_CHECK_LIB(c, canonicalize_file_name, | ||||
|   AC_DEFINE([HAVE_CANONICALIZE_FILE_NAME], 1, | ||||
|     [Define to 1 if canonicalize_file_name is available.])) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin | ||||
| if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; | ||||
|  then  exec_prefix=""; | ||||
| fi; | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for termcap (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE != xno; then | ||||
| 	AC_SEARCH_LIBS([tgetent], [ncurses curses termcap termlib], | ||||
| 	  [tg_found=yes], [tg_found=no]) | ||||
| 	test x$READLINE:$tg_found = xyes:no && | ||||
| 	  AC_MSG_ERROR( | ||||
| termcap could not be found which is required for the | ||||
| --enable-readline option (which is enabled by default).  Either disable readline | ||||
| support with --disable-readline or download and install termcap from: | ||||
| 	ftp.gnu.org/gnu/termcap | ||||
| Note: if you are using precompiled packages you will also need the development | ||||
|   package as well (which may be called termcap-devel or something similar). | ||||
| Note: (n)curses also seems to work as a substitute for termcap.  This was | ||||
|   not found either - but you could try installing that as well. | ||||
| ) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for dlopen | ||||
| AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no) | ||||
|  | ||||
| if [[ "x$HAVE_LIBDL" = xyes ]]; then | ||||
| 	AC_DEFINE([HAVE_LIBDL], 1, [Define to 1 if dynamic libraries are available.]) | ||||
| 	LIBS="-ldl $LIBS" | ||||
| else | ||||
| 	HAVE_LIBDL=no | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for shared/static conflicts | ||||
| if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ | ||||
|       -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ | ||||
|       \) -a "x$STATIC_LINK" = xyes ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| Features cannot be 'shared' when building statically | ||||
| ) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enables statically-linked tools | ||||
| AC_MSG_CHECKING(whether to use static linking) | ||||
| AC_ARG_ENABLE(static_link, | ||||
|   [  --enable-static_link    Use this to link the tools to their libraries | ||||
|                           statically.  Default is dynamic linking], | ||||
|   STATIC_LINK=$enableval, STATIC_LINK=no) | ||||
| AC_MSG_RESULT($STATIC_LINK) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable selinux | ||||
| AC_MSG_CHECKING(whether to enable selinux support) | ||||
| AC_ARG_ENABLE(selinux, [  --disable-selinux       Disable selinux support], | ||||
|   SELINUX=$enableval) | ||||
| AC_MSG_RESULT($SELINUX) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for selinux | ||||
| if test x$SELINUX = xyes; then | ||||
| 	AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no) | ||||
|  | ||||
| 	if test x$HAVE_SEPOL = xyes; then | ||||
| 		AC_DEFINE([HAVE_SEPOL], 1, | ||||
| 		  [Define to 1 if sepol_check_context is available.]) | ||||
| 		LIBS="-lsepol $LIBS" | ||||
| 	fi | ||||
|  | ||||
| 	AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no) | ||||
|  | ||||
| 	if test x$HAVE_SELINUX = xyes; then | ||||
| 		AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.]) | ||||
| 		LIBS="-lselinux $LIBS" | ||||
| 	else | ||||
| 		AC_MSG_WARN(Disabling selinux) | ||||
| 	fi | ||||
|  | ||||
| 	# With --enable-static_link and selinux enabled, linking | ||||
| 	# fails on at least Debian unstable due to unsatisfied references | ||||
| 	# to pthread_mutex_lock and _unlock.  See if we need -lpthread. | ||||
| 	if test "$STATIC_LINK-$HAVE_SELINUX" = yes-yes; then | ||||
| 		lvm_saved_libs=$LIBS | ||||
| 		LIBS="$LIBS -static" | ||||
| 		AC_SEARCH_LIBS([pthread_mutex_lock], [pthread], | ||||
| 		  [test "$ac_cv_search_pthread_mutex_lock" = "none required" || | ||||
| 				LIB_PTHREAD=-lpthread]) | ||||
| 		LIBS=$lvm_saved_libs | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for realtime clock support | ||||
| if test x$REALTIME = xyes; then | ||||
| 	AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no) | ||||
|  | ||||
| 	if test x$HAVE_REALTIME = xyes; then | ||||
| 		AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.]) | ||||
| 		LIBS="-lrt $LIBS" | ||||
| 	else | ||||
| 		AC_MSG_WARN(Disabling realtime clock) | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for getopt | ||||
| AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.])) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for readline (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE != xno; then | ||||
| 	rl_found=yes | ||||
| 	AC_CHECK_LIB([readline], [readline], , [rl_found=no]) | ||||
| 	test x$READLINE:$rl_found = xyes:no && | ||||
| 	  AC_MSG_ERROR( | ||||
| GNU Readline could not be found which is required for the | ||||
| --enable-readline option (which is enabled by default).  Either disable readline | ||||
| support with --disable-readline or download and install readline from: | ||||
| 	ftp.gnu.org/gnu/readline | ||||
| Note: if you are using precompiled packages you will also need the development | ||||
| package as well (which may be called readline-devel or something similar). | ||||
| ) | ||||
| 	if test $rl_found = yes; then | ||||
| 		AC_CHECK_FUNCS([rl_completion_matches]) | ||||
| 		AC_DEFINE([READLINE_SUPPORT], 1, | ||||
| 		  [Define to 1 to include the LVM readline shell.]) | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Internationalisation stuff | ||||
| AC_MSG_CHECKING(whether to enable internationalisation) | ||||
| AC_ARG_ENABLE(nls, [  --enable-nls            Enable Native Language Support], | ||||
| 		INTL=$enableval, INTL=no) | ||||
| AC_MSG_RESULT($INTL) | ||||
|  | ||||
| if test x$INTL = xyes; then | ||||
| # FIXME - Move this - can be device-mapper too | ||||
| 	INTL_PACKAGE="lvm2" | ||||
| 	AC_PATH_PROG(MSGFMT, msgfmt) | ||||
| 	if [[ "x$MSGFMT" == x ]]; | ||||
| 		then  AC_MSG_ERROR( | ||||
| 		msgfmt not found in path $PATH | ||||
| 		) | ||||
| 	fi; | ||||
|  | ||||
| 	AC_ARG_WITH(localedir, | ||||
| 		    [  --with-localedir=DIR    Translation files in DIR [[PREFIX/share/locale]] ], | ||||
| 		    [ LOCALEDIR="$withval" ], | ||||
| 		    [ LOCALEDIR='${prefix}/share/locale' ]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_ARG_WITH(confdir, | ||||
| 	    [  --with-confdir=DIR      Configuration files in DIR [/etc]], | ||||
| 	    [ CONFDIR="$withval" ], | ||||
| 	    [ CONFDIR='/etc' ]) | ||||
|  | ||||
| AC_ARG_WITH(staticdir, | ||||
| 	    [  --with-staticdir=DIR    Static binary in DIR [EXEC_PREFIX/sbin]], | ||||
| 	    [ STATICDIR="$withval" ], | ||||
| 	    [ STATICDIR='${exec_prefix}/sbin' ]) | ||||
|  | ||||
| AC_ARG_WITH(usrlibdir, | ||||
| 	    [  --with-usrlibdir=DIR], | ||||
| 	    [ usrlibdir="$withval"], | ||||
| 	    [ usrlibdir='${prefix}/lib' ]) | ||||
|  | ||||
| AC_ARG_WITH(usrsbindir, | ||||
| 	    [  --with-usrsbindir=DIR], | ||||
| 	    [ usrsbindir="$withval"], | ||||
| 	    [ usrsbindir='${prefix}/sbin' ]) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Ensure additional headers required | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$CLVMD != xnone; then | ||||
| 	AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_FUNC_GETMNTENT | ||||
| #	AC_FUNC_REALLOC | ||||
| 	AC_FUNC_SELECT_ARGTYPES | ||||
| fi | ||||
|  | ||||
| if test x$CLUSTER != xnone; then | ||||
| 	AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$HAVE_LIBDL = xyes; then | ||||
| 	AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$INTL = xyes; then | ||||
| 	AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$HAVE_SELINUX = xyes; then | ||||
| 	AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_PATH_PROG(MODPROBE_CMD, modprobe) | ||||
|  | ||||
| if test x$MODPROBE_CMD != x; then | ||||
| 	AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- dmeventd pidfile and executable path | ||||
| AH_TEMPLATE(DMEVENTD_PIDFILE, [Path to dmeventd pidfile.]) | ||||
| if test "$BUILD_DMEVENTD" = yes; then | ||||
| 	AC_ARG_WITH(dmeventd-pidfile, | ||||
| 		    [  --with-dmeventd-pidfile=PATH    dmeventd pidfile [[/var/run/dmeventd.pid]] ], | ||||
| 		    [ AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE,"$withval") ], | ||||
| 		    [ AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE,"/var/run/dmeventd.pid") ]) | ||||
| fi | ||||
|  | ||||
| AH_TEMPLATE(DMEVENTD_PATH, [Path to dmeventd binary.]) | ||||
| if test "$BUILD_DMEVENTD" = yes; then | ||||
|         dmeventd_prefix="$exec_prefix" | ||||
|         if test "x$dmeventd_prefix" = "xNONE"; then | ||||
|                 dmeventd_prefix="$prefix" | ||||
|         fi | ||||
|         if test "x$dmeventd_prefix" = "xNONE"; then | ||||
|                 dmeventd_prefix="" | ||||
|         fi | ||||
| 	AC_ARG_WITH(dmeventd-path, | ||||
| 		    [  --with-dmeventd-path=PATH       dmeventd path [[${exec_prefix}/sbin/dmeventd]] ], | ||||
| 		    [ AC_DEFINE_UNQUOTED(DMEVENTD_PATH,"$withval") ], | ||||
| 		    [ AC_DEFINE_UNQUOTED(DMEVENTD_PATH,"$dmeventd_prefix/sbin/dmeventd") ]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- which kernel interface to use (ioctl only) | ||||
| AC_MSG_CHECKING(for kernel interface choice) | ||||
| AC_ARG_WITH(interface, | ||||
|   [  --with-interface=IFACE  Choose kernel interface (ioctl) [[ioctl]] ], | ||||
|   [ interface="$withval" ], | ||||
|   [ interface=ioctl ]) | ||||
| if [[ "x$interface" != xioctl ]]; | ||||
| then | ||||
|   AC_MSG_ERROR(--with-interface=ioctl required. fs no longer supported.) | ||||
| fi | ||||
| AC_MSG_RESULT($interface) | ||||
|  | ||||
| ################################################################################ | ||||
| DM_LIB_VERSION="\"`cat VERSION_DM 2>/dev/null || echo Unknown`\"" | ||||
| AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version]) | ||||
|  | ||||
| DM_LIB_PATCHLEVEL=`cat VERSION_DM | awk -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'` | ||||
|  | ||||
| LVM_VERSION="\"`cat VERSION 2>/dev/null || echo Unknown`\"" | ||||
|  | ||||
| ################################################################################ | ||||
| AC_SUBST(BUILD_DMEVENTD) | ||||
| AC_SUBST(CFLAGS) | ||||
| AC_SUBST(CFLOW_CMD) | ||||
| AC_SUBST(CLDFLAGS) | ||||
| AC_SUBST(CLDNOWHOLEARCHIVE) | ||||
| AC_SUBST(CLDWHOLEARCHIVE) | ||||
| AC_SUBST(CLUSTER) | ||||
| AC_SUBST(CLVMD) | ||||
| AC_SUBST(CMDLIB) | ||||
| AC_SUBST(COPTIMISE_FLAG) | ||||
| AC_SUBST(CSCOPE_CMD) | ||||
| AC_SUBST(DEBUG) | ||||
| AC_SUBST(DEVMAPPER) | ||||
| AC_SUBST(DMEVENTD) | ||||
| AC_SUBST(DM_COMPAT) | ||||
| AC_SUBST(DM_DEVICE_GID) | ||||
| AC_SUBST(DM_DEVICE_MODE) | ||||
| AC_SUBST(DM_DEVICE_UID) | ||||
| AC_SUBST(DM_IOCTLS) | ||||
| AC_SUBST(DM_LIB_VERSION) | ||||
| AC_SUBST(DM_LIB_PATCHLEVEL) | ||||
| AC_SUBST(FSADM) | ||||
| AC_SUBST(GROUP) | ||||
| AC_SUBST(HAVE_LIBDL) | ||||
| AC_SUBST(HAVE_REALTIME) | ||||
| AC_SUBST(HAVE_SELINUX) | ||||
| AC_SUBST(INTL) | ||||
| AC_SUBST(INTL_PACKAGE) | ||||
| AC_SUBST(JOBS) | ||||
| AC_SUBST(LDDEPS) | ||||
| AC_SUBST(LIBS) | ||||
| AC_SUBST(LIB_SUFFIX) | ||||
| AC_SUBST(LOCALEDIR) | ||||
| AC_SUBST(LVM1) | ||||
| AC_SUBST(LVM1_FALLBACK) | ||||
| AC_SUBST(CONFDIR) | ||||
| AC_SUBST(LVM_VERSION) | ||||
| AC_SUBST(MIRRORS) | ||||
| AC_SUBST(MSGFMT) | ||||
| AC_SUBST(OWNER) | ||||
| AC_SUBST(PKGCONFIG) | ||||
| AC_SUBST(POOL) | ||||
| AC_SUBST(SNAPSHOTS) | ||||
| AC_SUBST(STATICDIR) | ||||
| AC_SUBST(STATIC_LINK) | ||||
| AC_SUBST([LIB_PTHREAD]) | ||||
| AC_SUBST(interface) | ||||
| AC_SUBST(kerneldir) | ||||
| AC_SUBST(missingkernel) | ||||
| AC_SUBST(kernelvsn) | ||||
| AC_SUBST(tmpdir) | ||||
| AC_SUBST(usrlibdir) | ||||
| AC_SUBST(usrsbindir) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- First and last lines should not contain files to generate in order to | ||||
| dnl -- keep utility scripts running properly | ||||
| AC_CONFIG_FILES([ | ||||
| Makefile | ||||
| make.tmpl | ||||
| daemons/Makefile | ||||
| daemons/clvmd/Makefile | ||||
| daemons/dmeventd/Makefile | ||||
| daemons/dmeventd/libdevmapper-event.pc | ||||
| daemons/dmeventd/plugins/Makefile | ||||
| daemons/dmeventd/plugins/mirror/Makefile | ||||
| daemons/dmeventd/plugins/snapshot/Makefile | ||||
| doc/Makefile | ||||
| include/Makefile | ||||
| lib/Makefile | ||||
| lib/format1/Makefile | ||||
| lib/format_pool/Makefile | ||||
| lib/locking/Makefile | ||||
| lib/mirror/Makefile | ||||
| lib/snapshot/Makefile | ||||
| libdm/Makefile | ||||
| libdm/libdevmapper.pc | ||||
| man/Makefile | ||||
| po/Makefile | ||||
| scripts/Makefile | ||||
| test/Makefile | ||||
| tools/Makefile | ||||
| tools/version.h | ||||
| ]) | ||||
| AC_OUTPUT | ||||
|  | ||||
| if test x$ODIRECT != xyes; then | ||||
|   AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up) | ||||
| fi | ||||
							
								
								
									
										32
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| # | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| .PHONY: dmeventd clvmd | ||||
|  | ||||
| ifneq ("@CLVMD@", "none") | ||||
|   SUBDIRS = clvmd | ||||
| endif | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
|   SUBDIRS += dmeventd | ||||
| endif | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
| device-mapper: dmeventd.device-mapper | ||||
| endif | ||||
							
								
								
									
										98
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| # | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SOURCES = \ | ||||
| 	clvmd-command.c  \ | ||||
| 	clvmd.c          \ | ||||
| 	lvm-functions.c  \ | ||||
| 	refresh_clvmd.c | ||||
|  | ||||
| ifeq ("@CLVMD@", "gulm") | ||||
| 	GULM = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "cman") | ||||
| 	CMAN = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "openais") | ||||
| 	OPENAIS = yes | ||||
| 	GULM = no | ||||
| 	CMAN = no | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "all") | ||||
| 	GULM = yes | ||||
| 	CMAN = yes | ||||
| 	OPENAIS = no | ||||
| endif | ||||
|  | ||||
| ifeq ("@DEBUG@", "yes") | ||||
| 	DEFS += -DDEBUG | ||||
| endif | ||||
|  | ||||
| ifeq ("$(GULM)", "yes") | ||||
| 	SOURCES += clvmd-gulm.c tcp-comms.c | ||||
| 	LMLIBS += -lccs -lgulm | ||||
| 	DEFS += -DUSE_GULM | ||||
| endif | ||||
|  | ||||
| ifeq ("$(CMAN)", "yes") | ||||
| 	SOURCES += clvmd-cman.c | ||||
| 	LMLIBS += -ldlm -lcman | ||||
| 	DEFS += -DUSE_CMAN | ||||
| endif | ||||
|  | ||||
| ifeq ("$(OPENAIS)", "yes") | ||||
| 	SOURCES += clvmd-openais.c | ||||
| 	LMLIBS += -lSaLck -lcpg | ||||
| 	DEFS += -DUSE_OPENAIS | ||||
| endif | ||||
|  | ||||
| TARGETS = \ | ||||
| 	clvmd | ||||
|  | ||||
| LVMLIBS = -llvm -lpthread | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
| 	LVMLIBS += -ldevmapper-event | ||||
| endif | ||||
|   | ||||
| LVMLIBS += -ldevmapper | ||||
|  | ||||
| DEFS += -D_REENTRANT | ||||
| CFLAGS += -fno-strict-aliasing | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| INSTALL_TARGETS = \ | ||||
| 	install_clvmd | ||||
|  | ||||
| clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a | ||||
| 	$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \ | ||||
| 		$(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| .PHONY: install_clvmd | ||||
|  | ||||
| install_clvmd: $(TARGETS) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) clvmd \ | ||||
| 		$(usrsbindir)/clvmd | ||||
|  | ||||
| install: $(INSTALL_TARGETS) | ||||
|  | ||||
| install_cluster: $(INSTALL_TARGETS) | ||||
|  | ||||
							
								
								
									
										71
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Definitions for CLVMD server and clients */ | ||||
|  | ||||
| /* | ||||
|  * The protocol spoken over the cluster and across the local socket. | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVM_H | ||||
| #define _CLVM_H | ||||
|  | ||||
| struct clvm_header { | ||||
| 	uint8_t  cmd;	        /* See below */ | ||||
| 	uint8_t  flags;	        /* See below */ | ||||
| 	uint16_t xid;	        /* Transaction ID */ | ||||
| 	uint32_t clientid;	/* Only used in Daemon->Daemon comms */ | ||||
| 	int32_t  status;	/* For replies, whether request succeeded */ | ||||
| 	uint32_t arglen;	/* Length of argument below.  | ||||
| 				   If >1500 then it will be passed  | ||||
| 				   around the cluster in the system LV */ | ||||
| 	char node[1];		/* Actually a NUL-terminated string, node name. | ||||
| 				   If this is empty then the command is  | ||||
| 				   forwarded to all cluster nodes unless  | ||||
| 				   FLAG_LOCAL is also set. */ | ||||
| 	char args[1];		/* Arguments for the command follow the  | ||||
| 				   node name, This member is only | ||||
| 				   valid if the node name is empty */ | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| /* Flags */ | ||||
| #define CLVMD_FLAG_LOCAL        1	/* Only do this on the local node */ | ||||
| #define CLVMD_FLAG_SYSTEMLV     2	/* Data in system LV under my node name */ | ||||
| #define CLVMD_FLAG_NODEERRS     4       /* Reply has errors in node-specific portion */ | ||||
|  | ||||
| /* Name of the local socket to communicate between libclvm and clvmd */ | ||||
| //static const char CLVMD_SOCKNAME[]="/var/run/clvmd"; | ||||
| static const char CLVMD_SOCKNAME[] = "\0clvmd"; | ||||
|  | ||||
| /* Internal commands & replies */ | ||||
| #define CLVMD_CMD_REPLY    1 | ||||
| #define CLVMD_CMD_VERSION  2	/* Send version around cluster when we start */ | ||||
| #define CLVMD_CMD_GOAWAY   3	/* Die if received this - we are running  | ||||
| 				   an incompatible version */ | ||||
| #define CLVMD_CMD_TEST     4	/* Just for mucking about */ | ||||
|  | ||||
| #define CLVMD_CMD_LOCK              30 | ||||
| #define CLVMD_CMD_UNLOCK            31 | ||||
|  | ||||
| /* Lock/Unlock commands */ | ||||
| #define CLVMD_CMD_LOCK_LV           50 | ||||
| #define CLVMD_CMD_LOCK_VG           51 | ||||
|  | ||||
| /* Misc functions */ | ||||
| #define CLVMD_CMD_REFRESH	    40 | ||||
| #define CLVMD_CMD_GET_CLUSTERNAME   41 | ||||
| #define CLVMD_CMD_SET_DEBUG	    42 | ||||
| #define CLVMD_CMD_VG_BACKUP	    43 | ||||
| #endif | ||||
							
								
								
									
										518
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										518
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,518 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * CMAN communication layer for clvmd. | ||||
|  */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <syslog.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stddef.h> | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <getopt.h> | ||||
| #include <errno.h> | ||||
| #include <libdevmapper.h> | ||||
| #include <libdlm.h> | ||||
|  | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "lvm-logging.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #define LOCKSPACE_NAME "clvmd" | ||||
|  | ||||
| struct clvmd_node | ||||
| { | ||||
| 	struct cman_node *node; | ||||
| 	int clvmd_up; | ||||
| }; | ||||
|  | ||||
| static int num_nodes; | ||||
| static struct cman_node *nodes = NULL; | ||||
| static struct cman_node this_node; | ||||
| static int count_nodes; /* size of allocated nodes array */ | ||||
| static struct dm_hash_table *node_updown_hash; | ||||
| static dlm_lshandle_t *lockspace; | ||||
| static cman_handle_t c_handle; | ||||
|  | ||||
| static void count_clvmds_running(void); | ||||
| static void get_members(void); | ||||
| static int nodeid_from_csid(const char *csid); | ||||
| static int name_from_nodeid(int nodeid, char *name); | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg); | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid); | ||||
|  | ||||
| struct lock_wait { | ||||
| 	pthread_cond_t cond; | ||||
| 	pthread_mutex_t mutex; | ||||
| 	struct dlm_lksb lksb; | ||||
| }; | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	node_updown_hash = dm_hash_create(100); | ||||
|  | ||||
| 	/* Open the cluster communication socket */ | ||||
| 	c_handle = cman_init(NULL); | ||||
| 	if (!c_handle) { | ||||
| 		syslog(LOG_ERR, "Can't open cluster manager socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	DEBUGLOG("Connected to CMAN\n"); | ||||
|  | ||||
| 	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) { | ||||
| 		syslog(LOG_ERR, "Can't bind cluster socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (cman_start_notification(c_handle, event_callback)) { | ||||
| 		syslog(LOG_ERR, "Can't start cluster event listening"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the cluster members list */ | ||||
| 	get_members(); | ||||
| 	count_clvmds_running(); | ||||
|  | ||||
| 	DEBUGLOG("CMAN initialisation complete\n"); | ||||
|  | ||||
| 	/* Create a lockspace for LV & VG locks to live in */ | ||||
| 	lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 	if (!lockspace) { | ||||
| 		syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	dlm_ls_pthread_init(lockspace); | ||||
| 	DEBUGLOG("DLM initialisation complete\n"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_init_completed(void) | ||||
| { | ||||
| 	clvmd_cluster_init_completed(); | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd() | ||||
| { | ||||
| 	return cman_get_fd(c_handle); | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	int i; | ||||
| 	int nnodes = 0; | ||||
|  | ||||
| 	/* return number of ACTIVE nodes */ | ||||
| 	for (i=0; i<num_nodes; i++) { | ||||
| 		if (nodes[i].cn_member && nodes[i].cn_nodeid) | ||||
| 			nnodes++; | ||||
| 	} | ||||
| 	return nnodes; | ||||
| } | ||||
|  | ||||
| /* send_message with the fd check removed */ | ||||
| static int _cluster_send_message(const void *buf, int msglen, const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	int nodeid = 0; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0) | ||||
| 	{ | ||||
| 		log_error("%s", errtext); | ||||
| 	} | ||||
| 	return msglen; | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	if (this_node.cn_nodeid == 0) { | ||||
| 		cman_get_node(c_handle, 0, &this_node); | ||||
| 	} | ||||
| 	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| /* Call a callback routine for each node is that known (down means not running a clvmd) */ | ||||
| static int _cluster_do_node_callback(struct local_client *client, | ||||
| 				     void (*callback) (struct local_client *, | ||||
| 						       const char *, | ||||
| 						       int)) | ||||
| { | ||||
| 	int i; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	for (i = 0; i < _get_num_nodes(); i++) { | ||||
| 		if (nodes[i].cn_member && nodes[i].cn_nodeid) { | ||||
| 			int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int)); | ||||
|  | ||||
| 			callback(client, (char *)&nodes[i].cn_nodeid, up); | ||||
| 			if (!up) | ||||
| 				somedown = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Process OOB messages from the cluster socket */ | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg) | ||||
| { | ||||
| 	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
| 	switch (reason) { | ||||
|         case CMAN_REASON_PORTCLOSED: | ||||
| 		name_from_nodeid(arg, namebuf); | ||||
| 		log_notice("clvmd on node %s has died\n", namebuf); | ||||
| 		DEBUGLOG("Got port closed message, removing node %s\n", namebuf); | ||||
|  | ||||
| 		dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0); | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_STATECHANGE: | ||||
| 		DEBUGLOG("Got state change message, re-reading members list\n"); | ||||
| 		get_members(); | ||||
| 		break; | ||||
|  | ||||
| #if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2 | ||||
| 	case CMAN_REASON_PORTOPENED: | ||||
| 		/* Ignore this, wait for startup message from clvmd itself */ | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_TRY_SHUTDOWN: | ||||
| 		DEBUGLOG("Got try shutdown, sending OK\n"); | ||||
| 		cman_replyto_shutdown(c_handle, 1); | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		/* ERROR */ | ||||
| 		DEBUGLOG("Got unknown event callback message: %d\n", reason); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static struct local_client *cman_client; | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
|  | ||||
| 	/* Save this for data_callback */ | ||||
| 	cman_client = fd; | ||||
|  | ||||
| 	/* We never return a new client */ | ||||
| 	*new_client = NULL; | ||||
|  | ||||
| 	return cman_dispatch(c_handle, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid) | ||||
| { | ||||
| 	/* Ignore looped back messages */ | ||||
| 	if (nodeid == this_node.cn_nodeid) | ||||
| 		return; | ||||
| 	process_message(cman_client, buf, len, (char *)&nodeid); | ||||
| } | ||||
|  | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| 	/* It's up ! */ | ||||
| 	int nodeid = nodeid_from_csid(csid); | ||||
|  | ||||
| 	dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1); | ||||
| 	DEBUGLOG("Added new node %d to updown list\n", nodeid); | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown() | ||||
| { | ||||
| 	unlock_all(); | ||||
| 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 	cman_finish(c_handle); | ||||
| } | ||||
|  | ||||
| static int is_listening(int nodeid) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	do { | ||||
| 		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD); | ||||
| 		if (status < 0 && errno == EBUSY) {	/* Don't busywait */ | ||||
| 			sleep(1); | ||||
| 			errno = EBUSY;	/* In case sleep trashes it */ | ||||
| 		} | ||||
| 	} | ||||
| 	while (status < 0 && errno == EBUSY); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Populate the list of CLVMDs running. | ||||
|    called only at startup time */ | ||||
| static void count_clvmds_running(void) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		int nodeid = nodes[i].cn_nodeid; | ||||
|  | ||||
| 		if (is_listening(nodeid) == 1) | ||||
| 			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1); | ||||
| 		else | ||||
| 			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get a list of active cluster members */ | ||||
| static void get_members() | ||||
| { | ||||
| 	int retnodes; | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int high_nodeid = 0; | ||||
|  | ||||
| 	num_nodes = cman_get_node_count(c_handle); | ||||
| 	if (num_nodes == -1) { | ||||
| 		log_error("Unable to get node count"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* Not enough room for new nodes list ? */ | ||||
| 	if (num_nodes > count_nodes && nodes) { | ||||
| 		free(nodes); | ||||
| 		nodes = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (nodes == NULL) { | ||||
| 		count_nodes = num_nodes + 10; /* Overallocate a little */ | ||||
| 		nodes = malloc(count_nodes * sizeof(struct cman_node)); | ||||
| 		if (!nodes) { | ||||
| 			log_error("Unable to allocate nodes array\n"); | ||||
| 			exit(5); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes); | ||||
| 	if (status < 0) { | ||||
| 		log_error("Unable to get node details"); | ||||
| 		exit(6); | ||||
| 	} | ||||
|  | ||||
| 	/* Get the highest nodeid */ | ||||
| 	for (i=0; i<retnodes; i++) { | ||||
| 		if (nodes[i].cn_nodeid > high_nodeid) | ||||
| 			high_nodeid = nodes[i].cn_nodeid; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Convert a node name to a CSID */ | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (strcmp(name, nodes[i].cn_name) == 0) { | ||||
| 			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node name */ | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a node ID to a node name */ | ||||
| static int name_from_nodeid(int nodeid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (nodeid == nodes[i].cn_nodeid) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node ID */ | ||||
| static int nodeid_from_csid(const char *csid) | ||||
| { | ||||
|         int nodeid; | ||||
|  | ||||
| 	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	return nodeid; | ||||
| } | ||||
|  | ||||
| static int _is_quorate() | ||||
| { | ||||
| 	return cman_is_quorate(c_handle); | ||||
| } | ||||
|  | ||||
| static void sync_ast_routine(void *arg) | ||||
| { | ||||
| 	struct lock_wait *lwait = arg; | ||||
|  | ||||
| 	pthread_mutex_lock(&lwait->mutex); | ||||
| 	pthread_cond_signal(&lwait->cond); | ||||
| 	pthread_mutex_unlock(&lwait->mutex); | ||||
| } | ||||
|  | ||||
| static int _sync_lock(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	if (!lockid) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags); | ||||
| 	/* Conversions need the lockid in the LKSB */ | ||||
| 	if (flags & LKF_CONVERT) | ||||
| 		lwait.lksb.sb_lkid = *lockid; | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_lock(lockspace, | ||||
| 			     mode, | ||||
| 			     &lwait.lksb, | ||||
| 			     flags, | ||||
| 			     resource, | ||||
| 			     strlen(resource), | ||||
| 			     0, sync_ast_routine, &lwait, NULL, NULL); | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	*lockid = lwait.lksb.sb_lkid; | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	DEBUGLOG("sync_lock: returning lkid %x\n", *lockid); | ||||
| 	if (lwait.lksb.sb_status) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| static int _sync_unlock(const char *resource /* UNUSED */, int lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid); | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait); | ||||
|  | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	if (lwait.lksb.sb_status != EUNLOCK) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	cman_cluster_t cluster_info; | ||||
| 	int status; | ||||
|  | ||||
| 	status = cman_get_cluster(c_handle, &cluster_info); | ||||
| 	if (!status) { | ||||
| 		strncpy(buf, cluster_info.ci_name, buflen); | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_cman_ops = { | ||||
| 	.cluster_init_completed   = _cluster_init_completed, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_cman_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_cman_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										341
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,341 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  | ||||
|   CLVMD Cluster LVM daemon command processor. | ||||
|  | ||||
|   To add commands to the daemon simply add a processor in do_command and return | ||||
|   and messages back in buf and the length in *retlen. The initial value of | ||||
|   buflen is the maximum size of the buffer. if buf is not large enough then it | ||||
|   may be reallocated by the functions in here to a suitable size bearing in | ||||
|   mind that anything larger than the passed-in size will have to be returned | ||||
|   using the system LV and so performance will suffer. | ||||
|  | ||||
|   The status return will be negated and passed back to the originating node. | ||||
|  | ||||
|   pre- and post- command routines are called only on the local node. The | ||||
|   purpose is primarily to get and release locks, though the pre- routine should | ||||
|   also do any other local setups required by the command (if any) and can | ||||
|   return a failure code that prevents the command from being distributed around | ||||
|   the cluster | ||||
|  | ||||
|   The pre- and post- routines are run in their own thread so can block as long | ||||
|   they like, do_command is run in the main clvmd thread so should not block for | ||||
|   too long. If the pre-command returns an error code (!=0) then the command | ||||
|   will not be propogated around the cluster but the post-command WILL be called | ||||
|  | ||||
|   Also note that the pre and post routine are *always* called on the local | ||||
|   node, even if the command to be executed was only requested to run on a | ||||
|   remote node. It may peek inside the client structure to check the status of | ||||
|   the command. | ||||
|  | ||||
|   The clients of the daemon must, naturally, understand the return messages and | ||||
|   codes. | ||||
|  | ||||
|   Routines in here may only READ the values in the client structure passed in | ||||
|   apart from client->private which they are free to do what they like with. | ||||
|  | ||||
| */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <libdevmapper.h> | ||||
| #include <libdlm.h> | ||||
|  | ||||
| #include "locking.h" | ||||
| #include "lvm-logging.h" | ||||
| #include "lvm-functions.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
|  | ||||
| extern debug_t debug; | ||||
| extern struct cluster_ops *clops; | ||||
|  | ||||
| /* This is where all the real work happens: | ||||
|    NOTE: client will be NULL when this is executed on a remote node */ | ||||
| int do_command(struct local_client *client, struct clvm_header *msg, int msglen, | ||||
| 	       char **buf, int buflen, int *retlen) | ||||
| { | ||||
| 	char *args = msg->node + strlen(msg->node) + 1; | ||||
| 	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node); | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
| 	struct utsname nodeinfo; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
|  | ||||
| 	/* Do the command */ | ||||
| 	switch (msg->cmd) { | ||||
| 		/* Just a test message */ | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		if (arglen > buflen) { | ||||
| 			char *new_buf; | ||||
| 			buflen = arglen + 200; | ||||
| 			new_buf = realloc(*buf, buflen); | ||||
| 			if (new_buf == NULL) { | ||||
| 				status = errno; | ||||
| 				free (*buf); | ||||
| 			} | ||||
| 			*buf = new_buf; | ||||
| 		} | ||||
| 		if (*buf) { | ||||
| 			uname(&nodeinfo); | ||||
| 			*retlen = 1 + snprintf(*buf, buflen, | ||||
| 					       "TEST from %s: %s v%s", | ||||
| 					       nodeinfo.nodename, args, | ||||
| 					       nodeinfo.release); | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		lockname = &args[2]; | ||||
| 		/* Check to see if the VG is in use by LVM1 */ | ||||
| 		status = do_check_lvm1(lockname); | ||||
| 		/* P_#global causes a full cache refresh */ | ||||
| 		if (!strcmp(lockname, "P_" VG_GLOBAL)) | ||||
| 			do_refresh_cache(); | ||||
| 		else | ||||
| 			drop_metadata(lockname + 2); | ||||
|  | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		/* This is the biggie */ | ||||
| 		lock_cmd = args[0] & 0x3F; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = do_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		/* Replace EIO with something less scary */ | ||||
| 		if (status == EIO) { | ||||
| 			*retlen = | ||||
| 			    1 + snprintf(*buf, buflen, "%s", | ||||
| 					 get_last_lvm_error()); | ||||
| 			return EIO; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 		do_refresh_cache(); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_SET_DEBUG: | ||||
| 		debug = args[0]; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 		status = clops->get_cluster_name(*buf, buflen); | ||||
| 		if (!status) | ||||
| 			*retlen = strlen(*buf)+1; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 		lvm_do_backup(&args[2]); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		/* Won't get here because command is validated in pre_command */ | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	/* Check the status of the command and return the error text */ | ||||
| 	if (status) { | ||||
| 		*retlen = 1 + snprintf(*buf, buflen, "%s", strerror(status)); | ||||
| 	} | ||||
|  | ||||
| 	return status; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int lock_vg(struct local_client *client) | ||||
| { | ||||
|     struct dm_hash_table *lock_hash; | ||||
|     struct clvm_header *header = | ||||
| 	(struct clvm_header *) client->bits.localsock.cmd; | ||||
|     unsigned char lock_cmd; | ||||
|     unsigned char lock_flags; | ||||
|     char *args = header->node + strlen(header->node) + 1; | ||||
|     int lkid; | ||||
|     int status = 0; | ||||
|     char *lockname; | ||||
|  | ||||
|     /* Keep a track of VG locks in our own hash table. In current | ||||
|        practice there should only ever be more than two VGs locked | ||||
|        if a user tries to merge lots of them at once */ | ||||
|     if (client->bits.localsock.private) { | ||||
| 	lock_hash = (struct dm_hash_table *)client->bits.localsock.private; | ||||
|     } | ||||
|     else { | ||||
| 	lock_hash = dm_hash_create(3); | ||||
| 	if (!lock_hash) | ||||
| 	    return ENOMEM; | ||||
| 	client->bits.localsock.private = (void *)lock_hash; | ||||
|     } | ||||
|  | ||||
|     lock_cmd = args[0] & 0x3F; | ||||
|     lock_flags = args[1]; | ||||
|     lockname = &args[2]; | ||||
|     DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client); | ||||
|  | ||||
|     if (lock_cmd == LCK_UNLOCK) { | ||||
|  | ||||
| 	lkid = (int)(long)dm_hash_lookup(lock_hash, lockname); | ||||
| 	if (lkid == 0) | ||||
| 	    return EINVAL; | ||||
|  | ||||
| 	status = sync_unlock(lockname, lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    dm_hash_remove(lock_hash, lockname); | ||||
|     } | ||||
|     else { | ||||
| 	/* Read locks need to be PR; other modes get passed through */ | ||||
| 	if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) { | ||||
| 	    lock_cmd &= ~LCK_TYPE_MASK; | ||||
| 	    lock_cmd |= LCK_PREAD; | ||||
| 	} | ||||
| 	status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    dm_hash_insert(lock_hash, lockname, (void *)(long)lkid); | ||||
|     } | ||||
|  | ||||
|     return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Pre-command is a good place to get locks that are needed only for the duration | ||||
|    of the commands around the cluster (don't forget to free them in post-command), | ||||
|    and to sanity check the command arguments */ | ||||
| int do_pre_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	int lockid; | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid); | ||||
| 		client->bits.localsock.private = (void *)(long)lockid; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		lockname = &args[2]; | ||||
| 		/* We take out a real lock unless LCK_CACHE was set */ | ||||
| 		if (!strncmp(lockname, "V_", 2) || | ||||
| 		    !strncmp(lockname, "P_#", 3)) | ||||
| 			status = lock_vg(client); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = pre_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 	case CLVMD_CMD_SET_DEBUG: | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_error("Unknown command %d received\n", header->cmd); | ||||
| 		status = EINVAL; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Note that the post-command routine is called even if the pre-command or the real command | ||||
|    failed */ | ||||
| int do_post_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	int status = 0; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = | ||||
| 		    sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private); | ||||
| 		client->bits.localsock.private = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 		/* Nothing to do here */ | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = post_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Called when the client is about to be deleted */ | ||||
| void cmd_client_cleanup(struct local_client *client) | ||||
| { | ||||
|     if (client->bits.localsock.private) { | ||||
|  | ||||
| 	struct dm_hash_node *v; | ||||
| 	struct dm_hash_table *lock_hash = | ||||
| 	    (struct dm_hash_table *)client->bits.localsock.private; | ||||
|  | ||||
| 	dm_hash_iterate(v, lock_hash) { | ||||
| 		int lkid = (int)(long)dm_hash_get_data(lock_hash, v); | ||||
| 		char *lockname = dm_hash_get_key(lock_hash, v); | ||||
|  | ||||
| 		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid); | ||||
| 		sync_unlock(lockname, lkid); | ||||
| 	} | ||||
|  | ||||
| 	dm_hash_destroy(lock_hash); | ||||
| 	client->bits.localsock.private = 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										97
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Abstraction layer for clvmd cluster communications | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_COMMS_H | ||||
| #define _CLVMD_COMMS_H | ||||
|  | ||||
| struct local_client; | ||||
|  | ||||
| struct cluster_ops { | ||||
| 	void (*cluster_init_completed) (void); | ||||
|  | ||||
| 	int (*cluster_send_message) (const void *buf, int msglen, | ||||
| 				     const char *csid, | ||||
| 				     const char *errtext); | ||||
| 	int (*name_from_csid) (const char *csid, char *name); | ||||
| 	int (*csid_from_name) (char *csid, const char *name); | ||||
| 	int (*get_num_nodes) (void); | ||||
| 	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len, | ||||
| 				    const char *csid, | ||||
| 				    struct local_client **new_client); | ||||
| 	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */ | ||||
| 	int (*cluster_do_node_callback) (struct local_client *client, | ||||
| 					 void (*callback) (struct local_client *, | ||||
| 							   const char *csid, | ||||
| 							   int node_up)); | ||||
| 	int (*is_quorate) (void); | ||||
|  | ||||
| 	void (*get_our_csid) (char *csid); | ||||
| 	void (*add_up_node) (const char *csid); | ||||
| 	void (*reread_config) (void); | ||||
| 	void (*cluster_closedown) (void); | ||||
|  | ||||
| 	int (*get_cluster_name)(char *buf, int buflen); | ||||
|  | ||||
| 	int (*sync_lock) (const char *resource, int mode, | ||||
| 			  int flags, int *lockid); | ||||
| 	int (*sync_unlock) (const char *resource, int lockid); | ||||
|  | ||||
| }; | ||||
|  | ||||
| #ifdef USE_GULM | ||||
| #  include "tcp-comms.h" | ||||
| struct cluster_ops *init_gulm_cluster(void); | ||||
| #define MAX_CSID_LEN 			GULM_MAX_CSID_LEN | ||||
| #define MAX_CLUSTER_MEMBER_NAME_LEN	GULM_MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_CMAN | ||||
| #  include <netinet/in.h> | ||||
| #  include "libcman.h" | ||||
| #  define CMAN_MAX_CSID_LEN 4 | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN CMAN_MAX_CSID_LEN | ||||
| #  endif | ||||
| #  undef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN | ||||
| #  define CMAN_MAX_CLUSTER_MESSAGE 1500 | ||||
| #  define CLUSTER_PORT_CLVMD 11 | ||||
| struct cluster_ops *init_cman_cluster(void); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_OPENAIS | ||||
| #  include <openais/saAis.h> | ||||
| #  include <openais/totem/totem.h> | ||||
| #  define OPENAIS_CSID_LEN (sizeof(int)) | ||||
| #  define OPENAIS_MAX_CLUSTER_MESSAGE         MESSAGE_SIZE_MAX | ||||
| #  define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH | ||||
| #  ifndef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #    define MAX_CLUSTER_MEMBER_NAME_LEN       SA_MAX_NAME_LENGTH | ||||
| #  endif | ||||
| #  ifndef CMAN_MAX_CLUSTER_MESSAGE | ||||
| #    define CMAN_MAX_CLUSTER_MESSAGE          MESSAGE_SIZE_MAX | ||||
| #  endif | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN sizeof(int) | ||||
| #  endif | ||||
| struct cluster_ops *init_openais_cluster(void); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1011
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1011
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
|  | ||||
| /* DLM constant that clvmd uses as a generic NONBLOCK lock flag */ | ||||
| #define LKF_NOQUEUE 1 | ||||
|  | ||||
| extern int get_next_node_csid(void **context, char *csid); | ||||
| extern void add_down_node(char *csid); | ||||
| extern int gulm_fd(void); | ||||
| extern int get_ip_address(const char *node, char *addr); | ||||
| extern void tcp_remove_client(const char *csid); | ||||
| extern int alloc_client(int fd, const char *csid, struct local_client **new_client); | ||||
|  | ||||
| void gulm_add_up_node(const char *csid); | ||||
| int gulm_name_from_csid(const char *csid, char *name); | ||||
							
								
								
									
										707
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										707
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,707 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) 2007 Red Hat, Inc. All rights reserved. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* This provides the interface between clvmd and OpenAIS as the cluster | ||||
|  * and lock manager. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/file.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <signal.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <utmpx.h> | ||||
| #include <syslog.h> | ||||
| #include <assert.h> | ||||
| #include <libdevmapper.h> | ||||
|  | ||||
| #include <openais/saAis.h> | ||||
| #include <openais/saLck.h> | ||||
| #include <openais/cpg.h> | ||||
|  | ||||
| #include "locking.h" | ||||
| #include "lvm-logging.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "lvm-functions.h" | ||||
| #include "clvmd.h" | ||||
|  | ||||
| /* Timeout value for several openais calls */ | ||||
| #define TIMEOUT 10 | ||||
|  | ||||
| static void cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  int msg_len); | ||||
| static void cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 struct cpg_name *groupName, | ||||
| 				 struct cpg_address *member_list, int member_list_entries, | ||||
| 				 struct cpg_address *left_list, int left_list_entries, | ||||
| 				 struct cpg_address *joined_list, int joined_list_entries); | ||||
| static void _cluster_closedown(void); | ||||
|  | ||||
| /* Hash list of nodes in the cluster */ | ||||
| static struct dm_hash_table *node_hash; | ||||
|  | ||||
| /* For associating lock IDs & resource handles */ | ||||
| static struct dm_hash_table *lock_hash; | ||||
|  | ||||
| /* Number of active nodes */ | ||||
| static int num_nodes; | ||||
| static unsigned int our_nodeid; | ||||
|  | ||||
| static struct local_client *cluster_client; | ||||
|  | ||||
| /* OpenAIS handles */ | ||||
| static cpg_handle_t cpg_handle; | ||||
| static SaLckHandleT lck_handle; | ||||
|  | ||||
| static struct cpg_name cpg_group_name; | ||||
|  | ||||
| /* Openais callback structs */ | ||||
| cpg_callbacks_t cpg_callbacks = { | ||||
| 	.cpg_deliver_fn =            cpg_deliver_callback, | ||||
| 	.cpg_confchg_fn =            cpg_confchg_callback, | ||||
| }; | ||||
|  | ||||
| struct node_info | ||||
| { | ||||
| 	enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state; | ||||
| 	int nodeid; | ||||
| }; | ||||
|  | ||||
| struct lock_info | ||||
| { | ||||
| 	SaLckResourceHandleT res_handle; | ||||
| 	SaLckLockIdT         lock_id; | ||||
| 	SaNameT              lock_name; | ||||
| }; | ||||
|  | ||||
| /* Set errno to something approximating the right value and return 0 or -1 */ | ||||
| static int ais_to_errno(SaAisErrorT err) | ||||
| { | ||||
| 	switch(err) | ||||
| 	{ | ||||
| 	case SA_AIS_OK: | ||||
| 		return 0; | ||||
|         case SA_AIS_ERR_LIBRARY: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_VERSION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INIT: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TIMEOUT: | ||||
| 		errno = ETIME; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TRY_AGAIN: | ||||
| 		errno = EAGAIN; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INVALID_PARAM: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_MEMORY: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_HANDLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BUSY: | ||||
| 		errno = EBUSY; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_ACCESS: | ||||
| 		errno = EPERM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NOT_EXIST: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NAME_TOO_LONG: | ||||
| 		errno = ENAMETOOLONG; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_EXIST: | ||||
| 		errno = EEXIST; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_SPACE: | ||||
| 		errno = ENOSPC; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INTERRUPT: | ||||
| 		errno = EINTR; | ||||
| 		break; | ||||
| 	case SA_AIS_ERR_NAME_NOT_FOUND: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_RESOURCES: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NOT_SUPPORTED: | ||||
| 		errno = EOPNOTSUPP; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_OPERATION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_FAILED_OPERATION: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_MESSAGE_ERROR: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_QUEUE_FULL: | ||||
| 		errno = EXFULL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_QUEUE_NOT_AVAILABLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_FLAGS: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TOO_BIG: | ||||
| 		errno = E2BIG; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_SECTIONS: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
| 	default: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static char *print_csid(const char *csid) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	int id; | ||||
|  | ||||
| 	memcpy(&id, csid, sizeof(int)); | ||||
| 	sprintf(buf, "%d", id); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| static int add_internal_client(int fd, fd_callback_t callback) | ||||
| { | ||||
| 	struct local_client *client; | ||||
|  | ||||
| 	DEBUGLOG("Add_internal_client, fd = %d\n", fd); | ||||
|  | ||||
| 	client = malloc(sizeof(struct local_client)); | ||||
| 	if (!client) | ||||
| 	{ | ||||
| 		DEBUGLOG("malloc failed\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	memset(client, 0, sizeof(struct local_client)); | ||||
| 	client->fd = fd; | ||||
| 	client->type = CLUSTER_INTERNAL; | ||||
| 	client->callback = callback; | ||||
| 	add_client(client); | ||||
|  | ||||
| 	/* Set Close-on-exec */ | ||||
| 	fcntl(fd, F_SETFD, 1); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  int msg_len) | ||||
| { | ||||
| 	int target_nodeid; | ||||
|  | ||||
| 	memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN); | ||||
|  | ||||
| 	DEBUGLOG("%u got message from nodeid %d for %d. len %d\n", | ||||
| 		 our_nodeid, nodeid, target_nodeid, msg_len-4); | ||||
|  | ||||
| 	if (nodeid != our_nodeid) | ||||
| 		if (target_nodeid == our_nodeid || target_nodeid == 0) | ||||
| 			process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN, | ||||
| 					msg_len-OPENAIS_CSID_LEN, (char*)&nodeid); | ||||
| } | ||||
|  | ||||
| static void cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 struct cpg_name *groupName, | ||||
| 				 struct cpg_address *member_list, int member_list_entries, | ||||
| 				 struct cpg_address *left_list, int left_list_entries, | ||||
| 				 struct cpg_address *joined_list, int joined_list_entries) | ||||
| { | ||||
| 	int i; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	DEBUGLOG("confchg callback. %d joined, %d left, %d members\n", | ||||
| 		 joined_list_entries, left_list_entries, member_list_entries); | ||||
|  | ||||
| 	for (i=0; i<joined_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&joined_list[i].nodeid, | ||||
| 					      OPENAIS_CSID_LEN); | ||||
| 		if (!ninfo) { | ||||
| 			ninfo = malloc(sizeof(struct node_info)); | ||||
| 			if (!ninfo) { | ||||
| 				break; | ||||
| 			} | ||||
| 			else { | ||||
| 				ninfo->nodeid = joined_list[i].nodeid; | ||||
| 				dm_hash_insert_binary(node_hash, | ||||
| 						      (char *)&ninfo->nodeid, | ||||
| 						      OPENAIS_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	for (i=0; i<left_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&left_list[i].nodeid, | ||||
| 					      OPENAIS_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			ninfo->state = NODE_DOWN; | ||||
| 	} | ||||
|  | ||||
| 	for (i=0; i<member_list_entries; i++) { | ||||
| 		if (member_list[i].nodeid == 0) continue; | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 				(char *)&member_list[i].nodeid, | ||||
| 				OPENAIS_CSID_LEN); | ||||
| 		if (!ninfo) { | ||||
| 			ninfo = malloc(sizeof(struct node_info)); | ||||
| 			if (!ninfo) { | ||||
| 				break; | ||||
| 			} | ||||
| 			else { | ||||
| 				ninfo->nodeid = member_list[i].nodeid; | ||||
| 				dm_hash_insert_binary(node_hash, | ||||
| 						(char *)&ninfo->nodeid, | ||||
| 						OPENAIS_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	num_nodes = member_list_entries; | ||||
| } | ||||
|  | ||||
| static int lck_dispatch(struct local_client *client, char *buf, int len, | ||||
| 			const char *csid, struct local_client **new_client) | ||||
| { | ||||
| 	*new_client = NULL; | ||||
| 	saLckDispatch(lck_handle, SA_DISPATCH_ONE); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	SaAisErrorT err; | ||||
| 	SaVersionT  ver = { 'B', 1, 1 }; | ||||
| 	int select_fd; | ||||
|  | ||||
| 	node_hash = dm_hash_create(100); | ||||
| 	lock_hash = dm_hash_create(10); | ||||
|  | ||||
| 	err = cpg_initialize(&cpg_handle, | ||||
| 			     &cpg_callbacks); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = saLckInitialize(&lck_handle, | ||||
| 					NULL, | ||||
| 			      &ver); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_initialize(&cpg_handle, &cpg_callbacks); | ||||
| 		syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Connect to the clvmd group */ | ||||
| 	strcpy((char *)cpg_group_name.value, "clvmd"); | ||||
| 	cpg_group_name.length = strlen((char *)cpg_group_name.value); | ||||
| 	err = cpg_join(cpg_handle, &cpg_group_name); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		saLckFinalize(lck_handle); | ||||
| 		syslog(LOG_ERR, "Cannot join clvmd process group"); | ||||
| 		DEBUGLOG("Cannot join clvmd process group: %d\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = cpg_local_get(cpg_handle, | ||||
| 			    &our_nodeid); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		saLckFinalize(lck_handle); | ||||
| 		syslog(LOG_ERR, "Cannot get local node id\n"); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
| 	DEBUGLOG("Our local node id is %d\n", our_nodeid); | ||||
|  | ||||
| 	saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd); | ||||
| 	add_internal_client(select_fd, lck_dispatch); | ||||
|  | ||||
| 	DEBUGLOG("Connected to OpenAIS\n"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	DEBUGLOG("cluster_closedown\n"); | ||||
| 	unlock_all(); | ||||
|  | ||||
| 	saLckFinalize(lck_handle); | ||||
| 	cpg_finalize(cpg_handle); | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	memcpy(csid, &our_nodeid, sizeof(int)); | ||||
| } | ||||
|  | ||||
| /* OpenAIS doesn't really have nmode names so we | ||||
|    just use the node ID in hex instead */ | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	int nodeid; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	if (sscanf(name, "%x", &nodeid) == 1) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			return nodeid; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 	if (!ninfo) | ||||
| 	{ | ||||
| 		sprintf(name, "UNKNOWN %s", print_csid(csid)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(name, "%x", ninfo->nodeid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	DEBUGLOG("num_nodes = %d\n", num_nodes); | ||||
| 	return num_nodes; | ||||
| } | ||||
|  | ||||
| /* Node is now known to be running a clvmd */ | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 	if (!ninfo) { | ||||
| 		DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n", | ||||
| 			 print_csid(csid)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid); | ||||
|  | ||||
| 	ninfo->state = NODE_CLVMD; | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| /* Call a callback for each node, so the caller knows whether it's up or down */ | ||||
| static int _cluster_do_node_callback(struct local_client *master_client, | ||||
| 				     void (*callback)(struct local_client *, | ||||
| 						      const char *csid, int node_up)) | ||||
| { | ||||
| 	struct dm_hash_node *hn; | ||||
| 	struct node_info *ninfo; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	dm_hash_iterate(hn, node_hash) | ||||
| 	{ | ||||
| 		char csid[OPENAIS_CSID_LEN]; | ||||
|  | ||||
| 		ninfo = dm_hash_get_data(node_hash, hn); | ||||
| 		memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN); | ||||
|  | ||||
| 		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid, | ||||
| 			 ninfo->state); | ||||
|  | ||||
| 		if (ninfo->state != NODE_DOWN) | ||||
| 			callback(master_client, csid, ninfo->state == NODE_CLVMD); | ||||
| 		if (ninfo->state != NODE_CLVMD) | ||||
| 			somedown = -1; | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	struct lock_info *linfo; | ||||
| 	SaLckResourceHandleT res_handle; | ||||
| 	SaAisErrorT err; | ||||
| 	SaLckLockIdT lock_id; | ||||
| 	SaLckLockStatusT lockStatus; | ||||
|  | ||||
| 	/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */ | ||||
| 	if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE; | ||||
|  | ||||
| 	linfo = malloc(sizeof(struct lock_info)); | ||||
| 	if (!linfo) | ||||
| 		return -1; | ||||
|  | ||||
| 	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode); | ||||
|  | ||||
| 	linfo->lock_name.length = strlen(resource)+1; | ||||
| 	strcpy((char *)linfo->lock_name.value, resource); | ||||
|  | ||||
| 	err = saLckResourceOpen(lck_handle, &linfo->lock_name, | ||||
| 				SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle); | ||||
| 	if (err != SA_AIS_OK) | ||||
| 	{ | ||||
| 		DEBUGLOG("ResourceOpen returned %d\n", err); | ||||
| 		free(linfo); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = saLckResourceLock( | ||||
| 			res_handle, | ||||
| 			&lock_id, | ||||
| 			mode, | ||||
| 			flags, | ||||
| 			0, | ||||
| 			SA_TIME_END, | ||||
| 			&lockStatus); | ||||
| 	if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED) | ||||
| 	{ | ||||
| 		free(linfo); | ||||
| 		saLckResourceClose(res_handle); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
| 			 | ||||
| 	/* Wait for it to complete */ | ||||
|  | ||||
| 	DEBUGLOG("lock_resource returning %d, lock_id=%llx\n", err, | ||||
| 		 lock_id); | ||||
|  | ||||
| 	linfo->lock_id = lock_id; | ||||
| 	linfo->res_handle = res_handle; | ||||
|  | ||||
| 	dm_hash_insert(lock_hash, resource, linfo); | ||||
|  | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _unlock_resource(char *resource, int lockid) | ||||
| { | ||||
| 	SaAisErrorT err; | ||||
| 	struct lock_info *linfo; | ||||
|  | ||||
| 	DEBUGLOG("unlock_resource %s\n", resource); | ||||
| 	linfo = dm_hash_lookup(lock_hash, resource); | ||||
| 	if (!linfo) | ||||
| 		return 0; | ||||
|  | ||||
| 	DEBUGLOG("unlock_resource: lockid: %llx\n", linfo->lock_id); | ||||
| 	err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END); | ||||
| 	if (err != SA_AIS_OK) | ||||
| 	{ | ||||
| 		DEBUGLOG("Unlock returned %d\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Release the resource */ | ||||
| 	dm_hash_remove(lock_hash, resource); | ||||
| 	saLckResourceClose(linfo->res_handle); | ||||
| 	free(linfo); | ||||
|  | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
| static int _sync_lock(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	char lock1[strlen(resource)+3]; | ||||
| 	char lock2[strlen(resource)+3]; | ||||
|  | ||||
| 	snprintf(lock1, sizeof(lock1), "%s-1", resource); | ||||
| 	snprintf(lock2, sizeof(lock2), "%s-2", resource); | ||||
|  | ||||
| 	switch (mode) | ||||
| 	{ | ||||
| 	case LCK_EXCL: | ||||
| 		status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
|  | ||||
| 		/* If we can't get this lock too then bail out */ | ||||
| 		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK, | ||||
| 					lockid); | ||||
| 		if (status == SA_LCK_LOCK_NOT_QUEUED) | ||||
| 		{ | ||||
| 			_unlock_resource(lock1, *lockid); | ||||
| 			status = -1; | ||||
| 			errno = EAGAIN; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_PREAD: | ||||
| 	case LCK_READ: | ||||
| 		status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
| 		_unlock_resource(lock2, *lockid); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_WRITE: | ||||
| 		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
| 		_unlock_resource(lock1, *lockid); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		status = -1; | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| out: | ||||
| 	*lockid = mode; | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static int _sync_unlock(const char *resource, int lockid) | ||||
| { | ||||
| 	int status = 0; | ||||
| 	char lock1[strlen(resource)+3]; | ||||
| 	char lock2[strlen(resource)+3]; | ||||
|  | ||||
| 	snprintf(lock1, sizeof(lock1), "%s-1", resource); | ||||
| 	snprintf(lock2, sizeof(lock2), "%s-2", resource); | ||||
|  | ||||
| 	_unlock_resource(lock1, lockid); | ||||
| 	_unlock_resource(lock2, lockid); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* We are always quorate ! */ | ||||
| static int _is_quorate() | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	int select_fd; | ||||
|  | ||||
| 	cpg_fd_get(cpg_handle, &select_fd); | ||||
| 	return select_fd; | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
| 	cluster_client = fd; | ||||
| 	*new_client = NULL; | ||||
| 	cpg_dispatch(cpg_handle, SA_DISPATCH_ONE); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _cluster_send_message(const void *buf, int msglen, const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	struct iovec iov[2]; | ||||
| 	SaAisErrorT err; | ||||
| 	int target_node; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&target_node, csid, OPENAIS_CSID_LEN); | ||||
| 	else | ||||
| 		target_node = 0; | ||||
|  | ||||
| 	iov[0].iov_base = &target_node; | ||||
| 	iov[0].iov_len = sizeof(int); | ||||
| 	iov[1].iov_base = (char *)buf; | ||||
| 	iov[1].iov_len = msglen; | ||||
|  | ||||
| 	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2); | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
| /* We don't have a cluster name to report here */ | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	strncpy(buf, "OpenAIS", buflen); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_openais_ops = { | ||||
| 	.cluster_init_completed   = NULL, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.reread_config            = NULL, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_openais_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_openais_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										2001
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2001
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										126
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_H | ||||
| #define _CLVMD_H | ||||
|  | ||||
| #define CLVMD_MAJOR_VERSION 0 | ||||
| #define CLVMD_MINOR_VERSION 2 | ||||
| #define CLVMD_PATCH_VERSION 1 | ||||
|  | ||||
| /* Name of the cluster LVM admin lock */ | ||||
| #define ADMIN_LOCK_NAME "CLVMD_ADMIN" | ||||
|  | ||||
| /* Default time (in seconds) we will wait for all remote commands to execute | ||||
|    before declaring them dead */ | ||||
| #define DEFAULT_CMD_TIMEOUT 60 | ||||
|  | ||||
| /* One of these for each reply we get from command execution on a node */ | ||||
| struct node_reply { | ||||
| 	char node[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| 	char *replymsg; | ||||
| 	int status; | ||||
| 	struct node_reply *next; | ||||
| }; | ||||
|  | ||||
| typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t; | ||||
|  | ||||
| /* | ||||
|  * These exist for the use of local sockets only when we are | ||||
|  * collecting responses from all cluster nodes | ||||
|  */ | ||||
| struct localsock_bits { | ||||
| 	struct node_reply *replies; | ||||
| 	int num_replies; | ||||
| 	int expected_replies; | ||||
| 	time_t sent_time;	/* So we can check for timeouts */ | ||||
| 	int in_progress;	/* Only execute one cmd at a time per client */ | ||||
| 	int sent_out;		/* Flag to indicate that a command was sent | ||||
| 				   to remote nodes */ | ||||
| 	void *private;		/* Private area for command processor use */ | ||||
| 	void *cmd;		/* Whole command as passed down local socket */ | ||||
| 	int cmd_len;		/* Length of above */ | ||||
| 	int pipe;		/* Pipe to send PRE completion status down */ | ||||
| 	int finished;		/* Flag to tell subthread to exit */ | ||||
| 	int all_success;	/* Set to 0 if any node (or the pre_command) | ||||
| 				   failed */ | ||||
| 	struct local_client *pipe_client; | ||||
| 	pthread_t threadid; | ||||
| 	enum { PRE_COMMAND, POST_COMMAND, QUIT } state; | ||||
| 	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */ | ||||
| 	pthread_cond_t cond; | ||||
|  | ||||
| 	pthread_mutex_t reply_mutex;	/* Protect reply structure */ | ||||
| }; | ||||
|  | ||||
| /* Entries for PIPE clients */ | ||||
| struct pipe_bits { | ||||
| 	struct local_client *client;	/* Actual (localsock) client */ | ||||
| 	pthread_t threadid;		/* Our own copy of the thread id */ | ||||
| }; | ||||
|  | ||||
| /* Entries for Network socket clients */ | ||||
| struct netsock_bits { | ||||
| 	void *private; | ||||
| 	int flags; | ||||
| }; | ||||
|  | ||||
| typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len, | ||||
| 			      const char *csid, | ||||
| 			      struct local_client ** new_client); | ||||
|  | ||||
| /* One of these for each fd we are listening on */ | ||||
| struct local_client { | ||||
| 	int fd; | ||||
| 	enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS, | ||||
| 		    LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type; | ||||
| 	struct local_client *next; | ||||
| 	unsigned short xid; | ||||
| 	fd_callback_t callback; | ||||
| 	uint8_t removeme; | ||||
|  | ||||
| 	union { | ||||
| 		struct localsock_bits localsock; | ||||
| 		struct pipe_bits pipe; | ||||
| 		struct netsock_bits net; | ||||
| 	} bits; | ||||
| }; | ||||
|  | ||||
| #define DEBUGLOG(fmt, args...) debuglog(fmt, ## args); | ||||
|  | ||||
| #ifndef max | ||||
| #define max(a,b) ((a)>(b)?(a):(b)) | ||||
| #endif | ||||
|  | ||||
| /* The real command processor is in clvmd-command.c */ | ||||
| extern int do_command(struct local_client *client, struct clvm_header *msg, | ||||
| 		      int msglen, char **buf, int buflen, int *retlen); | ||||
|  | ||||
| /* Pre and post command routines are called only on the local node */ | ||||
| extern int do_pre_command(struct local_client *client); | ||||
| extern int do_post_command(struct local_client *client); | ||||
| extern void cmd_client_cleanup(struct local_client *client); | ||||
| extern int add_client(struct local_client *new_client); | ||||
|  | ||||
| extern void clvmd_cluster_init_completed(void); | ||||
| extern void process_message(struct local_client *client, const char *buf, | ||||
| 			    int len, const char *csid); | ||||
| extern void debuglog(const char *fmt, ... ) | ||||
|   __attribute__ ((format(printf, 1, 2))); | ||||
|  | ||||
| int sync_lock(const char *resource, int mode, int flags, int *lockid); | ||||
| int sync_unlock(const char *resource, int lockid); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										755
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										755
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,755 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <syslog.h> | ||||
| #include <assert.h> | ||||
| #include <libdevmapper.h> | ||||
| #include <libdlm.h> | ||||
|  | ||||
| #include "lvm-types.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| /* LVM2 headers */ | ||||
| #include "toolcontext.h" | ||||
| #include "lvmcache.h" | ||||
| #include "lvm-logging.h" | ||||
| #include "lvm-globals.h" | ||||
| #include "activate.h" | ||||
| #include "locking.h" | ||||
| #include "archiver.h" | ||||
| #include "defaults.h" | ||||
|  | ||||
| static struct cmd_context *cmd = NULL; | ||||
| static struct dm_hash_table *lv_hash = NULL; | ||||
| static pthread_mutex_t lv_hash_lock; | ||||
| static pthread_mutex_t lvm_lock; | ||||
| static char last_error[1024]; | ||||
| static int suspended = 0; | ||||
|  | ||||
| struct lv_info { | ||||
| 	int lock_id; | ||||
| 	int lock_mode; | ||||
| }; | ||||
|  | ||||
| #define LCK_MASK (LCK_TYPE_MASK | LCK_SCOPE_MASK) | ||||
|  | ||||
| static const char *decode_locking_cmd(unsigned char cmdl) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	const char *type; | ||||
| 	const char *scope; | ||||
| 	const char *command; | ||||
|  | ||||
| 	switch (cmdl & LCK_TYPE_MASK) { | ||||
| 	case LCK_NULL:    | ||||
| 		type = "NULL";    | ||||
| 		break; | ||||
| 	case LCK_READ:    | ||||
| 		type = "READ";    | ||||
| 		break; | ||||
| 	case LCK_PREAD:   | ||||
| 		type = "PREAD";   | ||||
| 		break; | ||||
| 	case LCK_WRITE:   | ||||
| 		type = "WRITE";   | ||||
| 		break; | ||||
| 	case LCK_EXCL:    | ||||
| 		type = "EXCL";    | ||||
| 		break; | ||||
| 	case LCK_UNLOCK:  | ||||
| 		type = "UNLOCK";  | ||||
| 		break; | ||||
| 	default: | ||||
| 		type = "unknown"; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	switch (cmdl & LCK_SCOPE_MASK) { | ||||
| 	case LCK_VG:  | ||||
| 		scope = "VG";  | ||||
| 		break; | ||||
| 	case LCK_LV:  | ||||
| 		scope = "LV";  | ||||
| 		break; | ||||
| 	default: | ||||
| 		scope = "unknown"; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	switch (cmdl & LCK_MASK) { | ||||
| 	case LCK_LV_EXCLUSIVE & LCK_MASK: | ||||
| 		command = "LCK_LV_EXCLUSIVE";   | ||||
| 		break; | ||||
| 	case LCK_LV_SUSPEND & LCK_MASK:     | ||||
| 		command = "LCK_LV_SUSPEND";     | ||||
| 		break; | ||||
| 	case LCK_LV_RESUME & LCK_MASK:      | ||||
| 		command = "LCK_LV_RESUME";      | ||||
| 		break; | ||||
| 	case LCK_LV_ACTIVATE & LCK_MASK:    | ||||
| 		command = "LCK_LV_ACTIVATE";    | ||||
| 		break; | ||||
| 	case LCK_LV_DEACTIVATE & LCK_MASK:  | ||||
| 		command = "LCK_LV_DEACTIVATE";  | ||||
| 		break; | ||||
| 	default: | ||||
| 		command = "unknown"; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(buf, "0x%x %s (%s|%s%s%s%s%s%s)", cmdl, command, type, scope, | ||||
| 		cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "", | ||||
| 		cmdl & LCK_HOLD       ? "|HOLD" : "", | ||||
| 		cmdl & LCK_LOCAL      ? "|LOCAL" : "", | ||||
| 		cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "", | ||||
| 		cmdl & LCK_CACHE      ? "|CACHE" : ""); | ||||
|  | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| static const char *decode_flags(unsigned char flags) | ||||
| { | ||||
| 	static char buf[128]; | ||||
|  | ||||
| 	sprintf(buf, "0x%x (%s%s)", flags, | ||||
| 		flags & LCK_MIRROR_NOSYNC_MODE	  ? "MIRROR_NOSYNC " : "", | ||||
| 		flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR " : ""); | ||||
|  | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| char *get_last_lvm_error() | ||||
| { | ||||
| 	return last_error; | ||||
| } | ||||
|  | ||||
| /* Return the mode a lock is currently held at (or -1 if not held) */ | ||||
| static int get_current_lock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (lvi) { | ||||
| 		return lvi->lock_mode; | ||||
| 	} else { | ||||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Called at shutdown to tidy the lockspace */ | ||||
| void unlock_all() | ||||
| { | ||||
| 	struct dm_hash_node *v; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	dm_hash_iterate(v, lv_hash) { | ||||
| 		struct lv_info *lvi = dm_hash_get_data(lv_hash, v); | ||||
|  | ||||
| 		sync_unlock(dm_hash_get_key(lv_hash, v), lvi->lock_id); | ||||
| 	} | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| } | ||||
|  | ||||
| /* Gets a real lock and keeps the info in the hash table */ | ||||
| int hold_lock(char *resource, int mode, int flags) | ||||
| { | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	flags &= LKF_NOQUEUE;	/* Only LKF_NOQUEUE is valid here */ | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (lvi) { | ||||
| 		/* Already exists - convert it */ | ||||
| 		status = | ||||
| 		    sync_lock(resource, mode, LKF_CONVERT | flags, | ||||
| 			      &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (!status) | ||||
| 			lvi->lock_mode = mode; | ||||
|  | ||||
| 		if (status) { | ||||
| 			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} | ||||
| 		errno = saved_errno; | ||||
| 	} else { | ||||
| 		lvi = malloc(sizeof(struct lv_info)); | ||||
| 		if (!lvi) | ||||
| 			return -1; | ||||
|  | ||||
| 		lvi->lock_mode = mode; | ||||
| 		status = sync_lock(resource, mode, flags, &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (status) { | ||||
| 			free(lvi); | ||||
| 			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} else { | ||||
| 		        pthread_mutex_lock(&lv_hash_lock); | ||||
| 			dm_hash_insert(lv_hash, resource, lvi); | ||||
| 			pthread_mutex_unlock(&lv_hash_lock); | ||||
| 		} | ||||
| 		errno = saved_errno; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Unlock and remove it from the hash table */ | ||||
| int hold_unlock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (!lvi) { | ||||
| 		DEBUGLOG("hold_unlock, lock not already held\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	status = sync_unlock(resource, lvi->lock_id); | ||||
| 	saved_errno = errno; | ||||
| 	if (!status) { | ||||
| 	    	pthread_mutex_lock(&lv_hash_lock); | ||||
| 		dm_hash_remove(lv_hash, resource); | ||||
| 		pthread_mutex_unlock(&lv_hash_lock); | ||||
| 		free(lvi); | ||||
| 	} else { | ||||
| 		DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status, | ||||
| 			 strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| 	errno = saved_errno; | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Watch the return codes here. | ||||
|    liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno. | ||||
|    libdlm API functions return 0 for success, -1 for failure and do set errno. | ||||
|    These functions here return 0 for success or >0 for failure (where the retcode is errno) | ||||
| */ | ||||
|  | ||||
| /* Activate LV exclusive or non-exclusive */ | ||||
| static int do_activate_lv(char *resource, unsigned char lock_flags, int mode) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
| 	int activate_lv; | ||||
| 	int exclusive = 0; | ||||
| 	struct lvinfo lvi; | ||||
|  | ||||
| 	/* Is it already open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == mode) { | ||||
| 		return 0;	/* Nothing to do */ | ||||
| 	} | ||||
|  | ||||
| 	/* Does the config file want us to activate this LV ? */ | ||||
| 	if (!lv_activation_filter(cmd, resource, &activate_lv)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (!activate_lv) | ||||
| 		return 0;	/* Success, we did nothing! */ | ||||
|  | ||||
| 	/* Do we need to activate exclusively? */ | ||||
| 	if ((activate_lv == 2) || (mode == LKM_EXMODE)) { | ||||
| 		exclusive = 1; | ||||
| 		mode = LKM_EXMODE; | ||||
| 	} | ||||
|  | ||||
| 	/* Try to get the lock if it's a clustered volume group */ | ||||
| 	if (lock_flags & LCK_CLUSTER_VG) { | ||||
| 		status = hold_lock(resource, mode, LKF_NOQUEUE); | ||||
| 		if (status) { | ||||
| 			/* Return an LVM-sensible error for this. | ||||
| 			 * Forcing EIO makes the upper level return this text | ||||
| 			 * rather than the strerror text for EAGAIN. | ||||
| 			 */ | ||||
| 			if (errno == EAGAIN) { | ||||
| 				sprintf(last_error, "Volume is busy on another node"); | ||||
| 				errno = EIO; | ||||
| 			} | ||||
| 			return errno; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* If it's suspended then resume it */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, &lvi, 0, 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.suspended) | ||||
| 		if (!lv_resume(cmd, resource)) | ||||
| 			return EIO; | ||||
|  | ||||
| 	/* Now activate it */ | ||||
| 	if (!lv_activate(cmd, resource, exclusive)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Resume the LV if it was active */ | ||||
| static int do_resume_lv(char *resource) | ||||
| { | ||||
| 	int oldmode; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1) { | ||||
| 		DEBUGLOG("do_resume_lv, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_resume_if_active(cmd, resource)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Suspend the device if active */ | ||||
| static int do_suspend_lv(char *resource) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	struct lvinfo lvi; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1) { | ||||
| 		DEBUGLOG("do_suspend_lv, lock held at %d\n", oldmode); | ||||
| 		return 0; /* Not active, so it's OK */ | ||||
| 	} | ||||
|  | ||||
| 	/* Only suspend it if it exists */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, &lvi, 0, 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.exists) { | ||||
| 		if (!lv_suspend_if_active(cmd, resource)) { | ||||
| 			return EIO; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_deactivate_lv(char *resource, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_deactivate_lock, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_deactivate(cmd, resource)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lock_flags & LCK_CLUSTER_VG) { | ||||
| 		status = hold_unlock(resource); | ||||
| 		if (status) | ||||
| 			return errno; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* This is the LOCK_LV part that happens on all nodes in the cluster - | ||||
|    it is responsible for the interaction with device-mapper and LVM */ | ||||
| int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	int status = 0; | ||||
|  | ||||
| 	DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 		 resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	if (!cmd->config_valid || config_files_changed(cmd)) { | ||||
| 		/* Reinitialise various settings inc. logging, filters */ | ||||
| 		if (do_refresh_cache()) { | ||||
| 			log_error("Updated config file invalid. Aborting."); | ||||
| 			pthread_mutex_unlock(&lvm_lock); | ||||
| 			return EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(1); | ||||
|  | ||||
| 	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE)) | ||||
| 		init_dmeventd_monitor(0); | ||||
|  | ||||
| 	switch (command) { | ||||
| 	case LCK_LV_EXCLUSIVE: | ||||
| 		status = do_activate_lv(resource, lock_flags, LKM_EXMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_SUSPEND: | ||||
| 		status = do_suspend_lv(resource); | ||||
| 		if (!status) | ||||
| 			suspended++; | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_UNLOCK: | ||||
| 	case LCK_LV_RESUME:	/* if active */ | ||||
| 		status = do_resume_lv(resource); | ||||
| 		if (!status) | ||||
| 			suspended--; | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_ACTIVATE: | ||||
| 		status = do_activate_lv(resource, lock_flags, LKM_CRMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_DEACTIVATE: | ||||
| 		status = do_deactivate_lv(resource, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		DEBUGLOG("Invalid LV command 0x%x\n", command); | ||||
| 		status = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(0); | ||||
|  | ||||
| 	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE)) | ||||
| 		init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR); | ||||
|  | ||||
| 	/* clean the pool for another command */ | ||||
| 	dm_pool_empty(cmd->mem); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
|  | ||||
| 	DEBUGLOG("Command return is %d\n", status); | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */ | ||||
| int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the | ||||
| 	   lock out on this node (because we are the node modifying the metadata) | ||||
| 	   before suspending cluster-wide. | ||||
| 	 */ | ||||
| 	if (command == LCK_LV_SUSPEND) { | ||||
| 		DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 			 resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 		if (hold_lock(resource, LKM_PWMODE, LKF_NOQUEUE)) | ||||
| 			return errno; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only AFTER the cluster-wide stuff above happens */ | ||||
| int post_lock_lv(unsigned char command, unsigned char lock_flags, | ||||
| 		 char *resource) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	/* Opposite of above, done on resume after a metadata update */ | ||||
| 	if (command == LCK_LV_RESUME) { | ||||
| 		int oldmode; | ||||
|  | ||||
| 		DEBUGLOG | ||||
| 		    ("post_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 		     resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 		/* If the lock state is PW then restore it to what it was */ | ||||
| 		oldmode = get_current_lock(resource); | ||||
| 		if (oldmode == LKM_PWMODE) { | ||||
| 			struct lvinfo lvi; | ||||
|  | ||||
| 			pthread_mutex_lock(&lvm_lock); | ||||
| 			status = lv_info_by_lvid(cmd, resource, &lvi, 0, 0); | ||||
| 			pthread_mutex_unlock(&lvm_lock); | ||||
| 			if (!status) | ||||
| 				return EIO; | ||||
|  | ||||
| 			if (lvi.exists) { | ||||
| 				if (hold_lock(resource, LKM_CRMODE, 0)) | ||||
| 					return errno; | ||||
| 			} else { | ||||
| 				if (hold_unlock(resource)) | ||||
| 					return errno; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Check if a VG is in use by LVM1 so we don't stomp on it */ | ||||
| int do_check_lvm1(const char *vgname) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	status = check_lvm1_vg_inactive(cmd, vgname); | ||||
|  | ||||
| 	return status == 1 ? 0 : EBUSY; | ||||
| } | ||||
|  | ||||
| int do_refresh_cache() | ||||
| { | ||||
| 	int ret; | ||||
| 	DEBUGLOG("Refreshing context\n"); | ||||
| 	log_notice("Refreshing context"); | ||||
|  | ||||
| 	ret = refresh_toolcontext(cmd); | ||||
| 	init_full_scan_done(0); | ||||
| 	lvmcache_label_scan(cmd, 2); | ||||
|  | ||||
| 	return ret==1?0:-1; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Only called at gulm startup. Drop any leftover VG or P_orphan locks | ||||
|    that might be hanging around if we died for any reason | ||||
| */ | ||||
| static void drop_vg_locks() | ||||
| { | ||||
| 	char vg[128]; | ||||
| 	char line[255]; | ||||
| 	FILE *vgs = | ||||
| 	    popen | ||||
| 	    ("lvm pvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_name", "r"); | ||||
|  | ||||
| 	sync_unlock("P_" VG_ORPHANS, LCK_EXCL); | ||||
| 	sync_unlock("P_" VG_GLOBAL, LCK_EXCL); | ||||
|  | ||||
| 	if (!vgs) | ||||
| 		return; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), vgs)) { | ||||
| 		char *vgend; | ||||
| 		char *vgstart; | ||||
|  | ||||
| 		if (line[strlen(line)-1] == '\n') | ||||
| 			line[strlen(line)-1] = '\0'; | ||||
|  | ||||
| 		vgstart = line + strspn(line, " "); | ||||
| 		vgend = vgstart + strcspn(vgstart, " "); | ||||
| 		*vgend = '\0'; | ||||
|  | ||||
| 		if (strncmp(vgstart, "WARNING:", 8) == 0) | ||||
| 			continue; | ||||
|  | ||||
| 		sprintf(vg, "V_%s", vgstart); | ||||
| 		sync_unlock(vg, LCK_EXCL); | ||||
|  | ||||
| 	} | ||||
| 	if (fclose(vgs)) | ||||
| 		DEBUGLOG("vgs fclose failed: %s\n", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Drop lvmcache metadata | ||||
|  */ | ||||
| void drop_metadata(const char *vgname) | ||||
| { | ||||
| 	DEBUGLOG("Dropping metadata for VG %s\n", vgname); | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	lvmcache_drop_metadata(vgname); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Ideally, clvmd should be started before any LVs are active | ||||
|  * but this may not be the case... | ||||
|  * I suppose this also comes in handy if clvmd crashes, not that it would! | ||||
|  */ | ||||
| static void *get_initial_state() | ||||
| { | ||||
| 	char lv[64], vg[64], flags[25], vg_flags[25]; | ||||
| 	char uuid[65]; | ||||
| 	char line[255]; | ||||
| 	FILE *lvs = | ||||
| 	    popen | ||||
| 	    ("lvm lvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr", | ||||
| 	     "r"); | ||||
|  | ||||
| 	if (!lvs) | ||||
| 		return NULL; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), lvs)) { | ||||
| 	        if (sscanf(line, "%s %s %s %s\n", vg, lv, flags, vg_flags) == 4) { | ||||
|  | ||||
| 			/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */ | ||||
| 		        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */ | ||||
| 			    (flags[4] == 'a' || flags[4] == 's') &&	/* is it active or suspended? */ | ||||
| 			    vg_flags[5] == 'c') {			/* is it clustered ? */ | ||||
| 				/* Convert hyphen-separated UUIDs into one */ | ||||
| 				memcpy(&uuid[0], &vg[0], 6); | ||||
| 				memcpy(&uuid[6], &vg[7], 4); | ||||
| 				memcpy(&uuid[10], &vg[12], 4); | ||||
| 				memcpy(&uuid[14], &vg[17], 4); | ||||
| 				memcpy(&uuid[18], &vg[22], 4); | ||||
| 				memcpy(&uuid[22], &vg[27], 4); | ||||
| 				memcpy(&uuid[26], &vg[32], 6); | ||||
| 				memcpy(&uuid[32], &lv[0], 6); | ||||
| 				memcpy(&uuid[38], &lv[7], 4); | ||||
| 				memcpy(&uuid[42], &lv[12], 4); | ||||
| 				memcpy(&uuid[46], &lv[17], 4); | ||||
| 				memcpy(&uuid[50], &lv[22], 4); | ||||
| 				memcpy(&uuid[54], &lv[27], 4); | ||||
| 				memcpy(&uuid[58], &lv[32], 6); | ||||
| 				uuid[64] = '\0'; | ||||
|  | ||||
| 				DEBUGLOG("getting initial lock for %s\n", uuid); | ||||
| 				hold_lock(uuid, LKM_CRMODE, LKF_NOQUEUE); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (fclose(lvs)) | ||||
| 		DEBUGLOG("lvs fclose failed: %s\n", strerror(errno)); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static void lvm2_log_fn(int level, const char *file, int line, | ||||
| 			const char *message) | ||||
| { | ||||
|  | ||||
| 	/* Send messages to the normal LVM2 logging system too, | ||||
| 	   so we get debug output when it's asked for. | ||||
|  	   We need to NULL the function ptr otherwise it will just call | ||||
| 	   back into here! */ | ||||
| 	init_log_fn(NULL); | ||||
| 	print_log(level, file, line, "%s", message); | ||||
| 	init_log_fn(lvm2_log_fn); | ||||
|  | ||||
| 	/* | ||||
| 	 * Ignore non-error messages, but store the latest one for returning | ||||
| 	 * to the user. | ||||
| 	 */ | ||||
| 	if (level != _LOG_ERR && level != _LOG_FATAL) | ||||
| 		return; | ||||
|  | ||||
| 	strncpy(last_error, message, sizeof(last_error)); | ||||
| 	last_error[sizeof(last_error)-1] = '\0'; | ||||
| } | ||||
|  | ||||
| /* This checks some basic cluster-LVM configuration stuff */ | ||||
| static void check_config() | ||||
| { | ||||
| 	int locking_type; | ||||
|  | ||||
| 	locking_type = find_config_tree_int(cmd, "global/locking_type", 1); | ||||
|  | ||||
| 	if (locking_type == 3) /* compiled-in cluster support */ | ||||
| 		return; | ||||
|  | ||||
| 	if (locking_type == 2) { /* External library, check name */ | ||||
| 		const char *libname; | ||||
|  | ||||
| 		libname = find_config_tree_str(cmd, "global/locking_library", | ||||
| 					  ""); | ||||
| 		if (strstr(libname, "liblvm2clusterlock.so")) | ||||
| 			return; | ||||
|  | ||||
| 		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work."); | ||||
| 		return; | ||||
| 	} | ||||
| 	log_error("locking_type not set correctly in lvm.conf, cluster operations will not work."); | ||||
| } | ||||
|  | ||||
| void init_lvhash() | ||||
| { | ||||
| 	/* Create hash table for keeping LV locks & status */ | ||||
| 	lv_hash = dm_hash_create(100); | ||||
| 	pthread_mutex_init(&lv_hash_lock, NULL); | ||||
| 	pthread_mutex_init(&lvm_lock, NULL); | ||||
| } | ||||
|  | ||||
| /* Backups up the LVM metadata if it's changed */ | ||||
| void lvm_do_backup(const char *vgname) | ||||
| { | ||||
| 	struct volume_group * vg; | ||||
| 	int consistent = 0; | ||||
|  | ||||
| 	DEBUGLOG("Triggering backup of VG metadata for %s. suspended=%d\n", vgname, suspended); | ||||
|  | ||||
| 	vg = vg_read(cmd, vgname, NULL /*vgid*/, &consistent); | ||||
| 	if (vg) { | ||||
| 		if (consistent) | ||||
| 			check_current_backup(vg); | ||||
| 	} | ||||
| 	else { | ||||
| 		log_error("Error backing up metadata, can't find VG for group %s", vgname); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Called to initialise the LVM context of the daemon */ | ||||
| int init_lvm(int using_gulm) | ||||
| { | ||||
| 	if (!(cmd = create_toolcontext(NULL, 0, 1))) { | ||||
| 		log_error("Failed to allocate command context"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */ | ||||
| 	init_syslog(LOG_DAEMON); | ||||
| 	openlog("clvmd", LOG_PID, LOG_DAEMON); | ||||
| 	init_debug(cmd->current_settings.debug); | ||||
| 	init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL); | ||||
| 	set_activation(cmd->current_settings.activation); | ||||
| 	archive_enable(cmd, cmd->current_settings.archive); | ||||
| 	backup_enable(cmd, cmd->current_settings.backup); | ||||
| 	cmd->cmd_line = (char *)"clvmd"; | ||||
|  | ||||
| 	/* Check lvm.conf is setup for cluster-LVM */ | ||||
| 	check_config(); | ||||
|  | ||||
| 	/* Remove any non-LV locks that may have been left around */ | ||||
| 	if (using_gulm) | ||||
| 		drop_vg_locks(); | ||||
|  | ||||
| 	get_initial_state(); | ||||
|  | ||||
| 	/* Trap log messages so we can pass them back to the user */ | ||||
| 	init_log_fn(lvm2_log_fn); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										38
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Functions in lvm-functions.c */ | ||||
|  | ||||
| #ifndef _LVM_FUNCTIONS_H | ||||
| #define _LVM_FUNCTIONS_H | ||||
|  | ||||
| extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		       char *resource); | ||||
| extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		      char *resource); | ||||
| extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 			char *resource); | ||||
| extern int do_check_lvm1(const char *vgname); | ||||
| extern int do_refresh_cache(void); | ||||
| extern int init_lvm(int using_gulm); | ||||
| extern void init_lvhash(void); | ||||
| extern void lvm_do_backup(const char *vgname); | ||||
| extern int hold_unlock(char *resource); | ||||
| extern int hold_lock(char *resource, int mode, int flags); | ||||
| extern void unlock_all(void); | ||||
| extern char *get_last_lvm_error(void); | ||||
| extern void drop_metadata(const char *vgname); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										368
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,368 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Tell all clvmds in a cluster to refresh their toolcontext | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <stddef.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <libdevmapper.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "refresh_clvmd.h" | ||||
|  | ||||
| typedef struct lvm_response { | ||||
| 	char node[255]; | ||||
| 	char *response; | ||||
| 	int status; | ||||
| 	int len; | ||||
| } lvm_response_t; | ||||
|  | ||||
| /* | ||||
|  * This gets stuck at the start of memory we allocate so we | ||||
|  * can sanity-check it at deallocation time | ||||
|  */ | ||||
| #define LVM_SIGNATURE 0x434C564D | ||||
|  | ||||
| static int _clvmd_sock = -1; | ||||
|  | ||||
| /* Open connection to the clvm daemon */ | ||||
| static int _open_local_sock(void) | ||||
| { | ||||
| 	int local_socket; | ||||
| 	struct sockaddr_un sockaddr; | ||||
|  | ||||
| 	/* Open local socket */ | ||||
| 	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
| 		fprintf(stderr, "Local socket creation failed: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	memset(&sockaddr, 0, sizeof(sockaddr)); | ||||
| 	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME)); | ||||
|  | ||||
| 	sockaddr.sun_family = AF_UNIX; | ||||
|  | ||||
| 	if (connect(local_socket,(struct sockaddr *) &sockaddr, | ||||
| 		    sizeof(sockaddr))) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		fprintf(stderr, "connect() failed on local socket: %s\n", | ||||
| 			  strerror(errno)); | ||||
| 		if (close(local_socket)) | ||||
| 			return -1; | ||||
|  | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return local_socket; | ||||
| } | ||||
|  | ||||
| /* Send a request and return the status */ | ||||
| static int _send_request(const char *inbuf, int inlen, char **retbuf) | ||||
| { | ||||
| 	char outbuf[PIPE_BUF]; | ||||
| 	struct clvm_header *outheader = (struct clvm_header *) outbuf; | ||||
| 	int len; | ||||
| 	int off; | ||||
| 	int buflen; | ||||
| 	int err; | ||||
|  | ||||
| 	/* Send it to CLVMD */ | ||||
|  rewrite: | ||||
| 	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) { | ||||
| 	        if (err == -1 && errno == EINTR) | ||||
| 		        goto rewrite; | ||||
| 		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the response */ | ||||
|  reread: | ||||
| 	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { | ||||
| 	        if (errno == EINTR) | ||||
| 		        goto reread; | ||||
| 		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (len == 0) { | ||||
| 		fprintf(stderr, "EOF reading CLVMD"); | ||||
| 		errno = ENOTCONN; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Allocate buffer */ | ||||
| 	buflen = len + outheader->arglen; | ||||
| 	*retbuf = dm_malloc(buflen); | ||||
| 	if (!*retbuf) { | ||||
| 		errno = ENOMEM; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Copy the header */ | ||||
| 	memcpy(*retbuf, outbuf, len); | ||||
| 	outheader = (struct clvm_header *) *retbuf; | ||||
|  | ||||
| 	/* Read the returned values */ | ||||
| 	off = 1;		/* we've already read the first byte */ | ||||
| 	while (off <= outheader->arglen && len > 0) { | ||||
| 		len = read(_clvmd_sock, outheader->args + off, | ||||
| 			   buflen - off - offsetof(struct clvm_header, args)); | ||||
| 		if (len > 0) | ||||
| 			off += len; | ||||
| 	} | ||||
|  | ||||
| 	/* Was it an error ? */ | ||||
| 	if (outheader->status != 0) { | ||||
| 		errno = outheader->status; | ||||
|  | ||||
| 		/* Only return an error here if there are no node-specific | ||||
| 		   errors present in the message that might have more detail */ | ||||
| 		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) { | ||||
| 			fprintf(stderr, "cluster request failed: %s\n", strerror(errno)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Build the structure header and parse-out wildcard node names */ | ||||
| static void _build_header(struct clvm_header *head, int cmd, const char *node, | ||||
| 			  int len) | ||||
| { | ||||
| 	head->cmd = cmd; | ||||
| 	head->status = 0; | ||||
| 	head->flags = 0; | ||||
| 	head->clientid = 0; | ||||
| 	head->arglen = len; | ||||
|  | ||||
| 	if (node) { | ||||
| 		/* | ||||
| 		 * Allow a couple of special node names: | ||||
| 		 * "*" for all nodes, | ||||
| 		 * "." for the local node only | ||||
| 		 */ | ||||
| 		if (strcmp(node, "*") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 		} else if (strcmp(node, ".") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 			head->flags = CLVMD_FLAG_LOCAL; | ||||
| 		} else | ||||
| 			strcpy(head->node, node); | ||||
| 	} else | ||||
| 		head->node[0] = '\0'; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Send a message to a(or all) node(s) in the cluster and wait for replies | ||||
|  */ | ||||
| static int _cluster_request(char cmd, const char *node, void *data, int len, | ||||
| 			   lvm_response_t ** response, int *num) | ||||
| { | ||||
| 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1]; | ||||
| 	char *inptr; | ||||
| 	char *retbuf = NULL; | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int num_responses = 0; | ||||
| 	struct clvm_header *head = (struct clvm_header *) outbuf; | ||||
| 	lvm_response_t *rarray; | ||||
|  | ||||
| 	*num = 0; | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		_clvmd_sock = _open_local_sock(); | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		return 0; | ||||
|  | ||||
| 	_build_header(head, cmd, node, len); | ||||
| 	memcpy(head->node + strlen(head->node) + 1, data, len); | ||||
|  | ||||
| 	status = _send_request(outbuf, sizeof(struct clvm_header) + | ||||
| 			      strlen(head->node) + len, &retbuf); | ||||
| 	if (!status) | ||||
| 		goto out; | ||||
|  | ||||
| 	/* Count the number of responses we got */ | ||||
| 	head = (struct clvm_header *) retbuf; | ||||
| 	inptr = head->args; | ||||
| 	while (inptr[0]) { | ||||
| 		num_responses++; | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		inptr += sizeof(int); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate response array. | ||||
| 	 * With an extra pair of INTs on the front to sanity | ||||
| 	 * check the pointer when we are given it back to free | ||||
| 	 */ | ||||
| 	*response = dm_malloc(sizeof(lvm_response_t) * num_responses + | ||||
| 			    sizeof(int) * 2); | ||||
| 	if (!*response) { | ||||
| 		errno = ENOMEM; | ||||
| 		status = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	rarray = *response; | ||||
|  | ||||
| 	/* Unpack the response into an lvm_response_t array */ | ||||
| 	inptr = head->args; | ||||
| 	i = 0; | ||||
| 	while (inptr[0]) { | ||||
| 		strcpy(rarray[i].node, inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
|  | ||||
| 		memcpy(&rarray[i].status, inptr, sizeof(int)); | ||||
| 		inptr += sizeof(int); | ||||
|  | ||||
| 		rarray[i].response = dm_malloc(strlen(inptr) + 1); | ||||
| 		if (rarray[i].response == NULL) { | ||||
| 			/* Free up everything else and return error */ | ||||
| 			int j; | ||||
| 			for (j = 0; j < i; j++) | ||||
| 				dm_free(rarray[i].response); | ||||
| 			free(*response); | ||||
| 			errno = ENOMEM; | ||||
| 			status = -1; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(rarray[i].response, inptr); | ||||
| 		rarray[i].len = strlen(inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		i++; | ||||
| 	} | ||||
| 	*num = num_responses; | ||||
| 	*response = rarray; | ||||
|  | ||||
|       out: | ||||
| 	if (retbuf) | ||||
| 		dm_free(retbuf); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Free reply array */ | ||||
| static int _cluster_free_request(lvm_response_t * response, int num) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num; i++) { | ||||
| 		dm_free(response[i].response); | ||||
| 	} | ||||
|  | ||||
| 	dm_free(response); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int refresh_clvmd() | ||||
| { | ||||
| 	int num_responses; | ||||
| 	char args[1]; // No args really. | ||||
| 	lvm_response_t *response; | ||||
| 	int saved_errno; | ||||
| 	int status; | ||||
| 	int i; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses); | ||||
|  | ||||
| 	/* If any nodes were down then display them and return an error */ | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status == EHOSTDOWN) { | ||||
| 			fprintf(stderr, "clvmd not running on node %s", | ||||
| 				  response[i].node); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} else if (response[i].status) { | ||||
| 			fprintf(stderr, "Error resetting node %s: %s", | ||||
| 				  response[i].node, | ||||
| 				  response[i].response[0] ? | ||||
| 				  	response[i].response : | ||||
| 				  	strerror(response[i].status)); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	saved_errno = errno; | ||||
| 	_cluster_free_request(response, num_responses); | ||||
| 	errno = saved_errno; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| int debug_clvmd(int level, int clusterwide) | ||||
| { | ||||
| 	int num_responses; | ||||
| 	char args[1]; | ||||
| 	const char *nodes; | ||||
| 	lvm_response_t *response; | ||||
| 	int saved_errno; | ||||
| 	int status; | ||||
| 	int i; | ||||
|  | ||||
| 	args[0] = level; | ||||
| 	if (clusterwide) | ||||
| 		nodes = "*"; | ||||
| 	else | ||||
| 		nodes = "."; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses); | ||||
|  | ||||
| 	/* If any nodes were down then display them and return an error */ | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status == EHOSTDOWN) { | ||||
| 			fprintf(stderr, "clvmd not running on node %s", | ||||
| 				  response[i].node); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} else if (response[i].status) { | ||||
| 			fprintf(stderr, "Error setting debug on node %s: %s", | ||||
| 				  response[i].node, | ||||
| 				  response[i].response[0] ? | ||||
| 				  	response[i].response : | ||||
| 				  	strerror(response[i].status)); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	saved_errno = errno; | ||||
| 	_cluster_free_request(response, num_responses); | ||||
| 	errno = saved_errno; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
							
								
								
									
										18
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
|  | ||||
| int refresh_clvmd(void); | ||||
| int debug_clvmd(int level, int clusterwide); | ||||
|  | ||||
							
								
								
									
										504
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,504 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  2002-2003  All rights reserved. | ||||
| **  Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* This provides the inter-clvmd communications for a system without CMAN. | ||||
|    There is a listening TCP socket which accepts new connections in the | ||||
|    normal way. | ||||
|    It can also make outgoing connnections to the other clvmd nodes. | ||||
| */ | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <configure.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <syslog.h> | ||||
| #include <netdb.h> | ||||
| #include <assert.h> | ||||
| #include <libdevmapper.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "clvmd-gulm.h" | ||||
|  | ||||
| #define DEFAULT_TCP_PORT 21064 | ||||
|  | ||||
| static int listen_fd = -1; | ||||
| static int tcp_port; | ||||
| struct dm_hash_table *sock_hash; | ||||
|  | ||||
| static int get_our_ip_address(char *addr, int *family); | ||||
| static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client); | ||||
|  | ||||
| /* Called by init_cluster() to open up the listening socket */ | ||||
| int init_comms(unsigned short port) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|  | ||||
|     sock_hash = dm_hash_create(100); | ||||
|     tcp_port = port ? : DEFAULT_TCP_PORT; | ||||
|  | ||||
|     listen_fd = socket(AF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (listen_fd < 0) | ||||
|     { | ||||
| 	return -1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int one = 1; | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|     } | ||||
|  | ||||
|     memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) | ||||
|     { | ||||
| 	DEBUGLOG("Can't bind to port: %s\n", strerror(errno)); | ||||
| 	syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port); | ||||
| 	close(listen_fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     listen(listen_fd, 5); | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(listen_fd, F_SETFD, 1); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void tcp_remove_client(const char *c_csid) | ||||
| { | ||||
|     struct local_client *client; | ||||
|     char csid[GULM_MAX_CSID_LEN]; | ||||
|     unsigned int i; | ||||
|     memcpy(csid, c_csid, sizeof csid); | ||||
|     DEBUGLOG("tcp_remove_client\n"); | ||||
|  | ||||
|     /* Don't actually close the socket here - that's the | ||||
|        job of clvmd.c whch will do the job when it notices the | ||||
|        other end has gone. We just need to remove the client(s) from | ||||
|        the hash table so we don't try to use it for sending any more */ | ||||
|     for (i = 0; i < 2; i++) | ||||
|     { | ||||
| 	client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	if (client) | ||||
| 	{ | ||||
| 	    dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	    client->removeme = 1; | ||||
| 	    close(client->fd); | ||||
| 	} | ||||
| 	/* Look for a mangled one too, on the 2nd iteration. */ | ||||
| 	csid[0] ^= 0x80; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int alloc_client(int fd, const char *c_csid, struct local_client **new_client) | ||||
| { | ||||
|     struct local_client *client; | ||||
|     char csid[GULM_MAX_CSID_LEN]; | ||||
|     memcpy(csid, c_csid, sizeof csid); | ||||
|  | ||||
|     DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid)); | ||||
|  | ||||
|     /* Create a local_client and return it */ | ||||
|     client = malloc(sizeof(struct local_client)); | ||||
|     if (!client) | ||||
|     { | ||||
| 	DEBUGLOG("malloc failed\n"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     memset(client, 0, sizeof(struct local_client)); | ||||
|     client->fd = fd; | ||||
|     client->type = CLUSTER_DATA_SOCK; | ||||
|     client->callback = read_from_tcpsock; | ||||
|     if (new_client) | ||||
| 	*new_client = client; | ||||
|  | ||||
|     /* Add to our list of node sockets */ | ||||
|     if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|     { | ||||
| 	DEBUGLOG("alloc_client mangling CSID for second connection\n"); | ||||
| 	/* This is a duplicate connection but we can't close it because | ||||
| 	   the other end may already have started sending. | ||||
| 	   So, we mangle the IP address and keep it, all sending will | ||||
| 	   go out of the main FD | ||||
| 	*/ | ||||
| 	csid[0] ^= 0x80; | ||||
| 	client->bits.net.flags = 1; /* indicate mangled CSID */ | ||||
|  | ||||
|         /* If it still exists then kill the connection as we should only | ||||
|            ever have one incoming connection from each node */ | ||||
|         if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|         { | ||||
| 	    DEBUGLOG("Multiple incoming connections from node\n"); | ||||
|             syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]); | ||||
|  | ||||
| 	    free(client); | ||||
|             errno = ECONNREFUSED; | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|     dm_hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int get_main_gulm_cluster_fd() | ||||
| { | ||||
|     return listen_fd; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Read on main comms (listen) socket, accept it */ | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid, | ||||
| 			struct local_client **new_client) | ||||
| { | ||||
|     int newfd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t addrlen = sizeof(addr); | ||||
|     int status; | ||||
|     char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback\n"); | ||||
|     *new_client = NULL; | ||||
|     newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen); | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno); | ||||
|     if (!newfd) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "error in accept: %m"); | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; /* Don't return an error or clvmd will close the listening FD */ | ||||
|     } | ||||
|  | ||||
|     /* Check that the client is a member of the cluster | ||||
|        and reject if not. | ||||
|     */ | ||||
|     if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Got connect from non-cluster node %s\n", | ||||
| 	       print_csid((char *)&addr.sin6_addr)); | ||||
| 	DEBUGLOG("Got connect from non-cluster node %s\n", | ||||
| 		 print_csid((char *)&addr.sin6_addr)); | ||||
| 	close(newfd); | ||||
|  | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status); | ||||
| 	close(newfd); | ||||
| 	/* See above... */ | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|     DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client); | ||||
|     return newfd; | ||||
| } | ||||
|  | ||||
| /* Try to get at least 'len' bytes from the socket */ | ||||
| static int really_read(int fd, char *buf, int len) | ||||
| { | ||||
| 	int got, offset; | ||||
|  | ||||
| 	got = offset = 0; | ||||
|  | ||||
| 	do { | ||||
| 		got = read(fd, buf+offset, len-offset); | ||||
| 		DEBUGLOG("really_read. got %d bytes\n", got); | ||||
| 		offset += got; | ||||
| 	} while (got > 0 && offset < len); | ||||
|  | ||||
| 	if (got < 0) | ||||
| 		return got; | ||||
| 	else | ||||
| 		return offset; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t slen = sizeof(addr); | ||||
|     struct clvm_header *header = (struct clvm_header *)buf; | ||||
|     int status; | ||||
|     uint32_t arglen; | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock fd %d\n", client->fd); | ||||
|     *new_client = NULL; | ||||
|  | ||||
|     /* Get "csid" */ | ||||
|     getpeername(client->fd, (struct sockaddr *)&addr, &slen); | ||||
|     memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     /* Read just the header first, then get the rest if there is any. | ||||
|      * Stream sockets, sigh. | ||||
|      */ | ||||
|     status = really_read(client->fd, buf, sizeof(struct clvm_header)); | ||||
|     if (status > 0) | ||||
|     { | ||||
| 	    int status2; | ||||
|  | ||||
| 	    arglen = ntohl(header->arglen); | ||||
|  | ||||
| 	    /* Get the rest */ | ||||
| 	    if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE) | ||||
| 	    { | ||||
| 		    status2 = really_read(client->fd, buf+status, arglen); | ||||
| 		    if (status2 > 0) | ||||
| 			    status += status2; | ||||
| 		    else | ||||
| 			    status = status2; | ||||
| 	    } | ||||
|     } | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno); | ||||
|  | ||||
|     /* Remove it from the hash table if there's an error, clvmd will | ||||
|        remove the socket from its lists and free the client struct */ | ||||
|     if (status == 0 || | ||||
| 	(status < 0 && errno != EAGAIN && errno != EINTR)) | ||||
|     { | ||||
| 	char remcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	memcpy(remcsid, csid, GULM_MAX_CSID_LEN); | ||||
| 	close(client->fd); | ||||
|  | ||||
| 	/* If the csid was mangled, then make sure we remove the right entry */ | ||||
| 	if (client->bits.net.flags) | ||||
| 	    remcsid[0] ^= 0x80; | ||||
| 	dm_hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN); | ||||
|  | ||||
| 	/* Tell cluster manager layer */ | ||||
| 	add_down_node(remcsid); | ||||
|     } | ||||
|     else { | ||||
| 	    gulm_add_up_node(csid); | ||||
| 	    /* Send it back to clvmd */ | ||||
| 	    process_message(client, buf, status, csid); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| int gulm_connect_csid(const char *csid, struct local_client **newclient) | ||||
| { | ||||
|     int fd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     int status; | ||||
|     int one = 1; | ||||
|  | ||||
|     DEBUGLOG("Connecting socket\n"); | ||||
|     fd = socket(PF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (fd < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Unable to create new socket: %m"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN); | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     DEBUGLOG("Connecting socket %d\n", fd); | ||||
|     if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) | ||||
|     { | ||||
| 	/* "Connection refused" is "normal" because clvmd may not yet be running | ||||
| 	 * on that node. | ||||
| 	 */ | ||||
| 	if (errno != ECONNREFUSED) | ||||
| 	{ | ||||
| 	    syslog(LOG_ERR, "Unable to connect to remote node: %m"); | ||||
| 	} | ||||
| 	DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno)); | ||||
| 	close(fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(fd, F_SETFD, 1); | ||||
|     setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|  | ||||
|     status = alloc_client(fd, csid, newclient); | ||||
|     if (status) | ||||
| 	close(fd); | ||||
|     else | ||||
| 	add_client(*newclient); | ||||
|  | ||||
|     /* If we can connect to it, it must be running a clvmd */ | ||||
|     gulm_add_up_node(csid); | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* Send a message to a known CSID */ | ||||
| static int tcp_send_message(void *buf, int msglen, const char *csid, const char *errtext) | ||||
| { | ||||
|     int status; | ||||
|     struct local_client *client; | ||||
|     char ourcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
|     assert(csid); | ||||
|  | ||||
|     DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen); | ||||
|  | ||||
|     /* Don't connect to ourself */ | ||||
|     get_our_gulm_csid(ourcsid); | ||||
|     if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0) | ||||
| 	return msglen; | ||||
|  | ||||
|     client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!client) | ||||
|     { | ||||
| 	status = gulm_connect_csid(csid, &client); | ||||
| 	if (status) | ||||
| 	    return -1; | ||||
|     } | ||||
|     DEBUGLOG("tcp_send_message, fd = %d\n", client->fd); | ||||
|  | ||||
|     return write(client->fd, buf, msglen); | ||||
| } | ||||
|  | ||||
|  | ||||
| int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext) | ||||
| { | ||||
|     int status=0; | ||||
|  | ||||
|     DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen); | ||||
|  | ||||
|     /* If csid is NULL then send to all known (not just connected) nodes */ | ||||
|     if (!csid) | ||||
|     { | ||||
| 	void *context = NULL; | ||||
| 	char loop_csid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	/* Loop round all gulm-known nodes */ | ||||
| 	while (get_next_node_csid(&context, loop_csid)) | ||||
| 	{ | ||||
| 	    status = tcp_send_message(buf, msglen, loop_csid, errtext); | ||||
| 	    if (status == 0 || | ||||
| 		(status < 0 && (errno == EAGAIN || errno == EINTR))) | ||||
| 		break; | ||||
| 	} | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  | ||||
| 	status = tcp_send_message(buf, msglen, csid, errtext); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* To get our own IP address we get the locally bound address of the | ||||
|    socket that's talking to GULM in the assumption(eek) that it will | ||||
|    be on the "right" network in a multi-homed system */ | ||||
| static int get_our_ip_address(char *addr, int *family) | ||||
| { | ||||
| 	struct utsname info; | ||||
|  | ||||
| 	uname(&info); | ||||
| 	get_ip_address(info.nodename, addr); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Public version of above for those that don't care what protocol | ||||
|    we're using */ | ||||
| void get_our_gulm_csid(char *csid) | ||||
| { | ||||
|     static char our_csid[GULM_MAX_CSID_LEN]; | ||||
|     static int got_csid = 0; | ||||
|  | ||||
|     if (!got_csid) | ||||
|     { | ||||
| 	int family; | ||||
|  | ||||
| 	memset(our_csid, 0, sizeof(our_csid)); | ||||
| 	if (get_our_ip_address(our_csid, &family)) | ||||
| 	{ | ||||
| 	    got_csid = 1; | ||||
| 	} | ||||
|     } | ||||
|     memcpy(csid, our_csid, GULM_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6) | ||||
| { | ||||
|    ip6->s6_addr32[0] = 0; | ||||
|    ip6->s6_addr32[1] = 0; | ||||
|    ip6->s6_addr32[2] = htonl(0xffff); | ||||
|    ip6->s6_addr32[3] = ip4->s_addr; | ||||
| } | ||||
|  | ||||
| /* Get someone else's IP address from DNS */ | ||||
| int get_ip_address(const char *node, char *addr) | ||||
| { | ||||
|     struct hostent *he; | ||||
|  | ||||
|     memset(addr, 0, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     // TODO: what do we do about multi-homed hosts ??? | ||||
|     // CCSs ip_interfaces solved this but some bugger removed it. | ||||
|  | ||||
|     /* Try IPv6 first. The man page for gethostbyname implies that | ||||
|        it will lookup ip6 & ip4 names, but it seems not to */ | ||||
|     he = gethostbyname2(node, AF_INET6); | ||||
|     if (he) | ||||
|     { | ||||
| 	memcpy(addr, he->h_addr_list[0], | ||||
| 	       he->h_length); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	he = gethostbyname2(node, AF_INET); | ||||
| 	if (!he) | ||||
| 	    return -1; | ||||
| 	map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| char *print_csid(const char *csid) | ||||
| { | ||||
|     static char buf[128]; | ||||
|     int *icsid = (int *)csid; | ||||
|  | ||||
|     sprintf(buf, "[%x.%x.%x.%x]", | ||||
| 	    icsid[0],icsid[1],icsid[2],icsid[3]); | ||||
|  | ||||
|     return buf; | ||||
| } | ||||
							
								
								
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #define GULM_MAX_CLUSTER_MESSAGE 1600 | ||||
| #define GULM_MAX_CSID_LEN sizeof(struct in6_addr) | ||||
| #define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128 | ||||
|  | ||||
| extern int init_comms(unsigned short); | ||||
| extern char *print_csid(const char *); | ||||
| int get_main_gulm_cluster_fd(void); | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client); | ||||
| int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext); | ||||
| void get_our_gulm_csid(char *csid); | ||||
| int gulm_connect_csid(const char *csid, struct local_client **newclient); | ||||
							
								
								
									
										19
									
								
								daemons/dmeventd/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								daemons/dmeventd/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| dm_event_handler_create | ||||
| dm_event_handler_destroy | ||||
| dm_event_handler_set_dso | ||||
| dm_event_handler_set_dev_name | ||||
| dm_event_handler_set_uuid | ||||
| dm_event_handler_set_major | ||||
| dm_event_handler_set_minor | ||||
| dm_event_handler_set_event_mask | ||||
| dm_event_handler_get_dso | ||||
| dm_event_handler_get_devname | ||||
| dm_event_handler_get_uuid | ||||
| dm_event_handler_get_major | ||||
| dm_event_handler_get_minor | ||||
| dm_event_handler_get_event_mask | ||||
| dm_event_register_handler | ||||
| dm_event_unregister_handler | ||||
| dm_event_get_registered_device | ||||
| dm_event_handler_set_timeout | ||||
| dm_event_handler_get_timeout | ||||
							
								
								
									
										98
									
								
								daemons/dmeventd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								daemons/dmeventd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| # | ||||
| # Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SOURCES = libdevmapper-event.c | ||||
|  | ||||
| LIB_STATIC = libdevmapper-event.a | ||||
| LIB_VERSION = $(LIB_VERSION_DM) | ||||
|  | ||||
| ifeq ("@LIB_SUFFIX@","dylib") | ||||
|   LIB_SHARED = libdevmapper-event.dylib | ||||
| else | ||||
|   LIB_SHARED = libdevmapper-event.so | ||||
|   VERSIONED_SHLIB = $(LIB_SHARED).$(LIB_VERSION) | ||||
| endif | ||||
|  | ||||
| TARGETS = dmeventd | ||||
| CLEAN_TARGETS = dmeventd.o | ||||
|  | ||||
| ifneq ($(MAKECMDGOALS),device-mapper) | ||||
|   SUBDIRS+=plugins | ||||
| endif | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| all: dmeventd | ||||
| device-mapper: dmeventd | ||||
|  | ||||
| LDFLAGS += -ldl -ldevmapper -lpthread | ||||
| CLDFLAGS += -ldl -ldevmapper -lpthread | ||||
|  | ||||
| dmeventd: $(LIB_SHARED) $(VERSIONED_SHLIB) dmeventd.o | ||||
| 	$(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \ | ||||
| 	-L. -ldevmapper-event $(LIBS) -rdynamic | ||||
|  | ||||
| .PHONY: install_dynamic install_static install_include \ | ||||
| 	install_pkgconfig install_dmeventd | ||||
|  | ||||
| INSTALL_TYPE = install_dynamic | ||||
|  | ||||
| ifeq ("@STATIC_LINK@", "yes") | ||||
|   INSTALL_TYPE += install_static | ||||
| endif | ||||
|  | ||||
| ifeq ("@PKGCONFIG@", "yes") | ||||
|   INSTALL_TYPE += install_pkgconfig | ||||
| endif | ||||
|  | ||||
| install: $(INSTALL_TYPE) install_include install_dmeventd | ||||
|  | ||||
| install_device-mapper: install | ||||
|  | ||||
| install_include: | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \ | ||||
| 		$(includedir)/libdevmapper-event.h | ||||
|  | ||||
| install_dynamic: libdevmapper-event.$(LIB_SUFFIX) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) | ||||
| 	$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \ | ||||
| 		$(libdir)/libdevmapper-event.$(LIB_SUFFIX) | ||||
|  | ||||
| install_dmeventd: dmeventd | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$< | ||||
|  | ||||
| install_pkgconfig: | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \ | ||||
| 		$(usrlibdir)/pkgconfig/devmapper-event.pc | ||||
|  | ||||
| install_static: libdevmapper-event.a | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/libdevmapper-event.a.$(LIB_VERSION) | ||||
| 	$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a | ||||
|  | ||||
| $(VERSIONED_SHLIB): $(LIB_SHARED) | ||||
| 	$(RM) -f $@ | ||||
| 	$(LN_S) $(LIB_SHARED) $@ | ||||
|  | ||||
| .PHONY: distclean_lib distclean | ||||
|  | ||||
| distclean_lib:  | ||||
| 	$(RM) libdevmapper-event.pc | ||||
|  | ||||
| distclean: distclean_lib | ||||
|  | ||||
							
								
								
									
										1761
									
								
								daemons/dmeventd/dmeventd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1761
									
								
								daemons/dmeventd/dmeventd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										66
									
								
								daemons/dmeventd/dmeventd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								daemons/dmeventd/dmeventd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef __DMEVENTD_DOT_H__ | ||||
| #define __DMEVENTD_DOT_H__ | ||||
|  | ||||
| /* FIXME This stuff must be configurable. */ | ||||
|  | ||||
| #define	DM_EVENT_DAEMON		"/sbin/dmeventd" | ||||
| #define DM_EVENT_LOCKFILE	"/var/lock/dmeventd" | ||||
| #define	DM_EVENT_FIFO_CLIENT	"/var/run/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	"/var/run/dmeventd-server" | ||||
| #define DM_EVENT_PIDFILE	"/var/run/dmeventd.pid" | ||||
|  | ||||
| #define DM_EVENT_DEFAULT_TIMEOUT 10 | ||||
|  | ||||
| /* Commands for the daemon passed in the message below. */ | ||||
| enum dm_event_command { | ||||
| 	DM_EVENT_CMD_ACTIVE = 1, | ||||
| 	DM_EVENT_CMD_REGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_UNREGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_GET_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_SET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_GET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_HELLO, | ||||
| }; | ||||
|  | ||||
| /* Message passed between client and daemon. */ | ||||
| struct dm_event_daemon_message { | ||||
| 	uint32_t cmd; | ||||
| 	uint32_t size; | ||||
| 	char *data; | ||||
| }; | ||||
|  | ||||
| /* FIXME Is this meant to be exported?  I can't see where the | ||||
|    interface uses it. */ | ||||
| /* Fifos for client/daemon communication. */ | ||||
| struct dm_event_fifos { | ||||
| 	int client; | ||||
| 	int server; | ||||
| 	const char *client_path; | ||||
| 	const char *server_path; | ||||
| }; | ||||
|  | ||||
| /*      EXIT_SUCCESS             0 -- stdlib.h */ | ||||
| /*      EXIT_FAILURE             1 -- stdlib.h */ | ||||
| #define EXIT_LOCKFILE_INUSE      2 | ||||
| #define EXIT_DESC_CLOSE_FAILURE  3 | ||||
| #define EXIT_DESC_OPEN_FAILURE   4 | ||||
| #define EXIT_OPEN_PID_FAILURE    5 | ||||
| #define EXIT_FIFO_FAILURE        6 | ||||
| #define EXIT_CHDIR_FAILURE       7 | ||||
|  | ||||
| #endif /* __DMEVENTD_DOT_H__ */ | ||||
							
								
								
									
										809
									
								
								daemons/dmeventd/libdevmapper-event.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										809
									
								
								daemons/dmeventd/libdevmapper-event.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,809 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "dmlib.h" | ||||
| #include "libdevmapper-event.h" | ||||
| //#include "libmultilog.h" | ||||
| #include "dmeventd.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/file.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/wait.h> | ||||
| #include <arpa/inet.h>		/* for htonl, ntohl */ | ||||
|  | ||||
| static int _sequence_nr = 0; | ||||
|  | ||||
| struct dm_event_handler { | ||||
| 	char *dso; | ||||
|  | ||||
| 	char *dev_name; | ||||
|  | ||||
| 	char *uuid; | ||||
| 	int major; | ||||
| 	int minor; | ||||
| 	uint32_t timeout; | ||||
|  | ||||
| 	enum dm_event_mask mask; | ||||
| }; | ||||
|  | ||||
| static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	if (dmevh->dev_name) | ||||
| 		dm_free(dmevh->dev_name); | ||||
| 	if (dmevh->uuid) | ||||
| 		dm_free(dmevh->uuid); | ||||
| 	dmevh->dev_name = dmevh->uuid = NULL; | ||||
| 	dmevh->major = dmevh->minor = 0; | ||||
| } | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void) | ||||
| { | ||||
| 	struct dm_event_handler *dmevh = NULL; | ||||
|  | ||||
| 	if (!(dmevh = dm_malloc(sizeof(*dmevh)))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL; | ||||
| 	dmevh->major = dmevh->minor = 0; | ||||
| 	dmevh->mask = 0; | ||||
| 	dmevh->timeout = 0; | ||||
|  | ||||
| 	return dmevh; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_destroy(struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	if (dmevh->dso) | ||||
| 		dm_free(dmevh->dso); | ||||
| 	dm_free(dmevh); | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path) | ||||
| { | ||||
| 	if (!path) /* noop */ | ||||
| 		return 0; | ||||
| 	if (dmevh->dso) | ||||
| 		dm_free(dmevh->dso); | ||||
|  | ||||
| 	dmevh->dso = dm_strdup(path); | ||||
| 	if (!dmevh->dso) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name) | ||||
| { | ||||
| 	if (!dev_name) | ||||
| 		return 0; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->dev_name = dm_strdup(dev_name); | ||||
| 	if (!dmevh->dev_name) | ||||
| 		return -ENOMEM; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid) | ||||
| { | ||||
| 	if (!uuid) | ||||
| 		return 0; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->uuid = dm_strdup(uuid); | ||||
| 	if (!dmevh->dev_name) | ||||
| 		return -ENOMEM; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major) | ||||
| { | ||||
| 	int minor = dmevh->minor; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->major = major; | ||||
| 	dmevh->minor = minor; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor) | ||||
| { | ||||
| 	int major = dmevh->major; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->major = major; | ||||
| 	dmevh->minor = minor; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask) | ||||
| { | ||||
| 	dmevh->mask = evmask; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout) | ||||
| { | ||||
| 	dmevh->timeout = timeout; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->dso; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->dev_name; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->uuid; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->major; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->minor; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->timeout; | ||||
| } | ||||
|  | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->mask; | ||||
| } | ||||
|  | ||||
| static int _check_message_id(struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	int pid, seq_nr; | ||||
|  | ||||
| 	if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) || | ||||
| 	    (pid != getpid()) || (seq_nr != _sequence_nr)) { | ||||
| 		log_error("Ignoring out-of-sequence reply from dmeventd. " | ||||
| 			  "Expected %d:%d but received %s", getpid(), | ||||
| 			  _sequence_nr, msg->data); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemon_read | ||||
|  * @fifos | ||||
|  * @msg | ||||
|  * | ||||
|  * Read message from daemon. | ||||
|  * | ||||
|  * Returns: 0 on failure, 1 on success | ||||
|  */ | ||||
| static int _daemon_read(struct dm_event_fifos *fifos, | ||||
| 			struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	unsigned bytes = 0; | ||||
| 	int ret, i; | ||||
| 	fd_set fds; | ||||
| 	struct timeval tval = { 0, 0 }; | ||||
| 	size_t size = 2 * sizeof(uint32_t);	/* status + size */ | ||||
| 	char *buf = alloca(size); | ||||
| 	int header = 1; | ||||
|  | ||||
| 	while (bytes < size) { | ||||
| 		for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) { | ||||
| 			/* Watch daemon read FIFO for input. */ | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(fifos->server, &fds); | ||||
| 			tval.tv_sec = 1; | ||||
| 			ret = select(fifos->server + 1, &fds, NULL, NULL, | ||||
| 				     &tval); | ||||
| 			if (ret < 0 && errno != EINTR) { | ||||
| 				log_error("Unable to read from event server"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		if (ret < 1) { | ||||
| 			log_error("Unable to read from event server."); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		ret = read(fifos->server, buf + bytes, size); | ||||
| 		if (ret < 0) { | ||||
| 			if ((errno == EINTR) || (errno == EAGAIN)) | ||||
| 				continue; | ||||
| 			else { | ||||
| 				log_error("Unable to read from event server."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		bytes += ret; | ||||
| 		if (bytes == 2 * sizeof(uint32_t) && header) { | ||||
| 			msg->cmd = ntohl(*((uint32_t *)buf)); | ||||
| 			msg->size = ntohl(*((uint32_t *)buf + 1)); | ||||
| 			buf = msg->data = dm_malloc(msg->size); | ||||
| 			size = msg->size; | ||||
| 			bytes = 0; | ||||
| 			header = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (bytes != size) { | ||||
| 		if (msg->data) | ||||
| 			dm_free(msg->data); | ||||
| 		msg->data = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return bytes == size; | ||||
| } | ||||
|  | ||||
| /* Write message to daemon. */ | ||||
| static int _daemon_write(struct dm_event_fifos *fifos, | ||||
| 			 struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	unsigned bytes = 0; | ||||
| 	int ret = 0; | ||||
| 	fd_set fds; | ||||
|  | ||||
| 	size_t size = 2 * sizeof(uint32_t) + msg->size; | ||||
| 	char *buf = alloca(size); | ||||
| 	char drainbuf[128]; | ||||
| 	struct timeval tval = { 0, 0 }; | ||||
|  | ||||
| 	*((uint32_t *)buf) = htonl(msg->cmd); | ||||
| 	*((uint32_t *)buf + 1) = htonl(msg->size); | ||||
| 	memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size); | ||||
|  | ||||
| 	/* drain the answer fifo */ | ||||
| 	while (1) { | ||||
| 		FD_ZERO(&fds); | ||||
| 		FD_SET(fifos->server, &fds); | ||||
| 		tval.tv_usec = 100; | ||||
| 		ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); | ||||
| 		if ((ret < 0) && (errno != EINTR)) { | ||||
| 			log_error("Unable to talk to event daemon"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (ret == 0) | ||||
| 			break; | ||||
| 		read(fifos->server, drainbuf, 127); | ||||
| 	} | ||||
|  | ||||
| 	while (bytes < size) { | ||||
| 		do { | ||||
| 			/* Watch daemon write FIFO to be ready for output. */ | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(fifos->client, &fds); | ||||
| 			ret = select(fifos->client + 1, NULL, &fds, NULL, NULL); | ||||
| 			if ((ret < 0) && (errno != EINTR)) { | ||||
| 				log_error("Unable to talk to event daemon"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} while (ret < 1); | ||||
|  | ||||
| 		ret = write(fifos->client, ((char *) buf) + bytes, | ||||
| 			    size - bytes); | ||||
| 		if (ret < 0) { | ||||
| 			if ((errno == EINTR) || (errno == EAGAIN)) | ||||
| 				continue; | ||||
| 			else { | ||||
| 				log_error("Unable to talk to event daemon"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		bytes += ret; | ||||
| 	} | ||||
|  | ||||
| 	return bytes == size; | ||||
| } | ||||
|  | ||||
| static int _daemon_talk(struct dm_event_fifos *fifos, | ||||
| 			struct dm_event_daemon_message *msg, int cmd, | ||||
| 			const char *dso_name, const char *dev_name, | ||||
| 			enum dm_event_mask evmask, uint32_t timeout) | ||||
| { | ||||
| 	const char *dso = dso_name ? dso_name : ""; | ||||
| 	const char *dev = dev_name ? dev_name : ""; | ||||
| 	const char *fmt = "%d:%d %s %s %u %" PRIu32; | ||||
| 	int msg_size; | ||||
| 	memset(msg, 0, sizeof(*msg)); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set command and pack the arguments | ||||
| 	 * into ASCII message string. | ||||
| 	 */ | ||||
| 	msg->cmd = cmd; | ||||
| 	if (cmd == DM_EVENT_CMD_HELLO) | ||||
| 		fmt = "%d:%d HELLO"; | ||||
| 	if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr, | ||||
| 				    dso, dev, evmask, timeout)) < 0) { | ||||
| 		log_error("_daemon_talk: message allocation failed"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	msg->size = msg_size; | ||||
|  | ||||
| 	/* | ||||
| 	 * Write command and message to and | ||||
| 	 * read status return code from daemon. | ||||
| 	 */ | ||||
| 	if (!_daemon_write(fifos, msg)) { | ||||
| 		stack; | ||||
| 		dm_free(msg->data); | ||||
| 		msg->data = 0; | ||||
| 		return -EIO; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
|  | ||||
| 		if (msg->data) | ||||
| 			dm_free(msg->data); | ||||
| 		msg->data = 0; | ||||
|  | ||||
| 		if (!_daemon_read(fifos, msg)) { | ||||
| 			stack; | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 	} while (!_check_message_id(msg)); | ||||
|  | ||||
| 	_sequence_nr++; | ||||
|  | ||||
| 	return (int32_t) msg->cmd; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * start_daemon | ||||
|  * | ||||
|  * This function forks off a process (dmeventd) that will handle | ||||
|  * the events.  I am currently test opening one of the fifos to | ||||
|  * ensure that the daemon is running and listening...  I thought | ||||
|  * this would be less expensive than fork/exec'ing every time. | ||||
|  * Perhaps there is an even quicker/better way (no, checking the | ||||
|  * lock file is _not_ a better way). | ||||
|  * | ||||
|  * Returns: 1 on success, 0 otherwise | ||||
|  */ | ||||
| static int _start_daemon(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	int pid, ret = 0; | ||||
| 	int status; | ||||
| 	struct stat statbuf; | ||||
|  | ||||
| 	if (stat(fifos->client_path, &statbuf)) | ||||
| 		goto start_server; | ||||
|  | ||||
| 	if (!S_ISFIFO(statbuf.st_mode)) { | ||||
| 		log_error("%s is not a fifo.", fifos->client_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Anyone listening?  If not, errno will be ENXIO */ | ||||
| 	fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK); | ||||
| 	if (fifos->client >= 0) { | ||||
| 		/* server is running and listening */ | ||||
|  | ||||
| 		close(fifos->client); | ||||
| 		return 1; | ||||
| 	} else if (errno != ENXIO) { | ||||
| 		/* problem */ | ||||
|  | ||||
| 		log_error("%s: Can't open client fifo %s: %s", | ||||
| 			  __func__, fifos->client_path, strerror(errno)); | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|       start_server: | ||||
| 	/* server is not running */ | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		log_error("Unable to fork."); | ||||
|  | ||||
| 	else if (!pid) { | ||||
| 		execvp(DMEVENTD_PATH, NULL); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} else { | ||||
| 		if (waitpid(pid, &status, 0) < 0) | ||||
| 			log_error("Unable to start dmeventd: %s", | ||||
| 				  strerror(errno)); | ||||
| 		else if (WEXITSTATUS(status)) | ||||
| 			log_error("Unable to start dmeventd."); | ||||
| 		else | ||||
| 			ret = 1; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Initialize client. */ | ||||
| static int _init_client(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	/* FIXME? Is fifo the most suitable method? Why not share | ||||
| 	   comms/daemon code with something else e.g. multipath? */ | ||||
|  | ||||
| 	/* init fifos */ | ||||
| 	memset(fifos, 0, sizeof(*fifos)); | ||||
| 	fifos->client_path = DM_EVENT_FIFO_CLIENT; | ||||
| 	fifos->server_path = DM_EVENT_FIFO_SERVER; | ||||
|  | ||||
| 	if (!_start_daemon(fifos)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Open the fifo used to read from the daemon. */ | ||||
| 	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { | ||||
| 		log_error("%s: open server fifo %s", | ||||
| 			  __func__, fifos->server_path); | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Lock out anyone else trying to do communication with the daemon. */ | ||||
| 	if (flock(fifos->server, LOCK_EX) < 0) { | ||||
| 		log_error("%s: flock %s", __func__, fifos->server_path); | ||||
| 		close(fifos->server); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| /*	if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/ | ||||
| 	if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) { | ||||
| 		log_error("%s: Can't open client fifo %s: %s", | ||||
| 			  __func__, fifos->client_path, strerror(errno)); | ||||
| 		close(fifos->server); | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _dtr_client(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	if (flock(fifos->server, LOCK_UN)) | ||||
| 		log_error("flock unlock %s", fifos->server_path); | ||||
|  | ||||
| 	close(fifos->client); | ||||
| 	close(fifos->server); | ||||
| } | ||||
|  | ||||
| /* Get uuid of a device */ | ||||
| static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_info info; | ||||
|  | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { | ||||
| 		log_error("_get_device_info: dm_task creation for info failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (dmevh->uuid) | ||||
| 		dm_task_set_uuid(dmt, dmevh->uuid); | ||||
| 	else if (dmevh->dev_name) | ||||
| 		dm_task_set_name(dmt, dmevh->dev_name); | ||||
| 	else if (dmevh->major && dmevh->minor) { | ||||
| 		dm_task_set_major(dmt, dmevh->major); | ||||
| 		dm_task_set_minor(dmt, dmevh->minor); | ||||
|         } | ||||
|  | ||||
| 	/* FIXME Add name or uuid or devno to messages */ | ||||
| 	if (!dm_task_run(dmt)) { | ||||
| 		log_error("_get_device_info: dm_task_run() failed"); | ||||
| 		goto failed; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_get_info(dmt, &info)) { | ||||
| 		log_error("_get_device_info: failed to get info for device"); | ||||
| 		goto failed; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists) { | ||||
| 		log_error("_get_device_info: device not found"); | ||||
| 		goto failed; | ||||
| 	} | ||||
|  | ||||
| 	return dmt; | ||||
|  | ||||
| failed: | ||||
| 	dm_task_destroy(dmt); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* Handle the event (de)registration call and return negative error codes. */ | ||||
| static int _do_event(int cmd, struct dm_event_daemon_message *msg, | ||||
| 		     const char *dso_name, const char *dev_name, | ||||
| 		     enum dm_event_mask evmask, uint32_t timeout) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct dm_event_fifos fifos; | ||||
|  | ||||
| 	if (!_init_client(&fifos)) { | ||||
| 		stack; | ||||
| 		return -ESRCH; | ||||
| 	} | ||||
|  | ||||
| 	ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0); | ||||
|  | ||||
| 	if (msg->data) | ||||
| 		dm_free(msg->data); | ||||
| 	msg->data = 0; | ||||
|  | ||||
| 	if (!ret) | ||||
| 		ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout); | ||||
|  | ||||
| 	/* what is the opposite of init? */ | ||||
| 	_dtr_client(&fifos); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* External library interface. */ | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	int ret = 1, err; | ||||
| 	const char *uuid; | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_event_daemon_message msg = { 0, 0, NULL }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg, | ||||
| 			     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { | ||||
| 		log_error("%s: event registration failed: %s", | ||||
| 			  dm_task_get_name(dmt), | ||||
| 			  msg.data ? msg.data : strerror(-err)); | ||||
| 		ret = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (msg.data) | ||||
| 		dm_free(msg.data); | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	int ret = 1, err; | ||||
| 	const char *uuid; | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_event_daemon_message msg = { 0, 0, NULL }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg, | ||||
| 			    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { | ||||
| 		log_error("%s: event deregistration failed: %s", | ||||
| 			  dm_task_get_name(dmt), | ||||
| 			  msg.data ? msg.data : strerror(-err)); | ||||
| 		ret = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (msg.data) | ||||
| 		dm_free(msg.data); | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Fetch a string off src and duplicate it into *dest. */ | ||||
| /* FIXME: move to separate module to share with the daemon. */ | ||||
| static char *_fetch_string(char **src, const int delimiter) | ||||
| { | ||||
| 	char *p, *ret; | ||||
|  | ||||
| 	if ((p = strchr(*src, delimiter))) | ||||
| 		*p = 0; | ||||
|  | ||||
| 	if ((ret = dm_strdup(*src))) | ||||
| 		*src += strlen(ret) + 1; | ||||
|  | ||||
| 	if (p) | ||||
| 		*p = delimiter; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Parse a device message from the daemon. */ | ||||
| static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name, | ||||
| 			 char **uuid, enum dm_event_mask *evmask) | ||||
| { | ||||
| 	char *id = NULL; | ||||
| 	char *p = msg->data; | ||||
|  | ||||
| 	if ((id = _fetch_string(&p, ' ')) && | ||||
| 	    (*dso_name = _fetch_string(&p, ' ')) && | ||||
| 	    (*uuid = _fetch_string(&p, ' '))) { | ||||
| 		*evmask = atoi(p); | ||||
|  | ||||
| 		dm_free(id); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (id) | ||||
| 		dm_free(id); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise. | ||||
|  */ | ||||
| int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	const char *uuid = NULL; | ||||
| 	char *reply_dso = NULL, *reply_uuid = NULL; | ||||
| 	enum dm_event_mask reply_mask = 0; | ||||
| 	struct dm_task *dmt = NULL; | ||||
| 	struct dm_event_daemon_message msg = { 0, 0, NULL }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE : | ||||
| 			     DM_EVENT_CMD_GET_REGISTERED_DEVICE, | ||||
| 			      &msg, dmevh->dso, uuid, dmevh->mask, 0))) { | ||||
| 		/* FIXME this will probably horribly break if we get | ||||
| 		   ill-formatted reply */ | ||||
| 		ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask); | ||||
| 	} else { | ||||
| 		ret = -ENOENT; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
| 	dmt = NULL; | ||||
|  | ||||
| 	if (msg.data) { | ||||
| 		dm_free(msg.data); | ||||
| 		msg.data = NULL; | ||||
| 	} | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	dmevh->uuid = dm_strdup(reply_uuid); | ||||
| 	if (!dmevh->uuid) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	dm_event_handler_set_dso(dmevh, reply_dso); | ||||
| 	dm_event_handler_set_event_mask(dmevh, reply_mask); | ||||
|  | ||||
| 	if (reply_dso) { | ||||
| 		dm_free(reply_dso); | ||||
| 		reply_dso = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (reply_uuid) { | ||||
| 		dm_free(reply_uuid); | ||||
| 		reply_uuid = NULL; | ||||
| 	} | ||||
|  | ||||
| 	dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)); | ||||
| 	if (!dmevh->dev_name) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	struct dm_info info; | ||||
| 	if (!dm_task_get_info(dmt, &info)) { | ||||
| 		ret = -1; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	dmevh->major = info.major; | ||||
| 	dmevh->minor = info.minor; | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
|  | ||||
|  fail: | ||||
| 	if (msg.data) | ||||
| 		dm_free(msg.data); | ||||
| 	if (reply_dso) | ||||
| 		dm_free(reply_dso); | ||||
| 	if (reply_uuid) | ||||
| 		dm_free(reply_uuid); | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	if (dmt) | ||||
| 		dm_task_destroy(dmt); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| #if 0				/* left out for now */ | ||||
|  | ||||
| static char *_skip_string(char *src, const int delimiter) | ||||
| { | ||||
| 	src = srtchr(src, delimiter); | ||||
| 	if (src && *(src + 1)) | ||||
| 		return src + 1; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int dm_event_set_timeout(const char *device_path, uint32_t timeout) | ||||
| { | ||||
| 	struct dm_event_daemon_message msg = { 0, 0, NULL }; | ||||
|  | ||||
| 	if (!device_exists(device_path)) | ||||
| 		return -ENODEV; | ||||
|  | ||||
| 	return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg, | ||||
| 			 NULL, device_path, 0, timeout); | ||||
| } | ||||
|  | ||||
| int dm_event_get_timeout(const char *device_path, uint32_t *timeout) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct dm_event_daemon_message msg = { 0, 0, NULL }; | ||||
|  | ||||
| 	if (!device_exists(device_path)) | ||||
| 		return -ENODEV; | ||||
| 	if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, | ||||
| 			     0, 0))) { | ||||
| 		char *p = _skip_string(msg.data, ' '); | ||||
| 		if (!p) { | ||||
| 			log_error("malformed reply from dmeventd '%s'\n", | ||||
| 				  msg.data); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		*timeout = atoi(p); | ||||
| 	} | ||||
| 	if (msg.data) | ||||
| 		dm_free(msg.data); | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										106
									
								
								daemons/dmeventd/libdevmapper-event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								daemons/dmeventd/libdevmapper-event.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Note that this file is released only as part of a technology preview | ||||
|  * and its contents may change in future updates in ways that do not | ||||
|  * preserve compatibility. | ||||
|  */ | ||||
|  | ||||
| #ifndef LIB_DMEVENT_H | ||||
| #define LIB_DMEVENT_H | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* | ||||
|  * Event library interface. | ||||
|  */ | ||||
|  | ||||
| enum dm_event_mask { | ||||
| 	DM_EVENT_SETTINGS_MASK  = 0x0000FF, | ||||
| 	DM_EVENT_SINGLE		= 0x000001, /* Report multiple errors just once. */ | ||||
| 	DM_EVENT_MULTI		= 0x000002, /* Report all of them. */ | ||||
|  | ||||
| 	DM_EVENT_ERROR_MASK     = 0x00FF00, | ||||
| 	DM_EVENT_SECTOR_ERROR	= 0x000100, /* Failure on a particular sector. */ | ||||
| 	DM_EVENT_DEVICE_ERROR	= 0x000200, /* Device failure. */ | ||||
| 	DM_EVENT_PATH_ERROR	= 0x000400, /* Failure on an io path. */ | ||||
| 	DM_EVENT_ADAPTOR_ERROR	= 0x000800, /* Failure of a host adaptor. */ | ||||
|  | ||||
| 	DM_EVENT_STATUS_MASK    = 0xFF0000, | ||||
| 	DM_EVENT_SYNC_STATUS	= 0x010000, /* Mirror synchronization completed/failed. */ | ||||
| 	DM_EVENT_TIMEOUT	= 0x020000, /* Timeout has occured */ | ||||
|  | ||||
| 	DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */ | ||||
| }; | ||||
|  | ||||
| #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK | ||||
|  | ||||
| struct dm_event_handler; | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void); | ||||
| void dm_event_handler_destroy(struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* | ||||
|  * Path of shared library to handle events. | ||||
|  * | ||||
|  * All of dso, device_name and uuid strings are duplicated, you do not | ||||
|  * need to keep the pointers valid after the call succeeds. Thes may | ||||
|  * return -ENOMEM though. | ||||
|  */ | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path); | ||||
|  | ||||
| /* | ||||
|  * Identify the device to monitor by exactly one of device_name, uuid or | ||||
|  * device number. String arguments are duplicated, see above. | ||||
|  */ | ||||
| int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name); | ||||
|  | ||||
| int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid); | ||||
|  | ||||
| void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major); | ||||
| void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor); | ||||
| void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout); | ||||
|  | ||||
| /* | ||||
|  * Specify mask for events to monitor. | ||||
|  */ | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask); | ||||
|  | ||||
| const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh); | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* FIXME Review interface (what about this next thing?) */ | ||||
| int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next); | ||||
|  | ||||
| /* | ||||
|  * Initiate monitoring using dmeventd. | ||||
|  */ | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh); | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for | ||||
|    detailed descriptions. */ | ||||
| void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user); | ||||
| int register_device(const char *device_name, const char *uuid, int major, int minor, void **user); | ||||
| int unregister_device(const char *device_name, const char *uuid, int major, | ||||
| 		      int minor, void **user); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										12
									
								
								daemons/dmeventd/libdevmapper-event.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								daemons/dmeventd/libdevmapper-event.pc.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=@exec_prefix@ | ||||
| libdir=@libdir@ | ||||
| includedir=@includedir@ | ||||
|  | ||||
| Name: devmapper-event | ||||
| Description: device-mapper event library | ||||
| Version: @DM_LIB_VERSION@ | ||||
| Requires: devmapper | ||||
| Cflags: -I${includedir} | ||||
| Libs: -L${libdir} -ldevmapper-event | ||||
| Libs.private: -lpthread -ldl | ||||
							
								
								
									
										22
									
								
								daemons/dmeventd/plugins/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								daemons/dmeventd/plugins/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS += mirror snapshot | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
							
								
								
									
										3
									
								
								daemons/dmeventd/plugins/mirror/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								daemons/dmeventd/plugins/mirror/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
							
								
								
									
										37
									
								
								daemons/dmeventd/plugins/mirror/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								daemons/dmeventd/plugins/mirror/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2008 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| INCLUDES += -I${top_srcdir}/tools | ||||
| CLDFLAGS += -L${top_srcdir}/tools -ldevmapper @LVM2CMD_LIB@ | ||||
|  | ||||
| SOURCES = dmeventd_mirror.c | ||||
|  | ||||
| ifeq ("@LIB_SUFFIX@","dylib") | ||||
|   LIB_SHARED = libdevmapper-event-lvm2mirror.dylib | ||||
| else | ||||
|   LIB_SHARED = libdevmapper-event-lvm2mirror.so | ||||
| endif | ||||
|  | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/$<.$(LIB_VERSION) | ||||
| 	$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< | ||||
							
								
								
									
										289
									
								
								daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lvm2cmd.h" | ||||
|  | ||||
| #include <libdevmapper.h> | ||||
| #include <libdevmapper-event.h> | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <pthread.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* FIXME Missing openlog? */ | ||||
|  | ||||
| #define ME_IGNORE    0 | ||||
| #define ME_INSYNC    1 | ||||
| #define ME_FAILURE   2 | ||||
|  | ||||
| /* | ||||
|  * register_device() is called first and performs initialisation. | ||||
|  * Only one device may be registered or unregistered at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
|  | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| static int _get_mirror_event(char *params) | ||||
| { | ||||
| 	int i, r = ME_INSYNC; | ||||
| 	char **args = NULL; | ||||
| 	char *dev_status_str; | ||||
| 	char *log_status_str; | ||||
| 	char *sync_str; | ||||
| 	char *p = NULL; | ||||
| 	int log_argc, num_devs; | ||||
|  | ||||
| 	/* | ||||
| 	 * dm core parms:	     0 409600 mirror | ||||
| 	 * Mirror core parms:	     2 253:4 253:5 400/400 | ||||
| 	 * New-style failure params: 1 AA | ||||
| 	 * New-style log params:     3 cluster 253:3 A | ||||
| 	 *			 or  3 disk 253:3 A | ||||
| 	 *			 or  1 core | ||||
| 	 */ | ||||
|  | ||||
| 	/* number of devices */ | ||||
| 	if (!dm_split_words(params, 1, 0, &p)) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	if (!(num_devs = atoi(p))) | ||||
| 		goto out_parse; | ||||
| 	p += strlen(p) + 1; | ||||
|  | ||||
| 	/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */ | ||||
| 	args = dm_malloc((num_devs + 7) * sizeof(char *)); | ||||
| 	if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	dev_status_str = args[2 + num_devs]; | ||||
| 	log_argc = atoi(args[3 + num_devs]); | ||||
| 	log_status_str = args[3 + num_devs + log_argc]; | ||||
| 	sync_str = args[num_devs]; | ||||
|  | ||||
| 	/* Check for bad mirror devices */ | ||||
| 	for (i = 0; i < num_devs; i++) | ||||
| 		if (dev_status_str[i] == 'D') { | ||||
| 			syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]); | ||||
| 			r = ME_FAILURE; | ||||
| 		} | ||||
|  | ||||
| 	/* Check for bad disk log device */ | ||||
| 	if (log_argc > 1 && log_status_str[0] == 'D') { | ||||
| 		syslog(LOG_ERR, "Log device, %s, has failed.\n", | ||||
| 		       args[2 + num_devs + log_argc]); | ||||
| 		r = ME_FAILURE; | ||||
| 	} | ||||
|  | ||||
| 	if (r == ME_FAILURE) | ||||
| 		goto out; | ||||
|  | ||||
| 	p = strstr(sync_str, "/"); | ||||
| 	if (p) { | ||||
| 		p[0] = '\0'; | ||||
| 		if (strcmp(sync_str, p+1)) | ||||
| 			r = ME_IGNORE; | ||||
| 		p[0] = '/'; | ||||
| 	} else | ||||
| 		goto out_parse; | ||||
|  | ||||
| out: | ||||
| 	if (args) | ||||
| 		dm_free(args); | ||||
| 	return r; | ||||
| 	 | ||||
| out_parse: | ||||
| 	if (args) | ||||
| 		dm_free(args); | ||||
| 	syslog(LOG_ERR, "Unable to parse mirror status string."); | ||||
| 	return ME_IGNORE; | ||||
| } | ||||
|  | ||||
| static void _temporary_log_fn(int level, const char *file __attribute((unused)), | ||||
| 			      int line __attribute((unused)), | ||||
| 			      const char *format) | ||||
| { | ||||
| 	if (!strncmp(format, "WARNING: ", 9) && (level < 5)) | ||||
| 		syslog(LOG_CRIT, "%s", format); | ||||
| 	else | ||||
| 		syslog(LOG_DEBUG, "%s", format); | ||||
| } | ||||
|  | ||||
| static int _remove_failed_devices(const char *device) | ||||
| { | ||||
| 	int r; | ||||
| #define CMD_SIZE 256	/* FIXME Use system restriction */ | ||||
| 	char cmd_str[CMD_SIZE]; | ||||
| 	char *vg = NULL, *lv = NULL, *layer = NULL; | ||||
|  | ||||
| 	if (strlen(device) > 200)  /* FIXME Use real restriction */ | ||||
| 		return -ENAMETOOLONG;	/* FIXME These return code distinctions are not used so remove them! */ | ||||
|  | ||||
| 	if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) { | ||||
| 		syslog(LOG_ERR, "Unable to determine VG name from %s", | ||||
| 		       device); | ||||
| 		return -ENOMEM;	/* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME Is any sanity-checking required on %s? */ | ||||
| 	if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing --force %s", vg)) { | ||||
| 		/* this error should be caught above, but doesn't hurt to check again */ | ||||
| 		syslog(LOG_ERR, "Unable to form LVM command: Device name too long"); | ||||
| 		dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */ | ||||
| 		return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
| 	} | ||||
|  | ||||
| 	r = lvm2_run(_lvm_handle, cmd_str); | ||||
|  | ||||
| 	dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */ | ||||
| 	return (r == 1) ? 0 : -1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute((unused)), | ||||
| 		   void **unused __attribute((unused))) | ||||
| { | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	if (pthread_mutex_trylock(&_event_mutex)) { | ||||
| 		syslog(LOG_NOTICE, "Another thread is handling an event.  Waiting..."); | ||||
| 		pthread_mutex_lock(&_event_mutex); | ||||
| 	} | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			syslog(LOG_INFO, "%s mapping lost.\n", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, "mirror")) { | ||||
| 			syslog(LOG_INFO, "%s has unmirrored portion.\n", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		switch(_get_mirror_event(params)) { | ||||
| 		case ME_INSYNC: | ||||
| 			/* FIXME: all we really know is that this | ||||
| 			   _part_ of the device is in sync | ||||
| 			   Also, this is not an error | ||||
| 			*/ | ||||
| 			syslog(LOG_NOTICE, "%s is now in-sync\n", device); | ||||
| 			break; | ||||
| 		case ME_FAILURE: | ||||
| 			syslog(LOG_ERR, "Device failure in %s\n", device); | ||||
| 			if (_remove_failed_devices(device)) | ||||
| 				/* FIXME Why are all the error return codes unused? Get rid of them? */ | ||||
| 				syslog(LOG_ERR, "Failed to remove faulty devices in %s\n", | ||||
| 				       device); | ||||
| 			/* Should check before warning user that device is now linear | ||||
| 			else | ||||
| 				syslog(LOG_NOTICE, "%s is now a linear device.\n", | ||||
| 					device); | ||||
| 			*/ | ||||
| 			break; | ||||
| 		case ME_IGNORE: | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* FIXME Provide value then! */ | ||||
| 			syslog(LOG_INFO, "Unknown event received.\n"); | ||||
| 		} | ||||
| 	} while (next); | ||||
|  | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute((unused)), | ||||
| 		    int major __attribute((unused)), | ||||
| 		    int minor __attribute((unused)), | ||||
| 		    void **unused __attribute((unused))) | ||||
| { | ||||
| 	int r = 0; | ||||
|  | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device); | ||||
|  | ||||
| 	/* | ||||
| 	 * Need some space for allocations.  1024 should be more | ||||
| 	 * than enough for what we need (device mapper name splitting) | ||||
| 	 */ | ||||
| 	if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_temporary_log_fn); | ||||
| 		if (!(_lvm_handle = lvm2_init())) { | ||||
| 			dm_pool_destroy(_mem_pool); | ||||
| 			_mem_pool = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 	} | ||||
|  | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute((unused)), | ||||
| 		      int major __attribute((unused)), | ||||
| 		      int minor __attribute((unused)), | ||||
| 		      void **unused __attribute((unused))) | ||||
| { | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n", | ||||
| 	       device); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										3
									
								
								daemons/dmeventd/plugins/snapshot/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								daemons/dmeventd/plugins/snapshot/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
							
								
								
									
										37
									
								
								daemons/dmeventd/plugins/snapshot/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								daemons/dmeventd/plugins/snapshot/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| INCLUDES += -I${top_srcdir}/tools | ||||
| CLDFLAGS += -L${top_srcdir}/tools -ldevmapper @LVM2CMD_LIB@ | ||||
|  | ||||
| SOURCES = dmeventd_snapshot.c | ||||
|  | ||||
| ifeq ("@LIB_SUFFIX@","dylib") | ||||
|   LIB_SHARED = libdevmapper-event-lvm2snapshot.dylib | ||||
| else | ||||
|   LIB_SHARED = libdevmapper-event-lvm2snapshot.so | ||||
| endif | ||||
|  | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| install: libdevmapper-event-lvm2snapshot.$(LIB_SUFFIX) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/$<.$(LIB_VERSION) | ||||
| 	$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< | ||||
							
								
								
									
										213
									
								
								daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,213 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
| #include "libdevmapper-event.h" | ||||
| #include "lvm2cmd.h" | ||||
| #include "lvm-string.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <pthread.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* FIXME Missing openlog? */ | ||||
|  | ||||
| /* First warning when snapshot is 80% full. */ | ||||
| #define WARNING_THRESH 80 | ||||
| /* Further warnings at 85%, 90% and 95% fullness. */ | ||||
| #define WARNING_STEP 5 | ||||
|  | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
|  | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
|  | ||||
| struct snap_status { | ||||
| 	int invalid; | ||||
| 	int used; | ||||
| 	int max; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| static void _temporary_log_fn(int level, | ||||
| 			      const char *file __attribute((unused)), | ||||
| 			      int line __attribute((unused)), | ||||
| 			      const char *format) | ||||
| { | ||||
| 	if (!strncmp(format, "WARNING: ", 9) && (level < 5)) | ||||
| 		syslog(LOG_CRIT, "%s", format); | ||||
| 	else | ||||
| 		syslog(LOG_DEBUG, "%s", format); | ||||
| } | ||||
|  | ||||
| /* FIXME possibly reconcile this with target_percent when we gain | ||||
|    access to regular LVM library here. */ | ||||
| static void _parse_snapshot_params(char *params, struct snap_status *stat) | ||||
| { | ||||
| 	char *p; | ||||
| 	/* | ||||
| 	 * xx/xx	-- fractions used/max | ||||
| 	 * Invalid	-- snapshot invalidated | ||||
| 	 * Unknown	-- status unknown | ||||
| 	 */ | ||||
| 	stat->used = stat->max = 0; | ||||
|  | ||||
| 	if (!strncmp(params, "Invalid", 7)) { | ||||
| 		stat->invalid = 1; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * When we return without setting non-zero max, the parent is | ||||
| 	 * responsible for reporting errors. | ||||
| 	 */ | ||||
| 	if (!strncmp(params, "Unknown", 7)) | ||||
| 		return; | ||||
|  | ||||
| 	if (!(p = strstr(params, "/"))) | ||||
| 		return; | ||||
|  | ||||
| 	*p = '\0'; | ||||
| 	p++; | ||||
|  | ||||
| 	stat->used = atoi(params); | ||||
| 	stat->max = atoi(p); | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute((unused)), | ||||
| 		   void **private) | ||||
| { | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	struct snap_status stat = { 0 }; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	int percent, *percent_warning = (int*)private; | ||||
|  | ||||
| 	/* No longer monitoring, waiting for remove */ | ||||
| 	if (!*percent_warning) | ||||
| 		return; | ||||
|  | ||||
| 	if (pthread_mutex_trylock(&_event_mutex)) { | ||||
| 		syslog(LOG_NOTICE, "Another thread is handling an event.  Waiting..."); | ||||
| 		pthread_mutex_lock(&_event_mutex); | ||||
| 	} | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
| 	if (!target_type) | ||||
| 		goto out; | ||||
|  | ||||
| 	_parse_snapshot_params(params, &stat); | ||||
| 	/* | ||||
| 	 * If the snapshot has been invalidated or we failed to parse | ||||
| 	 * the status string. Report the full status string to syslog. | ||||
| 	 */ | ||||
| 	if (stat.invalid || !stat.max) { | ||||
| 		syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params); | ||||
| 		*percent_warning = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	percent = 100 * stat.used / stat.max; | ||||
| 	if (percent >= *percent_warning) { | ||||
| 		syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent); | ||||
| 		/* Print warning on the next multiple of WARNING_STEP. */ | ||||
| 		*percent_warning = (percent / WARNING_STEP) * WARNING_STEP + WARNING_STEP; | ||||
| 	} | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute((unused)), | ||||
| 		    int major __attribute((unused)), | ||||
| 		    int minor __attribute((unused)), | ||||
| 		    void **private) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	int *percent_warning = (int*)private; | ||||
|  | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	/* | ||||
| 	 * Need some space for allocations.  1024 should be more | ||||
| 	 * than enough for what we need (device mapper name splitting) | ||||
| 	 */ | ||||
| 	if (!_mem_pool && !(_mem_pool = dm_pool_create("snapshot_dso", 1024))) | ||||
| 		goto out; | ||||
|  | ||||
| 	*percent_warning = WARNING_THRESH; /* Print warning if snapshot is full */ | ||||
|  | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_temporary_log_fn); | ||||
| 		if (!(_lvm_handle = lvm2_init())) { | ||||
| 			dm_pool_destroy(_mem_pool); | ||||
| 			_mem_pool = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 	} | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring snapshot %s\n", device); | ||||
|  | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute((unused)), | ||||
| 		      int major __attribute((unused)), | ||||
| 		      int minor __attribute((unused)), | ||||
| 		      void **unused __attribute((unused))) | ||||
| { | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	syslog(LOG_INFO, "No longer monitoring snapshot %s\n", | ||||
| 	       device); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										29
									
								
								doc/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								doc/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| # | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| CONFSRC=example.conf | ||||
| CONFDEST=lvm.conf | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| install: | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \ | ||||
| 		echo "Installing $(CONFSRC) as $(confdir)/$(CONFDEST)"; \ | ||||
| 		@INSTALL@ -D $(OWNER) $(GROUP) -m 644 $(CONFSRC) \ | ||||
| 			$(confdir)/$(CONFDEST); \ | ||||
| 	fi | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| Wow!  This is really incredible documentation! | ||||
							
								
								
									
										411
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,411 @@ | ||||
| # This is an example configuration file for the LVM2 system. | ||||
| # It contains the default settings that would be used if there was no | ||||
| # /etc/lvm/lvm.conf file. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information including the file layout. | ||||
| # | ||||
| # To put this file in a different directory and override /etc/lvm set | ||||
| # the environment variable LVM_SYSTEM_DIR before running the tools. | ||||
|  | ||||
|  | ||||
| # This section allows you to configure which block devices should | ||||
| # be used by the LVM system. | ||||
| devices { | ||||
|  | ||||
|     # Where do you want your volume groups to appear ? | ||||
|     dir = "/dev" | ||||
|  | ||||
|     # An array of directories that contain the device nodes you wish | ||||
|     # to use with LVM2. | ||||
|     scan = [ "/dev" ] | ||||
|  | ||||
|     # If several entries in the scanned directories correspond to the | ||||
|     # same block device and the tools need to display a name for device, | ||||
|     # all the pathnames are matched against each item in the following | ||||
|     # list of regular expressions in turn and the first match is used. | ||||
|     preferred_names = [ ] | ||||
|  | ||||
|     # Try to avoid using undescriptive /dev/dm-N names, if present. | ||||
|     # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] | ||||
|  | ||||
|     # A filter that tells LVM2 to only use a restricted set of devices. | ||||
|     # The filter consists of an array of regular expressions.  These | ||||
|     # expressions can be delimited by a character of your choice, and | ||||
|     # prefixed with either an 'a' (for accept) or 'r' (for reject). | ||||
|     # The first expression found to match a device name determines if | ||||
|     # the device will be accepted or rejected (ignored).  Devices that | ||||
|     # don't match any patterns are accepted. | ||||
|  | ||||
|     # Be careful if there there are symbolic links or multiple filesystem  | ||||
|     # entries for the same device as each name is checked separately against | ||||
|     # the list of patterns.  The effect is that if any name matches any 'a' | ||||
|     # pattern, the device is accepted; otherwise if any name matches any 'r' | ||||
|     # pattern it is rejected; otherwise it is accepted. | ||||
|  | ||||
|     # Don't have more than one filter line active at once: only one gets used. | ||||
|  | ||||
|     # Run vgscan after you change this parameter to ensure that | ||||
|     # the cache file gets regenerated (see below). | ||||
|     # If it doesn't do what you expect, check the output of 'vgscan -vvvv'. | ||||
|  | ||||
|  | ||||
|     # By default we accept every block device: | ||||
|     filter = [ "a/.*/" ] | ||||
|  | ||||
|     # Exclude the cdrom drive | ||||
|     # filter = [ "r|/dev/cdrom|" ] | ||||
|  | ||||
|     # When testing I like to work with just loopback devices: | ||||
|     # filter = [ "a/loop/", "r/.*/" ] | ||||
|  | ||||
|     # Or maybe all loops and ide drives except hdc: | ||||
|     # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ] | ||||
|  | ||||
|     # Use anchors if you want to be really specific | ||||
|     # filter = [ "a|^/dev/hda8$|", "r/.*/" ] | ||||
|  | ||||
|     # The results of the filtering are cached on disk to avoid | ||||
|     # rescanning dud devices (which can take a very long time). | ||||
|     # By default this cache is stored in the /etc/lvm/cache directory | ||||
|     # in a file called '.cache'. | ||||
|     # It is safe to delete the contents: the tools regenerate it. | ||||
|     # (The old setting 'cache' is still respected if neither of | ||||
|     # these new ones is present.) | ||||
|     cache_dir = "/etc/lvm/cache" | ||||
|     cache_file_prefix = "" | ||||
|  | ||||
|     # You can turn off writing this cache file by setting this to 0. | ||||
|     write_cache_state = 1 | ||||
|  | ||||
|     # Advanced settings. | ||||
|  | ||||
|     # List of pairs of additional acceptable block device types found  | ||||
|     # in /proc/devices with maximum (non-zero) number of partitions. | ||||
|     # types = [ "fd", 16 ] | ||||
|  | ||||
|     # If sysfs is mounted (2.6 kernels) restrict device scanning to  | ||||
|     # the block devices it believes are valid. | ||||
|     # 1 enables; 0 disables. | ||||
|     sysfs_scan = 1	 | ||||
|  | ||||
|     # By default, LVM2 will ignore devices used as components of | ||||
|     # software RAID (md) devices by looking for md superblocks. | ||||
|     # 1 enables; 0 disables. | ||||
|     md_component_detection = 1 | ||||
|  | ||||
|     # By default, if a PV is placed directly upon an md device, LVM2 | ||||
|     # will align its data blocks with the the chunk_size exposed in sysfs. | ||||
|     # 1 enables; 0 disables. | ||||
|     md_chunk_alignment = 1 | ||||
|  | ||||
|     # If, while scanning the system for PVs, LVM2 encounters a device-mapper | ||||
|     # device that has its I/O suspended, it waits for it to become accessible. | ||||
|     # Set this to 1 to skip such devices.  This should only be needed | ||||
|     # in recovery situations. | ||||
|     ignore_suspended_devices = 0 | ||||
| } | ||||
|  | ||||
| # This section that allows you to configure the nature of the | ||||
| # information that LVM2 reports. | ||||
| log { | ||||
|  | ||||
|     # Controls the messages sent to stdout or stderr. | ||||
|     # There are three levels of verbosity, 3 being the most verbose. | ||||
|     verbose = 0 | ||||
|  | ||||
|     # Should we send log messages through syslog? | ||||
|     # 1 is yes; 0 is no. | ||||
|     syslog = 1 | ||||
|  | ||||
|     # Should we log error and debug messages to a file? | ||||
|     # By default there is no log file. | ||||
|     #file = "/var/log/lvm2.log" | ||||
|  | ||||
|     # Should we overwrite the log file each time the program is run? | ||||
|     # By default we append. | ||||
|     overwrite = 0 | ||||
|  | ||||
|     # What level of log messages should we send to the log file and/or syslog? | ||||
|     # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive. | ||||
|     # 7 is the most verbose (LOG_DEBUG). | ||||
|     level = 0 | ||||
|      | ||||
|     # Format of output messages | ||||
|     # Whether or not (1 or 0) to indent messages according to their severity | ||||
|     indent = 1 | ||||
|  | ||||
|     # Whether or not (1 or 0) to display the command name on each line output | ||||
|     command_names = 0 | ||||
|  | ||||
|     # A prefix to use before the message text (but after the command name, | ||||
|     # if selected).  Default is two spaces, so you can see/grep the severity | ||||
|     # of each message. | ||||
|     prefix = "  " | ||||
|  | ||||
|     # To make the messages look similar to the original LVM tools use: | ||||
|     #   indent = 0 | ||||
|     #   command_names = 1 | ||||
|     #   prefix = " -- " | ||||
|  | ||||
|     # Set this if you want log messages during activation. | ||||
|     # Don't use this in low memory situations (can deadlock). | ||||
|     # activation = 0 | ||||
| } | ||||
|  | ||||
| # Configuration of metadata backups and archiving.  In LVM2 when we | ||||
| # talk about a 'backup' we mean making a copy of the metadata for the | ||||
| # *current* system.  The 'archive' contains old metadata configurations. | ||||
| # Backups are stored in a human readeable text format. | ||||
| backup { | ||||
|  | ||||
|     # Should we maintain a backup of the current metadata configuration ? | ||||
|     # Use 1 for Yes; 0 for No. | ||||
|     # Think very hard before turning this off! | ||||
|     backup = 1 | ||||
|  | ||||
|     # Where shall we keep it ? | ||||
|     # Remember to back up this directory regularly! | ||||
|     backup_dir = "/etc/lvm/backup" | ||||
|  | ||||
|     # Should we maintain an archive of old metadata configurations. | ||||
|     # Use 1 for Yes; 0 for No. | ||||
|     # On by default.  Think very hard before turning this off. | ||||
|     archive = 1 | ||||
|  | ||||
|     # Where should archived files go ? | ||||
|     # Remember to back up this directory regularly! | ||||
|     archive_dir = "/etc/lvm/archive" | ||||
|      | ||||
|     # What is the minimum number of archive files you wish to keep ? | ||||
|     retain_min = 10 | ||||
|  | ||||
|     # What is the minimum time you wish to keep an archive file for ? | ||||
|     retain_days = 30 | ||||
| } | ||||
|  | ||||
| # Settings for the running LVM2 in shell (readline) mode. | ||||
| shell { | ||||
|  | ||||
|     # Number of lines of history to store in ~/.lvm_history | ||||
|     history_size = 100 | ||||
| } | ||||
|  | ||||
|  | ||||
| # Miscellaneous global LVM2 settings | ||||
| global { | ||||
|      | ||||
|     # The file creation mask for any files and directories created. | ||||
|     # Interpreted as octal if the first digit is zero. | ||||
|     umask = 077 | ||||
|  | ||||
|     # Allow other users to read the files | ||||
|     #umask = 022 | ||||
|  | ||||
|     # Enabling test mode means that no changes to the on disk metadata | ||||
|     # will be made.  Equivalent to having the -t option on every | ||||
|     # command.  Defaults to off. | ||||
|     test = 0 | ||||
|  | ||||
|     # Default value for --units argument | ||||
|     units = "h" | ||||
|  | ||||
|     # Whether or not to communicate with the kernel device-mapper. | ||||
|     # Set to 0 if you want to use the tools to manipulate LVM metadata  | ||||
|     # without activating any logical volumes. | ||||
|     # If the device-mapper kernel driver is not present in your kernel | ||||
|     # setting this to 0 should suppress the error messages. | ||||
|     activation = 1 | ||||
|  | ||||
|     # If we can't communicate with device-mapper, should we try running  | ||||
|     # the LVM1 tools? | ||||
|     # This option only applies to 2.4 kernels and is provided to help you | ||||
|     # switch between device-mapper kernels and LVM1 kernels. | ||||
|     # The LVM1 tools need to be installed with .lvm1 suffices | ||||
|     # e.g. vgscan.lvm1 and they will stop working after you start using | ||||
|     # the new lvm2 on-disk metadata format. | ||||
|     # The default value is set when the tools are built. | ||||
|     # fallback_to_lvm1 = 0 | ||||
|  | ||||
|     # The default metadata format that commands should use - "lvm1" or "lvm2". | ||||
|     # The command line override is -M1 or -M2. | ||||
|     # Defaults to "lvm1" if compiled in, else "lvm2". | ||||
|     # format = "lvm1" | ||||
|  | ||||
|     # Location of proc filesystem | ||||
|     proc = "/proc" | ||||
|  | ||||
|     # Type of locking to use. Defaults to local file-based locking (1). | ||||
|     # Turn locking off by setting to 0 (dangerous: risks metadata corruption | ||||
|     # if LVM2 commands get run concurrently). | ||||
|     # Type 2 uses the external shared library locking_library. | ||||
|     # Type 3 uses built-in clustered locking. | ||||
|     locking_type = 1 | ||||
|  | ||||
|     # If using external locking (type 2) and initialisation fails, | ||||
|     # with this set to 1 an attempt will be made to use the built-in | ||||
|     # clustered locking. | ||||
|     # If you are using a customised locking_library you should set this to 0. | ||||
|     fallback_to_clustered_locking = 1 | ||||
|  | ||||
|     # If an attempt to initialise type 2 or type 3 locking failed, perhaps | ||||
|     # because cluster components such as clvmd are not running, with this set | ||||
|     # to 1 an attempt will be made to use local file-based locking (type 1). | ||||
|     # If this succeeds, only commands against local volume groups will proceed. | ||||
|     # Volume Groups marked as clustered will be ignored. | ||||
|     fallback_to_local_locking = 1 | ||||
|  | ||||
|     # Local non-LV directory that holds file-based locks while commands are | ||||
|     # in progress.  A directory like /tmp that may get wiped on reboot is OK. | ||||
|     locking_dir = "/var/lock/lvm" | ||||
|  | ||||
|     # Other entries can go here to allow you to load shared libraries | ||||
|     # e.g. if support for LVM1 metadata was compiled as a shared library use | ||||
|     #   format_libraries = "liblvm2format1.so"  | ||||
|     # Full pathnames can be given. | ||||
|  | ||||
|     # Search this directory first for shared libraries. | ||||
|     #   library_dir = "/lib" | ||||
|  | ||||
|     # The external locking library to load if locking_type is set to 2. | ||||
|     #   locking_library = "liblvm2clusterlock.so" | ||||
| } | ||||
|  | ||||
| activation { | ||||
|     # How to fill in missing stripes if activating an incomplete volume. | ||||
|     # Using "error" will make inaccessible parts of the device return | ||||
|     # I/O errors on access.  You can instead use a device path, in which  | ||||
|     # case, that device will be used to in place of missing stripes. | ||||
|     # But note that using anything other than "error" with mirrored  | ||||
|     # or snapshotted volumes is likely to result in data corruption. | ||||
|     missing_stripe_filler = "error" | ||||
|  | ||||
|     # How much stack (in KB) to reserve for use while devices suspended | ||||
|     reserved_stack = 256 | ||||
|  | ||||
|     # How much memory (in KB) to reserve for use while devices suspended | ||||
|     reserved_memory = 8192 | ||||
|  | ||||
|     # Nice value used while devices suspended | ||||
|     process_priority = -18 | ||||
|  | ||||
|     # If volume_list is defined, each LV is only activated if there is a | ||||
|     # match against the list. | ||||
|     #   "vgname" and "vgname/lvname" are matched exactly. | ||||
|     #   "@tag" matches any tag set in the LV or VG. | ||||
|     #   "@*" matches if any tag defined on the host is also set in the LV or VG | ||||
|     # | ||||
|     # volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ] | ||||
|  | ||||
|     # Size (in KB) of each copy operation when mirroring | ||||
|     mirror_region_size = 512 | ||||
|  | ||||
|     # Setting to use when there is no readahead value stored in the metadata. | ||||
|     # | ||||
|     # "none" - Disable readahead. | ||||
|     # "auto" - Use default value chosen by kernel. | ||||
|     readahead = "auto" | ||||
|  | ||||
|     # 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define | ||||
|     # how a device failure affecting a mirror is handled. | ||||
|     # A mirror is composed of mirror images (copies) and a log. | ||||
|     # A disk log ensures that a mirror does not need to be re-synced | ||||
|     # (all copies made the same) every time a machine reboots or crashes. | ||||
|     # | ||||
|     # In the event of a failure, the specified policy will be used to | ||||
|     # determine what happens: | ||||
|     # | ||||
|     # "remove" - Simply remove the faulty device and run without it.  If | ||||
|     #            the log device fails, the mirror would convert to using | ||||
|     #            an in-memory log.  This means the mirror will not | ||||
|     #            remember its sync status across crashes/reboots and | ||||
|     #            the entire mirror will be re-synced.  If a | ||||
|     #            mirror image fails, the mirror will convert to a | ||||
|     #            non-mirrored device if there is only one remaining good | ||||
|     #            copy. | ||||
|     # | ||||
|     # "allocate" - Remove the faulty device and try to allocate space on | ||||
|     #            a new device to be a replacement for the failed device. | ||||
|     #            Using this policy for the log is fast and maintains the | ||||
|     #            ability to remember sync state through crashes/reboots. | ||||
|     #            Using this policy for a mirror device is slow, as it | ||||
|     #            requires the mirror to resynchronize the devices, but it | ||||
|     #            will preserve the mirror characteristic of the device. | ||||
|     #            This policy acts like "remove" if no suitable device and | ||||
|     #            space can be allocated for the replacement. | ||||
|     #            Currently this is not implemented properly and behaves | ||||
|     #            similarly to: | ||||
|     # | ||||
|     # "allocate_anywhere" - Operates like "allocate", but it does not | ||||
|     #            require that the new space being allocated be on a | ||||
|     #            device is not part of the mirror.  For a log device | ||||
|     #            failure, this could mean that the log is allocated on | ||||
|     #            the same device as a mirror device.  For a mirror | ||||
|     #            device, this could mean that the mirror device is | ||||
|     #            allocated on the same device as another mirror device. | ||||
|     #            This policy would not be wise for mirror devices | ||||
|     #            because it would break the redundant nature of the | ||||
|     #            mirror.  This policy acts like "remove" if no suitable | ||||
|     #            device and space can be allocated for the replacement. | ||||
|  | ||||
|     mirror_log_fault_policy = "allocate" | ||||
|     mirror_device_fault_policy = "remove" | ||||
| } | ||||
|  | ||||
|  | ||||
| #################### | ||||
| # Advanced section # | ||||
| #################### | ||||
|  | ||||
| # Metadata settings | ||||
| # | ||||
| # metadata { | ||||
|     # Default number of copies of metadata to hold on each PV.  0, 1 or 2. | ||||
|     # You might want to override it from the command line with 0  | ||||
|     # when running pvcreate on new PVs which are to be added to large VGs. | ||||
|  | ||||
|     # pvmetadatacopies = 1 | ||||
|  | ||||
|     # Approximate default size of on-disk metadata areas in sectors. | ||||
|     # You should increase this if you have large volume groups or | ||||
|     # you want to retain a large on-disk history of your metadata changes. | ||||
|  | ||||
|     # pvmetadatasize = 255 | ||||
|  | ||||
|     # List of directories holding live copies of text format metadata. | ||||
|     # These directories must not be on logical volumes! | ||||
|     # It's possible to use LVM2 with a couple of directories here, | ||||
|     # preferably on different (non-LV) filesystems, and with no other  | ||||
|     # on-disk metadata (pvmetadatacopies = 0). Or this can be in | ||||
|     # addition to on-disk metadata areas. | ||||
|     # The feature was originally added to simplify testing and is not | ||||
|     # supported under low memory situations - the machine could lock up. | ||||
|     # | ||||
|     # Never edit any files in these directories by hand unless you | ||||
|     # you are absolutely sure you know what you are doing! Use | ||||
|     # the supplied toolset to make changes (e.g. vgcfgrestore). | ||||
|  | ||||
|     # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ] | ||||
| #} | ||||
|  | ||||
| # Event daemon | ||||
| # | ||||
| # dmeventd { | ||||
|     # mirror_library is the library used when monitoring a mirror device. | ||||
|     # | ||||
|     # "libdevmapper-event-lvm2mirror.so" attempts to recover from | ||||
|     # failures.  It removes failed devices from a volume group and | ||||
|     # reconfigures a mirror as necessary. If no mirror library is | ||||
|     # provided, mirrors are not monitored through dmeventd. | ||||
|  | ||||
|     # mirror_library = "libdevmapper-event-lvm2mirror.so" | ||||
|  | ||||
|     # snapshot_library is the library used when monitoring a snapshot device. | ||||
|     # | ||||
|     # "libdevmapper-event-lvm2snapshot.so" monitors the filling of | ||||
|     # snapshots and emits a warning through syslog, when the use of | ||||
|     # snapshot exceedes 80%. The warning is repeated when 85%, 90% and | ||||
|     # 95% of the snapshot are filled. | ||||
|  | ||||
|     # snapshot_library = "libdevmapper-event-lvm2snapshot.so" | ||||
| #} | ||||
|  | ||||
							
								
								
									
										47
									
								
								doc/example_cmdlib.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								doc/example_cmdlib.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lvm2cmd.h" | ||||
|  | ||||
| /* All output gets passed to this function line-by-line */ | ||||
| void test_log_fn(int level, const char *file, int line, const char *format) | ||||
| { | ||||
| 	/* Extract and process output here rather than printing it */ | ||||
|  | ||||
| 	if (level != 4) | ||||
| 		return; | ||||
|  | ||||
| 	printf("%s\n", format); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	void *handle; | ||||
| 	int r; | ||||
|  | ||||
| 	lvm2_log_fn(test_log_fn); | ||||
|  | ||||
| 	handle = lvm2_init(); | ||||
|  | ||||
| 	lvm2_log_level(handle, 1); | ||||
| 	r = lvm2_run(handle, "vgs --noheadings vg1"); | ||||
|  | ||||
| 	/* More commands here */ | ||||
|  | ||||
| 	lvm2_exit(handle); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
							
								
								
									
										52
									
								
								doc/pvmove_outline.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								doc/pvmove_outline.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| Let's say we have an LV, made up of three segments of different PV's, | ||||
| I've also added in the device major:minor as this will be useful | ||||
| later: | ||||
|  | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV2   |   PV3  | 254:3 | ||||
| +----------+---------+--------+ | ||||
|  | ||||
|  | ||||
| Now our hero decides to PV move PV2 to PV4: | ||||
|  | ||||
| 1. Suspend our LV (254:3), this starts queueing all io, and flushes | ||||
|    all pending io.  Once the suspend has completed we are free to change | ||||
|    the mapping table. | ||||
|  | ||||
| 2. Set up *another* (254:4) device with the mapping table of our LV. | ||||
|  | ||||
| 3. Load a new mapping table into (254:3) that has identity targets for | ||||
|    parts that aren't moving, and a mirror target for parts that are. | ||||
|  | ||||
| 4. Unsuspend (254:3) | ||||
|  | ||||
| So now we have: | ||||
|                            destination of copy | ||||
|                +--------------------->--------------+ | ||||
|                |                                    | | ||||
| +-----------------------------+               + -----------+ | ||||
| | Identity | mirror  | Ident. | 254:3         |    PV4     | | ||||
| +----------+---------+--------+               +------------+ | ||||
|      |         |         | | ||||
|      \/        \/        \/ | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV2   |   PV3  | 254:4 | ||||
| +----------+---------+--------+ | ||||
|  | ||||
| Any writes to segment2 of the LV get intercepted by the mirror target | ||||
| who checks that that chunk has been copied to the new destination, if | ||||
| it hasn't it queues the initial copy and defers the current io until | ||||
| it has finished.  Then the current io is written to *both* PV2 and the | ||||
| PV4. | ||||
|  | ||||
| 5. When the copying has completed 254:3 is suspended/pending flushed. | ||||
|  | ||||
| 6. 254:4 is taken down | ||||
|  | ||||
| 7. metadata is updated on disk | ||||
|  | ||||
| 8. 254:3 has new mapping table loaded: | ||||
|  | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV4   |   PV3  | 254:3 | ||||
| +----------+---------+--------+ | ||||
							
								
								
									
										165
									
								
								doc/tagging.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								doc/tagging.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| Tagging aims | ||||
| ============ | ||||
|   1) Ability to attach an unordered list of tags to LVM metadata objects. | ||||
|   2) Ability to add or remove tags easily. | ||||
|   3) Ability to select LVM objects for processing according to presence/absence | ||||
|      of specific tags. | ||||
|   4) Ability to control through the config file which VGs/LVs are activated  | ||||
|      on different machines using names or tags. | ||||
|   5) Ability to overlay settings from different config files e.g. override | ||||
|      some settings in a global config file locally. | ||||
|  | ||||
| Clarifications | ||||
| ============== | ||||
|   1) Tag character set: A-Za-z0-9_+.-  | ||||
|      Can't start with hyphen & max length is 128 (NAME_LEN). | ||||
|   2) LVM object types that can be tagged: | ||||
|        VG, LV, LV segment | ||||
|        PV - tags are stored in VG metadata so disappear when PV becomes orphaned | ||||
|      Snapshots can't be tagged, but their origin may be. | ||||
|   3) A tag can be used in place of any command line LVM object reference that | ||||
|      accepts (a) a list of objects; or (b) a single object as long as the | ||||
|      tag expands to a single object.  This is not supported everywhere yet. | ||||
|      Duplicate arguments in a list after argument expansion may get removed  | ||||
|      retaining the first copy of each argument. | ||||
|   4) Wherever there may be ambiguity of argument type, a tag must be prefixed  | ||||
|      by '@'; elsewhere an '@' prefix is optional. | ||||
|   5) LVM1 objects cannot be tagged, as the disk format doesn't support it. | ||||
|   6) Tags can be added or removed with --addtag or --deltag. | ||||
|  | ||||
| Config file Extensions | ||||
| ====================== | ||||
|   To define host tags in config file: | ||||
|  | ||||
|   tags { | ||||
|   	# Set a tag with the hostname | ||||
| 	hosttags = 1 | ||||
|  | ||||
| 	tag1 { } | ||||
|  | ||||
|   	tag2 { | ||||
| 		# If no exact match, tag is not set. | ||||
| 		host_list = [ "hostname", "dbase" ] | ||||
| 	} | ||||
|   } | ||||
|  | ||||
| Activation config file example | ||||
| ============================== | ||||
|   activation { | ||||
|       volume_list = [ "vg1/lvol0", "@database" ] | ||||
|   } | ||||
|  | ||||
|   Matches against vgname, vgname/lvname or @tag set in *metadata*. | ||||
|   @* matches exactly against *any* tag set on the host. | ||||
|   The VG or LV only gets activated if a metadata tag matches. | ||||
|   The default if there is no match is not to activate. | ||||
|   If volume_list is not present and any tags are defined on the host  | ||||
|   then it only activates if a host tag matches a metadata tag. | ||||
|   If volume_list is not present and no tags are defined on the host  | ||||
|   then it does activate. | ||||
|  | ||||
| Multiple config files | ||||
| ===================== | ||||
|   (a) lvm.conf | ||||
|   (b) lvm_<host_tag>.conf | ||||
|  | ||||
|   At startup, load lvm.conf. | ||||
|   Process tag settings. | ||||
|   If any host tags were defined, load lvm_tag.conf for each tag, if present. | ||||
|  | ||||
|   When searching for a specific config file entry, search order is (b) | ||||
|   then (a), stopping at the first match.   | ||||
|   Within (b) use reverse order tags got set, so file for last tag set is | ||||
|   searched first. | ||||
|   New tags set in (b) *do* trigger additional config file loads.  | ||||
|  | ||||
| Usage Examples | ||||
| ============== | ||||
|   1) Simple activation control via metadata with static config files | ||||
|  | ||||
|   lvm.conf:  (Identical on every machine - global settings) | ||||
|     tags { | ||||
|       hostname_tags = 1 | ||||
|     } | ||||
|  | ||||
|   From any machine in the cluster, add db1 to the list of machines that | ||||
|   activate vg1/lvol2: | ||||
|  | ||||
|   lvchange --tag @db1 vg1/lvol2 | ||||
|   (followed by lvchange -ay to actually activate it) | ||||
|  | ||||
|  | ||||
|   2) Multiple hosts.   | ||||
|  | ||||
|     Activate vg1 only on the database hosts, db1 and db2. | ||||
|     Activate vg2 only on the fileserver host fs1. | ||||
|     Activate nothing initially on the fileserver backup host fsb1, but be | ||||
|     prepared for it to take over from fs1. | ||||
|  | ||||
|   Option (i) - centralised admin, static configuration replicated between hosts   | ||||
|     # Add @database tag to vg1's metadata | ||||
|     vgchange --tag @database vg1 | ||||
|  | ||||
|     # Add @fileserver tag to vg2's metadata | ||||
|     vgchange --tag @fileserver vg2 | ||||
|  | ||||
|     lvm.conf:  (Identical on every machine) | ||||
|       tags { | ||||
|         database { | ||||
|           host_list = [ "db1", "db2" ] | ||||
|         } | ||||
|         fileserver { | ||||
| 	  host_list = [ "fs1" ] | ||||
|         } | ||||
|         fileserverbackup { | ||||
|           host_list = [ "fsb1" ] | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       activation { | ||||
|         # Only activate if host has a tag that matches a metadata tag | ||||
|         volume_list = [ "@*" ] | ||||
|       } | ||||
|    | ||||
|   In the event of the fileserver host going down, vg2 can be brought up | ||||
|   on fsb1 by running *on any node* 'vgchange --tag @fileserverbackup vg2' | ||||
|   followed by 'vgchange -ay vg2' | ||||
|    | ||||
|    | ||||
|   Option (ii) - localised admin & configuation | ||||
|   (i.e. each host holds *locally* which classes of volumes to activate) | ||||
|     # Add @database tag to vg1's metadata | ||||
|     vgchange --tag @database vg1 | ||||
|    | ||||
|     # Add @fileserver tag to vg2's metadata | ||||
|     vgchange --tag @fileserver vg2 | ||||
|    | ||||
|     lvm.conf:  (Identical on every machine - global settings) | ||||
|       tags { | ||||
|         hosttags = 1 | ||||
|       } | ||||
|    | ||||
|     lvm_db1.conf: (only needs to be on db1 - could be symlink to lvm_db.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@database" ] | ||||
|       } | ||||
|    | ||||
|     lvm_db2.conf: (only needs to be on db2 - could be symlink to lvm_db.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@database" ] | ||||
|       } | ||||
|    | ||||
|     lvm_fs1.conf: (only needs to be on fs1 - could be symlink to lvm_fs.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@fileserver" ] | ||||
|       } | ||||
|    | ||||
|     If fileserver goes down, to bring a spare machine fsb1 in as fileserver, | ||||
|     create lvm_fsb1.conf on fsb1 (or symlink to lvm_fs.conf): | ||||
|  | ||||
|       activation { | ||||
|         volume_list = [ "@fileserver" ] | ||||
|       } | ||||
|  | ||||
|     and run 'vgchange -ay vg2' or 'vgchange -ay @fileserver' | ||||
|  | ||||
							
								
								
									
										41
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| Here's how I test new LVM2 builds without interfering with the stable | ||||
| LVM2 that is running the LV's on my development box. | ||||
|  | ||||
| 1) Create a set of loopback devices. | ||||
|  | ||||
| 2) Create a new directory to contain the LVM2 configuration files for | ||||
|    this setup.  (I use /etc/lvm_loops) | ||||
|  | ||||
| 3) Write a suitable lvm.conf file, this goes in the directory you just | ||||
|    created.  eg, my /etc/lvm_loops/lvm.conf looks like: | ||||
|  | ||||
|    log { | ||||
|         file="/tmp/lvm2_loop.log" | ||||
|         level=9 | ||||
|         verbose=0 | ||||
|         overwrite=1 | ||||
|    } | ||||
|  | ||||
|    devices { | ||||
|         scan = "/dev" | ||||
|         filter = ["a/loop/", "r/.*/"] | ||||
|    } | ||||
|  | ||||
|  | ||||
|    The important thing to note is the devices section which makes sure | ||||
|    that only the loopback devices are considered for LVM2 operations. | ||||
|  | ||||
| 4) When you want to use this test setup just set the environment | ||||
|    variable LVM_SYSTEM_DIR to point to your config directory | ||||
|    (/etc/lvm_loops in my case). | ||||
|  | ||||
| 5) It's a good idea to do a vgscan to initialise the filters: | ||||
|  | ||||
|    export LVM_SYSTEM_DIR=/etc/lvm_loops | ||||
|    ./lvm vgscan | ||||
|  | ||||
|    where ./lvm is the new build of LVM2 that I'm trying out. | ||||
|  | ||||
| 7) Test away.  Make sure that you are explicit about which lvm | ||||
|    executable you want to execute (eg, ./lvm if you are in | ||||
|    LVM2/tools). | ||||
| @@ -1 +0,0 @@ | ||||
| The driver directory | ||||
							
								
								
									
										59
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| ../daemons/clvmd/clvm.h | ||||
| ../daemons/dmeventd/libdevmapper-event.h | ||||
| ../lib/activate/activate.h | ||||
| ../lib/activate/targets.h | ||||
| ../lib/cache/lvmcache.h | ||||
| ../lib/commands/errors.h | ||||
| ../lib/commands/toolcontext.h | ||||
| ../lib/config/config.h | ||||
| ../lib/config/defaults.h | ||||
| ../lib/datastruct/btree.h | ||||
| ../lib/datastruct/lvm-types.h | ||||
| ../lib/datastruct/str_list.h | ||||
| ../lib/device/dev-cache.h | ||||
| ../lib/device/device.h | ||||
| ../lib/display/display.h | ||||
| ../lib/filters/filter-composite.h | ||||
| ../lib/filters/filter-md.h | ||||
| ../lib/filters/filter-persistent.h | ||||
| ../lib/filters/filter-regex.h | ||||
| ../lib/filters/filter-sysfs.h | ||||
| ../lib/filters/filter.h | ||||
| ../lib/format1/format1.h | ||||
| ../lib/format_pool/format_pool.h | ||||
| ../lib/format_text/archiver.h | ||||
| ../lib/format_text/format-text.h | ||||
| ../lib/format_text/text_export.h | ||||
| ../lib/format_text/text_import.h | ||||
| ../lib/label/label.h | ||||
| ../lib/locking/locking.h | ||||
| ../lib/log/log.h | ||||
| ../lib/log/lvm-logging.h | ||||
| ../lib/metadata/lv_alloc.h | ||||
| ../lib/metadata/metadata.h | ||||
| ../lib/metadata/metadata-exported.h | ||||
| ../lib/metadata/pv_alloc.h | ||||
| ../lib/metadata/segtype.h | ||||
| ../lib/mm/memlock.h | ||||
| ../lib/mm/xlate.h | ||||
| ../lib/misc/configure.h | ||||
| ../lib/misc/crc.h | ||||
| ../lib/misc/intl.h | ||||
| ../lib/misc/util.h | ||||
| ../lib/misc/last-path-component.h | ||||
| ../lib/misc/lib.h | ||||
| ../lib/misc/lvm-exec.h | ||||
| ../lib/misc/lvm-file.h | ||||
| ../lib/misc/lvm-globals.h | ||||
| ../lib/misc/lvm-string.h | ||||
| ../lib/misc/lvm-wrappers.h | ||||
| ../lib/misc/sharedlib.h | ||||
| ../lib/report/report.h | ||||
| ../lib/uuid/uuid.h | ||||
| ../libdm/libdevmapper.h | ||||
| ../libdm/misc/dm-ioctl.h | ||||
| ../libdm/misc/dm-logging.h | ||||
| ../libdm/misc/dmlib.h | ||||
| ../libdm/misc/kdev_t.h | ||||
| ../po/pogen.h | ||||
| ../tools/version.h | ||||
							
								
								
									
										49
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| SHELL = /bin/sh | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| LN_S = @LN_S@ | ||||
|  | ||||
| .PHONY: clean distclean all install pofile install_cluster install_device-mapper | ||||
|  | ||||
| all: .symlinks_created | ||||
|  | ||||
| .symlinks_created: .symlinks | ||||
| 	find . -maxdepth 1 -type l -exec $(RM) \{\} \; | ||||
| 	for i in `cat .symlinks`; do $(LN_S) $$i ; done | ||||
| 	touch $@ | ||||
|  | ||||
| distclean: | ||||
| 	find . -maxdepth 1 -type l -exec $(RM) \{\} \; | ||||
| 	$(RM) Makefile .include_symlinks .symlinks_created | ||||
|  | ||||
| pofile: all | ||||
|  | ||||
| device-mapper: all | ||||
|  | ||||
| clean: | ||||
|  | ||||
| install: | ||||
|  | ||||
| install_cluster: | ||||
|  | ||||
| install_device-mapper: | ||||
|  | ||||
| cflow: | ||||
|  | ||||
							
								
								
									
										156
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| ifeq ("@LVM1@", "shared") | ||||
|   SUBDIRS = format1 | ||||
| endif | ||||
|  | ||||
| ifeq ("@POOL@", "shared") | ||||
|   SUBDIRS += format_pool | ||||
| endif | ||||
|  | ||||
| ifeq ("@SNAPSHOTS@", "shared") | ||||
|   SUBDIRS += snapshot | ||||
| endif | ||||
|  | ||||
| ifeq ("@MIRRORS@", "shared") | ||||
|   SUBDIRS += mirror | ||||
| endif | ||||
|  | ||||
| SOURCES =\ | ||||
| 	activate/activate.c \ | ||||
| 	cache/lvmcache.c \ | ||||
| 	commands/toolcontext.c \ | ||||
| 	config/config.c \ | ||||
| 	datastruct/btree.c \ | ||||
| 	datastruct/str_list.c \ | ||||
| 	device/dev-cache.c \ | ||||
| 	device/dev-io.c \ | ||||
| 	device/dev-md.c \ | ||||
| 	device/device.c \ | ||||
| 	display/display.c \ | ||||
| 	error/errseg.c \ | ||||
| 	filters/filter-composite.c \ | ||||
| 	filters/filter-persistent.c \ | ||||
| 	filters/filter-regex.c \ | ||||
| 	filters/filter-sysfs.c \ | ||||
| 	filters/filter-md.c \ | ||||
| 	filters/filter.c \ | ||||
| 	format_text/archive.c \ | ||||
| 	format_text/archiver.c \ | ||||
| 	format_text/export.c \ | ||||
| 	format_text/flags.c \ | ||||
| 	format_text/format-text.c \ | ||||
| 	format_text/import.c \ | ||||
| 	format_text/import_vsn1.c \ | ||||
| 	format_text/tags.c \ | ||||
| 	format_text/text_label.c \ | ||||
| 	freeseg/freeseg.c \ | ||||
| 	label/label.c \ | ||||
| 	locking/file_locking.c \ | ||||
| 	locking/locking.c \ | ||||
| 	locking/no_locking.c \ | ||||
| 	log/log.c \ | ||||
| 	metadata/lv_manip.c \ | ||||
| 	metadata/merge.c \ | ||||
| 	metadata/metadata.c \ | ||||
| 	metadata/mirror.c \ | ||||
| 	metadata/pv_manip.c \ | ||||
| 	metadata/pv_map.c \ | ||||
| 	metadata/segtype.c \ | ||||
| 	metadata/snapshot_manip.c \ | ||||
| 	misc/crc.c \ | ||||
| 	misc/lvm-exec.c \ | ||||
| 	misc/lvm-file.c \ | ||||
| 	misc/lvm-globals.c \ | ||||
| 	misc/lvm-string.c \ | ||||
| 	misc/lvm-wrappers.c \ | ||||
| 	misc/timestamp.c \ | ||||
| 	misc/util.c \ | ||||
| 	mm/memlock.c \ | ||||
| 	report/report.c \ | ||||
| 	striped/striped.c \ | ||||
| 	uuid/uuid.c \ | ||||
| 	zero/zero.c | ||||
|  | ||||
| ifeq ("@LVM1@", "internal") | ||||
|   SOURCES +=\ | ||||
| 	format1/disk-rep.c \ | ||||
| 	format1/format1.c \ | ||||
| 	format1/import-export.c \ | ||||
| 	format1/import-extents.c \ | ||||
| 	format1/layout.c \ | ||||
| 	format1/lvm1-label.c \ | ||||
| 	format1/vg_number.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@POOL@", "internal") | ||||
|   SOURCES +=\ | ||||
| 	format_pool/disk_rep.c \ | ||||
| 	format_pool/format_pool.c \ | ||||
| 	format_pool/import_export.c \ | ||||
| 	format_pool/pool_label.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLUSTER@", "internal") | ||||
|   SOURCES += locking/cluster_locking.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLUSTER@", "shared") | ||||
|   SUBDIRS += locking | ||||
| endif | ||||
|  | ||||
| ifeq ("@SNAPSHOTS@", "internal") | ||||
|   SOURCES += snapshot/snapshot.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@MIRRORS@", "internal") | ||||
|   SOURCES += mirror/mirrored.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@DEVMAPPER@", "yes") | ||||
|   SOURCES +=\ | ||||
| 	activate/dev_manager.c \ | ||||
| 	activate/fs.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@HAVE_LIBDL@", "yes") | ||||
|   SOURCES +=\ | ||||
| 	locking/external_locking.c \ | ||||
| 	misc/sharedlib.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
|   CLDFLAGS += -ldevmapper-event | ||||
| endif | ||||
|  | ||||
| LIB_STATIC = liblvm.a | ||||
|  | ||||
| $(SUBDIRS): $(LIB_STATIC) | ||||
|  | ||||
| CLEAN_TARGETS += liblvm.cflow | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| liblvm.cflow: $(SOURCES) | ||||
| 	set -e; (echo -n "SOURCES += "; \ | ||||
| 		 echo $(SOURCES) | \ | ||||
| 		 sed "s/^/ /;s/ / $(top_srcdir)\/lib\//g;s/$$//"; \ | ||||
| 		 ) > $@ | ||||
|  | ||||
| cflow: liblvm.cflow | ||||
| @@ -1 +0,0 @@ | ||||
| Base library directory | ||||
							
								
								
									
										1122
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1122
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										110
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef LVM_ACTIVATE_H | ||||
| #define LVM_ACTIVATE_H | ||||
|  | ||||
| #include "metadata-exported.h" | ||||
|  | ||||
| struct lvinfo { | ||||
| 	int exists; | ||||
| 	int suspended; | ||||
| 	unsigned int open_count; | ||||
| 	int major; | ||||
| 	int minor; | ||||
| 	int read_only; | ||||
| 	int live_table; | ||||
| 	int inactive_table; | ||||
| 	uint32_t read_ahead; | ||||
| }; | ||||
|  | ||||
| /* target attribute flags */ | ||||
| #define MIRROR_LOG_CLUSTERED	0x00000001U | ||||
|  | ||||
| void set_activation(int activation); | ||||
| int activation(void); | ||||
|  | ||||
| int driver_version(char *version, size_t size); | ||||
| int library_version(char *version, size_t size); | ||||
| int lvm1_present(struct cmd_context *cmd); | ||||
|  | ||||
| int module_present(const char *target_name); | ||||
| int target_present(const char *target_name, int use_modprobe); | ||||
| int target_version(const char *target_name, uint32_t *maj, | ||||
|                    uint32_t *min, uint32_t *patchlevel); | ||||
| int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg, | ||||
| 			 struct dm_list *modules); | ||||
| int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv, | ||||
| 		    struct dm_list *modules); | ||||
|  | ||||
| void activation_release(void); | ||||
| void activation_exit(void); | ||||
|  | ||||
| int lv_suspend(struct cmd_context *cmd, const char *lvid_s); | ||||
| int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s); | ||||
| int lv_resume(struct cmd_context *cmd, const char *lvid_s); | ||||
| int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s); | ||||
| int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive); | ||||
| int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			    int exclusive); | ||||
| int lv_deactivate(struct cmd_context *cmd, const char *lvid_s); | ||||
|  | ||||
| int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if info structure has been populated, else 0. | ||||
|  */ | ||||
| int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info, | ||||
| 	    int with_open_count, int with_read_ahead); | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info, int with_open_count, int with_read_ahead); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if activate_lv has been set: 1 = activate; 0 = don't. | ||||
|  */ | ||||
| int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			 int *activate_lv); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if percent has been set, else 0. | ||||
|  */ | ||||
| int lv_snapshot_percent(const struct logical_volume *lv, float *percent); | ||||
| int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 		      int wait, float *percent, uint32_t *event_nr); | ||||
|  | ||||
| /* | ||||
|  * Return number of LVs in the VG that are active. | ||||
|  */ | ||||
| int lvs_in_vg_activated(struct volume_group *vg); | ||||
| int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg); | ||||
| int lvs_in_vg_opened(const struct volume_group *vg); | ||||
|  | ||||
| int lv_is_active(struct logical_volume *lv); | ||||
|  | ||||
| int monitor_dev_for_events(struct cmd_context *cmd, | ||||
| 			    struct logical_volume *lv, int do_reg); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if PV has a dependency tree that uses anything in VG. | ||||
|  */ | ||||
| int pv_uses_vg(struct physical_volume *pv, | ||||
| 	       struct volume_group *vg); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if mapped device is not suspended. | ||||
|  */ | ||||
| int device_is_usable(dev_t dev); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1236
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1236
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										68
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEV_MANAGER_H | ||||
| #define _LVM_DEV_MANAGER_H | ||||
|  | ||||
| struct logical_volume; | ||||
| struct volume_group; | ||||
| struct cmd_context; | ||||
| struct dev_manager; | ||||
| struct dm_info; | ||||
| struct device; | ||||
|  | ||||
| /* | ||||
|  * Constructor and destructor. | ||||
|  */ | ||||
| struct dev_manager *dev_manager_create(struct cmd_context *cmd, | ||||
| 				       const char *vg_name); | ||||
| void dev_manager_destroy(struct dev_manager *dm); | ||||
| void dev_manager_release(void); | ||||
| void dev_manager_exit(void); | ||||
|  | ||||
| /* | ||||
|  * The device handler is responsible for creating all the layered | ||||
|  * dm devices, and ensuring that all constraints are maintained | ||||
|  * (eg, an origin is created before its snapshot, but is not | ||||
|  * unsuspended until the snapshot is also created.) | ||||
|  */ | ||||
| int dev_manager_info(struct dm_pool *mem, const char *name, | ||||
| 		     const struct logical_volume *lv, | ||||
| 		     int mknodes, int with_open_count, int with_read_ahead, | ||||
| 		     struct dm_info *info, uint32_t *read_ahead); | ||||
| int dev_manager_snapshot_percent(struct dev_manager *dm, | ||||
| 				 const struct logical_volume *lv, | ||||
| 				 float *percent); | ||||
| int dev_manager_mirror_percent(struct dev_manager *dm, | ||||
| 			       struct logical_volume *lv, int wait, | ||||
| 			       float *percent, uint32_t *event_nr); | ||||
| int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv, | ||||
| 			int lockfs); | ||||
| int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv); | ||||
| int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv); | ||||
| int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv); | ||||
|  | ||||
| int dev_manager_lv_mknodes(const struct logical_volume *lv); | ||||
| int dev_manager_lv_rmnodes(const struct logical_volume *lv); | ||||
|  | ||||
| /* | ||||
|  * Put the desired changes into effect. | ||||
|  */ | ||||
| int dev_manager_execute(struct dev_manager *dm); | ||||
|  | ||||
| int dev_manager_device_uses_vg(struct device *dev, | ||||
| 			       struct volume_group *vg); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										351
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,351 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "fs.h" | ||||
| #include "toolcontext.h" | ||||
| #include "lvm-string.h" | ||||
| #include "lvm-file.h" | ||||
| #include "memlock.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <limits.h> | ||||
| #include <dirent.h> | ||||
|  | ||||
| static int _mk_dir(const char *dev_dir, const char *vg_name) | ||||
| { | ||||
| 	char vg_path[PATH_MAX]; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't construct name of volume " | ||||
| 			  "group directory."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dir_exists(vg_path)) | ||||
| 		return 1; | ||||
|  | ||||
| 	log_very_verbose("Creating directory %s", vg_path); | ||||
| 	if (mkdir(vg_path, 0777)) { | ||||
| 		log_sys_error("mkdir", vg_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _rm_dir(const char *dev_dir, const char *vg_name) | ||||
| { | ||||
| 	char vg_path[PATH_MAX]; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't construct name of volume " | ||||
| 			  "group directory."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dir_exists(vg_path) && is_empty_dir(vg_path)) { | ||||
| 		log_very_verbose("Removing directory %s", vg_path); | ||||
| 		rmdir(vg_path); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _rm_blks(const char *dir) | ||||
| { | ||||
| 	const char *name; | ||||
| 	char path[PATH_MAX]; | ||||
| 	struct dirent *dirent; | ||||
| 	struct stat buf; | ||||
| 	DIR *d; | ||||
|  | ||||
| 	if (!(d = opendir(dir))) { | ||||
| 		log_sys_error("opendir", dir); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while ((dirent = readdir(d))) { | ||||
| 		name = dirent->d_name; | ||||
|  | ||||
| 		if (!strcmp(name, ".") || !strcmp(name, "..")) | ||||
| 			continue; | ||||
|  | ||||
| 		if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) { | ||||
| 			log_error("Couldn't create path for %s", name); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!lstat(path, &buf)) { | ||||
| 			if (!S_ISBLK(buf.st_mode)) | ||||
| 				continue; | ||||
| 			log_very_verbose("Removing %s", path); | ||||
| 			if (unlink(path) < 0) | ||||
| 				log_sys_error("unlink", path); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _mk_link(const char *dev_dir, const char *vg_name, | ||||
| 		    const char *lv_name, const char *dev) | ||||
| { | ||||
| 	char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX]; | ||||
| 	char vg_path[PATH_MAX]; | ||||
| 	struct stat buf; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't create path for volume group dir %s", | ||||
| 			  vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path, | ||||
| 			 lv_name) == -1) { | ||||
| 		log_error("Couldn't create source pathname for " | ||||
| 			  "logical volume link %s", lv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(link_path, sizeof(link_path), "%s/%s", | ||||
| 			 dm_dir(), dev) == -1) { | ||||
| 		log_error("Couldn't create destination pathname for " | ||||
| 			  "logical volume link for %s", lv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group", | ||||
| 			 vg_path) == -1) { | ||||
| 		log_error("Couldn't create pathname for LVM1 group file for %s", | ||||
| 			  vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* To reach this point, the VG must have been locked. | ||||
| 	 * As locking fails if the VG is active under LVM1, it's | ||||
| 	 * now safe to remove any LVM1 devices we find here | ||||
| 	 * (as well as any existing LVM2 symlink). */ | ||||
| 	if (!lstat(lvm1_group_path, &buf)) { | ||||
| 		if (!S_ISCHR(buf.st_mode)) { | ||||
| 			log_error("Non-LVM1 character device found at %s", | ||||
| 				  lvm1_group_path); | ||||
| 		} else { | ||||
| 			_rm_blks(vg_path); | ||||
|  | ||||
| 			log_very_verbose("Removing %s", lvm1_group_path); | ||||
| 			if (unlink(lvm1_group_path) < 0) | ||||
| 				log_sys_error("unlink", lvm1_group_path); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!lstat(lv_path, &buf)) { | ||||
| 		if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) { | ||||
| 			log_error("Symbolic link %s not created: file exists", | ||||
| 				  link_path); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		log_very_verbose("Removing %s", lv_path); | ||||
| 		if (unlink(lv_path) < 0) { | ||||
| 			log_sys_error("unlink", lv_path); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Linking %s -> %s", lv_path, link_path); | ||||
| 	if (symlink(link_path, lv_path) < 0) { | ||||
| 		log_sys_error("symlink", lv_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifdef HAVE_SELINUX | ||||
| 	if (!dm_set_selinux_context(lv_path, S_IFLNK)) | ||||
| 		return_0; | ||||
| #endif | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _rm_link(const char *dev_dir, const char *vg_name, | ||||
| 		    const char *lv_name) | ||||
| { | ||||
| 	struct stat buf; | ||||
| 	char lv_path[PATH_MAX]; | ||||
|  | ||||
| 	if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", | ||||
| 			 dev_dir, vg_name, lv_name) == -1) { | ||||
| 		log_error("Couldn't determine link pathname."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) { | ||||
| 		if (errno == ENOENT) | ||||
| 			return 1; | ||||
| 		log_error("%s not symbolic link - not removing", lv_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Removing link %s", lv_path); | ||||
| 	if (unlink(lv_path) < 0) { | ||||
| 		log_sys_error("unlink", lv_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| typedef enum { | ||||
| 	FS_ADD, | ||||
| 	FS_DEL, | ||||
| 	FS_RENAME | ||||
| } fs_op_t; | ||||
|  | ||||
| static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 		     const char *lv_name, const char *dev, | ||||
| 		     const char *old_lv_name) | ||||
| { | ||||
| 	switch (type) { | ||||
| 	case FS_ADD: | ||||
| 		if (!_mk_dir(dev_dir, vg_name) || | ||||
| 		    !_mk_link(dev_dir, vg_name, lv_name, dev)) | ||||
| 			return_0; | ||||
| 		break; | ||||
| 	case FS_DEL: | ||||
| 		if (!_rm_link(dev_dir, vg_name, lv_name) || | ||||
| 		    !_rm_dir(dev_dir, vg_name)) | ||||
| 			return_0; | ||||
| 		break; | ||||
| 		/* FIXME Use rename() */ | ||||
| 	case FS_RENAME: | ||||
| 		if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name)) | ||||
| 			stack; | ||||
|  | ||||
| 		if (!_mk_link(dev_dir, vg_name, lv_name, dev)) | ||||
| 			stack; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static DM_LIST_INIT(_fs_ops); | ||||
|  | ||||
| struct fs_op_parms { | ||||
| 	struct dm_list list; | ||||
| 	fs_op_t type; | ||||
| 	char *dev_dir; | ||||
| 	char *vg_name; | ||||
| 	char *lv_name; | ||||
| 	char *dev; | ||||
| 	char *old_lv_name; | ||||
| 	char names[0]; | ||||
| }; | ||||
|  | ||||
| static void _store_str(char **pos, char **ptr, const char *str) | ||||
| { | ||||
| 	strcpy(*pos, str); | ||||
| 	*ptr = *pos; | ||||
| 	*pos += strlen(*ptr) + 1; | ||||
| } | ||||
|  | ||||
| static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 			const char *lv_name, const char *dev, | ||||
| 			const char *old_lv_name) | ||||
| { | ||||
| 	struct fs_op_parms *fsp; | ||||
| 	size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) + | ||||
| 	    strlen(dev) + strlen(old_lv_name) + 5; | ||||
| 	char *pos; | ||||
|  | ||||
| 	if (!(fsp = dm_malloc(sizeof(*fsp) + len))) { | ||||
| 		log_error("No space to stack fs operation"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pos = fsp->names; | ||||
| 	fsp->type = type; | ||||
|  | ||||
| 	_store_str(&pos, &fsp->dev_dir, dev_dir); | ||||
| 	_store_str(&pos, &fsp->vg_name, vg_name); | ||||
| 	_store_str(&pos, &fsp->lv_name, lv_name); | ||||
| 	_store_str(&pos, &fsp->dev, dev); | ||||
| 	_store_str(&pos, &fsp->old_lv_name, old_lv_name); | ||||
|  | ||||
| 	dm_list_add(&_fs_ops, &fsp->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _pop_fs_ops(void) | ||||
| { | ||||
| 	struct dm_list *fsph, *fspht; | ||||
| 	struct fs_op_parms *fsp; | ||||
|  | ||||
| 	dm_list_iterate_safe(fsph, fspht, &_fs_ops) { | ||||
| 		fsp = dm_list_item(fsph, struct fs_op_parms); | ||||
| 		_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name, | ||||
| 			  fsp->dev, fsp->old_lv_name); | ||||
| 		dm_list_del(&fsp->list); | ||||
| 		dm_free(fsp); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 		  const char *lv_name, const char *dev, const char *old_lv_name) | ||||
| { | ||||
| 	if (memlock()) { | ||||
| 		if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev, | ||||
| 				  old_lv_name)) | ||||
| 			return_0; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name); | ||||
| } | ||||
|  | ||||
| int fs_add_lv(const struct logical_volume *lv, const char *dev) | ||||
| { | ||||
| 	return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 		      dev, ""); | ||||
| } | ||||
|  | ||||
| int fs_del_lv(const struct logical_volume *lv) | ||||
| { | ||||
| 	return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 		      "", ""); | ||||
| } | ||||
|  | ||||
| int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name) | ||||
| { | ||||
| 	return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", ""); | ||||
| } | ||||
|  | ||||
| int fs_rename_lv(struct logical_volume *lv, | ||||
| 		 const char *dev, const char *old_name) | ||||
| { | ||||
| 	return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 		      dev, old_name); | ||||
| } | ||||
|  | ||||
| void fs_unlock(void) | ||||
| { | ||||
| 	if (!memlock()) { | ||||
| 		dm_lib_release(); | ||||
| 		_pop_fs_ops(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										33
									
								
								lib/activate/fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/activate/fs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FS_H | ||||
| #define _LVM_FS_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| /* | ||||
|  * These calls, private to the activate unit, set | ||||
|  * up the volume group directory in /dev and the | ||||
|  * symbolic links to the dm device. | ||||
|  */ | ||||
| int fs_add_lv(const struct logical_volume *lv, const char *dev); | ||||
| int fs_del_lv(const struct logical_volume *lv); | ||||
| int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name); | ||||
| int fs_rename_lv(struct logical_volume *lv, | ||||
| 		 const char *dev, const char *old_name); | ||||
| void fs_unlock(void); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										34
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TARGETS_H | ||||
| #define _LVM_TARGETS_H | ||||
|  | ||||
| struct dev_manager; | ||||
| struct lv_segment; | ||||
|  | ||||
| int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, | ||||
| 		       char *params, size_t paramsize, int *pos, | ||||
| 		       int start_area, int areas); | ||||
|  | ||||
| int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, | ||||
|                    struct dm_tree_node *node, uint32_t start_area, uint32_t areas); | ||||
|  | ||||
| int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf, | ||||
| 		     size_t bufsize, const char *desc); | ||||
|  | ||||
| char *build_dlid(struct dev_manager *dm, const char *lvid, const char *layer); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1255
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1255
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										115
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CACHE_H | ||||
| #define _LVM_CACHE_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
| #include "uuid.h" | ||||
| #include "label.h" | ||||
|  | ||||
| #define ORPHAN_PREFIX "#" | ||||
| #define ORPHAN_VG_NAME(fmt) ORPHAN_PREFIX "orphans_" fmt | ||||
|  | ||||
| #define CACHE_INVALID	0x00000001 | ||||
| #define CACHE_LOCKED	0x00000002 | ||||
|  | ||||
| /* LVM specific per-volume info */ | ||||
| /* Eventual replacement for struct physical_volume perhaps? */ | ||||
|  | ||||
| struct cmd_context; | ||||
| struct format_type; | ||||
| struct volume_group; | ||||
|  | ||||
| /* One per VG */ | ||||
| struct lvmcache_vginfo { | ||||
| 	struct dm_list list;	/* Join these vginfos together */ | ||||
| 	struct dm_list infos;	/* List head for lvmcache_infos */ | ||||
| 	const struct format_type *fmt; | ||||
| 	char *vgname;		/* "" == orphan */ | ||||
| 	uint32_t status; | ||||
| 	char vgid[ID_LEN + 1]; | ||||
| 	char _padding[7]; | ||||
| 	struct lvmcache_vginfo *next; /* Another VG with same name? */ | ||||
| 	char *creation_host; | ||||
| 	char *vgmetadata;	/* Copy of VG metadata as format_text string */ | ||||
| 	unsigned precommitted;	/* Is vgmetadata live or precommitted? */ | ||||
| }; | ||||
|  | ||||
| /* One per device */ | ||||
| struct lvmcache_info { | ||||
| 	struct dm_list list;	/* Join VG members together */ | ||||
| 	struct dm_list mdas;	/* list head for metadata areas */ | ||||
| 	struct dm_list das;	/* list head for data areas */ | ||||
| 	struct lvmcache_vginfo *vginfo;	/* NULL == unknown */ | ||||
| 	struct label *label; | ||||
| 	const struct format_type *fmt; | ||||
| 	struct device *dev; | ||||
| 	uint64_t device_size;	/* Bytes */ | ||||
| 	uint32_t status; | ||||
| }; | ||||
|  | ||||
| int lvmcache_init(void); | ||||
| void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans); | ||||
|  | ||||
| /* Set full_scan to 1 to reread every filtered device label or | ||||
|  * 2 to rescan /dev for new devices */ | ||||
| int lvmcache_label_scan(struct cmd_context *cmd, int full_scan); | ||||
|  | ||||
| /* Add/delete a device */ | ||||
| struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, | ||||
| 				   struct device *dev, | ||||
| 				   const char *vgname, const char *vgid, | ||||
| 				   uint32_t vgstatus); | ||||
| int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt); | ||||
| void lvmcache_del(struct lvmcache_info *info); | ||||
|  | ||||
| /* Update things */ | ||||
| int lvmcache_update_vgname_and_id(struct lvmcache_info *info, | ||||
| 				  const char *vgname, const char *vgid, | ||||
| 				  uint32_t vgstatus, const char *hostname); | ||||
| int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted); | ||||
|  | ||||
| void lvmcache_lock_vgname(const char *vgname, int read_only); | ||||
| void lvmcache_unlock_vgname(const char *vgname); | ||||
|  | ||||
| /* Queries */ | ||||
| const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid); | ||||
| struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, | ||||
| 					   const char *vgid); | ||||
| struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid); | ||||
| struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only); | ||||
| const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid); | ||||
| struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid); | ||||
| int vgs_locked(void); | ||||
| int vgname_is_locked(const char *vgname); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of vgnames */ | ||||
| /* Set full_scan to 1 to reread every filtered device label */ | ||||
| struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of vgids */ | ||||
| /* Set full_scan to 1 to reread every filtered device label */ | ||||
| struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of pvids */ | ||||
| struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, | ||||
| 				const char *vgid); | ||||
|  | ||||
| /* Returns cached volume group metadata. */ | ||||
| struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted); | ||||
| void lvmcache_drop_metadata(const char *vgname); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										24
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_ERRORS_H | ||||
| #define _LVM_ERRORS_H | ||||
|  | ||||
| #define ECMD_PROCESSED		1 | ||||
| #define ENO_SUCH_CMD		2 | ||||
| #define EINVALID_CMD_LINE	3 | ||||
| #define ECMD_FAILED		5 | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1219
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1219
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										104
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TOOLCONTEXT_H | ||||
| #define _LVM_TOOLCONTEXT_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| /* | ||||
|  * Config options that can be changed while commands are processed | ||||
|  */ | ||||
| struct config_info { | ||||
| 	int debug; | ||||
| 	int verbose; | ||||
| 	int test; | ||||
| 	int syslog; | ||||
| 	int activation; | ||||
| 	int suffix; | ||||
| 	int archive;		/* should we archive ? */ | ||||
| 	int backup;		/* should we backup ? */ | ||||
| 	int read_ahead;		/* DM_READ_AHEAD_NONE or _AUTO */ | ||||
| 	int cache_vgmetadata; | ||||
| 	const char *msg_prefix; | ||||
| 	struct format_type *fmt; | ||||
| 	uint64_t unit_factor; | ||||
| 	int cmd_name;		/* Show command name? */ | ||||
| 	mode_t umask; | ||||
| 	char unit_type; | ||||
| 	char _padding[1]; | ||||
| }; | ||||
|  | ||||
| struct config_tree; | ||||
| struct archive_params; | ||||
| struct backup_params; | ||||
|  | ||||
| /* FIXME Split into tool & library contexts */ | ||||
| /* command-instance-related variables needed by library */ | ||||
| struct cmd_context { | ||||
| 	struct dm_pool *libmem;	/* For permanent config data */ | ||||
| 	struct dm_pool *mem;	/* Transient: Cleared between each command */ | ||||
|  | ||||
| 	const struct format_type *fmt;	/* Current format to use by default */ | ||||
| 	struct format_type *fmt_backup;	/* Format to use for backups */ | ||||
|  | ||||
| 	struct dm_list formats;	/* Available formats */ | ||||
| 	struct dm_list segtypes;	/* Available segment types */ | ||||
| 	const char *hostname; | ||||
| 	const char *kernel_vsn; | ||||
|  | ||||
| 	char *cmd_line; | ||||
| 	struct command *command; | ||||
| 	struct arg *args; | ||||
| 	char **argv; | ||||
| 	unsigned is_static:1;	/* Static binary? */ | ||||
| 	unsigned is_long_lived:1;	/* Optimises persistent_filter handling */ | ||||
| 	unsigned handles_missing_pvs:1; | ||||
| 	unsigned partial_activation:1; | ||||
|  | ||||
| 	struct dev_filter *filter; | ||||
| 	int dump_filter;	/* Dump filter when exiting? */ | ||||
|  | ||||
| 	struct dm_list config_files; | ||||
| 	int config_valid; | ||||
| 	struct config_tree *cft; | ||||
| 	struct config_tree *cft_override; | ||||
| 	struct config_info default_settings; | ||||
| 	struct config_info current_settings; | ||||
|  | ||||
| 	struct archive_params *archive_params; | ||||
| 	struct backup_params *backup_params; | ||||
| 	const char *stripe_filler; | ||||
|  | ||||
| 	/* List of defined tags */ | ||||
| 	struct dm_list tags; | ||||
| 	int hosttags; | ||||
|  | ||||
| 	char sys_dir[PATH_MAX]; | ||||
| 	char dev_dir[PATH_MAX]; | ||||
| 	char proc_dir[PATH_MAX]; | ||||
| 	char sysfs_dir[PATH_MAX]; | ||||
| }; | ||||
|  | ||||
| struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived); | ||||
| void destroy_toolcontext(struct cmd_context *cmd); | ||||
| int refresh_toolcontext(struct cmd_context *cmd); | ||||
| int config_files_changed(struct cmd_context *cmd); | ||||
| int init_lvmcache_orphans(struct cmd_context *cmd); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1282
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1282
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										113
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CONFIG_H | ||||
| #define _LVM_CONFIG_H | ||||
|  | ||||
| #include "lvm-types.h" | ||||
|  | ||||
| struct device; | ||||
| struct cmd_context; | ||||
|  | ||||
| enum { | ||||
| 	CFG_STRING, | ||||
| 	CFG_FLOAT, | ||||
| 	CFG_INT, | ||||
| 	CFG_EMPTY_ARRAY | ||||
| }; | ||||
|  | ||||
| struct config_value { | ||||
| 	int type; | ||||
| 	union { | ||||
| 		int64_t i; | ||||
| 		float r; | ||||
| 		char *str; | ||||
| 	} v; | ||||
| 	struct config_value *next;	/* for arrays */ | ||||
| }; | ||||
|  | ||||
| struct config_node { | ||||
| 	char *key; | ||||
| 	struct config_node *sib, *child; | ||||
| 	struct config_value *v; | ||||
| }; | ||||
|  | ||||
| struct config_tree { | ||||
| 	struct config_node *root; | ||||
| }; | ||||
|  | ||||
| struct config_tree_list { | ||||
| 	struct dm_list list; | ||||
| 	struct config_tree *cft; | ||||
| }; | ||||
|  | ||||
| struct config_tree *create_config_tree(const char *filename, int keep_open); | ||||
| struct config_tree *create_config_tree_from_string(struct cmd_context *cmd, | ||||
| 						   const char *config_settings); | ||||
| void destroy_config_tree(struct config_tree *cft); | ||||
|  | ||||
| typedef uint32_t (*checksum_fn_t) (uint32_t initial, const void *buf, uint32_t size); | ||||
|  | ||||
| int read_config_fd(struct config_tree *cft, struct device *dev, | ||||
| 		   off_t offset, size_t size, off_t offset2, size_t size2, | ||||
| 		   checksum_fn_t checksum_fn, uint32_t checksum); | ||||
|  | ||||
| int read_config_file(struct config_tree *cft); | ||||
| int write_config_file(struct config_tree *cft, const char *file, | ||||
| 		      int argc, char **argv); | ||||
| time_t config_file_timestamp(struct config_tree *cft); | ||||
| int config_file_changed(struct config_tree *cft); | ||||
| int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft, | ||||
| 		      struct config_tree *newdata); | ||||
|  | ||||
| struct config_node *find_config_node(const struct config_node *cn, | ||||
| 				     const char *path); | ||||
| const char *find_config_str(const struct config_node *cn, const char *path, | ||||
| 			    const char *fail); | ||||
| int find_config_int(const struct config_node *cn, const char *path, int fail); | ||||
| float find_config_float(const struct config_node *cn, const char *path, | ||||
| 			float fail); | ||||
|  | ||||
| /* | ||||
|  * These versions check an override tree, if present, first. | ||||
|  */ | ||||
| struct config_node *find_config_tree_node(struct cmd_context *cmd, | ||||
| 					  const char *path); | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, | ||||
| 				 const char *path, const char *fail); | ||||
| int find_config_tree_int(struct cmd_context *cmd, const char *path, | ||||
| 			 int fail); | ||||
| float find_config_tree_float(struct cmd_context *cmd, const char *path, | ||||
| 			     float fail); | ||||
|  | ||||
| /* | ||||
|  * Understands (0, ~0), (y, n), (yes, no), (on, | ||||
|  * off), (true, false). | ||||
|  */ | ||||
| int find_config_bool(const struct config_node *cn, const char *path, int fail); | ||||
| int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail); | ||||
|  | ||||
| int get_config_uint32(const struct config_node *cn, const char *path, | ||||
| 		      uint32_t *result); | ||||
|  | ||||
| int get_config_uint64(const struct config_node *cn, const char *path, | ||||
| 		      uint64_t *result); | ||||
|  | ||||
| int get_config_str(const struct config_node *cn, const char *path, | ||||
| 		   char **result); | ||||
|  | ||||
| unsigned maybe_config_section(const char *str, unsigned len); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										129
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEFAULTS_H | ||||
| #define _LVM_DEFAULTS_H | ||||
|  | ||||
| #define DEFAULT_ARCHIVE_ENABLED 1 | ||||
| #define DEFAULT_BACKUP_ENABLED 1 | ||||
|  | ||||
| #define DEFAULT_ARCHIVE_SUBDIR "archive" | ||||
| #define DEFAULT_BACKUP_SUBDIR "backup" | ||||
| #define DEFAULT_CACHE_SUBDIR "cache" | ||||
| #define DEFAULT_CACHE_FILE_PREFIX "" | ||||
|  | ||||
| #define DEFAULT_ARCHIVE_DAYS 30 | ||||
| #define DEFAULT_ARCHIVE_NUMBER 10 | ||||
|  | ||||
| #define DEFAULT_SYS_DIR "/etc/lvm" | ||||
| #define DEFAULT_DEV_DIR "/dev" | ||||
| #define DEFAULT_PROC_DIR "/proc" | ||||
| #define DEFAULT_SYSFS_SCAN 1 | ||||
| #define DEFAULT_MD_COMPONENT_DETECTION 1 | ||||
| #define DEFAULT_MD_CHUNK_ALIGNMENT 1 | ||||
| #define DEFAULT_IGNORE_SUSPENDED_DEVICES 1 | ||||
|  | ||||
| #define DEFAULT_LOCK_DIR "/var/lock/lvm" | ||||
| #define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so" | ||||
| #define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1 | ||||
| #define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1 | ||||
|  | ||||
| #define DEFAULT_MIRRORLOG "disk" | ||||
| #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate" | ||||
| #define DEFAULT_MIRROR_DEV_FAULT_POLICY "remove" | ||||
| #define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so" | ||||
| #define DEFAULT_DMEVENTD_MONITOR 1 | ||||
|  | ||||
| #define DEFAULT_UMASK 0077 | ||||
|  | ||||
| #ifdef LVM1_FALLBACK | ||||
| #  define DEFAULT_FALLBACK_TO_LVM1 1 | ||||
| #else | ||||
| #  define DEFAULT_FALLBACK_TO_LVM1 0 | ||||
| #endif | ||||
|  | ||||
| #ifdef LVM1_SUPPORT | ||||
| #  define DEFAULT_FORMAT "lvm1" | ||||
| #else | ||||
| #  define DEFAULT_FORMAT "lvm2" | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_STRIPESIZE 64	/* KB */ | ||||
| #define DEFAULT_PVMETADATASIZE 255 | ||||
| #define DEFAULT_PVMETADATACOPIES 1 | ||||
| #define DEFAULT_LABELSECTOR UINT64_C(1) | ||||
| #define DEFAULT_READ_AHEAD "auto" | ||||
| #define DEFAULT_EXTENT_SIZE 4096	/* In KB */ | ||||
|  | ||||
| #define DEFAULT_MSG_PREFIX "  " | ||||
| #define DEFAULT_CMD_NAME 0 | ||||
| #define DEFAULT_OVERWRITE 0 | ||||
|  | ||||
| #ifndef DEFAULT_LOG_FACILITY | ||||
| #  define DEFAULT_LOG_FACILITY LOG_USER | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_SYSLOG 1 | ||||
| #define DEFAULT_VERBOSE 0 | ||||
| #define DEFAULT_LOGLEVEL 0 | ||||
| #define DEFAULT_INDENT 1 | ||||
| #define DEFAULT_UNITS "h" | ||||
| #define DEFAULT_SUFFIX 1 | ||||
| #define DEFAULT_HOSTTAGS 0 | ||||
|  | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| #  define DEFAULT_ACTIVATION 1 | ||||
| #  define DEFAULT_RESERVED_MEMORY 8192 | ||||
| #  define DEFAULT_RESERVED_STACK 256 | ||||
| #  define DEFAULT_PROCESS_PRIORITY -18 | ||||
| #else | ||||
| #  define DEFAULT_ACTIVATION 0 | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_STRIPE_FILLER "error" | ||||
| #define DEFAULT_MIRROR_REGION_SIZE 512	/* KB */ | ||||
| #define DEFAULT_INTERVAL 15 | ||||
|  | ||||
| #ifdef READLINE_SUPPORT | ||||
| #  define DEFAULT_MAX_HISTORY 100 | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_REP_ALIGNED 1 | ||||
| #define DEFAULT_REP_BUFFERED 1 | ||||
| #define DEFAULT_REP_COLUMNS_AS_ROWS 0 | ||||
| #define DEFAULT_REP_HEADINGS 1 | ||||
| #define DEFAULT_REP_PREFIXES 0 | ||||
| #define DEFAULT_REP_QUOTED 1 | ||||
| #define DEFAULT_REP_SEPARATOR " " | ||||
|  | ||||
| #define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent,convert_lv" | ||||
| #define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" | ||||
| #define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" | ||||
| #define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size" | ||||
| #define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" | ||||
|  | ||||
| #define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid" | ||||
| #define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid" | ||||
| #define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" | ||||
| #define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" | ||||
| #define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges" | ||||
|  | ||||
| #define DEFAULT_LVS_SORT "vg_name,lv_name" | ||||
| #define DEFAULT_VGS_SORT "vg_name" | ||||
| #define DEFAULT_PVS_SORT "pv_name" | ||||
| #define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start" | ||||
| #define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start" | ||||
|  | ||||
| #endif				/* _LVM_DEFAULTS_H */ | ||||
							
								
								
									
										137
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "btree.h" | ||||
|  | ||||
| struct node { | ||||
| 	uint32_t key; | ||||
| 	struct node *l, *r, *p; | ||||
|  | ||||
| 	void *data; | ||||
| }; | ||||
|  | ||||
| struct btree { | ||||
| 	struct dm_pool *mem; | ||||
| 	struct node *root; | ||||
| }; | ||||
|  | ||||
| struct btree *btree_create(struct dm_pool *mem) | ||||
| { | ||||
| 	struct btree *t = dm_pool_alloc(mem, sizeof(*t)); | ||||
|  | ||||
| 	if (t) { | ||||
| 		t->mem = mem; | ||||
| 		t->root = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Shuffle the bits in a key, to try and remove | ||||
|  * any ordering. | ||||
|  */ | ||||
| static uint32_t _shuffle(uint32_t k) | ||||
| { | ||||
| #if 1 | ||||
| 	return ((k & 0xff) << 24 | | ||||
| 		(k & 0xff00) << 8 | | ||||
| 		(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24); | ||||
| #else | ||||
| 	return k; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static struct node **_lookup(struct node *const *c, uint32_t key, | ||||
| 			     struct node **p) | ||||
| { | ||||
| 	*p = NULL; | ||||
| 	while (*c) { | ||||
| 		*p = *c; | ||||
| 		if ((*c)->key == key) | ||||
| 			break; | ||||
|  | ||||
| 		if (key < (*c)->key) | ||||
| 			c = &(*c)->l; | ||||
|  | ||||
| 		else | ||||
| 			c = &(*c)->r; | ||||
| 	} | ||||
|  | ||||
| 	return (struct node **)c; | ||||
| } | ||||
|  | ||||
| void *btree_lookup(const struct btree *t, uint32_t k) | ||||
| { | ||||
| 	uint32_t key = _shuffle(k); | ||||
| 	struct node *p, **c = _lookup(&t->root, key, &p); | ||||
| 	return (*c) ? (*c)->data : NULL; | ||||
| } | ||||
|  | ||||
| int btree_insert(struct btree *t, uint32_t k, void *data) | ||||
| { | ||||
| 	uint32_t key = _shuffle(k); | ||||
| 	struct node *p, **c = _lookup(&t->root, key, &p), *n; | ||||
|  | ||||
| 	if (!*c) { | ||||
| 		if (!(n = dm_pool_alloc(t->mem, sizeof(*n)))) | ||||
| 			return_0; | ||||
|  | ||||
| 		n->key = key; | ||||
| 		n->data = data; | ||||
| 		n->l = n->r = NULL; | ||||
| 		n->p = p; | ||||
|  | ||||
| 		*c = n; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void *btree_get_data(const struct btree_iter *it) | ||||
| { | ||||
| 	return ((struct node *) it)->data; | ||||
| } | ||||
|  | ||||
| static struct node *_left(struct node *n) | ||||
| { | ||||
| 	while (n->l) | ||||
| 		n = n->l; | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_first(const struct btree *t) | ||||
| { | ||||
| 	if (!t->root) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return (struct btree_iter *) _left(t->root); | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_next(const struct btree_iter *it) | ||||
| { | ||||
| 	struct node *n = (struct node *) it; | ||||
| 	uint32_t k = n->key; | ||||
|  | ||||
| 	if (n->r) | ||||
| 		return (struct btree_iter *) _left(n->r); | ||||
|  | ||||
| 	do | ||||
| 		n = n->p; | ||||
| 	while (n && k > n->key); | ||||
|  | ||||
| 	return (struct btree_iter *) n; | ||||
| } | ||||
							
								
								
									
										32
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_BTREE_H | ||||
| #define _LVM_BTREE_H | ||||
|  | ||||
| struct btree; | ||||
|  | ||||
| struct btree *btree_create(struct dm_pool *mem); | ||||
|  | ||||
| void *btree_lookup(const struct btree *t, uint32_t k); | ||||
| int btree_insert(struct btree *t, uint32_t k, void *data); | ||||
|  | ||||
| struct btree_iter; | ||||
| void *btree_get_data(const struct btree_iter *it); | ||||
|  | ||||
| struct btree_iter *btree_first(const struct btree *t); | ||||
| struct btree_iter *btree_next(const struct btree_iter *it); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										145
									
								
								lib/datastruct/list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								lib/datastruct/list.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| void dm_list_init(struct dm_list *head) | ||||
| { | ||||
| 	head->n = head->p = head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head; | ||||
| 	elem->p = head->p; | ||||
|  | ||||
| 	head->p->n = elem; | ||||
| 	head->p = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head->n; | ||||
| 	elem->p = head; | ||||
|  | ||||
| 	head->n->p = elem; | ||||
| 	head->n = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem) | ||||
| { | ||||
| 	elem->n->p = elem->p; | ||||
| 	elem->p->n = elem->n; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
|         dm_list_del(elem); | ||||
|         dm_list_add(head, elem); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head) | ||||
| { | ||||
| 	return head->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->p == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_start(head, elem) ? NULL : elem->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_end(head, elem) ? NULL : elem->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head) | ||||
| { | ||||
| 	unsigned int s = 0; | ||||
| 	const struct dm_list *v; | ||||
|  | ||||
| 	dm_list_iterate(v, head) | ||||
| 	    s++; | ||||
|  | ||||
| 	return s; | ||||
| } | ||||
							
								
								
									
										208
									
								
								lib/datastruct/list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								lib/datastruct/list.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_LIST_H | ||||
| #define _LVM_LIST_H | ||||
|  | ||||
| #include <assert.h> | ||||
|  | ||||
| /* | ||||
|  * A list consists of a list head plus elements. | ||||
|  * Each element has 'next' and 'previous' pointers. | ||||
|  * The list head's pointers point to the first and the last element. | ||||
|  */ | ||||
|  | ||||
| struct dm_list { | ||||
| 	struct dm_list *n, *p; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| #define DM_LIST_INIT(name)	struct dm_list name = { &(name), &(name) } | ||||
| void dm_list_init(struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list' called 'head'  | ||||
|  * contained in a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_struct_base(v, t, head) \ | ||||
|     ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head)) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list list' contained in | ||||
|  * a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_item(v, t) dm_list_struct_base((v), t, list) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of one known element e in a known structure of type t, | ||||
|  * return another element f. | ||||
|  */ | ||||
| #define dm_struct_field(v, t, e, f) \ | ||||
|     (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of a known element e in a known structure of type t, | ||||
|  * return the list head 'list' | ||||
|  */ | ||||
| #define dm_list_head(v, t, e) dm_struct_field(v, t, e, list) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element of a list in turn. | ||||
|  */ | ||||
| #define dm_list_iterate(v, head) \ | ||||
| 	for (v = (head)->n; v != head; v = v->n) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element in a list in turn, starting from the element  | ||||
|  * in front of 'start'. | ||||
|  * You can use this to 'unwind' a list_iterate and back out actions on | ||||
|  * already-processed elements. | ||||
|  * If 'start' is 'head' it walks the list backwards. | ||||
|  */ | ||||
| #define dm_list_uniterate(v, head, start) \ | ||||
| 	for (v = (start)->p; v != head; v = v->p) | ||||
|  | ||||
| /* | ||||
|  * A safe way to walk a list and delete and free some elements along | ||||
|  * the way. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_safe(v, t, head) \ | ||||
| 	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, typeof(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.n, typeof(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_items(v, head) dm_list_iterate_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen_safe(v, t, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, typeof(*v), field), \ | ||||
| 	     t = dm_list_struct_base(v->field.n, typeof(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = t, t = dm_list_struct_base(v->field.n, typeof(*v), field)) | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_safe(v, t, head) \ | ||||
| 	dm_list_iterate_items_gen_safe(v, t, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure  | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->p, typeof(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.p, typeof(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure  | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items(v, head) dm_list_iterate_back_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								lib/datastruct/lvm-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/datastruct/lvm-types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TYPES_H | ||||
| #define _LVM_TYPES_H | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
| /* Define some portable printing types */ | ||||
| #define PRIsize_t "zu" | ||||
| #define PRIptrdiff_t "td" | ||||
| #define PRIpid_t PRId32 | ||||
|  | ||||
| struct str_list { | ||||
| 	struct dm_list list; | ||||
| 	const char *str; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										121
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "str_list.h" | ||||
|  | ||||
| struct dm_list *str_list_create(struct dm_pool *mem) | ||||
| { | ||||
| 	struct dm_list *sl; | ||||
|  | ||||
| 	if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) | ||||
| 		return_NULL; | ||||
|  | ||||
| 	dm_list_init(sl); | ||||
|  | ||||
| 	return sl; | ||||
| } | ||||
|  | ||||
| int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sln; | ||||
|  | ||||
| 	if (!str) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* Already in list? */ | ||||
| 	if (str_list_match_item(sll, str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(sln = dm_pool_alloc(mem, sizeof(*sln)))) | ||||
| 		return_0; | ||||
|  | ||||
| 	sln->str = str; | ||||
| 	dm_list_add(sll, &sln->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_del(struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct dm_list *slh, *slht; | ||||
|  | ||||
| 	dm_list_iterate_safe(slh, slht, sll) { | ||||
| 		if (!strcmp(str, dm_list_item(slh, struct str_list)->str)) | ||||
| 			 dm_list_del(slh); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew, | ||||
| 		 const struct dm_list *sllold) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_init(sllnew); | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sllold) { | ||||
| 		if (!str_list_add(mem, sllnew, dm_pool_strdup(mem, sl->str))) | ||||
| 			return_0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is item on list? | ||||
|  */ | ||||
| int str_list_match_item(const struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 	    if (!strcmp(str, sl->str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is at least one item on both lists? | ||||
|  */ | ||||
| int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 	    if (str_list_match_item(sll2, sl->str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Do both lists contain the same set of items? | ||||
|  */ | ||||
| int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	if (dm_list_size(sll) != dm_list_size(sll2)) | ||||
| 		return 0; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 	    if (!str_list_match_item(sll2, sl->str)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/datastruct/str_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/datastruct/str_list.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_STR_LIST_H | ||||
| #define _LVM_STR_LIST_H | ||||
|  | ||||
| struct dm_list *str_list_create(struct dm_pool *mem); | ||||
| int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str); | ||||
| int str_list_del(struct dm_list *sll, const char *str); | ||||
| int str_list_match_item(const struct dm_list *sll, const char *str); | ||||
| int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2); | ||||
| int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2); | ||||
| int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew, | ||||
| 		 const struct dm_list *sllold); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										781
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										781
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,781 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "dev-cache.h" | ||||
| #include "lvm-types.h" | ||||
| #include "btree.h" | ||||
| #include "filter.h" | ||||
| #include "filter-persistent.h" | ||||
| #include "toolcontext.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <sys/param.h> | ||||
| #include <dirent.h> | ||||
|  | ||||
| struct dev_iter { | ||||
| 	struct btree_iter *current; | ||||
| 	struct dev_filter *filter; | ||||
| }; | ||||
|  | ||||
| struct dir_list { | ||||
| 	struct dm_list list; | ||||
| 	char dir[0]; | ||||
| }; | ||||
|  | ||||
| static struct { | ||||
| 	struct dm_pool *mem; | ||||
| 	struct dm_hash_table *names; | ||||
| 	struct btree *devices; | ||||
| 	struct dm_regex *preferred_names_matcher; | ||||
|  | ||||
| 	int has_scanned; | ||||
| 	struct dm_list dirs; | ||||
| 	struct dm_list files; | ||||
|  | ||||
| } _cache; | ||||
|  | ||||
| #define _alloc(x) dm_pool_zalloc(_cache.mem, (x)) | ||||
| #define _free(x) dm_pool_free(_cache.mem, (x)) | ||||
| #define _strdup(x) dm_pool_strdup(_cache.mem, (x)) | ||||
|  | ||||
| static int _insert(const char *path, int rec); | ||||
|  | ||||
| struct device *dev_create_file(const char *filename, struct device *dev, | ||||
| 			       struct str_list *alias, int use_malloc) | ||||
| { | ||||
| 	int allocate = !dev; | ||||
|  | ||||
| 	if (allocate) { | ||||
| 		if (use_malloc) { | ||||
| 			if (!(dev = dm_malloc(sizeof(*dev)))) { | ||||
| 				log_error("struct device allocation failed"); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			if (!(alias = dm_malloc(sizeof(*alias)))) { | ||||
| 				log_error("struct str_list allocation failed"); | ||||
| 				dm_free(dev); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			if (!(alias->str = dm_strdup(filename))) { | ||||
| 				log_error("filename strdup failed"); | ||||
| 				dm_free(dev); | ||||
| 				dm_free(alias); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			dev->flags = DEV_ALLOCED; | ||||
| 		} else { | ||||
| 			if (!(dev = _alloc(sizeof(*dev)))) { | ||||
| 				log_error("struct device allocation failed"); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			if (!(alias = _alloc(sizeof(*alias)))) { | ||||
| 				log_error("struct str_list allocation failed"); | ||||
| 				_free(dev); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			if (!(alias->str = _strdup(filename))) { | ||||
| 				log_error("filename strdup failed"); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 		} | ||||
| 	} else if (!(alias->str = dm_strdup(filename))) { | ||||
| 		log_error("filename strdup failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	dev->flags |= DEV_REGULAR; | ||||
| 	dm_list_init(&dev->aliases); | ||||
| 	dm_list_add(&dev->aliases, &alias->list); | ||||
| 	dev->end = UINT64_C(0); | ||||
| 	dev->dev = 0; | ||||
| 	dev->fd = -1; | ||||
| 	dev->open_count = 0; | ||||
| 	dev->block_size = -1; | ||||
| 	memset(dev->pvid, 0, sizeof(dev->pvid)); | ||||
| 	dm_list_init(&dev->open_list); | ||||
|  | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| static struct device *_dev_create(dev_t d) | ||||
| { | ||||
| 	struct device *dev; | ||||
|  | ||||
| 	if (!(dev = _alloc(sizeof(*dev)))) { | ||||
| 		log_error("struct device allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	dev->flags = 0; | ||||
| 	dm_list_init(&dev->aliases); | ||||
| 	dev->dev = d; | ||||
| 	dev->fd = -1; | ||||
| 	dev->open_count = 0; | ||||
| 	dev->block_size = -1; | ||||
| 	dev->end = UINT64_C(0); | ||||
| 	memset(dev->pvid, 0, sizeof(dev->pvid)); | ||||
| 	dm_list_init(&dev->open_list); | ||||
|  | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| void dev_set_preferred_name(struct str_list *sl, struct device *dev) | ||||
| { | ||||
| 	/* | ||||
| 	 * Don't interfere with ordering specified in config file. | ||||
| 	 */ | ||||
| 	if (_cache.preferred_names_matcher) | ||||
| 		return; | ||||
|  | ||||
| 	log_debug("%s: New preferred name", sl->str); | ||||
| 	dm_list_del(&sl->list); | ||||
| 	dm_list_add_h(&dev->aliases, &sl->list); | ||||
| } | ||||
|  | ||||
| /* Return 1 if we prefer path1 else return 0 */ | ||||
| static int _compare_paths(const char *path0, const char *path1) | ||||
| { | ||||
| 	int slash0 = 0, slash1 = 0; | ||||
| 	int m0, m1; | ||||
| 	const char *p; | ||||
| 	char p0[PATH_MAX], p1[PATH_MAX]; | ||||
| 	char *s0, *s1; | ||||
| 	struct stat stat0, stat1; | ||||
|  | ||||
| 	/* | ||||
| 	 * FIXME Better to compare patterns one-at-a-time against all names. | ||||
| 	 */ | ||||
| 	if (_cache.preferred_names_matcher) { | ||||
| 		m0 = dm_regex_match(_cache.preferred_names_matcher, path0); | ||||
| 		m1 = dm_regex_match(_cache.preferred_names_matcher, path1); | ||||
|  | ||||
| 		if (m0 != m1) { | ||||
| 			if (m0 < 0) | ||||
| 				return 1; | ||||
| 			if (m1 < 0) | ||||
| 				return 0; | ||||
| 			if (m0 < m1) | ||||
| 				return 1; | ||||
| 			if (m1 < m0) | ||||
| 				return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Built-in rules. | ||||
| 	 */ | ||||
|  | ||||
| 	/* Return the path with fewer slashes */ | ||||
| 	for (p = path0; p++; p = (const char *) strchr(p, '/')) | ||||
| 		slash0++; | ||||
|  | ||||
| 	for (p = path1; p++; p = (const char *) strchr(p, '/')) | ||||
| 		slash1++; | ||||
|  | ||||
| 	if (slash0 < slash1) | ||||
| 		return 0; | ||||
| 	if (slash1 < slash0) | ||||
| 		return 1; | ||||
|  | ||||
| 	strncpy(p0, path0, PATH_MAX); | ||||
| 	strncpy(p1, path1, PATH_MAX); | ||||
| 	s0 = &p0[0] + 1; | ||||
| 	s1 = &p1[0] + 1; | ||||
|  | ||||
| 	/* We prefer symlinks - they exist for a reason! | ||||
| 	 * So we prefer a shorter path before the first symlink in the name. | ||||
| 	 * FIXME Configuration option to invert this? */ | ||||
| 	while (s0) { | ||||
| 		s0 = strchr(s0, '/'); | ||||
| 		s1 = strchr(s1, '/'); | ||||
| 		if (s0) { | ||||
| 			*s0 = '\0'; | ||||
| 			*s1 = '\0'; | ||||
| 		} | ||||
| 		if (lstat(p0, &stat0)) { | ||||
| 			log_sys_very_verbose("lstat", p0); | ||||
| 			return 1; | ||||
| 		} | ||||
| 		if (lstat(p1, &stat1)) { | ||||
| 			log_sys_very_verbose("lstat", p1); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode)) | ||||
| 			return 0; | ||||
| 		if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode)) | ||||
| 			return 1; | ||||
| 		if (s0) { | ||||
| 			*s0++ = '/'; | ||||
| 			*s1++ = '/'; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* ASCII comparison */ | ||||
| 	if (strcmp(path0, path1) < 0) | ||||
| 		return 0; | ||||
| 	else | ||||
| 		return 1; | ||||
| } | ||||
|  | ||||
| static int _add_alias(struct device *dev, const char *path) | ||||
| { | ||||
| 	struct str_list *sl = _alloc(sizeof(*sl)); | ||||
| 	struct str_list *strl; | ||||
| 	const char *oldpath; | ||||
| 	int prefer_old = 1; | ||||
|  | ||||
| 	if (!sl) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* Is name already there? */ | ||||
| 	dm_list_iterate_items(strl, &dev->aliases) { | ||||
| 		if (!strcmp(strl->str, path)) { | ||||
| 			log_debug("%s: Already in device cache", path); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!(sl->str = dm_pool_strdup(_cache.mem, path))) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!dm_list_empty(&dev->aliases)) { | ||||
| 		oldpath = dm_list_item(dev->aliases.n, struct str_list)->str; | ||||
| 		prefer_old = _compare_paths(path, oldpath); | ||||
| 		log_debug("%s: Aliased to %s in device cache%s", | ||||
| 			  path, oldpath, prefer_old ? "" : " (preferred name)"); | ||||
|  | ||||
| 	} else | ||||
| 		log_debug("%s: Added to device cache", path); | ||||
|  | ||||
| 	if (prefer_old) | ||||
| 		dm_list_add(&dev->aliases, &sl->list); | ||||
| 	else | ||||
| 		dm_list_add_h(&dev->aliases, &sl->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Either creates a new dev, or adds an alias to | ||||
|  * an existing dev. | ||||
|  */ | ||||
| static int _insert_dev(const char *path, dev_t d) | ||||
| { | ||||
| 	struct device *dev; | ||||
| 	static dev_t loopfile_count = 0; | ||||
| 	int loopfile = 0; | ||||
|  | ||||
| 	/* Generate pretend device numbers for loopfiles */ | ||||
| 	if (!d) { | ||||
| 		if (dm_hash_lookup(_cache.names, path)) | ||||
| 			return 1; | ||||
| 		d = ++loopfile_count; | ||||
| 		loopfile = 1; | ||||
| 	} | ||||
|  | ||||
| 	/* is this device already registered ? */ | ||||
| 	if (!(dev = (struct device *) btree_lookup(_cache.devices, | ||||
| 						   (uint32_t) d))) { | ||||
| 		/* create new device */ | ||||
| 		if (loopfile) { | ||||
| 			if (!(dev = dev_create_file(path, NULL, NULL, 0))) | ||||
| 				return_0; | ||||
| 		} else if (!(dev = _dev_create(d))) | ||||
| 			return_0; | ||||
|  | ||||
| 		if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) { | ||||
| 			log_err("Couldn't insert device into binary tree."); | ||||
| 			_free(dev); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!loopfile && !_add_alias(dev, path)) { | ||||
| 		log_err("Couldn't add alias to dev cache."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_hash_insert(_cache.names, path, dev)) { | ||||
| 		log_err("Couldn't add name to hash in dev cache."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static char *_join(const char *dir, const char *name) | ||||
| { | ||||
| 	size_t len = strlen(dir) + strlen(name) + 2; | ||||
| 	char *r = dm_malloc(len); | ||||
| 	if (r) | ||||
| 		snprintf(r, len, "%s/%s", dir, name); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Get rid of extra slashes in the path string. | ||||
|  */ | ||||
| static void _collapse_slashes(char *str) | ||||
| { | ||||
| 	char *ptr; | ||||
| 	int was_slash = 0; | ||||
|  | ||||
| 	for (ptr = str; *ptr; ptr++) { | ||||
| 		if (*ptr == '/') { | ||||
| 			if (was_slash) | ||||
| 				continue; | ||||
|  | ||||
| 			was_slash = 1; | ||||
| 		} else | ||||
| 			was_slash = 0; | ||||
| 		*str++ = *ptr; | ||||
| 	} | ||||
|  | ||||
| 	*str = *ptr; | ||||
| } | ||||
|  | ||||
| static int _insert_dir(const char *dir) | ||||
| { | ||||
| 	int n, dirent_count, r = 1; | ||||
| 	struct dirent **dirent; | ||||
| 	char *path; | ||||
|  | ||||
| 	dirent_count = scandir(dir, &dirent, NULL, alphasort); | ||||
| 	if (dirent_count > 0) { | ||||
| 		for (n = 0; n < dirent_count; n++) { | ||||
| 			if (dirent[n]->d_name[0] == '.') { | ||||
| 				free(dirent[n]); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if (!(path = _join(dir, dirent[n]->d_name))) | ||||
| 				return_0; | ||||
|  | ||||
| 			_collapse_slashes(path); | ||||
| 			r &= _insert(path, 1); | ||||
| 			dm_free(path); | ||||
|  | ||||
| 			free(dirent[n]); | ||||
| 		} | ||||
| 		free(dirent); | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _insert_file(const char *path) | ||||
| { | ||||
| 	struct stat info; | ||||
|  | ||||
| 	if (stat(path, &info) < 0) { | ||||
| 		log_sys_very_verbose("stat", path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!S_ISREG(info.st_mode)) { | ||||
| 		log_debug("%s: Not a regular file", path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_insert_dev(path, 0)) | ||||
| 		return_0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _insert(const char *path, int rec) | ||||
| { | ||||
| 	struct stat info; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (stat(path, &info) < 0) { | ||||
| 		log_sys_very_verbose("stat", path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (S_ISDIR(info.st_mode)) {	/* add a directory */ | ||||
| 		/* check it's not a symbolic link */ | ||||
| 		if (lstat(path, &info) < 0) { | ||||
| 			log_sys_very_verbose("lstat", path); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (S_ISLNK(info.st_mode)) { | ||||
| 			log_debug("%s: Symbolic link to directory", path); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (rec) | ||||
| 			r = _insert_dir(path); | ||||
|  | ||||
| 	} else {		/* add a device */ | ||||
| 		if (!S_ISBLK(info.st_mode)) { | ||||
| 			log_debug("%s: Not a block device", path); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (!_insert_dev(path, info.st_rdev)) | ||||
| 			return_0; | ||||
|  | ||||
| 		r = 1; | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static void _full_scan(int dev_scan) | ||||
| { | ||||
| 	struct dir_list *dl; | ||||
|  | ||||
| 	if (_cache.has_scanned && !dev_scan) | ||||
| 		return; | ||||
|  | ||||
| 	dm_list_iterate_items(dl, &_cache.dirs) | ||||
| 		_insert_dir(dl->dir); | ||||
|  | ||||
| 	dm_list_iterate_items(dl, &_cache.files) | ||||
| 		_insert_file(dl->dir); | ||||
|  | ||||
| 	_cache.has_scanned = 1; | ||||
| 	init_full_scan_done(1); | ||||
| } | ||||
|  | ||||
| int dev_cache_has_scanned(void) | ||||
| { | ||||
| 	return _cache.has_scanned; | ||||
| } | ||||
|  | ||||
| void dev_cache_scan(int do_scan) | ||||
| { | ||||
| 	if (!do_scan) | ||||
| 		_cache.has_scanned = 1; | ||||
| 	else | ||||
| 		_full_scan(1); | ||||
| } | ||||
|  | ||||
| static int _init_preferred_names(struct cmd_context *cmd) | ||||
| { | ||||
| 	const struct config_node *cn; | ||||
| 	struct config_value *v; | ||||
| 	struct dm_pool *scratch = NULL; | ||||
| 	char **regex; | ||||
| 	unsigned count = 0; | ||||
| 	int i, r = 0; | ||||
|  | ||||
| 	_cache.preferred_names_matcher = NULL; | ||||
|  | ||||
| 	if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) || | ||||
| 	    cn->v->type == CFG_EMPTY_ARRAY) { | ||||
| 		log_very_verbose("devices/preferred_names not found in config file: " | ||||
| 				 "using built-in preferences"); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	for (v = cn->v; v; v = v->next) { | ||||
| 		if (v->type != CFG_STRING) { | ||||
| 			log_error("preferred_names patterns must be enclosed in quotes"); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		count++; | ||||
| 	} | ||||
|  | ||||
| 	if (!(scratch = dm_pool_create("preferred device name matcher", 1024))) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) { | ||||
| 		log_error("Failed to allocate preferred device name " | ||||
| 			  "pattern list."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	for (v = cn->v, i = count - 1; v; v = v->next, i--) { | ||||
| 		if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) { | ||||
| 			log_error("Failed to allocate a preferred device name " | ||||
| 				  "pattern."); | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!(_cache.preferred_names_matcher = | ||||
| 		dm_regex_create(_cache.mem,(const char **) regex, count))) { | ||||
| 		log_error("Preferred device name pattern matcher creation failed."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	dm_pool_destroy(scratch); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int dev_cache_init(struct cmd_context *cmd) | ||||
| { | ||||
| 	_cache.names = NULL; | ||||
| 	_cache.has_scanned = 0; | ||||
|  | ||||
| 	if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024))) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!(_cache.names = dm_hash_create(128))) { | ||||
| 		dm_pool_destroy(_cache.mem); | ||||
| 		_cache.mem = 0; | ||||
| 		return_0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(_cache.devices = btree_create(_cache.mem))) { | ||||
| 		log_err("Couldn't create binary tree for dev-cache."); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	dm_list_init(&_cache.dirs); | ||||
| 	dm_list_init(&_cache.files); | ||||
|  | ||||
| 	if (!_init_preferred_names(cmd)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	return 1; | ||||
|  | ||||
|       bad: | ||||
| 	dev_cache_exit(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _check_closed(struct device *dev) | ||||
| { | ||||
| 	if (dev->fd >= 0) | ||||
| 		log_err("Device '%s' has been left open.", dev_name(dev)); | ||||
| } | ||||
|  | ||||
| static void _check_for_open_devices(void) | ||||
| { | ||||
| 	dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed); | ||||
| } | ||||
|  | ||||
| void dev_cache_exit(void) | ||||
| { | ||||
| 	if (_cache.names) | ||||
| 		_check_for_open_devices(); | ||||
|  | ||||
| 	if (_cache.preferred_names_matcher) | ||||
| 		_cache.preferred_names_matcher = NULL; | ||||
|  | ||||
| 	if (_cache.mem) { | ||||
| 		dm_pool_destroy(_cache.mem); | ||||
| 		_cache.mem = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (_cache.names) { | ||||
| 		dm_hash_destroy(_cache.names); | ||||
| 		_cache.names = NULL; | ||||
| 	} | ||||
|  | ||||
| 	_cache.devices = NULL; | ||||
| 	_cache.has_scanned = 0; | ||||
| 	dm_list_init(&_cache.dirs); | ||||
| 	dm_list_init(&_cache.files); | ||||
| } | ||||
|  | ||||
| int dev_cache_add_dir(const char *path) | ||||
| { | ||||
| 	struct dir_list *dl; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (stat(path, &st)) { | ||||
| 		log_error("Ignoring %s: %s", path, strerror(errno)); | ||||
| 		/* But don't fail */ | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!S_ISDIR(st.st_mode)) { | ||||
| 		log_error("Ignoring %s: Not a directory", path); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) { | ||||
| 		log_error("dir_list allocation failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	strcpy(dl->dir, path); | ||||
| 	dm_list_add(&_cache.dirs, &dl->list); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int dev_cache_add_loopfile(const char *path) | ||||
| { | ||||
| 	struct dir_list *dl; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (stat(path, &st)) { | ||||
| 		log_error("Ignoring %s: %s", path, strerror(errno)); | ||||
| 		/* But don't fail */ | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!S_ISREG(st.st_mode)) { | ||||
| 		log_error("Ignoring %s: Not a regular file", path); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) { | ||||
| 		log_error("dir_list allocation failed for file"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	strcpy(dl->dir, path); | ||||
| 	dm_list_add(&_cache.files, &dl->list); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Check cached device name is still valid before returning it */ | ||||
| /* This should be a rare occurrence */ | ||||
| /* set quiet if the cache is expected to be out-of-date */ | ||||
| /* FIXME Make rest of code pass/cache struct device instead of dev_name */ | ||||
| const char *dev_name_confirmed(struct device *dev, int quiet) | ||||
| { | ||||
| 	struct stat buf; | ||||
| 	const char *name; | ||||
| 	int r; | ||||
|  | ||||
| 	if ((dev->flags & DEV_REGULAR)) | ||||
| 		return dev_name(dev); | ||||
|  | ||||
| 	while ((r = stat(name = dm_list_item(dev->aliases.n, | ||||
| 					  struct str_list)->str, &buf)) || | ||||
| 	       (buf.st_rdev != dev->dev)) { | ||||
| 		if (r < 0) { | ||||
| 			if (quiet) | ||||
| 				log_sys_debug("stat", name); | ||||
| 			else | ||||
| 				log_sys_error("stat", name); | ||||
| 		} | ||||
| 		if (quiet) | ||||
| 			log_debug("Path %s no longer valid for device(%d,%d)", | ||||
| 				  name, (int) MAJOR(dev->dev), | ||||
| 				  (int) MINOR(dev->dev)); | ||||
| 		else | ||||
| 			log_error("Path %s no longer valid for device(%d,%d)", | ||||
| 				  name, (int) MAJOR(dev->dev), | ||||
| 				  (int) MINOR(dev->dev)); | ||||
|  | ||||
| 		/* Remove the incorrect hash entry */ | ||||
| 		dm_hash_remove(_cache.names, name); | ||||
|  | ||||
| 		/* Leave list alone if there isn't an alternative name */ | ||||
| 		/* so dev_name will always find something to return. */ | ||||
| 		/* Otherwise add the name to the correct device. */ | ||||
| 		if (dm_list_size(&dev->aliases) > 1) { | ||||
| 			dm_list_del(dev->aliases.n); | ||||
| 			if (!r) | ||||
| 				_insert(name, 0); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* Scanning issues this inappropriately sometimes. */ | ||||
| 		log_debug("Aborting - please provide new pathname for what " | ||||
| 			  "used to be %s", name); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return dev_name(dev); | ||||
| } | ||||
|  | ||||
| struct device *dev_cache_get(const char *name, struct dev_filter *f) | ||||
| { | ||||
| 	struct stat buf; | ||||
| 	struct device *d = (struct device *) dm_hash_lookup(_cache.names, name); | ||||
|  | ||||
| 	if (d && (d->flags & DEV_REGULAR)) | ||||
| 		return d; | ||||
|  | ||||
| 	/* If the entry's wrong, remove it */ | ||||
| 	if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) { | ||||
| 		dm_hash_remove(_cache.names, name); | ||||
| 		d = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!d) { | ||||
| 		_insert(name, 0); | ||||
| 		d = (struct device *) dm_hash_lookup(_cache.names, name); | ||||
| 		if (!d) { | ||||
| 			_full_scan(0); | ||||
| 			d = (struct device *) dm_hash_lookup(_cache.names, name); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return (d && (!f || (d->flags & DEV_REGULAR) || | ||||
| 		      f->passes_filter(f, d))) ? d : NULL; | ||||
| } | ||||
|  | ||||
| struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan) | ||||
| { | ||||
| 	struct dev_iter *di = dm_malloc(sizeof(*di)); | ||||
|  | ||||
| 	if (!di) { | ||||
| 		log_error("dev_iter allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (dev_scan && !trust_cache()) { | ||||
| 		/* Flag gets reset between each command */ | ||||
| 		if (!full_scan_done()) | ||||
| 			persistent_filter_wipe(f); /* Calls _full_scan(1) */ | ||||
| 	} else | ||||
| 		_full_scan(0); | ||||
|  | ||||
| 	di->current = btree_first(_cache.devices); | ||||
| 	di->filter = f; | ||||
|  | ||||
| 	return di; | ||||
| } | ||||
|  | ||||
| void dev_iter_destroy(struct dev_iter *iter) | ||||
| { | ||||
| 	dm_free(iter); | ||||
| } | ||||
|  | ||||
| static struct device *_iter_next(struct dev_iter *iter) | ||||
| { | ||||
| 	struct device *d = btree_get_data(iter->current); | ||||
| 	iter->current = btree_next(iter->current); | ||||
| 	return d; | ||||
| } | ||||
|  | ||||
| struct device *dev_iter_get(struct dev_iter *iter) | ||||
| { | ||||
| 	while (iter->current) { | ||||
| 		struct device *d = _iter_next(iter); | ||||
| 		if (!iter->filter || (d->flags & DEV_REGULAR) || | ||||
| 		    iter->filter->passes_filter(iter->filter, d)) | ||||
| 			return d; | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int dev_fd(struct device *dev) | ||||
| { | ||||
| 	return dev->fd; | ||||
| } | ||||
|  | ||||
| const char *dev_name(const struct device *dev) | ||||
| { | ||||
| 	return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str : | ||||
| 	    "unknown device"; | ||||
| } | ||||
							
								
								
									
										55
									
								
								lib/device/dev-cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								lib/device/dev-cache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEV_CACHE_H | ||||
| #define _LVM_DEV_CACHE_H | ||||
|  | ||||
| #include "device.h" | ||||
|  | ||||
| /* | ||||
|  * predicate for devices. | ||||
|  */ | ||||
| struct dev_filter { | ||||
| 	int (*passes_filter) (struct dev_filter * f, struct device * dev); | ||||
| 	void (*destroy) (struct dev_filter * f); | ||||
| 	void *private; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * The global device cache. | ||||
|  */ | ||||
| struct cmd_context; | ||||
| int dev_cache_init(struct cmd_context *cmd); | ||||
| void dev_cache_exit(void); | ||||
|  | ||||
| /* Trigger(1) or avoid(0) a scan */ | ||||
| void dev_cache_scan(int do_scan); | ||||
| int dev_cache_has_scanned(void); | ||||
|  | ||||
| int dev_cache_add_dir(const char *path); | ||||
| int dev_cache_add_loopfile(const char *path); | ||||
| struct device *dev_cache_get(const char *name, struct dev_filter *f); | ||||
|  | ||||
| void dev_set_preferred_name(struct str_list *sl, struct device *dev); | ||||
|  | ||||
| /* | ||||
|  * Object for iterating through the cache. | ||||
|  */ | ||||
| struct dev_iter; | ||||
| struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan); | ||||
| void dev_iter_destroy(struct dev_iter *iter); | ||||
| struct device *dev_iter_get(struct dev_iter *iter); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										665
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										665
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,665 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "lvm-types.h" | ||||
| #include "device.h" | ||||
| #include "metadata.h" | ||||
| #include "lvmcache.h" | ||||
| #include "memlock.h" | ||||
| #include "locking.h" | ||||
|  | ||||
| #include <limits.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/ioctl.h> | ||||
|  | ||||
| #ifdef linux | ||||
| #  define u64 uint64_t		/* Missing without __KERNEL__ */ | ||||
| #  undef WNOHANG		/* Avoid redefinition */ | ||||
| #  undef WUNTRACED		/* Avoid redefinition */ | ||||
| #  include <linux/fs.h>		/* For block ioctl definitions */ | ||||
| #  define BLKSIZE_SHIFT SECTOR_SHIFT | ||||
| #  ifndef BLKGETSIZE64		/* fs.h out-of-date */ | ||||
| #    define BLKGETSIZE64 _IOR(0x12, 114, size_t) | ||||
| #  endif /* BLKGETSIZE64 */ | ||||
| #else | ||||
| #  include <sys/disk.h> | ||||
| #  define BLKBSZGET DKIOCGETBLOCKSIZE | ||||
| #  define BLKSSZGET DKIOCGETBLOCKSIZE | ||||
| #  define BLKGETSIZE64 DKIOCGETBLOCKCOUNT | ||||
| #  define BLKFLSBUF DKIOCSYNCHRONIZECACHE | ||||
| #  define BLKSIZE_SHIFT 0 | ||||
| #endif | ||||
|  | ||||
| #ifdef O_DIRECT_SUPPORT | ||||
| #  ifndef O_DIRECT | ||||
| #    error O_DIRECT support configured but O_DIRECT definition not found in headers | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| static DM_LIST_INIT(_open_devices); | ||||
|  | ||||
| /*----------------------------------------------------------------- | ||||
|  * The standard io loop that keeps submitting an io until it's | ||||
|  * all gone. | ||||
|  *---------------------------------------------------------------*/ | ||||
| static int _io(struct device_area *where, void *buffer, int should_write) | ||||
| { | ||||
| 	int fd = dev_fd(where->dev); | ||||
| 	ssize_t n = 0; | ||||
| 	size_t total = 0; | ||||
|  | ||||
| 	if (fd < 0) { | ||||
| 		log_error("Attempt to read an unopened device (%s).", | ||||
| 			  dev_name(where->dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Skip all writes in test mode. | ||||
| 	 */ | ||||
| 	if (should_write && test_mode()) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (where->size > SSIZE_MAX) { | ||||
| 		log_error("Read size too large: %" PRIu64, where->size); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) { | ||||
| 		log_error("%s: lseek %" PRIu64 " failed: %s", | ||||
| 			  dev_name(where->dev), (uint64_t) where->start, | ||||
| 			  strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (total < (size_t) where->size) { | ||||
| 		do | ||||
| 			n = should_write ? | ||||
| 			    write(fd, buffer, (size_t) where->size - total) : | ||||
| 			    read(fd, buffer, (size_t) where->size - total); | ||||
| 		while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); | ||||
|  | ||||
| 		if (n < 0) | ||||
| 			log_error("%s: %s failed after %" PRIu64 " of %" PRIu64 | ||||
| 				  " at %" PRIu64 ": %s", dev_name(where->dev), | ||||
| 				  should_write ? "write" : "read", | ||||
| 				  (uint64_t) total, | ||||
| 				  (uint64_t) where->size, | ||||
| 				  (uint64_t) where->start, strerror(errno)); | ||||
|  | ||||
| 		if (n <= 0) | ||||
| 			break; | ||||
|  | ||||
| 		total += n; | ||||
| 		buffer += n; | ||||
| 	} | ||||
|  | ||||
| 	return (total == (size_t) where->size); | ||||
| } | ||||
|  | ||||
| /*----------------------------------------------------------------- | ||||
|  * LVM2 uses O_DIRECT when performing metadata io, which requires | ||||
|  * block size aligned accesses.  If any io is not aligned we have | ||||
|  * to perform the io via a bounce buffer, obviously this is quite | ||||
|  * inefficient. | ||||
|  *---------------------------------------------------------------*/ | ||||
|  | ||||
| /* | ||||
|  * Get the sector size from an _open_ device. | ||||
|  */ | ||||
| static int _get_block_size(struct device *dev, unsigned int *size) | ||||
| { | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	if ((dev->block_size == -1)) { | ||||
| 		if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) { | ||||
| 			log_sys_error("ioctl BLKBSZGET", name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		log_debug("%s: block size is %u bytes", name, dev->block_size); | ||||
| 	} | ||||
|  | ||||
| 	*size = (unsigned int) dev->block_size; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Widens a region to be an aligned region. | ||||
|  */ | ||||
| static void _widen_region(unsigned int block_size, struct device_area *region, | ||||
| 			  struct device_area *result) | ||||
| { | ||||
| 	uint64_t mask = block_size - 1, delta; | ||||
| 	memcpy(result, region, sizeof(*result)); | ||||
|  | ||||
| 	/* adjust the start */ | ||||
| 	delta = result->start & mask; | ||||
| 	if (delta) { | ||||
| 		result->start -= delta; | ||||
| 		result->size += delta; | ||||
| 	} | ||||
|  | ||||
| 	/* adjust the end */ | ||||
| 	delta = (result->start + result->size) & mask; | ||||
| 	if (delta) | ||||
| 		result->size += block_size - delta; | ||||
| } | ||||
|  | ||||
| static int _aligned_io(struct device_area *where, void *buffer, | ||||
| 		       int should_write) | ||||
| { | ||||
| 	void *bounce; | ||||
| 	unsigned int block_size = 0; | ||||
| 	uintptr_t mask; | ||||
| 	struct device_area widened; | ||||
|  | ||||
| 	if (!(where->dev->flags & DEV_REGULAR) && | ||||
| 	    !_get_block_size(where->dev, &block_size)) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!block_size) | ||||
| 		block_size = lvm_getpagesize(); | ||||
|  | ||||
| 	_widen_region(block_size, where, &widened); | ||||
|  | ||||
| 	/* Do we need to use a bounce buffer? */ | ||||
| 	mask = block_size - 1; | ||||
| 	if (!memcmp(where, &widened, sizeof(widened)) && | ||||
| 	    !((uintptr_t) buffer & mask)) | ||||
| 		return _io(where, buffer, should_write); | ||||
|  | ||||
| 	/* Allocate a bounce buffer with an extra block */ | ||||
| 	if (!(bounce = alloca((size_t) widened.size + block_size))) { | ||||
| 		log_error("Bounce buffer alloca failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Realign start of bounce buffer (using the extra sector) | ||||
| 	 */ | ||||
| 	if (((uintptr_t) bounce) & mask) | ||||
| 		bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask); | ||||
|  | ||||
| 	/* channel the io through the bounce buffer */ | ||||
| 	if (!_io(&widened, bounce, 0)) { | ||||
| 		if (!should_write) | ||||
| 			return_0; | ||||
| 		/* FIXME pre-extend the file */ | ||||
| 		memset(bounce, '\n', widened.size); | ||||
| 	} | ||||
|  | ||||
| 	if (should_write) { | ||||
| 		memcpy(bounce + (where->start - widened.start), buffer, | ||||
| 		       (size_t) where->size); | ||||
|  | ||||
| 		/* ... then we write */ | ||||
| 		return _io(&widened, bounce, 1); | ||||
| 	} | ||||
|  | ||||
| 	memcpy(buffer, bounce + (where->start - widened.start), | ||||
| 	       (size_t) where->size); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _dev_get_size_file(const struct device *dev, uint64_t *size) | ||||
| { | ||||
| 	const char *name = dev_name(dev); | ||||
| 	struct stat info; | ||||
|  | ||||
| 	if (stat(name, &info)) { | ||||
| 		log_sys_error("stat", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*size = info.st_size; | ||||
| 	*size >>= SECTOR_SHIFT;	/* Convert to sectors */ | ||||
|  | ||||
| 	log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _dev_get_size_dev(const struct device *dev, uint64_t *size) | ||||
| { | ||||
| 	int fd; | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	if ((fd = open(name, O_RDONLY)) < 0) { | ||||
| 		log_sys_error("open", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (ioctl(fd, BLKGETSIZE64, size) < 0) { | ||||
| 		log_sys_error("ioctl BLKGETSIZE64", name); | ||||
| 		if (close(fd)) | ||||
| 			log_sys_error("close", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*size >>= BLKSIZE_SHIFT;	/* Convert to sectors */ | ||||
| 	if (close(fd)) | ||||
| 		log_sys_error("close", name); | ||||
|  | ||||
| 	log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /*----------------------------------------------------------------- | ||||
|  * Public functions | ||||
|  *---------------------------------------------------------------*/ | ||||
|  | ||||
| int dev_get_size(const struct device *dev, uint64_t *size) | ||||
| { | ||||
| 	if ((dev->flags & DEV_REGULAR)) | ||||
| 		return _dev_get_size_file(dev, size); | ||||
| 	else | ||||
| 		return _dev_get_size_dev(dev, size); | ||||
| } | ||||
|  | ||||
| /* FIXME Unused | ||||
| int dev_get_sectsize(struct device *dev, uint32_t *size) | ||||
| { | ||||
| 	int fd; | ||||
| 	int s; | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	if ((fd = open(name, O_RDONLY)) < 0) { | ||||
| 		log_sys_error("open", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (ioctl(fd, BLKSSZGET, &s) < 0) { | ||||
| 		log_sys_error("ioctl BLKSSZGET", name); | ||||
| 		if (close(fd)) | ||||
| 			log_sys_error("close", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (close(fd)) | ||||
| 		log_sys_error("close", name); | ||||
|  | ||||
| 	*size = (uint32_t) s; | ||||
|  | ||||
| 	log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| */ | ||||
|  | ||||
| void dev_flush(struct device *dev) | ||||
| { | ||||
| 	if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0) | ||||
| 		return; | ||||
|  | ||||
| 	if (fsync(dev->fd) >= 0) | ||||
| 		return; | ||||
|  | ||||
| 	sync(); | ||||
| } | ||||
|  | ||||
| int dev_open_flags(struct device *dev, int flags, int direct, int quiet) | ||||
| { | ||||
| 	struct stat buf; | ||||
| 	const char *name; | ||||
| 	int need_excl = 0, need_rw = 0; | ||||
|  | ||||
| 	if ((flags & O_ACCMODE) == O_RDWR) | ||||
| 		need_rw = 1; | ||||
|  | ||||
| 	if ((flags & O_EXCL)) | ||||
| 		need_excl = 1; | ||||
|  | ||||
| 	if (dev->fd >= 0) { | ||||
| 		if (((dev->flags & DEV_OPENED_RW) || !need_rw) && | ||||
| 		    ((dev->flags & DEV_OPENED_EXCL) || !need_excl)) { | ||||
| 			dev->open_count++; | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 		if (dev->open_count && !need_excl) { | ||||
| 			/* FIXME Ensure we never get here */ | ||||
| 			log_debug("WARNING: %s already opened read-only", | ||||
| 				  dev_name(dev)); | ||||
| 			dev->open_count++; | ||||
| 		} | ||||
|  | ||||
| 		dev_close_immediate(dev); | ||||
| 	} | ||||
|  | ||||
| 	if (memlock()) | ||||
| 		log_error("WARNING: dev_open(%s) called while suspended", | ||||
| 			  dev_name(dev)); | ||||
|  | ||||
| 	if (dev->flags & DEV_REGULAR) | ||||
| 		name = dev_name(dev); | ||||
| 	else if (!(name = dev_name_confirmed(dev, quiet))) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!(dev->flags & DEV_REGULAR)) { | ||||
| 		if (stat(name, &buf) < 0) { | ||||
| 			log_sys_error("%s: stat failed", name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (buf.st_rdev != dev->dev) { | ||||
| 			log_error("%s: device changed", name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| #ifdef O_DIRECT_SUPPORT | ||||
| 	if (direct) { | ||||
| 		if (!(dev->flags & DEV_O_DIRECT_TESTED)) | ||||
| 			dev->flags |= DEV_O_DIRECT; | ||||
|  | ||||
| 		if ((dev->flags & DEV_O_DIRECT)) | ||||
| 			flags |= O_DIRECT; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef O_NOATIME | ||||
| 	/* Don't update atime on device inodes */ | ||||
| 	if (!(dev->flags & DEV_REGULAR)) | ||||
| 		flags |= O_NOATIME; | ||||
| #endif | ||||
|  | ||||
| 	if ((dev->fd = open(name, flags, 0777)) < 0) { | ||||
| #ifdef O_DIRECT_SUPPORT | ||||
| 		if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) { | ||||
| 			flags &= ~O_DIRECT; | ||||
| 			if ((dev->fd = open(name, flags, 0777)) >= 0) { | ||||
| 				dev->flags &= ~DEV_O_DIRECT; | ||||
| 				log_debug("%s: Not using O_DIRECT", name); | ||||
| 				goto opened; | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
| 		if (quiet) | ||||
| 			log_sys_debug("open", name); | ||||
| 		else | ||||
| 			log_sys_error("open", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifdef O_DIRECT_SUPPORT | ||||
|       opened: | ||||
| 	if (direct) | ||||
| 		dev->flags |= DEV_O_DIRECT_TESTED; | ||||
| #endif | ||||
| 	dev->open_count++; | ||||
| 	dev->flags &= ~DEV_ACCESSED_W; | ||||
|  | ||||
| 	if (need_rw) | ||||
| 		dev->flags |= DEV_OPENED_RW; | ||||
| 	else | ||||
| 		dev->flags &= ~DEV_OPENED_RW; | ||||
|  | ||||
| 	if (need_excl) | ||||
| 		dev->flags |= DEV_OPENED_EXCL; | ||||
| 	else | ||||
| 		dev->flags &= ~DEV_OPENED_EXCL; | ||||
|  | ||||
| 	if (!(dev->flags & DEV_REGULAR) && | ||||
| 	    ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) { | ||||
| 		log_error("%s: fstat failed: Has device name changed?", name); | ||||
| 		dev_close_immediate(dev); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifndef O_DIRECT_SUPPORT | ||||
| 	if (!(dev->flags & DEV_REGULAR)) | ||||
| 		dev_flush(dev); | ||||
| #endif | ||||
|  | ||||
| 	if ((flags & O_CREAT) && !(flags & O_TRUNC)) | ||||
| 		dev->end = lseek(dev->fd, (off_t) 0, SEEK_END); | ||||
|  | ||||
| 	dm_list_add(&_open_devices, &dev->open_list); | ||||
|  | ||||
| 	log_debug("Opened %s %s%s%s", dev_name(dev), | ||||
| 		  dev->flags & DEV_OPENED_RW ? "RW" : "RO", | ||||
| 		  dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "", | ||||
| 		  dev->flags & DEV_O_DIRECT ? " O_DIRECT" : ""); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int dev_open_quiet(struct device *dev) | ||||
| { | ||||
| 	int flags; | ||||
|  | ||||
| 	flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; | ||||
|  | ||||
| 	return dev_open_flags(dev, flags, 1, 1); | ||||
| } | ||||
|  | ||||
| int dev_open(struct device *dev) | ||||
| { | ||||
| 	int flags; | ||||
|  | ||||
| 	flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; | ||||
|  | ||||
| 	return dev_open_flags(dev, flags, 1, 0); | ||||
| } | ||||
|  | ||||
| int dev_test_excl(struct device *dev) | ||||
| { | ||||
| 	int flags; | ||||
| 	int r; | ||||
|  | ||||
| 	flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; | ||||
| 	flags |= O_EXCL; | ||||
|  | ||||
| 	r = dev_open_flags(dev, flags, 1, 1); | ||||
| 	if (r) | ||||
| 		dev_close_immediate(dev); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static void _close(struct device *dev) | ||||
| { | ||||
| 	if (close(dev->fd)) | ||||
| 		log_sys_error("close", dev_name(dev)); | ||||
| 	dev->fd = -1; | ||||
| 	dev->block_size = -1; | ||||
| 	dm_list_del(&dev->open_list); | ||||
|  | ||||
| 	log_debug("Closed %s", dev_name(dev)); | ||||
|  | ||||
| 	if (dev->flags & DEV_ALLOCED) { | ||||
| 		dm_free((void *) dm_list_item(dev->aliases.n, struct str_list)-> | ||||
| 			 str); | ||||
| 		dm_free(dev->aliases.n); | ||||
| 		dm_free(dev); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _dev_close(struct device *dev, int immediate) | ||||
| { | ||||
| 	struct lvmcache_info *info; | ||||
|  | ||||
| 	if (dev->fd < 0) { | ||||
| 		log_error("Attempt to close device '%s' " | ||||
| 			  "which is not open.", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifndef O_DIRECT_SUPPORT | ||||
| 	if (dev->flags & DEV_ACCESSED_W) | ||||
| 		dev_flush(dev); | ||||
| #endif | ||||
|  | ||||
| 	if (dev->open_count > 0) | ||||
| 		dev->open_count--; | ||||
|  | ||||
| 	if (immediate && dev->open_count) | ||||
| 		log_debug("%s: Immediate close attempt while still referenced", | ||||
| 			  dev_name(dev)); | ||||
|  | ||||
| 	/* Close unless device is known to belong to a locked VG */ | ||||
| 	if (immediate || | ||||
| 	    (dev->open_count < 1 && | ||||
| 	     (!(info = info_from_pvid(dev->pvid, 0)) || | ||||
| 	      !info->vginfo || | ||||
| 	      !vgname_is_locked(info->vginfo->vgname)))) | ||||
| 		_close(dev); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int dev_close(struct device *dev) | ||||
| { | ||||
| 	return _dev_close(dev, 0); | ||||
| } | ||||
|  | ||||
| int dev_close_immediate(struct device *dev) | ||||
| { | ||||
| 	return _dev_close(dev, 1); | ||||
| } | ||||
|  | ||||
| void dev_close_all(void) | ||||
| { | ||||
| 	struct dm_list *doh, *doht; | ||||
| 	struct device *dev; | ||||
|  | ||||
| 	dm_list_iterate_safe(doh, doht, &_open_devices) { | ||||
| 		dev = dm_list_struct_base(doh, struct device, open_list); | ||||
| 		if (dev->open_count < 1) | ||||
| 			_close(dev); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) | ||||
| { | ||||
| 	struct device_area where; | ||||
|  | ||||
| 	if (!dev->open_count) | ||||
| 		return_0; | ||||
|  | ||||
| 	where.dev = dev; | ||||
| 	where.start = offset; | ||||
| 	where.size = len; | ||||
|  | ||||
| 	return _aligned_io(&where, buffer, 0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted | ||||
|  * by (offset,len) and (offset2,len2).  Thus, the total size of | ||||
|  * 'buf' should be len+len2. | ||||
|  */ | ||||
| int dev_read_circular(struct device *dev, uint64_t offset, size_t len, | ||||
| 		      uint64_t offset2, size_t len2, void *buf) | ||||
| { | ||||
| 	if (!dev_read(dev, offset, len, buf)) { | ||||
| 		log_error("Read from %s failed", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * The second region is optional, and allows for | ||||
| 	 * a circular buffer on the device. | ||||
| 	 */ | ||||
| 	if (!len2) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!dev_read(dev, offset2, len2, buf + len)) { | ||||
| 		log_error("Circular read from %s failed", | ||||
| 			  dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after. | ||||
|  *       But fails if concurrent processes writing | ||||
|  */ | ||||
|  | ||||
| /* FIXME pre-extend the file */ | ||||
| int dev_append(struct device *dev, size_t len, void *buffer) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	if (!dev->open_count) | ||||
| 		return_0; | ||||
|  | ||||
| 	r = dev_write(dev, dev->end, len, buffer); | ||||
| 	dev->end += (uint64_t) len; | ||||
|  | ||||
| #ifndef O_DIRECT_SUPPORT | ||||
| 	dev_flush(dev); | ||||
| #endif | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) | ||||
| { | ||||
| 	struct device_area where; | ||||
|  | ||||
| 	if (!dev->open_count) | ||||
| 		return_0; | ||||
|  | ||||
| 	where.dev = dev; | ||||
| 	where.start = offset; | ||||
| 	where.size = len; | ||||
|  | ||||
| 	dev->flags |= DEV_ACCESSED_W; | ||||
|  | ||||
| 	return _aligned_io(&where, buffer, 1); | ||||
| } | ||||
|  | ||||
| int dev_set(struct device *dev, uint64_t offset, size_t len, int value) | ||||
| { | ||||
| 	size_t s; | ||||
| 	char buffer[4096] __attribute((aligned(8))); | ||||
|  | ||||
| 	if (!dev_open(dev)) | ||||
| 		return_0; | ||||
|  | ||||
| 	if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE)) | ||||
| 		log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t, | ||||
| 			  dev_name(dev), offset, len); | ||||
| 	else | ||||
| 		log_debug("Wiping %s at sector %" PRIu64 " length %" PRIsize_t | ||||
| 			  " sectors", dev_name(dev), offset >> SECTOR_SHIFT, | ||||
| 			  len >> SECTOR_SHIFT); | ||||
|  | ||||
| 	memset(buffer, value, sizeof(buffer)); | ||||
| 	while (1) { | ||||
| 		s = len > sizeof(buffer) ? sizeof(buffer) : len; | ||||
| 		if (!dev_write(dev, offset, s, buffer)) | ||||
| 			break; | ||||
|  | ||||
| 		len -= s; | ||||
| 		if (!len) | ||||
| 			break; | ||||
|  | ||||
| 		offset += s; | ||||
| 	} | ||||
|  | ||||
| 	dev->flags |= DEV_ACCESSED_W; | ||||
|  | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	return (len == 0); | ||||
| } | ||||
							
								
								
									
										198
									
								
								lib/device/dev-md.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								lib/device/dev-md.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Luca Berra | ||||
|  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "metadata.h" | ||||
| #include "xlate.h" | ||||
| #include "filter.h" | ||||
|  | ||||
| #ifdef linux | ||||
|  | ||||
| /* Lifted from <linux/raid/md_p.h> because of difficulty including it */ | ||||
|  | ||||
| #define MD_SB_MAGIC 0xa92b4efc | ||||
| #define MD_RESERVED_BYTES (64 * 1024ULL) | ||||
| #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) | ||||
| #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \ | ||||
| 				- MD_RESERVED_SECTORS) | ||||
|  | ||||
| static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset) | ||||
| { | ||||
| 	uint32_t md_magic; | ||||
|  | ||||
| 	/* Version 1 is little endian; version 0.90.0 is machine endian */ | ||||
| 	if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) && | ||||
| 	    ((md_magic == xlate32(MD_SB_MAGIC)) || | ||||
| 	     (md_magic == MD_SB_MAGIC))) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Calculate the position of the superblock. | ||||
|  * It is always aligned to a 4K boundary and | ||||
|  * depending on minor_version, it can be: | ||||
|  * 0: At least 8K, but less than 12K, from end of device | ||||
|  * 1: At start of device | ||||
|  * 2: 4K from start of device. | ||||
|  */ | ||||
| typedef enum { | ||||
| 	MD_MINOR_VERSION_MIN, | ||||
| 	MD_MINOR_V0 = MD_MINOR_VERSION_MIN, | ||||
| 	MD_MINOR_V1, | ||||
| 	MD_MINOR_V2, | ||||
| 	MD_MINOR_VERSION_MAX = MD_MINOR_V2 | ||||
| } md_minor_version_t; | ||||
|  | ||||
| static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version) | ||||
| { | ||||
| 	uint64_t uninitialized_var(sb_offset); | ||||
|  | ||||
| 	switch(minor_version) { | ||||
| 	case MD_MINOR_V0: | ||||
| 		sb_offset = (size - 8 * 2) & ~(4 * 2 - 1ULL); | ||||
| 		break; | ||||
| 	case MD_MINOR_V1: | ||||
| 		sb_offset = 0; | ||||
| 		break; | ||||
| 	case MD_MINOR_V2: | ||||
| 		sb_offset = 4 * 2; | ||||
| 		break; | ||||
| 	} | ||||
| 	sb_offset <<= SECTOR_SHIFT; | ||||
|  | ||||
| 	return sb_offset; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns -1 on error | ||||
|  */ | ||||
| int dev_is_md(struct device *dev, uint64_t *sb) | ||||
| { | ||||
| 	int ret = 1; | ||||
| 	md_minor_version_t minor; | ||||
| 	uint64_t size, sb_offset; | ||||
|  | ||||
| 	if (!dev_get_size(dev, &size)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (size < MD_RESERVED_SECTORS * 2) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Check if it is an md component device. */ | ||||
| 	/* Version 0.90.0 */ | ||||
| 	sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT; | ||||
| 	if (_dev_has_md_magic(dev, sb_offset)) | ||||
| 		goto out; | ||||
|  | ||||
| 	minor = MD_MINOR_VERSION_MIN; | ||||
| 	/* Version 1, try v1.0 -> v1.2 */ | ||||
| 	do { | ||||
| 		sb_offset = _v1_sb_offset(size, minor); | ||||
| 		if (_dev_has_md_magic(dev, sb_offset)) | ||||
| 			goto out; | ||||
| 	} while (++minor <= MD_MINOR_VERSION_MAX); | ||||
|  | ||||
| 	ret = 0; | ||||
|  | ||||
| out: | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	if (ret && sb) | ||||
| 		*sb = sb_offset; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Retrieve chunk size from md device using sysfs. | ||||
|  */ | ||||
| unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev) | ||||
| { | ||||
| 	char path[PATH_MAX+1], buffer[64]; | ||||
| 	FILE *fp; | ||||
| 	struct stat info; | ||||
| 	unsigned long chunk_size_bytes = 0UL; | ||||
|  | ||||
| 	if (MAJOR(dev->dev) != md_major()) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!sysfs_dir || !*sysfs_dir) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/md/chunk_size", | ||||
| 	    sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev)) < 0) { | ||||
| 		log_error("dm_snprintf md chunk_size failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* old sysfs structure */ | ||||
| 	if (stat(path, &info) && | ||||
| 	    dm_snprintf(path, PATH_MAX, "%s/block/md%d/md/chunk_size", | ||||
| 			sysfs_dir, MINOR(dev->dev)) < 0) { | ||||
| 		log_error("dm_snprintf old md chunk size failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(fp = fopen(path, "r"))) { | ||||
| 		log_sys_error("fopen", path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!fgets(buffer, sizeof(buffer), fp)) { | ||||
| 		log_sys_error("fgets", path); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (sscanf(buffer, "%lu", &chunk_size_bytes) != 1) { | ||||
| 		log_error("sysfs file %s not in expected format: %s", path, | ||||
| 			  buffer); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Device %s md chunk size is %lu bytes.", | ||||
| 			 dev_name(dev), chunk_size_bytes); | ||||
|  | ||||
| out: | ||||
| 	if (fclose(fp)) | ||||
| 		log_sys_error("fclose", path); | ||||
|  | ||||
| 	return chunk_size_bytes >> SECTOR_SHIFT; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| int dev_is_md(struct device *dev __attribute((unused)), | ||||
| 	      uint64_t *sb __attribute((unused))) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| unsigned long dev_md_chunk_size(const char *sysfs_dir __attribute((unused)), | ||||
| 				struct device *dev  __attribute((unused))) | ||||
| { | ||||
| 	return 0UL; | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										280
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "lvm-types.h" | ||||
| #include "device.h" | ||||
| #include "metadata.h" | ||||
| #include "filter.h" | ||||
| #include "xlate.h" | ||||
|  | ||||
| /* See linux/genhd.h and fs/partitions/msdos */ | ||||
|  | ||||
| #define PART_MAGIC 0xAA55 | ||||
| #define PART_MAGIC_OFFSET UINT64_C(0x1FE) | ||||
| #define PART_OFFSET UINT64_C(0x1BE) | ||||
|  | ||||
| struct partition { | ||||
| 	uint8_t boot_ind; | ||||
| 	uint8_t head; | ||||
| 	uint8_t sector; | ||||
| 	uint8_t cyl; | ||||
| 	uint8_t sys_ind;	/* partition type */ | ||||
| 	uint8_t end_head; | ||||
| 	uint8_t end_sector; | ||||
| 	uint8_t end_cyl; | ||||
| 	uint32_t start_sect; | ||||
| 	uint32_t nr_sects; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
| static int _is_partitionable(struct device *dev) | ||||
| { | ||||
| 	int parts = max_partitions(MAJOR(dev->dev)); | ||||
|  | ||||
| 	if ((parts <= 1) || (MINOR(dev->dev) % parts)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _has_partition_table(struct device *dev) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	unsigned p; | ||||
| 	uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)]; | ||||
| 	uint16_t *part_magic; | ||||
| 	struct partition *part; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf)) | ||||
| 		goto_out; | ||||
|  | ||||
| 	/* FIXME Check for other types of partition table too */ | ||||
|  | ||||
| 	/* Check for msdos partition table */ | ||||
| 	part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]); | ||||
| 	if ((*part_magic == xlate16(PART_MAGIC))) { | ||||
| 		part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0])); | ||||
| 		for (p = 0; p < 4; p++, part++) { | ||||
| 			/* Table is invalid if boot indicator not 0 or 0x80 */ | ||||
| 			if ((part->boot_ind & 0x7f)) { | ||||
| 				ret = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 			/* Must have at least one non-empty partition */ | ||||
| 			if (part->nr_sects) | ||||
| 				ret = 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|       out: | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int is_partitioned_dev(struct device *dev) | ||||
| { | ||||
| 	if (!_is_partitionable(dev)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return _has_partition_table(dev); | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| #include <sys/stat.h> | ||||
| #include <sys/mman.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <ctype.h> | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/major.h> | ||||
| #include <linux/genhd.h> | ||||
|  | ||||
| int _get_partition_type(struct dev_filter *filter, struct device *d); | ||||
|  | ||||
| #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev))) | ||||
|  | ||||
| int is_extended_partition(struct device *d) | ||||
| { | ||||
| 	return (MINOR_PART(d) > 4) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| struct device *dev_primary(struct dev_mgr *dm, struct device *d) | ||||
| { | ||||
| 	struct device *ret; | ||||
|  | ||||
| 	ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); | ||||
| 	/* FIXME: Needs replacing with a 'refresh' */ | ||||
| 	if (!ret) { | ||||
| 		init_dev_scan(dm); | ||||
| 		ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
|  | ||||
| } | ||||
|  | ||||
| int partition_type_is_lvm(struct dev_mgr *dm, struct device *d) | ||||
| { | ||||
| 	int pt; | ||||
|  | ||||
| 	pt = _get_partition_type(dm, d); | ||||
|  | ||||
| 	if (!pt) { | ||||
| 		if (is_whole_disk(dm, d)) | ||||
| 			/* FIXME: Overloaded pt=0 in error cases */ | ||||
| 			return 1; | ||||
| 		else { | ||||
| 			log_error | ||||
| 			    ("%s: missing partition table " | ||||
| 			     "on partitioned device", d->name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (is_whole_disk(dm, d)) { | ||||
| 		log_error("%s: looks to possess partition table", d->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* check part type */ | ||||
| 	if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) { | ||||
| 		log_error("%s: invalid partition type 0x%x " | ||||
| 			  "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (pt == LVM_PARTITION) { | ||||
| 		log_error | ||||
| 		    ("%s: old LVM partition type found - please change to 0x%x", | ||||
| 		     d->name, LVM_NEW_PARTITION); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int _get_partition_type(struct dev_mgr *dm, struct device *d) | ||||
| { | ||||
| 	int pv_handle = -1; | ||||
| 	struct device *primary; | ||||
| 	ssize_t read_ret; | ||||
| 	ssize_t bytes_read = 0; | ||||
| 	char *buffer; | ||||
| 	unsigned short *s_buffer; | ||||
| 	struct partition *part; | ||||
| 	loff_t offset = 0; | ||||
| 	loff_t extended_offset = 0; | ||||
| 	int part_sought; | ||||
| 	int part_found = 0; | ||||
| 	int first_partition = 1; | ||||
| 	int extended_partition = 0; | ||||
| 	int p; | ||||
|  | ||||
| 	if (!(primary = dev_primary(dm, d))) { | ||||
| 		log_error | ||||
| 		    ("Failed to find main device containing partition %s", | ||||
| 		     d->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(buffer = dm_malloc(SECTOR_SIZE))) { | ||||
| 		log_error("Failed to allocate partition table buffer"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Get partition table */ | ||||
| 	if ((pv_handle = open(primary->name, O_RDONLY)) < 0) { | ||||
| 		log_error("%s: open failed: %s", primary->name, | ||||
| 			  strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	s_buffer = (unsigned short *) buffer; | ||||
| 	part = (struct partition *) (buffer + 0x1be); | ||||
| 	part_sought = MINOR_PART(dm, d); | ||||
|  | ||||
| 	do { | ||||
| 		bytes_read = 0; | ||||
|  | ||||
| 		if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) { | ||||
| 			log_error("%s: llseek failed: %s", | ||||
| 				  primary->name, strerror(errno)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		while ((bytes_read < SECTOR_SIZE) && | ||||
| 		       (read_ret = | ||||
| 			read(pv_handle, buffer + bytes_read, | ||||
| 			     SECTOR_SIZE - bytes_read)) != -1) | ||||
| 			bytes_read += read_ret; | ||||
|  | ||||
| 		if (read_ret == -1) { | ||||
| 			log_error("%s: read failed: %s", primary->name, | ||||
| 				  strerror(errno)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (s_buffer[255] == 0xAA55) { | ||||
| 			if (is_whole_disk(dm, d)) | ||||
| 				return -1; | ||||
| 		} else | ||||
| 			return 0; | ||||
|  | ||||
| 		extended_partition = 0; | ||||
|  | ||||
| 		/* Loop through primary partitions */ | ||||
| 		for (p = 0; p < 4; p++) { | ||||
| 			if (part[p].sys_ind == DOS_EXTENDED_PARTITION || | ||||
| 			    part[p].sys_ind == LINUX_EXTENDED_PARTITION | ||||
| 			    || part[p].sys_ind == WIN98_EXTENDED_PARTITION) { | ||||
| 				extended_partition = 1; | ||||
| 				offset = extended_offset + part[p].start_sect; | ||||
| 				if (extended_offset == 0) | ||||
| 					extended_offset = part[p].start_sect; | ||||
| 				if (first_partition == 1) | ||||
| 					part_found++; | ||||
| 			} else if (first_partition == 1) { | ||||
| 				if (p == part_sought) { | ||||
| 					if (part[p].sys_ind == 0) { | ||||
| 						/* missing primary? */ | ||||
| 						return 0; | ||||
| 					} | ||||
| 				} else | ||||
| 					part_found++; | ||||
| 			} else if (!part[p].sys_ind) | ||||
| 				part_found++; | ||||
|  | ||||
| 			if (part_sought == part_found) | ||||
| 				return part[p].sys_ind; | ||||
|  | ||||
| 		} | ||||
| 		first_partition = 0; | ||||
| 	} | ||||
| 	while (extended_partition == 1); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										100
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEVICE_H | ||||
| #define _LVM_DEVICE_H | ||||
|  | ||||
| #include "uuid.h" | ||||
|  | ||||
| #include <fcntl.h> | ||||
|  | ||||
| #define DEV_ACCESSED_W		0x00000001	/* Device written to? */ | ||||
| #define DEV_REGULAR		0x00000002	/* Regular file? */ | ||||
| #define DEV_ALLOCED		0x00000004	/* dm_malloc used */ | ||||
| #define DEV_OPENED_RW		0x00000008	/* Opened RW */ | ||||
| #define DEV_OPENED_EXCL		0x00000010	/* Opened EXCL */ | ||||
| #define DEV_O_DIRECT		0x00000020	/* Use O_DIRECT */ | ||||
| #define DEV_O_DIRECT_TESTED	0x00000040	/* DEV_O_DIRECT is reliable */ | ||||
|  | ||||
| /* | ||||
|  * All devices in LVM will be represented by one of these. | ||||
|  * pointer comparisons are valid. | ||||
|  */ | ||||
| struct device { | ||||
| 	struct dm_list aliases;	/* struct str_list from lvm-types.h */ | ||||
| 	dev_t dev; | ||||
|  | ||||
| 	/* private */ | ||||
| 	int fd; | ||||
| 	int open_count; | ||||
| 	int block_size; | ||||
| 	uint32_t flags; | ||||
| 	uint64_t end; | ||||
| 	struct dm_list open_list; | ||||
|  | ||||
| 	char pvid[ID_LEN + 1]; | ||||
| 	char _padding[7]; | ||||
| }; | ||||
|  | ||||
| struct device_list { | ||||
| 	struct dm_list list; | ||||
| 	struct device *dev; | ||||
| }; | ||||
|  | ||||
| struct device_area { | ||||
| 	struct device *dev; | ||||
| 	uint64_t start;		/* Bytes */ | ||||
| 	uint64_t size;		/* Bytes */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * All io should use these routines. | ||||
|  */ | ||||
| int dev_get_size(const struct device *dev, uint64_t *size); | ||||
| int dev_get_sectsize(struct device *dev, uint32_t *size); | ||||
|  | ||||
| /* Use quiet version if device number could change e.g. when opening LV */ | ||||
| int dev_open(struct device *dev); | ||||
| int dev_open_quiet(struct device *dev); | ||||
| int dev_open_flags(struct device *dev, int flags, int direct, int quiet); | ||||
| int dev_close(struct device *dev); | ||||
| int dev_close_immediate(struct device *dev); | ||||
| void dev_close_all(void); | ||||
| int dev_test_excl(struct device *dev); | ||||
|  | ||||
| int dev_fd(struct device *dev); | ||||
| const char *dev_name(const struct device *dev); | ||||
|  | ||||
| int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); | ||||
| int dev_read_circular(struct device *dev, uint64_t offset, size_t len, | ||||
| 		      uint64_t offset2, size_t len2, void *buf); | ||||
| int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer); | ||||
| int dev_append(struct device *dev, size_t len, void *buffer); | ||||
| int dev_set(struct device *dev, uint64_t offset, size_t len, int value); | ||||
| void dev_flush(struct device *dev); | ||||
|  | ||||
| struct device *dev_create_file(const char *filename, struct device *dev, | ||||
| 			       struct str_list *alias, int use_malloc); | ||||
|  | ||||
| /* Return a valid device name from the alias list; NULL otherwise */ | ||||
| const char *dev_name_confirmed(struct device *dev, int quiet); | ||||
|  | ||||
| /* Does device contain md superblock?  If so, where? */ | ||||
| int dev_is_md(struct device *dev, uint64_t *sb); | ||||
| unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev); | ||||
|  | ||||
| int is_partitioned_dev(struct device *dev); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										773
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										773
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,773 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "metadata.h" | ||||
| #include "display.h" | ||||
| #include "activate.h" | ||||
| #include "toolcontext.h" | ||||
| #include "segtype.h" | ||||
|  | ||||
| #define SIZE_BUF 128 | ||||
|  | ||||
| typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t; | ||||
|  | ||||
| static const struct { | ||||
| 	alloc_policy_t alloc; | ||||
| 	const char str[12]; /* must be changed when size extends 11 chars */ | ||||
| } _policies[] = { | ||||
| 	{ | ||||
| 	ALLOC_CONTIGUOUS, "contiguous"}, { | ||||
| 	ALLOC_CLING, "cling"}, { | ||||
| 	ALLOC_NORMAL, "normal"}, { | ||||
| 	ALLOC_ANYWHERE, "anywhere"}, { | ||||
| 	ALLOC_INHERIT, "inherit"} | ||||
| }; | ||||
|  | ||||
| static const int _num_policies = sizeof(_policies) / sizeof(*_policies); | ||||
|  | ||||
| uint64_t units_to_bytes(const char *units, char *unit_type) | ||||
| { | ||||
| 	char *ptr = NULL; | ||||
| 	uint64_t v; | ||||
|  | ||||
| 	if (isdigit(*units)) { | ||||
| 		v = (uint64_t) strtod(units, &ptr); | ||||
| 		if (ptr == units) | ||||
| 			return 0; | ||||
| 		units = ptr; | ||||
| 	} else | ||||
| 		v = 1; | ||||
|  | ||||
| 	if (v == 1) | ||||
| 		*unit_type = *units; | ||||
| 	else | ||||
| 		*unit_type = 'U'; | ||||
|  | ||||
| 	switch (*units) { | ||||
| 	case 'h': | ||||
| 	case 'H': | ||||
| 		v = UINT64_C(1); | ||||
| 		*unit_type = *units; | ||||
| 		break; | ||||
| 	case 's': | ||||
| 		v *= SECTOR_SIZE; | ||||
| 		break; | ||||
| 	case 'b': | ||||
| 	case 'B': | ||||
| 		v *= UINT64_C(1); | ||||
| 		break; | ||||
| #define KILO UINT64_C(1024) | ||||
| 	case 'k': | ||||
| 		v *= KILO; | ||||
| 		break; | ||||
| 	case 'm': | ||||
| 		v *= KILO * KILO; | ||||
| 		break; | ||||
| 	case 'g': | ||||
| 		v *= KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 't': | ||||
| 		v *= KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 'p': | ||||
| 		v *= KILO * KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 'e': | ||||
| 		v *= KILO * KILO * KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| #undef KILO | ||||
| #define KILO UINT64_C(1000) | ||||
| 	case 'K': | ||||
| 		v *= KILO; | ||||
| 		break; | ||||
| 	case 'M': | ||||
| 		v *= KILO * KILO; | ||||
| 		break; | ||||
| 	case 'G': | ||||
| 		v *= KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 'T': | ||||
| 		v *= KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 'P': | ||||
| 		v *= KILO * KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| 	case 'E': | ||||
| 		v *= KILO * KILO * KILO * KILO * KILO * KILO; | ||||
| 		break; | ||||
| #undef KILO | ||||
| 	default: | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (*(units + 1)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| const char *get_alloc_string(alloc_policy_t alloc) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < _num_policies; i++) | ||||
| 		if (_policies[i].alloc == alloc) | ||||
| 			return _policies[i].str; | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| alloc_policy_t get_alloc_from_string(const char *str) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < _num_policies; i++) | ||||
| 		if (!strcmp(_policies[i].str, str)) | ||||
| 			return _policies[i].alloc; | ||||
|  | ||||
| 	/* Special case for old metadata */ | ||||
| 	if(!strcmp("next free", str)) | ||||
| 		return ALLOC_NORMAL; | ||||
|  | ||||
| 	log_error("Unrecognised allocation policy %s", str); | ||||
| 	return ALLOC_INVALID; | ||||
| } | ||||
|  | ||||
| /* Size supplied in sectors */ | ||||
| static const char *_display_size(const struct cmd_context *cmd, | ||||
| 				 uint64_t size, size_len_t sl) | ||||
| { | ||||
| 	int s; | ||||
| 	int suffix = 1, precision; | ||||
| 	uint64_t byte = UINT64_C(0); | ||||
| 	uint64_t units = UINT64_C(1024); | ||||
| 	char *size_buf = NULL; | ||||
| 	const char * const size_str[][3] = { | ||||
| 		{" Exabyte", " EB", "E"}, | ||||
| 		{" Petabyte", " PB", "P"}, | ||||
| 		{" Terabyte", " TB", "T"}, | ||||
| 		{" Gigabyte", " GB", "G"}, | ||||
| 		{" Megabyte", " MB", "M"}, | ||||
| 		{" Kilobyte", " KB", "K"}, | ||||
| 		{"", "", ""}, | ||||
| 		{" Byte    ", " B ", "B"}, | ||||
| 		{" Units   ", " Un", "U"}, | ||||
| 		{" Sectors ", " Se", "S"}, | ||||
| 		{"         ", "   ", " "}, | ||||
| 	}; | ||||
|  | ||||
| 	if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) { | ||||
| 		log_error("no memory for size display buffer"); | ||||
| 		return ""; | ||||
| 	} | ||||
|  | ||||
| 	suffix = cmd->current_settings.suffix; | ||||
|  | ||||
| 	for (s = 0; s < 10; s++) | ||||
| 		if (toupper((int) cmd->current_settings.unit_type) == | ||||
| 		    *size_str[s][2]) | ||||
| 			break; | ||||
|  | ||||
| 	if (size == UINT64_C(0)) { | ||||
| 		sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : ""); | ||||
| 		return size_buf; | ||||
| 	} | ||||
|  | ||||
| 	size *= UINT64_C(512); | ||||
|  | ||||
| 	if (s < 10) | ||||
| 		byte = cmd->current_settings.unit_factor; | ||||
| 	else { | ||||
| 		suffix = 1; | ||||
| 		if (cmd->current_settings.unit_type == 'H') | ||||
| 			units = UINT64_C(1000); | ||||
| 		else | ||||
| 			units = UINT64_C(1024); | ||||
| 		byte = units * units * units * units * units * units; | ||||
| 		s = 0; | ||||
| 		while (size_str[s] && size < byte) | ||||
| 			s++, byte /= units; | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME Make precision configurable */ | ||||
| 	switch(toupper((int) cmd->current_settings.unit_type)) { | ||||
| 	case 'B': | ||||
| 	case 'S': | ||||
| 		precision = 0; | ||||
| 		break; | ||||
| 	default: | ||||
| 		precision = 2; | ||||
| 	} | ||||
|  | ||||
| 	snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, | ||||
| 		 (double) size / byte, suffix ? size_str[s][sl] : ""); | ||||
|  | ||||
| 	return size_buf; | ||||
| } | ||||
|  | ||||
| const char *display_size_long(const struct cmd_context *cmd, uint64_t size) | ||||
| { | ||||
| 	return _display_size(cmd, size, SIZE_LONG); | ||||
| } | ||||
|  | ||||
| const char *display_size_units(const struct cmd_context *cmd, uint64_t size) | ||||
| { | ||||
| 	return _display_size(cmd, size, SIZE_UNIT); | ||||
| } | ||||
|  | ||||
| const char *display_size(const struct cmd_context *cmd, uint64_t size) | ||||
| { | ||||
| 	return _display_size(cmd, size, SIZE_SHORT); | ||||
| } | ||||
|  | ||||
| void pvdisplay_colons(const struct physical_volume *pv) | ||||
| { | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
|  | ||||
| 	if (!pv) | ||||
| 		return; | ||||
|  | ||||
| 	if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu32 ":%u:%u:%u:%s", | ||||
| 		  pv_dev_name(pv), pv->vg_name, pv->size, | ||||
| 		  /* FIXME pv->pv_number, Derive or remove? */ | ||||
| 		  pv->status,	/* FIXME Support old or new format here? */ | ||||
| 		  pv->status & ALLOCATABLE_PV,	/* FIXME remove? */ | ||||
| 		  /* FIXME pv->lv_cur, Remove? */ | ||||
| 		  pv->pe_size / 2, | ||||
| 		  pv->pe_count, | ||||
| 		  pv->pe_count - pv->pe_alloc_count, | ||||
| 		  pv->pe_alloc_count, *uuid ? uuid : "none"); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void pvdisplay_segments(const struct physical_volume *pv) | ||||
| { | ||||
| 	const struct pv_segment *pvseg; | ||||
|  | ||||
| 	if (pv->pe_size) | ||||
| 		log_print("--- Physical Segments ---"); | ||||
|  | ||||
| 	dm_list_iterate_items(pvseg, &pv->segments) { | ||||
| 		log_print("Physical extent %u to %u:", | ||||
| 			  pvseg->pe, pvseg->pe + pvseg->len - 1); | ||||
|  | ||||
| 		if (pvseg_is_allocated(pvseg)) { | ||||
| 			log_print("  Logical volume\t%s%s/%s", | ||||
| 				  pvseg->lvseg->lv->vg->cmd->dev_dir, | ||||
| 				  pvseg->lvseg->lv->vg->name, | ||||
| 				  pvseg->lvseg->lv->name); | ||||
| 			log_print("  Logical extents\t%d to %d", | ||||
| 				  pvseg->lvseg->le, pvseg->lvseg->le + | ||||
| 				  pvseg->lvseg->len - 1); | ||||
| 		} else | ||||
| 			log_print("  FREE"); | ||||
| 	} | ||||
|  | ||||
| 	log_print(" "); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| /* FIXME Include label fields */ | ||||
| void pvdisplay_full(const struct cmd_context *cmd, | ||||
| 		    const struct physical_volume *pv, | ||||
| 		    void *handle __attribute((unused))) | ||||
| { | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
| 	const char *size; | ||||
|  | ||||
| 	uint32_t pe_free; | ||||
| 	uint64_t data_size, pvsize, unusable; | ||||
|  | ||||
| 	if (!pv) | ||||
| 		return; | ||||
|  | ||||
| 	if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW "); | ||||
| 	log_print("PV Name               %s", pv_dev_name(pv)); | ||||
| 	log_print("VG Name               %s%s", | ||||
| 		  is_orphan(pv) ? "" : pv->vg_name, | ||||
| 		  pv->status & EXPORTED_VG ? " (exported)" : ""); | ||||
|  | ||||
| 	data_size = (uint64_t) pv->pe_count * pv->pe_size; | ||||
| 	if (pv->size > data_size + pv->pe_start) { | ||||
| 		pvsize = pv->size; | ||||
| 		unusable = pvsize - data_size; | ||||
| 	} else { | ||||
| 		pvsize = data_size + pv->pe_start; | ||||
| 		unusable = pvsize - pv->size; | ||||
| 	} | ||||
|  | ||||
| 	size = display_size(cmd, pvsize); | ||||
| 	if (data_size) | ||||
| 		log_print("PV Size               %s / not usable %s",	/*  [LVM: %s]", */ | ||||
| 			  size, display_size(cmd, unusable)); | ||||
| 	else | ||||
| 		log_print("PV Size               %s", size); | ||||
|  | ||||
| 	/* PV number not part of LVM2 design | ||||
| 	   log_print("PV#                   %u", pv->pv_number); | ||||
| 	 */ | ||||
|  | ||||
| 	pe_free = pv->pe_count - pv->pe_alloc_count; | ||||
| 	if (pv->pe_count && (pv->status & ALLOCATABLE_PV)) | ||||
| 		log_print("Allocatable           yes %s", | ||||
| 			  (!pe_free && pv->pe_count) ? "(but full)" : ""); | ||||
| 	else | ||||
| 		log_print("Allocatable           NO"); | ||||
|  | ||||
| 	/* LV count is no longer available when displaying PV | ||||
| 	   log_print("Cur LV                %u", vg->lv_count); | ||||
| 	 */ | ||||
| 	log_print("PE Size (KByte)       %" PRIu32, pv->pe_size / 2); | ||||
| 	log_print("Total PE              %u", pv->pe_count); | ||||
| 	log_print("Free PE               %" PRIu32, pe_free); | ||||
| 	log_print("Allocated PE          %u", pv->pe_alloc_count); | ||||
| 	log_print("PV UUID               %s", *uuid ? uuid : "none"); | ||||
| 	log_print(" "); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int pvdisplay_short(const struct cmd_context *cmd __attribute((unused)), | ||||
| 		    const struct volume_group *vg __attribute((unused)), | ||||
| 		    const struct physical_volume *pv, | ||||
| 		    void *handle __attribute((unused))) | ||||
| { | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
|  | ||||
| 	if (!pv) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!id_write_format(&pv->id, uuid, sizeof(uuid))) | ||||
| 		return_0; | ||||
|  | ||||
| 	log_print("PV Name               %s     ", pv_dev_name(pv)); | ||||
| 	/* FIXME  pv->pv_number); */ | ||||
| 	log_print("PV UUID               %s", *uuid ? uuid : "none"); | ||||
| 	log_print("PV Status             %sallocatable", | ||||
| 		  (pv->status & ALLOCATABLE_PV) ? "" : "NOT "); | ||||
| 	log_print("Total PE / Free PE    %u / %u", | ||||
| 		  pv->pe_count, pv->pe_count - pv->pe_alloc_count); | ||||
|  | ||||
| 	log_print(" "); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void lvdisplay_colons(const struct logical_volume *lv) | ||||
| { | ||||
| 	int inkernel; | ||||
| 	struct lvinfo info; | ||||
| 	inkernel = lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists; | ||||
|  | ||||
| 	log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d", | ||||
| 		  lv->vg->cmd->dev_dir, | ||||
| 		  lv->vg->name, | ||||
| 		  lv->name, | ||||
| 		  lv->vg->name, | ||||
| 		  (lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0, | ||||
| 		  /* FIXME lv->lv_number,  */ | ||||
| 		  inkernel ? info.open_count : 0, lv->size, lv->le_count, | ||||
| 		  /* FIXME Add num allocated to struct! lv->lv_allocated_le, */ | ||||
| 		  (lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead, | ||||
| 		  inkernel ? info.major : -1, inkernel ? info.minor : -1); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int lvdisplay_full(struct cmd_context *cmd, | ||||
| 		   const struct logical_volume *lv, | ||||
| 		   void *handle __attribute((unused))) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
| 	int inkernel, snap_active = 0; | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
| 	struct lv_segment *snap_seg = NULL; | ||||
| 	float snap_percent;	/* fused, fsize; */ | ||||
|  | ||||
| 	if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) | ||||
| 		return_0; | ||||
|  | ||||
| 	inkernel = lv_info(cmd, lv, &info, 1, 1) && info.exists; | ||||
|  | ||||
| 	log_print("--- Logical volume ---"); | ||||
|  | ||||
| 	log_print("LV Name                %s%s/%s", lv->vg->cmd->dev_dir, | ||||
| 		  lv->vg->name, lv->name); | ||||
| 	log_print("VG Name                %s", lv->vg->name); | ||||
|  | ||||
| 	log_print("LV UUID                %s", uuid); | ||||
|  | ||||
| 	log_print("LV Write Access        %s", | ||||
| 		  (lv->status & LVM_WRITE) ? "read/write" : "read only"); | ||||
|  | ||||
| 	if (lv_is_origin(lv)) { | ||||
| 		log_print("LV snapshot status     source of"); | ||||
|  | ||||
| 		dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, | ||||
| 				       origin_list) { | ||||
| 			if (inkernel && | ||||
| 			    (snap_active = lv_snapshot_percent(snap_seg->cow, | ||||
| 							       &snap_percent))) | ||||
| 				if (snap_percent < 0 || snap_percent >= 100) | ||||
| 					snap_active = 0; | ||||
| 			log_print("                       %s%s/%s [%s]", | ||||
| 				  lv->vg->cmd->dev_dir, lv->vg->name, | ||||
| 				  snap_seg->cow->name, | ||||
| 				  (snap_active > 0) ? "active" : "INACTIVE"); | ||||
| 		} | ||||
| 		snap_seg = NULL; | ||||
| 	} else if ((snap_seg = find_cow(lv))) { | ||||
| 		if (inkernel && | ||||
| 		    (snap_active = lv_snapshot_percent(snap_seg->cow, | ||||
| 						       &snap_percent))) | ||||
| 			if (snap_percent < 0 || snap_percent >= 100) | ||||
| 				snap_active = 0; | ||||
|  | ||||
| 		log_print("LV snapshot status     %s destination for %s%s/%s", | ||||
| 			  (snap_active > 0) ? "active" : "INACTIVE", | ||||
| 			  lv->vg->cmd->dev_dir, lv->vg->name, | ||||
| 			  snap_seg->origin->name); | ||||
| 	} | ||||
|  | ||||
| 	if (inkernel && info.suspended) | ||||
| 		log_print("LV Status              suspended"); | ||||
| 	else | ||||
| 		log_print("LV Status              %savailable", | ||||
| 			  inkernel ? "" : "NOT "); | ||||
|  | ||||
| /********* FIXME lv_number | ||||
|     log_print("LV #                   %u", lv->lv_number + 1); | ||||
| ************/ | ||||
|  | ||||
| 	if (inkernel) | ||||
| 		log_print("# open                 %u", info.open_count); | ||||
|  | ||||
| 	log_print("LV Size                %s", | ||||
| 		  display_size(cmd, | ||||
| 			       snap_seg ? snap_seg->origin->size : lv->size)); | ||||
|  | ||||
| 	log_print("Current LE             %u", | ||||
| 		  snap_seg ? snap_seg->origin->le_count : lv->le_count); | ||||
|  | ||||
| 	if (snap_seg) { | ||||
| 		log_print("COW-table size         %s", | ||||
| 			  display_size(cmd, (uint64_t) lv->size)); | ||||
| 		log_print("COW-table LE           %u", lv->le_count); | ||||
|  | ||||
| 		if (snap_active) | ||||
| 			log_print("Allocated to snapshot  %.2f%% ", snap_percent);	 | ||||
|  | ||||
| 		log_print("Snapshot chunk size    %s", | ||||
| 			  display_size(cmd, (uint64_t) snap_seg->chunk_size)); | ||||
| 	} | ||||
|  | ||||
| 	log_print("Segments               %u", dm_list_size(&lv->segments)); | ||||
|  | ||||
| /********* FIXME Stripes & stripesize for each segment | ||||
| 	log_print("Stripe size (KByte)    %u", lv->stripesize / 2); | ||||
| ***********/ | ||||
|  | ||||
| 	log_print("Allocation             %s", get_alloc_string(lv->alloc)); | ||||
| 	if (lv->read_ahead == DM_READ_AHEAD_AUTO) | ||||
| 		log_print("Read ahead sectors     auto"); | ||||
| 	else if (lv->read_ahead == DM_READ_AHEAD_NONE) | ||||
| 		log_print("Read ahead sectors     0"); | ||||
| 	else | ||||
| 		log_print("Read ahead sectors     %u", lv->read_ahead); | ||||
|  | ||||
| 	if (inkernel && lv->read_ahead != info.read_ahead) | ||||
| 		log_print("- currently set to     %u", info.read_ahead); | ||||
|  | ||||
| 	if (lv->status & FIXED_MINOR) { | ||||
| 		if (lv->major >= 0) | ||||
| 			log_print("Persistent major       %d", lv->major); | ||||
| 		log_print("Persistent minor       %d", lv->minor); | ||||
| 	} | ||||
|  | ||||
| 	if (inkernel) | ||||
| 		log_print("Block device           %d:%d", info.major, | ||||
| 			  info.minor); | ||||
|  | ||||
| 	log_print(" "); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre) | ||||
| { | ||||
| 	switch (seg_type(seg, s)) { | ||||
| 	case AREA_PV: | ||||
| 		/* FIXME Re-check the conditions for 'Missing' */ | ||||
| 		log_print("%sPhysical volume\t%s", pre, | ||||
| 			  seg_pv(seg, s) ? | ||||
| 			  pv_dev_name(seg_pv(seg, s)) : | ||||
| 			    "Missing"); | ||||
|  | ||||
| 		if (seg_pv(seg, s)) | ||||
| 			log_print("%sPhysical extents\t%d to %d", pre, | ||||
| 				  seg_pe(seg, s), | ||||
| 				  seg_pe(seg, s) + seg->area_len - 1); | ||||
| 		break; | ||||
| 	case AREA_LV: | ||||
| 		log_print("%sLogical volume\t%s", pre, | ||||
| 			  seg_lv(seg, s) ? | ||||
| 			  seg_lv(seg, s)->name : "Missing"); | ||||
|  | ||||
| 		if (seg_lv(seg, s)) | ||||
| 			log_print("%sLogical extents\t%d to %d", pre, | ||||
| 				  seg_le(seg, s), | ||||
| 				  seg_le(seg, s) + seg->area_len - 1); | ||||
| 		break; | ||||
| 	case AREA_UNASSIGNED: | ||||
| 		log_print("%sUnassigned area", pre); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int lvdisplay_segments(const struct logical_volume *lv) | ||||
| { | ||||
| 	const struct lv_segment *seg; | ||||
|  | ||||
| 	log_print("--- Segments ---"); | ||||
|  | ||||
| 	dm_list_iterate_items(seg, &lv->segments) { | ||||
| 		log_print("Logical extent %u to %u:", | ||||
| 			  seg->le, seg->le + seg->len - 1); | ||||
|  | ||||
| 		log_print("  Type\t\t%s", seg->segtype->ops->name(seg)); | ||||
|  | ||||
| 		if (seg->segtype->ops->display) | ||||
| 			seg->segtype->ops->display(seg); | ||||
| 	} | ||||
|  | ||||
| 	log_print(" "); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void vgdisplay_extents(const struct volume_group *vg __attribute((unused))) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void vgdisplay_full(const struct volume_group *vg) | ||||
| { | ||||
| 	uint32_t access_str; | ||||
| 	uint32_t active_pvs; | ||||
| 	uint32_t lv_count = 0; | ||||
| 	struct lv_list *lvl; | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
|  | ||||
| 	active_pvs = vg->pv_count - vg_missing_pv_count(vg); | ||||
|  | ||||
| 	log_print("--- Volume group ---"); | ||||
| 	log_print("VG Name               %s", vg->name); | ||||
| 	log_print("System ID             %s", vg->system_id); | ||||
| 	log_print("Format                %s", vg->fid->fmt->name); | ||||
| 	if (vg->fid->fmt->features & FMT_MDAS) { | ||||
| 		log_print("Metadata Areas        %d", | ||||
| 			  dm_list_size(&vg->fid->metadata_areas)); | ||||
| 		log_print("Metadata Sequence No  %d", vg->seqno); | ||||
| 	} | ||||
| 	access_str = vg->status & (LVM_READ | LVM_WRITE); | ||||
| 	log_print("VG Access             %s%s%s%s", | ||||
| 		  access_str == (LVM_READ | LVM_WRITE) ? "read/write" : "", | ||||
| 		  access_str == LVM_READ ? "read" : "", | ||||
| 		  access_str == LVM_WRITE ? "write" : "", | ||||
| 		  access_str == 0 ? "error" : ""); | ||||
| 	log_print("VG Status             %s%sresizable", | ||||
| 		  vg->status & EXPORTED_VG ? "exported/" : "", | ||||
| 		  vg->status & RESIZEABLE_VG ? "" : "NOT "); | ||||
| 	/* vg number not part of LVM2 design | ||||
| 	   log_print ("VG #                  %u\n", vg->vg_number); | ||||
| 	 */ | ||||
| 	if (vg_is_clustered(vg)) { | ||||
| 		log_print("Clustered             yes"); | ||||
| 		log_print("Shared                %s", | ||||
| 			  vg->status & SHARED ? "yes" : "no"); | ||||
| 	} | ||||
|  | ||||
| 	dm_list_iterate_items(lvl, &vg->lvs) | ||||
| 		if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT)) | ||||
| 			lv_count++; | ||||
|  | ||||
| 	log_print("MAX LV                %u", vg->max_lv); | ||||
| 	log_print("Cur LV                %u", lv_count); | ||||
| 	log_print("Open LV               %u", lvs_in_vg_opened(vg)); | ||||
| /****** FIXME Max LV Size | ||||
|       log_print ( "MAX LV Size           %s", | ||||
|                ( s1 = display_size ( LVM_LV_SIZE_MAX(vg)))); | ||||
|       free ( s1); | ||||
| *********/ | ||||
| 	log_print("Max PV                %u", vg->max_pv); | ||||
| 	log_print("Cur PV                %u", vg->pv_count); | ||||
| 	log_print("Act PV                %u", active_pvs); | ||||
|  | ||||
| 	log_print("VG Size               %s", | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->extent_count * vg->extent_size)); | ||||
|  | ||||
| 	log_print("PE Size               %s", | ||||
| 		  display_size(vg->cmd, (uint64_t) vg->extent_size)); | ||||
|  | ||||
| 	log_print("Total PE              %u", vg->extent_count); | ||||
|  | ||||
| 	log_print("Alloc PE / Size       %u / %s", | ||||
| 		  vg->extent_count - vg->free_count, | ||||
| 		  display_size(vg->cmd, | ||||
| 			       ((uint64_t) vg->extent_count - vg->free_count) * | ||||
| 			       vg->extent_size)); | ||||
|  | ||||
| 	log_print("Free  PE / Size       %u / %s", vg->free_count, | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->free_count * vg->extent_size)); | ||||
|  | ||||
| 	if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("VG UUID               %s", uuid); | ||||
| 	log_print(" "); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void vgdisplay_colons(const struct volume_group *vg) | ||||
| { | ||||
| 	uint32_t active_pvs; | ||||
| 	uint32_t lv_count; | ||||
| 	struct lv_list *lvl; | ||||
| 	const char *access_str; | ||||
| 	char uuid[64] __attribute((aligned(8))); | ||||
|  | ||||
| 	active_pvs = vg->pv_count - vg_missing_pv_count(vg); | ||||
|  | ||||
| 	dm_list_iterate_items(lvl, &vg->lvs) | ||||
| 		if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT)) | ||||
| 			lv_count++; | ||||
|  | ||||
| 	switch (vg->status & (LVM_READ | LVM_WRITE)) { | ||||
| 		case LVM_READ | LVM_WRITE: | ||||
| 			access_str = "r/w"; | ||||
| 			break; | ||||
| 		case LVM_READ: | ||||
| 			access_str = "r"; | ||||
| 			break; | ||||
| 		case LVM_WRITE: | ||||
| 			access_str = "w"; | ||||
| 			break; | ||||
| 		default: | ||||
| 			access_str = ""; | ||||
| 	} | ||||
|  | ||||
| 	if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("%s:%s:%d:-1:%u:%u:%u:-1:%u:%u:%u:%" PRIu64 ":%" PRIu32 | ||||
| 		  ":%u:%u:%u:%s", | ||||
| 		vg->name, | ||||
| 		access_str, | ||||
| 		vg->status, | ||||
| 		/* internal volume group number; obsolete */ | ||||
| 		vg->max_lv, | ||||
| 		vg->lv_count, | ||||
| 		lvs_in_vg_opened(vg), | ||||
| 		/* FIXME: maximum logical volume size */ | ||||
| 		vg->max_pv, | ||||
| 		vg->pv_count, | ||||
| 		active_pvs, | ||||
| 		(uint64_t) vg->extent_count * (vg->extent_size / 2), | ||||
| 		vg->extent_size / 2, | ||||
| 		vg->extent_count, | ||||
| 		vg->extent_count - vg->free_count, | ||||
| 		vg->free_count, | ||||
| 		uuid[0] ? uuid : "none"); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void vgdisplay_short(const struct volume_group *vg) | ||||
| { | ||||
| 	log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name, | ||||
| /********* FIXME if "open" print "/used" else print "/idle"???  ******/ | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->extent_count * vg->extent_size), | ||||
| 		  display_size(vg->cmd, | ||||
| 			       ((uint64_t) vg->extent_count - | ||||
| 				vg->free_count) * vg->extent_size), | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->free_count * vg->extent_size)); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void display_formats(const struct cmd_context *cmd) | ||||
| { | ||||
| 	const struct format_type *fmt; | ||||
|  | ||||
| 	dm_list_iterate_items(fmt, &cmd->formats) { | ||||
| 		log_print("%s", fmt->name); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void display_segtypes(const struct cmd_context *cmd) | ||||
| { | ||||
| 	const struct segment_type *segtype; | ||||
|  | ||||
| 	dm_list_iterate_items(segtype, &cmd->segtypes) { | ||||
| 		log_print("%s", segtype->name); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| char yes_no_prompt(const char *prompt, ...) | ||||
| { | ||||
| 	int c = 0, ret = 0; | ||||
| 	va_list ap; | ||||
|  | ||||
| 	sigint_allow(); | ||||
| 	do { | ||||
| 		if (c == '\n' || !c) { | ||||
| 			va_start(ap, prompt); | ||||
| 			vprintf(prompt, ap); | ||||
| 			va_end(ap); | ||||
| 		} | ||||
|  | ||||
| 		if ((c = getchar()) == EOF) { | ||||
| 			ret = 'n'; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		c = tolower(c); | ||||
| 		if ((c == 'y') || (c == 'n')) | ||||
| 			ret = c; | ||||
| 	} while (!ret || c != '\n'); | ||||
|  | ||||
| 	sigint_restore(); | ||||
|  | ||||
| 	if (c != '\n') | ||||
| 		printf("\n"); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
							
								
								
									
										64
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DISPLAY_H | ||||
| #define _LVM_DISPLAY_H | ||||
|  | ||||
| #include "metadata-exported.h" | ||||
| #include "locking.h" | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| uint64_t units_to_bytes(const char *units, char *unit_type); | ||||
|  | ||||
| /* Specify size in KB */ | ||||
| const char *display_size(const struct cmd_context *cmd, uint64_t size); | ||||
| const char *display_size_long(const struct cmd_context *cmd, uint64_t size); | ||||
| const char *display_size_units(const struct cmd_context *cmd, uint64_t size); | ||||
|  | ||||
| char *display_uuid(char *uuidstr); | ||||
| void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre); | ||||
|  | ||||
| void pvdisplay_colons(const struct physical_volume *pv); | ||||
| void pvdisplay_segments(const struct physical_volume *pv); | ||||
| void pvdisplay_full(const struct cmd_context *cmd, | ||||
| 		    const struct physical_volume *pv, | ||||
| 		    void *handle); | ||||
| int pvdisplay_short(const struct cmd_context *cmd, | ||||
| 		    const struct volume_group *vg, | ||||
| 		    const struct physical_volume *pv, void *handle); | ||||
|  | ||||
| void lvdisplay_colons(const struct logical_volume *lv); | ||||
| int lvdisplay_segments(const struct logical_volume *lv); | ||||
| int lvdisplay_full(struct cmd_context *cmd, const struct logical_volume *lv, | ||||
| 		   void *handle); | ||||
|  | ||||
| void vgdisplay_extents(const struct volume_group *vg); | ||||
| void vgdisplay_full(const struct volume_group *vg); | ||||
| void vgdisplay_colons(const struct volume_group *vg); | ||||
| void vgdisplay_short(const struct volume_group *vg); | ||||
|  | ||||
| void display_formats(const struct cmd_context *cmd); | ||||
| void display_segtypes(const struct cmd_context *cmd); | ||||
|  | ||||
| /* | ||||
|  * Allocation policy display conversion routines. | ||||
|  */ | ||||
| const char *get_alloc_string(alloc_policy_t alloc); | ||||
| alloc_policy_t get_alloc_from_string(const char *str); | ||||
|  | ||||
| char yes_no_prompt(const char *prompt, ...); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										114
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "toolcontext.h" | ||||
| #include "segtype.h" | ||||
| #include "display.h" | ||||
| #include "text_export.h" | ||||
| #include "text_import.h" | ||||
| #include "config.h" | ||||
| #include "str_list.h" | ||||
| #include "targets.h" | ||||
| #include "lvm-string.h" | ||||
| #include "activate.h" | ||||
| #include "str_list.h" | ||||
| #include "metadata.h" | ||||
|  | ||||
| static const char *_errseg_name(const struct lv_segment *seg) | ||||
| { | ||||
| 	return seg->segtype->name; | ||||
| } | ||||
|  | ||||
| static int _errseg_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) | ||||
| { | ||||
| 	seg1->len += seg2->len; | ||||
| 	seg1->area_len += seg2->area_len; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)), | ||||
| 				struct dm_pool *mem __attribute((unused)), | ||||
| 				struct cmd_context *cmd __attribute((unused)), | ||||
| 				void **target_state __attribute((unused)), | ||||
| 				struct lv_segment *seg __attribute((unused)), | ||||
| 				struct dm_tree_node *node, uint64_t len, | ||||
| 				uint32_t *pvmove_mirror_count __attribute((unused))) | ||||
| { | ||||
| 	return dm_tree_node_add_error_target(node, len); | ||||
| } | ||||
|  | ||||
| static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)), | ||||
| 				  unsigned *attributes __attribute((unused))) | ||||
| { | ||||
| 	static int _errseg_checked = 0; | ||||
| 	static int _errseg_present = 0; | ||||
|  | ||||
| 	/* Reported truncated in older kernels */ | ||||
| 	if (!_errseg_checked && | ||||
| 	    (target_present("error", 0) || target_present("erro", 0))) | ||||
| 		_errseg_present = 1; | ||||
|  | ||||
| 	_errseg_checked = 1; | ||||
| 	return _errseg_present; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static int _errseg_modules_needed(struct dm_pool *mem, | ||||
| 				  const struct lv_segment *seg __attribute((unused)), | ||||
| 				  struct dm_list *modules) | ||||
| { | ||||
| 	if (!str_list_add(mem, modules, "error")) { | ||||
| 		log_error("error module string list allocation failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _errseg_destroy(const struct segment_type *segtype) | ||||
| { | ||||
| 	dm_free((void *)segtype); | ||||
| } | ||||
|  | ||||
| static struct segtype_handler _error_ops = { | ||||
| 	.name = _errseg_name, | ||||
| 	.merge_segments = _errseg_merge_segments, | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| 	.add_target_line = _errseg_add_target_line, | ||||
| 	.target_present = _errseg_target_present, | ||||
| #endif | ||||
| 	.modules_needed = _errseg_modules_needed, | ||||
| 	.destroy = _errseg_destroy, | ||||
| }; | ||||
|  | ||||
| struct segment_type *init_error_segtype(struct cmd_context *cmd) | ||||
| { | ||||
| 	struct segment_type *segtype = dm_malloc(sizeof(*segtype)); | ||||
|  | ||||
| 	if (!segtype) | ||||
| 		return_NULL; | ||||
|  | ||||
| 	segtype->cmd = cmd; | ||||
| 	segtype->ops = &_error_ops; | ||||
| 	segtype->name = "error"; | ||||
| 	segtype->private = NULL; | ||||
| 	segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; | ||||
|  | ||||
| 	log_very_verbose("Initialised segtype: %s", segtype->name); | ||||
|  | ||||
| 	return segtype; | ||||
| } | ||||
							
								
								
									
										75
									
								
								lib/filters/filter-composite.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								lib/filters/filter-composite.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "filter-composite.h" | ||||
|  | ||||
| #include <stdarg.h> | ||||
|  | ||||
| static int _and_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	struct dev_filter **filters = (struct dev_filter **) f->private; | ||||
|  | ||||
| 	while (*filters) { | ||||
| 		if (!(*filters)->passes_filter(*filters, dev)) | ||||
| 			return 0; | ||||
| 		filters++; | ||||
| 	} | ||||
|  | ||||
| 	log_debug("Using %s", dev_name(dev)); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _composite_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct dev_filter **filters = (struct dev_filter **) f->private; | ||||
|  | ||||
| 	while (*filters) { | ||||
| 		(*filters)->destroy(*filters); | ||||
| 		filters++; | ||||
| 	} | ||||
|  | ||||
| 	dm_free(f->private); | ||||
| 	dm_free(f); | ||||
| } | ||||
|  | ||||
| struct dev_filter *composite_filter_create(int n, struct dev_filter **filters) | ||||
| { | ||||
| 	struct dev_filter **filters_copy, *cft; | ||||
|  | ||||
| 	if (!filters) | ||||
| 		return_NULL; | ||||
|  | ||||
| 	if (!(filters_copy = dm_malloc(sizeof(*filters) * (n + 1)))) { | ||||
| 		log_error("composite filters allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	memcpy(filters_copy, filters, sizeof(*filters) * n); | ||||
| 	filters_copy[n] = NULL; | ||||
|  | ||||
| 	if (!(cft = dm_malloc(sizeof(*cft)))) { | ||||
| 		log_error("compsoite filters allocation failed"); | ||||
| 		dm_free(filters_copy); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	cft->passes_filter = _and_p; | ||||
| 	cft->destroy = _composite_destroy; | ||||
| 	cft->private = filters_copy; | ||||
|  | ||||
| 	return cft; | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/filters/filter-composite.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/filters/filter-composite.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_COMPOSITE_H | ||||
| #define _LVM_FILTER_COMPOSITE_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| struct dev_filter *composite_filter_create(int n, struct dev_filter **filters); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										74
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Luca Berra | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "filter-md.h" | ||||
| #include "metadata.h" | ||||
|  | ||||
| #ifdef linux | ||||
|  | ||||
| static int _ignore_md(struct dev_filter *f __attribute((unused)), | ||||
| 		      struct device *dev) | ||||
| { | ||||
| 	int ret; | ||||
| 	 | ||||
| 	if (!md_filtering()) | ||||
| 		return 1; | ||||
| 	 | ||||
| 	ret = dev_is_md(dev, NULL); | ||||
|  | ||||
| 	if (ret == 1) { | ||||
| 		log_debug("%s: Skipping md component device", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (ret < 0) { | ||||
| 		log_debug("%s: Skipping: error in md component detection", | ||||
| 			  dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _destroy(struct dev_filter *f) | ||||
| { | ||||
| 	dm_free(f); | ||||
| } | ||||
|  | ||||
| struct dev_filter *md_filter_create(void) | ||||
| { | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!(f = dm_malloc(sizeof(*f)))) { | ||||
| 		log_error("md filter allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	f->passes_filter = _ignore_md; | ||||
| 	f->destroy = _destroy; | ||||
| 	f->private = NULL; | ||||
|  | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| struct dev_filter *md_filter_create(void) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										23
									
								
								lib/filters/filter-md.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/filters/filter-md.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Luca Berra | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_MD_H | ||||
| #define _LVM_FILTER_MD_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| struct dev_filter *md_filter_create(void); | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										333
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,333 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "config.h" | ||||
| #include "dev-cache.h" | ||||
| #include "filter-persistent.h" | ||||
| #include "lvm-file.h" | ||||
| #include "lvm-string.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| struct pfilter { | ||||
| 	char *file; | ||||
| 	struct dm_hash_table *devices; | ||||
| 	struct dev_filter *real; | ||||
| 	time_t ctime; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * The hash table holds one of these two states | ||||
|  * against each entry. | ||||
|  */ | ||||
| #define PF_BAD_DEVICE ((void *) 1) | ||||
| #define PF_GOOD_DEVICE ((void *) 2) | ||||
|  | ||||
| static int _init_hash(struct pfilter *pf) | ||||
| { | ||||
| 	if (pf->devices) | ||||
| 		dm_hash_destroy(pf->devices); | ||||
|  | ||||
| 	if (!(pf->devices = dm_hash_create(128))) | ||||
| 		return_0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int persistent_filter_wipe(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	log_verbose("Wiping cache of LVM-capable devices"); | ||||
| 	dm_hash_wipe(pf->devices); | ||||
|  | ||||
| 	/* Trigger complete device scan */ | ||||
| 	dev_cache_scan(1); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_array(struct pfilter *pf, struct config_tree *cft, | ||||
| 		       const char *path, void *data) | ||||
| { | ||||
| 	const struct config_node *cn; | ||||
| 	struct config_value *cv; | ||||
|  | ||||
| 	if (!(cn = find_config_node(cft->root, path))) { | ||||
| 		log_very_verbose("Couldn't find %s array in '%s'", | ||||
| 				 path, pf->file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * iterate through the array, adding | ||||
| 	 * devices as we go. | ||||
| 	 */ | ||||
| 	for (cv = cn->v; cv; cv = cv->next) { | ||||
| 		if (cv->type != CFG_STRING) { | ||||
| 			log_verbose("Devices array contains a value " | ||||
| 				    "which is not a string ... ignoring"); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!dm_hash_insert(pf->devices, cv->v.str, data)) | ||||
| 			log_verbose("Couldn't add '%s' to filter ... ignoring", | ||||
| 				    cv->v.str); | ||||
| 		/* Populate dev_cache ourselves */ | ||||
| 		dev_cache_get(cv->v.str, NULL); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
| 	struct config_tree *cft; | ||||
| 	struct stat info; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!stat(pf->file, &info)) | ||||
| 		pf->ctime = info.st_ctime; | ||||
| 	else { | ||||
| 		log_very_verbose("%s: stat failed: %s", pf->file, | ||||
| 				 strerror(errno)); | ||||
| 		return_0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(cft = create_config_tree(pf->file, 1))) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!read_config_file(cft)) | ||||
| 		goto_out; | ||||
|  | ||||
| 	_read_array(pf, cft, "persistent_filter_cache/valid_devices", | ||||
| 		    PF_GOOD_DEVICE); | ||||
| 	/* We don't gain anything by holding invalid devices */ | ||||
| 	/* _read_array(pf, cft, "persistent_filter_cache/invalid_devices", | ||||
| 	   PF_BAD_DEVICE); */ | ||||
|  | ||||
| 	/* Did we find anything? */ | ||||
| 	if (dm_hash_get_num_entries(pf->devices)) { | ||||
| 		/* We populated dev_cache ourselves */ | ||||
| 		dev_cache_scan(0); | ||||
| 		r = 1; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Loaded persistent filter cache from %s", pf->file); | ||||
|  | ||||
|       out: | ||||
| 	if (r && cft_out) | ||||
| 		*cft_out = cft; | ||||
| 	else | ||||
| 		destroy_config_tree(cft); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static void _write_array(struct pfilter *pf, FILE *fp, const char *path, | ||||
| 			 void *data) | ||||
| { | ||||
| 	void *d; | ||||
| 	int first = 1; | ||||
| 	char *buf, *str; | ||||
| 	struct dm_hash_node *n; | ||||
|  | ||||
| 	for (n = dm_hash_get_first(pf->devices); n; | ||||
| 	     n = dm_hash_get_next(pf->devices, n)) { | ||||
| 		d = dm_hash_get_data(pf->devices, n); | ||||
|  | ||||
| 		if (d != data) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!first) | ||||
| 			fprintf(fp, ",\n"); | ||||
| 		else { | ||||
| 			fprintf(fp, "\t%s=[\n", path); | ||||
| 			first = 0; | ||||
| 		} | ||||
|  | ||||
| 		str = dm_hash_get_key(pf->devices, n); | ||||
| 		if (!(buf = alloca(escaped_len(str)))) { | ||||
| 			log_error("persistent filter device path stack " | ||||
| 				  "allocation failed"); | ||||
| 			return; | ||||
| 		} | ||||
| 		fprintf(fp, "\t\t\"%s\"", escape_double_quotes(buf, str)); | ||||
| 	} | ||||
|  | ||||
| 	if (!first) | ||||
| 		fprintf(fp, "\n\t]\n"); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int persistent_filter_dump(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
| 	char *tmp_file; | ||||
| 	struct stat info, info2; | ||||
| 	struct config_tree *cft = NULL; | ||||
| 	FILE *fp; | ||||
| 	int lockfd; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!dm_hash_get_num_entries(pf->devices)) { | ||||
| 		log_very_verbose("Internal persistent device cache empty " | ||||
| 				 "- not writing to %s", pf->file); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (!dev_cache_has_scanned()) { | ||||
| 		log_very_verbose("Device cache incomplete - not writing " | ||||
| 				 "to %s", pf->file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Dumping persistent device cache to %s", pf->file); | ||||
|  | ||||
| 	while (1) { | ||||
| 		if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0) | ||||
| 			return_0; | ||||
|  | ||||
| 		/* | ||||
| 		 * Ensure we locked the file we expected | ||||
| 		 */ | ||||
| 		if (fstat(lockfd, &info)) { | ||||
| 			log_sys_error("fstat", pf->file); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		if (stat(pf->file, &info2)) { | ||||
| 			log_sys_error("stat", pf->file); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		if (is_same_inode(info, info2)) | ||||
| 			break; | ||||
| 	 | ||||
| 		fcntl_unlock_file(lockfd); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If file contents changed since we loaded it, merge new contents | ||||
| 	 */ | ||||
| 	if (info.st_ctime != pf->ctime) | ||||
| 		/* Keep cft open to avoid losing lock */ | ||||
| 		persistent_filter_load(f, &cft); | ||||
|  | ||||
| 	tmp_file = alloca(strlen(pf->file) + 5); | ||||
| 	sprintf(tmp_file, "%s.tmp", pf->file); | ||||
|  | ||||
| 	if (!(fp = fopen(tmp_file, "w"))) { | ||||
| 		/* EACCES has been reported over NFS */ | ||||
| 		if (errno != EROFS && errno != EACCES) | ||||
| 			log_sys_error("fopen", tmp_file); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	fprintf(fp, "# This file is automatically maintained by lvm.\n\n"); | ||||
| 	fprintf(fp, "persistent_filter_cache {\n"); | ||||
|  | ||||
| 	_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE); | ||||
| 	/* We don't gain anything by remembering invalid devices */ | ||||
| 	/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */ | ||||
|  | ||||
| 	fprintf(fp, "}\n"); | ||||
| 	if (lvm_fclose(fp, tmp_file)) | ||||
| 		goto_out; | ||||
|  | ||||
| 	if (rename(tmp_file, pf->file)) | ||||
| 		log_error("%s: rename to %s failed: %s", tmp_file, pf->file, | ||||
| 			  strerror(errno)); | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	fcntl_unlock_file(lockfd); | ||||
|  | ||||
| 	if (cft) | ||||
| 		destroy_config_tree(cft); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _lookup_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
| 	void *l = dm_hash_lookup(pf->devices, dev_name(dev)); | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	if (!l) { | ||||
| 		l = pf->real->passes_filter(pf->real, dev) ? | ||||
| 		    PF_GOOD_DEVICE : PF_BAD_DEVICE; | ||||
|  | ||||
| 		dm_list_iterate_items(sl, &dev->aliases) | ||||
| 			dm_hash_insert(pf->devices, sl->str, l); | ||||
|  | ||||
| 	} else if (l == PF_BAD_DEVICE) | ||||
| 			log_debug("%s: Skipping (cached)", dev_name(dev)); | ||||
|  | ||||
| 	return (l == PF_BAD_DEVICE) ? 0 : 1; | ||||
| } | ||||
|  | ||||
| static void _persistent_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	dm_hash_destroy(pf->devices); | ||||
| 	dm_free(pf->file); | ||||
| 	pf->real->destroy(pf->real); | ||||
| 	dm_free(pf); | ||||
| 	dm_free(f); | ||||
| } | ||||
|  | ||||
| struct dev_filter *persistent_filter_create(struct dev_filter *real, | ||||
| 					    const char *file) | ||||
| { | ||||
| 	struct pfilter *pf; | ||||
| 	struct dev_filter *f = NULL; | ||||
|  | ||||
| 	if (!(pf = dm_malloc(sizeof(*pf)))) | ||||
| 		return_NULL; | ||||
| 	memset(pf, 0, sizeof(*pf)); | ||||
|  | ||||
| 	if (!(pf->file = dm_malloc(strlen(file) + 1))) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	strcpy(pf->file, file); | ||||
| 	pf->real = real; | ||||
|  | ||||
| 	if (!(_init_hash(pf))) { | ||||
| 		log_error("Couldn't create hash table for persistent filter."); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(f = dm_malloc(sizeof(*f)))) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	f->passes_filter = _lookup_p; | ||||
| 	f->destroy = _persistent_destroy; | ||||
| 	f->private = pf; | ||||
|  | ||||
| 	return f; | ||||
|  | ||||
|       bad: | ||||
| 	dm_free(pf->file); | ||||
| 	if (pf->devices) | ||||
| 		dm_hash_destroy(pf->devices); | ||||
| 	dm_free(pf); | ||||
| 	dm_free(f); | ||||
| 	return NULL; | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/filters/filter-persistent.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/filters/filter-persistent.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_PERSISTENT_H | ||||
| #define _LVM_FILTER_PERSISTENT_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| struct dev_filter *persistent_filter_create(struct dev_filter *f, | ||||
| 					    const char *file); | ||||
|  | ||||
| int persistent_filter_wipe(struct dev_filter *f); | ||||
| int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out); | ||||
| int persistent_filter_dump(struct dev_filter *f); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										215
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "filter-regex.h" | ||||
| #include "device.h" | ||||
|  | ||||
| struct rfilter { | ||||
| 	struct dm_pool *mem; | ||||
| 	dm_bitset_t accept; | ||||
| 	struct dm_regex *engine; | ||||
| }; | ||||
|  | ||||
| static int _extract_pattern(struct dm_pool *mem, const char *pat, | ||||
| 			    char **regex, dm_bitset_t accept, int ix) | ||||
| { | ||||
| 	char sep, *r, *ptr; | ||||
|  | ||||
| 	/* | ||||
| 	 * is this an accept or reject pattern | ||||
| 	 */ | ||||
| 	switch (*pat) { | ||||
| 	case 'a': | ||||
| 		dm_bit_set(accept, ix); | ||||
| 		break; | ||||
|  | ||||
| 	case 'r': | ||||
| 		dm_bit_clear(accept, ix); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_info("pattern must begin with 'a' or 'r'"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	pat++; | ||||
|  | ||||
| 	/* | ||||
| 	 * get the separator | ||||
| 	 */ | ||||
| 	switch (*pat) { | ||||
| 	case '(': | ||||
| 		sep = ')'; | ||||
| 		break; | ||||
|  | ||||
| 	case '[': | ||||
| 		sep = ']'; | ||||
| 		break; | ||||
|  | ||||
| 	case '{': | ||||
| 		sep = '}'; | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		sep = *pat; | ||||
| 	} | ||||
| 	pat++; | ||||
|  | ||||
| 	/* | ||||
| 	 * copy the regex | ||||
| 	 */ | ||||
| 	if (!(r = dm_pool_strdup(mem, pat))) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* | ||||
| 	 * trim the trailing character, having checked it's sep. | ||||
| 	 */ | ||||
| 	ptr = r + strlen(r) - 1; | ||||
| 	if (*ptr != sep) { | ||||
| 		log_info("invalid separator at end of regex"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*ptr = '\0'; | ||||
|  | ||||
| 	regex[ix] = r; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _build_matcher(struct rfilter *rf, struct config_value *val) | ||||
| { | ||||
| 	struct dm_pool *scratch; | ||||
| 	struct config_value *v; | ||||
| 	char **regex; | ||||
| 	unsigned count = 0; | ||||
| 	int i, r = 0; | ||||
|  | ||||
| 	if (!(scratch = dm_pool_create("filter dm_regex", 1024))) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* | ||||
| 	 * count how many patterns we have. | ||||
| 	 */ | ||||
| 	for (v = val; v; v = v->next) { | ||||
| 		if (v->type != CFG_STRING) { | ||||
| 			log_error("filter patterns must be enclosed in quotes"); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		count++; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * allocate space for them | ||||
| 	 */ | ||||
| 	if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) | ||||
| 		goto_out; | ||||
|  | ||||
| 	/* | ||||
| 	 * create the accept/reject bitset | ||||
| 	 */ | ||||
| 	rf->accept = dm_bitset_create(rf->mem, count); | ||||
|  | ||||
| 	/* | ||||
| 	 * fill the array back to front because we | ||||
| 	 * want the opposite precedence to what | ||||
| 	 * the matcher gives. | ||||
| 	 */ | ||||
| 	for (v = val, i = count - 1; v; v = v->next, i--) | ||||
| 		if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) { | ||||
| 			log_error("invalid filter pattern"); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 	/* | ||||
| 	 * build the matcher. | ||||
| 	 */ | ||||
| 	if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex, | ||||
| 					   count))) | ||||
| 		stack; | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	dm_pool_destroy(scratch); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _accept_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	int m, first = 1, rejected = 0; | ||||
| 	struct rfilter *rf = (struct rfilter *) f->private; | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, &dev->aliases) { | ||||
| 		m = dm_regex_match(rf->engine, sl->str); | ||||
|  | ||||
| 		if (m >= 0) { | ||||
| 			if (dm_bit(rf->accept, m)) { | ||||
| 				if (!first) | ||||
| 					dev_set_preferred_name(sl, dev); | ||||
|  | ||||
| 				return 1; | ||||
| 			} | ||||
|  | ||||
| 			rejected = 1; | ||||
| 		} | ||||
|  | ||||
| 		first = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (rejected) | ||||
| 		log_debug("%s: Skipping (regex)", dev_name(dev)); | ||||
|  | ||||
| 	/* | ||||
| 	 * pass everything that doesn't match | ||||
| 	 * anything. | ||||
| 	 */ | ||||
| 	return !rejected; | ||||
| } | ||||
|  | ||||
| static void _regex_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct rfilter *rf = (struct rfilter *) f->private; | ||||
| 	dm_pool_destroy(rf->mem); | ||||
| } | ||||
|  | ||||
| struct dev_filter *regex_filter_create(struct config_value *patterns) | ||||
| { | ||||
| 	struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024); | ||||
| 	struct rfilter *rf; | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!mem) | ||||
| 		return_NULL; | ||||
|  | ||||
| 	if (!(rf = dm_pool_alloc(mem, sizeof(*rf)))) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	rf->mem = mem; | ||||
|  | ||||
| 	if (!_build_matcher(rf, patterns)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	f->passes_filter = _accept_p; | ||||
| 	f->destroy = _regex_destroy; | ||||
| 	f->private = rf; | ||||
| 	return f; | ||||
|  | ||||
|       bad: | ||||
| 	dm_pool_destroy(mem); | ||||
| 	return NULL; | ||||
| } | ||||
							
								
								
									
										32
									
								
								lib/filters/filter-regex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/filters/filter-regex.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_REGEX_H | ||||
| #define _LVM_FILTER_REGEX_H | ||||
|  | ||||
| #include "config.h" | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| /* | ||||
|  * patterns must be an array of strings of the form: | ||||
|  * [ra]<sep><regex><sep>, eg, | ||||
|  * r/cdrom/          - reject cdroms | ||||
|  * a|loop/[0-4]|     - accept loops 0 to 4 | ||||
|  * r|.*|             - reject everything else | ||||
|  */ | ||||
|  | ||||
| struct dev_filter *regex_filter_create(struct config_value *patterns); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										334
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,334 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "filter-sysfs.h" | ||||
| #include "lvm-string.h" | ||||
|  | ||||
| #ifdef linux | ||||
|  | ||||
| #include <dirent.h> | ||||
|  | ||||
| static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len, | ||||
| 				unsigned *sysfs_depth) | ||||
| { | ||||
| 	struct stat info; | ||||
|  | ||||
| 	/* | ||||
| 	 * unified classification directory for all kernel subsystems | ||||
| 	 * | ||||
| 	 * /sys/subsystem/block/devices | ||||
| 	 * |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda | ||||
| 	 * |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1 | ||||
| 	 *  `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0 | ||||
| 	 * | ||||
| 	 */ | ||||
| 	if (dm_snprintf(path, len, "%s/%s", sysfs_dir, | ||||
| 			"subsystem/block/devices") >= 0) { | ||||
| 		if (!stat(path, &info)) { | ||||
| 			*sysfs_depth = 0; | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * block subsystem as a class | ||||
| 	 * | ||||
| 	 * /sys/class/block | ||||
| 	 * |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda | ||||
| 	 * |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1 | ||||
| 	 *  `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0 | ||||
| 	 * | ||||
| 	 */ | ||||
| 	if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "class/block") >= 0) { | ||||
| 		if (!stat(path, &info)) { | ||||
| 			*sysfs_depth = 0; | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * old block subsystem layout with nested directories | ||||
| 	 * | ||||
| 	 * /sys/block/ | ||||
| 	 * |-- sda | ||||
| 	 * |   |-- capability | ||||
| 	 * |   |-- dev | ||||
| 	 * ... | ||||
| 	 * |   |-- sda1 | ||||
| 	 * |   |   |-- dev | ||||
| 	 * ... | ||||
| 	 * | | ||||
| 	 * `-- sr0 | ||||
| 	 *     |-- capability | ||||
| 	 *     |-- dev | ||||
| 	 * ... | ||||
| 	 * | ||||
| 	 */ | ||||
| 	if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "block") >= 0) { | ||||
| 		if (!stat(path, &info)) { | ||||
| 			*sysfs_depth = 1; | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*---------------------------------------------------------------- | ||||
|  * We need to store a set of dev_t. | ||||
|  *--------------------------------------------------------------*/ | ||||
| struct entry { | ||||
| 	struct entry *next; | ||||
| 	dev_t dev; | ||||
| }; | ||||
|  | ||||
| #define SET_BUCKETS 64 | ||||
| struct dev_set { | ||||
| 	struct dm_pool *mem; | ||||
| 	const char *sys_block; | ||||
| 	unsigned sysfs_depth; | ||||
| 	int initialised; | ||||
| 	struct entry *slots[SET_BUCKETS]; | ||||
| }; | ||||
|  | ||||
| static struct dev_set *_dev_set_create(struct dm_pool *mem, | ||||
| 				       const char *sys_block, | ||||
| 				       unsigned sysfs_depth) | ||||
| { | ||||
| 	struct dev_set *ds; | ||||
|  | ||||
| 	if (!(ds = dm_pool_zalloc(mem, sizeof(*ds)))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	ds->mem = mem; | ||||
| 	ds->sys_block = dm_pool_strdup(mem, sys_block); | ||||
| 	ds->sysfs_depth = sysfs_depth; | ||||
| 	ds->initialised = 0; | ||||
|  | ||||
| 	return ds; | ||||
| } | ||||
|  | ||||
| static unsigned _hash_dev(dev_t dev) | ||||
| { | ||||
| 	return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Doesn't check that the set already contains dev. | ||||
|  */ | ||||
| static int _set_insert(struct dev_set *ds, dev_t dev) | ||||
| { | ||||
| 	struct entry *e; | ||||
| 	unsigned h = _hash_dev(dev); | ||||
|  | ||||
| 	if (!(e = dm_pool_alloc(ds->mem, sizeof(*e)))) | ||||
| 		return 0; | ||||
|  | ||||
| 	e->next = ds->slots[h]; | ||||
| 	e->dev = dev; | ||||
| 	ds->slots[h] = e; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _set_lookup(struct dev_set *ds, dev_t dev) | ||||
| { | ||||
| 	unsigned h = _hash_dev(dev); | ||||
| 	struct entry *e; | ||||
|  | ||||
| 	for (e = ds->slots[h]; e; e = e->next) | ||||
| 		if (e->dev == dev) | ||||
| 			return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*---------------------------------------------------------------- | ||||
|  * filter methods | ||||
|  *--------------------------------------------------------------*/ | ||||
| static int _parse_dev(const char *file, FILE *fp, dev_t *result) | ||||
| { | ||||
| 	unsigned major, minor; | ||||
| 	char buffer[64]; | ||||
|  | ||||
| 	if (!fgets(buffer, sizeof(buffer), fp)) { | ||||
| 		log_error("Empty sysfs device file: %s", file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (sscanf(buffer, "%u:%u", &major, &minor) != 2) { | ||||
| 		log_info("sysfs device file not correct format"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*result = makedev(major, minor); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_dev(const char *file, dev_t *result) | ||||
| { | ||||
| 	int r; | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	if (!(fp = fopen(file, "r"))) { | ||||
| 		log_sys_error("fopen", file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	r = _parse_dev(file, fp, result); | ||||
|  | ||||
| 	if (fclose(fp)) | ||||
| 		log_sys_error("fclose", file); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Recurse through sysfs directories, inserting any devs found. | ||||
|  */ | ||||
| static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth) | ||||
| { | ||||
| 	struct dirent *d; | ||||
| 	DIR *dr; | ||||
| 	struct stat info; | ||||
| 	char path[PATH_MAX]; | ||||
| 	char file[PATH_MAX]; | ||||
| 	dev_t dev = { 0 }; | ||||
| 	int r = 1; | ||||
|  | ||||
| 	if (!(dr = opendir(dir))) { | ||||
| 		log_sys_error("opendir", dir); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while ((d = readdir(dr))) { | ||||
| 		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | ||||
| 			continue; | ||||
|  | ||||
| 		if (dm_snprintf(path, sizeof(path), "%s/%s", dir, | ||||
| 				 d->d_name) < 0) { | ||||
| 			log_error("sysfs path name too long: %s in %s", | ||||
| 				  d->d_name, dir); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* devices have a "dev" file */ | ||||
| 		if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) { | ||||
| 			log_error("sysfs path name too long: %s in %s", | ||||
| 				  d->d_name, dir); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!stat(file, &info)) { | ||||
| 			/* recurse if we found a device and expect subdirs */ | ||||
| 			if (sysfs_depth) | ||||
| 				_read_devs(ds, path, sysfs_depth - 1); | ||||
|  | ||||
| 			/* add the device we have found */ | ||||
| 			if (_read_dev(file, &dev)) | ||||
| 				_set_insert(ds, dev); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (closedir(dr)) | ||||
| 		log_sys_error("closedir", dir); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _init_devs(struct dev_set *ds) | ||||
| { | ||||
| 	if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) { | ||||
| 		ds->initialised = -1; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	ds->initialised = 1; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _accept_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	struct dev_set *ds = (struct dev_set *) f->private; | ||||
|  | ||||
| 	if (!ds->initialised) | ||||
| 		_init_devs(ds); | ||||
|  | ||||
| 	/* Pass through if initialisation failed */ | ||||
| 	if (ds->initialised != 1) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!_set_lookup(ds, dev->dev)) { | ||||
| 		log_debug("%s: Skipping (sysfs)", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} else | ||||
| 		return 1; | ||||
| } | ||||
|  | ||||
| static void _destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct dev_set *ds = (struct dev_set *) f->private; | ||||
| 	dm_pool_destroy(ds->mem); | ||||
| } | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *sysfs_dir) | ||||
| { | ||||
| 	char sys_block[PATH_MAX]; | ||||
| 	unsigned sysfs_depth; | ||||
| 	struct dm_pool *mem; | ||||
| 	struct dev_set *ds; | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!*sysfs_dir) { | ||||
| 		log_verbose("No proc filesystem found: skipping sysfs filter"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth)) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!(mem = dm_pool_create("sysfs", 256))) { | ||||
| 		log_error("sysfs pool creation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) { | ||||
| 		log_error("sysfs dev_set creation failed"); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	f->passes_filter = _accept_p; | ||||
| 	f->destroy = _destroy; | ||||
| 	f->private = ds; | ||||
| 	return f; | ||||
|  | ||||
|  bad: | ||||
| 	dm_pool_destroy(mem); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *sysfs_dir __attribute((unused))) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										23
									
								
								lib/filters/filter-sysfs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/filters/filter-sysfs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_SYSFS_H | ||||
| #define _LVM_FILTER_SYSFS_H | ||||
|  | ||||
| #include "config.h" | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *sysfs_dir); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										292
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,292 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "dev-cache.h" | ||||
| #include "filter.h" | ||||
| #include "lvm-string.h" | ||||
| #include "config.h" | ||||
| #include "metadata.h" | ||||
| #include "activate.h" | ||||
|  | ||||
| #include <dirent.h> | ||||
| #include <unistd.h> | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| #define NUMBER_OF_MAJORS 4096 | ||||
|  | ||||
| /* 0 means LVM won't use this major number. */ | ||||
| static int _max_partitions_by_major[NUMBER_OF_MAJORS]; | ||||
|  | ||||
| typedef struct { | ||||
| 	const char *name; | ||||
| 	const int max_partitions; | ||||
| } device_info_t; | ||||
|  | ||||
| static int _md_major = -1; | ||||
| static int _device_mapper_major = -1; | ||||
|  | ||||
| int md_major(void) | ||||
| { | ||||
| 	return _md_major; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Devices are only checked for partition tables if their minor number | ||||
|  * is a multiple of the number corresponding to their type below | ||||
|  * i.e. this gives the granularity of whole-device minor numbers. | ||||
|  * Use 1 if the device is not partitionable. | ||||
|  * | ||||
|  * The list can be supplemented with devices/types in the config file. | ||||
|  */ | ||||
| static const device_info_t device_info[] = { | ||||
| 	{"ide", 64},		/* IDE disk */ | ||||
| 	{"sd", 16},		/* SCSI disk */ | ||||
| 	{"md", 1},		/* Multiple Disk driver (SoftRAID) */ | ||||
| 	{"loop", 1},		/* Loop device */ | ||||
| 	{"dasd", 4},		/* DASD disk (IBM S/390, zSeries) */ | ||||
| 	{"dac960", 8},		/* DAC960 */ | ||||
| 	{"nbd", 16},		/* Network Block Device */ | ||||
| 	{"ida", 16},		/* Compaq SMART2 */ | ||||
| 	{"cciss", 16},		/* Compaq CCISS array */ | ||||
| 	{"ubd", 16},		/* User-mode virtual block device */ | ||||
| 	{"ataraid", 16},	/* ATA Raid */ | ||||
| 	{"drbd", 16},		/* Distributed Replicated Block Device */ | ||||
| 	{"emcpower", 16},	/* EMC Powerpath */ | ||||
| 	{"power2", 16},		/* EMC Powerpath */ | ||||
| 	{"i2o_block", 16},	/* i2o Block Disk */ | ||||
| 	{"iseries/vd", 8},	/* iSeries disks */ | ||||
| 	{"gnbd", 1},		/* Network block device */ | ||||
| 	{"ramdisk", 1},		/* RAM disk */ | ||||
| 	{"aoe", 16},		/* ATA over Ethernet */ | ||||
| 	{"device-mapper", 1},	/* Other mapped devices */ | ||||
| 	{"xvd", 16},		/* Xen virtual block device */ | ||||
| 	{"vdisk", 8},		/* SUN's LDOM virtual block device */ | ||||
| 	{"ps3disk", 16},	/* PlayStation 3 internal disk */ | ||||
| 	{"virtblk", 8},		/* VirtIO disk */ | ||||
| 	{NULL, 0} | ||||
| }; | ||||
|  | ||||
| static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute((unused)), | ||||
| 					  struct device *dev) | ||||
| { | ||||
| 	const char *name = dev_name(dev); | ||||
| 	int ret = 0; | ||||
| 	uint64_t size; | ||||
|  | ||||
| 	/* Is this a recognised device type? */ | ||||
| 	if (!_max_partitions_by_major[MAJOR(dev->dev)]) { | ||||
| 		log_debug("%s: Skipping: Unrecognised LVM device type %" | ||||
| 			  PRIu64, name, (uint64_t) MAJOR(dev->dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Skip suspended devices */ | ||||
| 	if (MAJOR(dev->dev) == _device_mapper_major && | ||||
| 	    ignore_suspended_devices() && !device_is_usable(dev->dev)) { | ||||
| 		log_debug("%s: Skipping: Suspended dm device", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Check it's accessible */ | ||||
| 	if (!dev_open_flags(dev, O_RDONLY, 0, 1)) { | ||||
| 		log_debug("%s: Skipping: open failed", name); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Check it's not too small */ | ||||
| 	if (!dev_get_size(dev, &size)) { | ||||
| 		log_debug("%s: Skipping: dev_get_size failed", name); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (size < PV_MIN_SIZE) { | ||||
| 		log_debug("%s: Skipping: Too small to hold a PV", name); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (is_partitioned_dev(dev)) { | ||||
| 		log_debug("%s: Skipping: Partition table signature found", | ||||
| 			  name); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	ret = 1; | ||||
|  | ||||
|       out: | ||||
| 	dev_close(dev); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int _scan_proc_dev(const char *proc, const struct config_node *cn) | ||||
| { | ||||
| 	char line[80]; | ||||
| 	char proc_devices[PATH_MAX]; | ||||
| 	FILE *pd = NULL; | ||||
| 	int i, j = 0; | ||||
| 	int line_maj = 0; | ||||
| 	int blocksection = 0; | ||||
| 	size_t dev_len = 0; | ||||
| 	struct config_value *cv; | ||||
| 	char *name; | ||||
|  | ||||
|  | ||||
| 	if (!*proc) { | ||||
| 		log_verbose("No proc filesystem found: using all block device " | ||||
| 			    "types"); | ||||
| 		for (i = 0; i < NUMBER_OF_MAJORS; i++) | ||||
| 			_max_partitions_by_major[i] = 1; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	/* All types unrecognised initially */ | ||||
| 	memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS); | ||||
|  | ||||
| 	if (dm_snprintf(proc_devices, sizeof(proc_devices), | ||||
| 			 "%s/devices", proc) < 0) { | ||||
| 		log_error("Failed to create /proc/devices string"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(pd = fopen(proc_devices, "r"))) { | ||||
| 		log_sys_error("fopen", proc_devices); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(line, 80, pd) != NULL) { | ||||
| 		i = 0; | ||||
| 		while (line[i] == ' ' && line[i] != '\0') | ||||
| 			i++; | ||||
|  | ||||
| 		/* If it's not a number it may be name of section */ | ||||
| 		line_maj = atoi(((char *) (line + i))); | ||||
| 		if (!line_maj) { | ||||
| 			blocksection = (line[i] == 'B') ? 1 : 0; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* We only want block devices ... */ | ||||
| 		if (!blocksection) | ||||
| 			continue; | ||||
|  | ||||
| 		/* Find the start of the device major name */ | ||||
| 		while (line[i] != ' ' && line[i] != '\0') | ||||
| 			i++; | ||||
| 		while (line[i] == ' ' && line[i] != '\0') | ||||
| 			i++; | ||||
|  | ||||
| 		/* Look for md device */ | ||||
| 		if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2))) | ||||
| 			_md_major = line_maj; | ||||
|  | ||||
| 		/* Look for device-mapper device */ | ||||
| 		/* FIXME Cope with multiple majors */ | ||||
| 		if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13))) | ||||
| 			_device_mapper_major = line_maj; | ||||
|  | ||||
| 		/* Go through the valid device names and if there is a | ||||
| 		   match store max number of partitions */ | ||||
| 		for (j = 0; device_info[j].name != NULL; j++) { | ||||
| 			dev_len = strlen(device_info[j].name); | ||||
| 			if (dev_len <= strlen(line + i) && | ||||
| 			    !strncmp(device_info[j].name, line + i, dev_len) && | ||||
| 			    (line_maj < NUMBER_OF_MAJORS)) { | ||||
| 				_max_partitions_by_major[line_maj] = | ||||
| 				    device_info[j].max_partitions; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (!cn) | ||||
| 			continue; | ||||
|  | ||||
| 		/* Check devices/types for local variations */ | ||||
| 		for (cv = cn->v; cv; cv = cv->next) { | ||||
| 			if (cv->type != CFG_STRING) { | ||||
| 				log_error("Expecting string in devices/types " | ||||
| 					  "in config file"); | ||||
| 				if (fclose(pd)) | ||||
| 					log_sys_error("fclose", proc_devices); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			dev_len = strlen(cv->v.str); | ||||
| 			name = cv->v.str; | ||||
| 			cv = cv->next; | ||||
| 			if (!cv || cv->type != CFG_INT) { | ||||
| 				log_error("Max partition count missing for %s " | ||||
| 					  "in devices/types in config file", | ||||
| 					  name); | ||||
| 				if (fclose(pd)) | ||||
| 					log_sys_error("fclose", proc_devices); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if (!cv->v.i) { | ||||
| 				log_error("Zero partition count invalid for " | ||||
| 					  "%s in devices/types in config file", | ||||
| 					  name); | ||||
| 				if (fclose(pd)) | ||||
| 					log_sys_error("fclose", proc_devices); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if (dev_len <= strlen(line + i) && | ||||
| 			    !strncmp(name, line + i, dev_len) && | ||||
| 			    (line_maj < NUMBER_OF_MAJORS)) { | ||||
| 				_max_partitions_by_major[line_maj] = cv->v.i; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (fclose(pd)) | ||||
| 		log_sys_error("fclose", proc_devices); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int max_partitions(int major) | ||||
| { | ||||
| 	return _max_partitions_by_major[major]; | ||||
| } | ||||
|  | ||||
| struct dev_filter *lvm_type_filter_create(const char *proc, | ||||
| 					  const struct config_node *cn) | ||||
| { | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!(f = dm_malloc(sizeof(struct dev_filter)))) { | ||||
| 		log_error("LVM type filter allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	f->passes_filter = _passes_lvm_type_device_filter; | ||||
| 	f->destroy = lvm_type_filter_destroy; | ||||
| 	f->private = NULL; | ||||
|  | ||||
| 	if (!_scan_proc_dev(proc, cn)) { | ||||
| 		dm_free(f); | ||||
| 		return_NULL; | ||||
| 	} | ||||
|  | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| void lvm_type_filter_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	dm_free(f); | ||||
| 	return; | ||||
| } | ||||
							
								
								
									
										41
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_FILTER_H | ||||
| #define _LVM_FILTER_H | ||||
|  | ||||
| #include "config.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #ifdef linux | ||||
| #  define MAJOR(dev)	((dev & 0xfff00) >> 8) | ||||
| #  define MINOR(dev)	((dev & 0xff) | ((dev >> 12) & 0xfff00)) | ||||
| #  define MKDEV(ma,mi)	((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12)) | ||||
| #else | ||||
| #  define MAJOR(x) major((x)) | ||||
| #  define MINOR(x) minor((x)) | ||||
| #  define MKDEV(x,y) makedev((x),(y)) | ||||
| #endif | ||||
|  | ||||
| struct dev_filter *lvm_type_filter_create(const char *proc, | ||||
| 					  const struct config_node *cn); | ||||
|  | ||||
| void lvm_type_filter_destroy(struct dev_filter *f); | ||||
|  | ||||
| int md_major(void); | ||||
| int max_partitions(int major); | ||||
|  | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user