mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-21 15:33:18 +03:00 
			
		
		
		
	Compare commits
	
		
			1413 Commits
		
	
	
		
			dev-mcsont
			...
			dm_v1_01_0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 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 | 
							
								
								
									
										0
									
								
								CONTRIBUTORS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								CONTRIBUTORS
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										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. | ||||
							
								
								
									
										483
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,483 @@ | ||||
|  | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 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. | ||||
|  | ||||
| [This is the first released version of the library GPL.  It is | ||||
|  numbered 2 because it goes with version 2 of the ordinary GPL.] | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| Licenses are intended to guarantee your freedom to share and change | ||||
| free software--to make sure the software is free for all its users. | ||||
|  | ||||
|   This license, the Library General Public License, applies to some | ||||
| specially designated Free Software Foundation software, and to any | ||||
| other libraries whose authors decide to use it.  You can use it for | ||||
| your libraries, too. | ||||
|  | ||||
|   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 library, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of the library, whether gratis | ||||
| or for a fee, you must give the recipients all the rights that we gave | ||||
| you.  You must make sure that they, too, receive or can get the source | ||||
| code.  If you link a program with the library, you must provide | ||||
| complete object files to the recipients so that they can relink them | ||||
| with the library, after making changes to the library and recompiling | ||||
| it.  And you must show them these terms so they know their rights. | ||||
|  | ||||
|   Our method of protecting your rights has two steps: (1) copyright | ||||
| the library, and (2) offer you this license which gives you legal | ||||
| permission to copy, distribute and/or modify the library. | ||||
|  | ||||
|   Also, for each distributor's protection, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| library.  If the library is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original | ||||
| version, so that any problems introduced by others will not reflect on | ||||
| the original authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that companies distributing free | ||||
| software will individually obtain patent licenses, thus in effect | ||||
| transforming the program into proprietary software.  To prevent this, | ||||
| we have made it clear that any patent must be licensed for everyone's | ||||
| free use or not licensed at all. | ||||
|  | ||||
|   Most GNU software, including some libraries, is covered by the ordinary | ||||
| GNU General Public License, which was designed for utility programs.  This | ||||
| license, the GNU Library General Public License, applies to certain | ||||
| designated libraries.  This license is quite different from the ordinary | ||||
| one; be sure to read it in full, and don't assume that anything in it is | ||||
| the same as in the ordinary license. | ||||
|  | ||||
|   The reason we have a separate public license for some libraries is that | ||||
| they blur the distinction we usually make between modifying or adding to a | ||||
| program and simply using it.  Linking a program with a library, without | ||||
| changing the library, is in some sense simply using the library, and is | ||||
| analogous to running a utility program or application program.  However, in | ||||
| a textual and legal sense, the linked executable is a combined work, a | ||||
| derivative of the original library, and the ordinary General Public License | ||||
| treats it as such. | ||||
|  | ||||
|   Because of this blurred distinction, using the ordinary General | ||||
| Public License for libraries did not effectively promote software | ||||
| sharing, because most developers did not use the libraries.  We | ||||
| concluded that weaker conditions might promote sharing better. | ||||
|  | ||||
|   However, unrestricted linking of non-free programs would deprive the | ||||
| users of those programs of all benefit from the free status of the | ||||
| libraries themselves.  This Library General Public License is intended to | ||||
| permit developers of non-free programs to use free libraries, while | ||||
| preserving your freedom as a user of such programs to change the free | ||||
| libraries that are incorporated in them.  (We have not seen how to achieve | ||||
| this as regards changes in header files, but we have achieved it as regards | ||||
| changes in the actual functions of the Library.)  The hope is that this | ||||
| will lead to faster development of free libraries. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow.  Pay close attention to the difference between a | ||||
| "work based on the library" and a "work that uses the library".  The | ||||
| former contains code derived from the library, while the latter only | ||||
| works together with the library. | ||||
|  | ||||
|   Note that it is possible for a library to be covered by the ordinary | ||||
| General Public License rather than by this special one. | ||||
|  | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License Agreement applies to any software library which | ||||
| contains a notice placed by the copyright holder or other authorized | ||||
| party saying it may be distributed under the terms of this Library | ||||
| General Public License (also called "this License").  Each licensee is | ||||
| addressed as "you". | ||||
|  | ||||
|   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 compile 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) Accompany the work with a written offer, valid for at | ||||
|     least three years, to give the same user the materials | ||||
|     specified in Subsection 6a, above, for a charge no more | ||||
|     than the cost of performing this distribution. | ||||
|  | ||||
|     c) If distribution of the work is made by offering access to copy | ||||
|     from a designated place, offer equivalent access to copy the above | ||||
|     specified materials from the same place. | ||||
|  | ||||
|     d) Verify that the user has already received a copy of these | ||||
|     materials or that you have already sent this user a copy. | ||||
|  | ||||
|   For an executable, the required form of the "work that uses the | ||||
| Library" must include any data and utility programs needed for | ||||
| reproducing the executable from it.  However, as a special exception, | ||||
| the source code distributed need not include anything that is normally | ||||
| distributed (in either source or binary form) with the major | ||||
| 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 to | ||||
| 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 Library 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 | ||||
|  | ||||
|      Appendix: 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 Library General Public | ||||
|     License as published by the Free Software Foundation; either | ||||
|     version 2 of the License, or (at your option) any later version. | ||||
|  | ||||
|     This library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|     Library General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Library General Public | ||||
|     License along with this library; if not, write to the Free | ||||
|     Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||||
|     MA 02111-1307, 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! | ||||
							
								
								
									
										45
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| LVM2 installation | ||||
| ================= | ||||
|  | ||||
| 1) Install device-mapper | ||||
|  | ||||
|    Ensure the device-mapper has been installed on the machine. | ||||
|  | ||||
|    The device-mapper should be in the kernel (look for 'device-mapper' | ||||
|    messages in the kernel logs) and /usr/include/libdevmapper.h  | ||||
|    and libdevmapper.so should be present. | ||||
|  | ||||
|    The device-mapper is available from: | ||||
|      ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
|  | ||||
| 2) Generate custom makefiles. | ||||
|  | ||||
|    Run the 'configure' script from the top directory. | ||||
|  | ||||
|    If you wish to use the built-in LVM2 shell and have GNU readline  | ||||
|    installed (http://www.gnu.org/directory/readline.html) use: | ||||
|      ./configure --enable-readline | ||||
|  | ||||
|    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 | ||||
|  | ||||
|  | ||||
| 3) Build and install LVM2. | ||||
|  | ||||
|    Run 'make install' from the top directory. | ||||
|  | ||||
|  | ||||
| 4) 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. | ||||
|    For example, specifying the devices that LVM2 is to use can | ||||
|    make the tools run more efficiently - and avoid scanning /dev/cdrom! | ||||
|  | ||||
| Please also refer to the WHATS_NEW file and the manual pages for the  | ||||
| individual commands. | ||||
|  | ||||
							
								
								
									
										52
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 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@ | ||||
|  | ||||
| SUBDIRS = doc include man  | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| SUBDIRS += lib tools daemons | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS += daemons/clvmd \ | ||||
| 	     lib/format1 \ | ||||
| 	     lib/format_pool \ | ||||
| 	     lib/locking \ | ||||
| 	     lib/mirror \ | ||||
| 	     lib/snapshot \ | ||||
| 	     po \ | ||||
| 	     test/mm test/device test/format1 test/regex test/filters | ||||
| endif | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| daemons: lib | ||||
| lib: include | ||||
| tools: lib | ||||
| po: tools daemons | ||||
|  | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										25
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README
									
									
									
									
									
								
							| @@ -1,2 +1,23 @@ | ||||
| This is pretty much empty so far...if you can't see subdirectories, | ||||
| try 'cvs -f update' | ||||
| This directory contains LVM2, the new version of the userland LVM | ||||
| tools designed for the new device-mapper for the Linux kernel. | ||||
|  | ||||
| The device-mapper needs to be installed before compiling these LVM2 tools. | ||||
|  | ||||
| For more information about LVM2 read 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/ | ||||
|   ftp://sources.redhat.com/pub/dm/ | ||||
|  | ||||
| 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 discussion/bug reports etc. | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
|   | ||||
							
								
								
									
										380
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| Version 2.01.00 -  | ||||
| ================================== | ||||
|   Fix vgscan metadata auto-correction. | ||||
|   Only ask libdevmapper for open_count when we need it. | ||||
|   Adjust RHEL4 clvmd init script priority. | ||||
|   Enable building of CMAN & GULM versions of clvmd into a single binary | ||||
|  | ||||
| Version 2.00.33 - 7th January 2005 | ||||
| ================================== | ||||
|   pvcreate wipes first 4 sectors unless given --zero n. | ||||
|   gulm clvmd now uses new ccsd key names. | ||||
|   gulm clvmd now doesn't ignore the first node in cluster.conf | ||||
|   Improve clvmd failure message if it's already running. | ||||
|   Allow user to kill clvmd during initialisation. | ||||
|   Fix off-by-one error in cluster_locking that could cause read hangs. | ||||
|  | ||||
| Version 2.00.32 - 22nd December 2004 | ||||
| ==================================== | ||||
|   Drop static/dl restriction for now. | ||||
|   Fix an error fprintf. | ||||
|   Fix vgdisplay -s. Breaks (undocumented) lvs/pvs/vgs -s instead for now. | ||||
|   Fix device reference counting on re-opens. | ||||
|   Ignore sysfs symlinks when DT_UNKNOWN. | ||||
|   Add clvmd init script for RHEL4. | ||||
|   Skip devices that are too small to be PVs. | ||||
|   Fix pvchange -x segfault with lvm2-format orphan. | ||||
|   Cope with empty msdos partition tables. | ||||
|   Add CONTRIBUTORS file. | ||||
|  | ||||
| Version 2.00.31 - 12th December 2004 | ||||
| ==================================== | ||||
|   Reopen RO file descriptors RW if necessary. | ||||
|  | ||||
| Version 2.00.30 - 10th December 2004 | ||||
| ==================================== | ||||
|   Additional device-handling debug messages. | ||||
|   Additional verbosity level -vvvv includes line numbers and backtraces. | ||||
|   Verbose messages now go to stderr not stdout. | ||||
|   Close any stray file descriptors before starting. | ||||
|   Refine partitionable checks for certain device types. | ||||
|   Allow devices/types to override built-ins. | ||||
|   Fix lvreduce man page .i->.I | ||||
|   Fix vgsplit man page title. | ||||
|   Fix clvmd man makefile. | ||||
|   Extend dev_open logging. | ||||
|   Make clvmd_fix_conf.sh UNDOable. | ||||
|  | ||||
| Version 2.00.29 - 27th November 2004 | ||||
| ==================================== | ||||
|   xlate compilation fix. | ||||
|  | ||||
| Version 2.00.28 - 27th November 2004 | ||||
| ==================================== | ||||
|   Fix partition table & md signature detection. | ||||
|   Minor configure/makefile tidy. | ||||
|   Export version.h from tools for clvmd. | ||||
|  | ||||
| Version 2.00.27 - 24th November 2004 | ||||
| ==================================== | ||||
|   Trap large memory allocation requests. | ||||
|   Fix to partition table detection code. | ||||
|   Improve filter debug mesgs. | ||||
|   Make clvmd_fix_conf.sh UNDOable | ||||
|  | ||||
| Version 2.00.26 - 23rd November 2004 | ||||
| ==================================== | ||||
|   Improve pool debugging stats. | ||||
|   Detect partition table signature. | ||||
|   pvcreate wipes md superblocks. (With --uuid or --restorefile it prompts.) | ||||
|   Separate out md superblock detection code. | ||||
|   Prevent snapshot origin resizing. | ||||
|   Improve a vgremove error message. | ||||
|   Update some man pages. | ||||
|   Allow y/n with -ae args (exclusive activation). | ||||
|   Fixes to lvcreate vgname parsing. | ||||
|   Fix dm_name string size calculation. | ||||
|   Improve clvmd error reporting during startup. | ||||
|   Make clvmd cope with large gaps in node numbers IDs. | ||||
|   Make clvmd initialisation cope better with debugging output. | ||||
|   Tidy clvmd socket callbacks so all work happens outside main loop. | ||||
|   clvmd -V now displays lvm version too. | ||||
|   Add optional gulm build for clvmd | ||||
|  | ||||
| Version 2.00.25 - 29th September 2004 | ||||
| ===================================== | ||||
|   Fix return code from rm_link for vgmknodes. | ||||
|   Make clvmd LV hash table thread-safe. | ||||
|   Fix clvmd locking so it will lock out multiple users on the same node. | ||||
|   Fix clvmd VG locking to it can cope with multiple VG locks. | ||||
|   Remove spurious trailing dot in lvreduce man page. | ||||
|   Fix vgremove locking. | ||||
|  | ||||
| Version 2.00.24 - 16th September 2004 | ||||
| ===================================== | ||||
|   Fix pool_empty so it really does empty the memory pool. | ||||
|   Rename old segtypes files to segtype. | ||||
|   Some fixes to memory debugging code. | ||||
|   Exclude internal commands formats & segtypes from install. | ||||
|  | ||||
| Version 2.00.23 - 15th September 2004 | ||||
| ===================================== | ||||
|   Export dm name build & split functions. | ||||
|   Use O_NOATIME on devices if available. | ||||
|   Write log message when each segtype/format gets initialised. | ||||
|   New commands 'segtypes' and 'formats'. | ||||
|   Suppress pvmove abort message in test mode. | ||||
|   Improve pvcreate/remove device not found error message. | ||||
|   Allow pvmove to move data within the same PV. | ||||
|   Describe how pvmove works on man page. | ||||
|   Test for incompatible format/segtype combinations in lv_extend. | ||||
|   Fix lvchange example on man page. | ||||
|  | ||||
| Version 2.00.22 - 3rd September 2004 | ||||
| ==================================== | ||||
|   Fix /dev/vgname perms. | ||||
|   Restructure xlate.h. | ||||
|   Add clvmd man page. | ||||
|  | ||||
| Version 2.00.21 - 19th August 2004 | ||||
| ================================== | ||||
|   Update cnxman-socket.h from cman. | ||||
|   Recognise iseries/vd devices. | ||||
|   Use 'make install_cluster' to install cluster extensions only. | ||||
|   Cope with DT_UNKNOWN in sysfs. | ||||
|   Fix extents_moved metadata size comment. | ||||
|   Remove duplicate line in pvremove help text. | ||||
|   Support variable mirror region size. | ||||
|   Support PE ranges in pvmove source PV. | ||||
|   Fixes to as-yet-unused LV segment splitting code. | ||||
|   Change alloc_areas to pe_ranges and allow suppression of availability checks. | ||||
|   Add dev_size column to pvs. | ||||
|   Add report columns for in-kernel device number. | ||||
|  | ||||
| Version 2.00.20 - 3 July 2004 | ||||
| ============================= | ||||
|   More autoconf fixes. | ||||
|   Fix device number handling for 2.6 kernels. | ||||
|  | ||||
| Version 2.00.19 - 29 June 2004 | ||||
| ============================== | ||||
|   Reduce severity of setlocale failure message. | ||||
|   Recognise argv[0] "initrd-lvm" (pld-linux). | ||||
|   Make -O2 configurable. | ||||
|   Added --disable-selinux to configure script. | ||||
|   LD_FLAGS->LDFLAGS & LD_DEPS->LDDEPS in configure script. | ||||
|   Add init_debug to clvmd. | ||||
|  | ||||
| Version 2.00.18 - 24 June 2004 | ||||
| ============================== | ||||
|   Fix vgchange activation. | ||||
|   Add cluster support. | ||||
|  | ||||
| Version 2.00.17 - 20 June 2004 | ||||
| ============================== | ||||
|   configure --enable-fsadm to try out fsadm.  fsadm is not tested yet. | ||||
|   Display all filtered devices, not just PVs, with pvs -a. | ||||
|   Fix sync_dir() when no / in filename | ||||
|   vgcfgbackup -f accepts template with %s for VG name. | ||||
|   Extend hash functions to handle non-null-terminated data. | ||||
|   Add local activation support. | ||||
|   Tidy relative paths in makefile includes. | ||||
|   fsadm support for fsck and resizing - needs testing. | ||||
|   Add read-only GFS pool support. | ||||
|   Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/ | ||||
|   Fix rounding of large diplayed sizes. | ||||
|   Suppress decimal point when using units of sectors/bytes. | ||||
|   Additional kernel target checks before pvmove & snapshot creation. | ||||
|   Add i2o_block. | ||||
|  | ||||
| Version 2.00.16 - 24 May 2004 | ||||
| ============================= | ||||
|   Set area_count within alloc_lv_segment. | ||||
|   Remove error labels from lvresize. | ||||
|   Fix a pvs error path. | ||||
|   xxchange -ae for exclusive activation. | ||||
|   Don't return non-zero status if there aren't any volume groups. | ||||
|   Add --alloc argument to tools. | ||||
|   Rename allocation policies to contiguous, normal, anywhere, inherit. | ||||
|   nextfree becomes normal; anywhere isn't implemented yet. | ||||
|   LV inherits allocation policy from VG. Defaults: LV - inherit; VG - normal | ||||
|   Additional status character added to vgs to indicate allocation policy. | ||||
|   Add reset_fn to external_locking. | ||||
|   Ensure presence of virtual targets before attempting activating. | ||||
|   Attempt to fix resizing of snapshot origins. | ||||
|   Restructure lvresize, bringing it closer to lvcreate. | ||||
|   A quick sanity check on vg_disk struct when read in.  More checks needed. | ||||
|   Only include visible LVs in active/open counts. | ||||
|   Add virtual segment types, zero and error.  A large sparse device can be | ||||
| constructed as a writeable snapshot of a large zero segment. | ||||
|   Add --type to lvcreate/resize. | ||||
|   Push lv_create & alloc policy up to tool level. | ||||
|   Fix pvdisplay return code. | ||||
|   Detect invalid LV names in arg lists. | ||||
|   Reporting uses line-at-a-time output. | ||||
|   lvm2 format sets unlimited_vols format flag. | ||||
|   Internal-only metadata flag support. | ||||
|   Basic checking for presence of device-mapper targets. | ||||
|   Separate out polldaemon. | ||||
|   Revise internal locking semantics. | ||||
|   Move find_pv_by_name to library. | ||||
|   Rename move->copy. | ||||
|   Add devices to segments report. | ||||
|   Begin separating out segment code. There's a lot of change here. | ||||
|   Compress any (obsolete) long LVM1 pvids encountered. | ||||
|   Support for tagged config files. | ||||
|   Don't abort operations if selinux present but disabled. | ||||
|   Fix typo in configure which left HAVE_LIBDL unset. | ||||
|  | ||||
| Version 2.00.15 - 19 Apr 2004 | ||||
| ============================= | ||||
|   configure --with-owner= --with-group= to avoid -o and -g args to 'install' | ||||
|  | ||||
| Version 2.00.14 - 16 Apr 2004 | ||||
| ============================= | ||||
|   Use 64-bit file functions by default. | ||||
|  | ||||
| Version 2.00.13 - 16 Apr 2004 | ||||
| ============================= | ||||
|   Set devices/md_component_detection = 1 to ignore devices containing md | ||||
|   superblocks. [Luca Berra] | ||||
|   Ignore error setting selinux file context if fs doesn't support it. | ||||
|  | ||||
| Version 2.00.12 - 14 Apr 2004 | ||||
| ============================= | ||||
|   Install a default lvm.conf into /etc/lvm if there isn't one already. | ||||
|   Allow different installation dir for lvm.static (configure --staticdir=) | ||||
|   Fix inverted selinux error check. | ||||
|   Recognise power2 in /proc/devices. | ||||
|   Fix counting in lvs_in_vg_opened. [It ignored devices open more than once.] | ||||
|  | ||||
| Version 2.00.11 - 8 Apr 2004 | ||||
| ============================ | ||||
|   Set fallback_to_lvm1 in lvm.conf (or configure --enable-lvm1_fallback) | ||||
|   to run lvm1 binaries if running a 2.4 kernel without device-mapper. | ||||
|  | ||||
| Version 2.00.10 - 7 Apr 2004 | ||||
| ============================ | ||||
|   More fixes for static build. | ||||
|   Add basic selinux support. | ||||
|   Fix sysfs detection. | ||||
|  | ||||
| Version 2.00.09 - 31 Mar 2004 | ||||
| ============================= | ||||
|   Update copyright notices for Red Hat. | ||||
|   Fix vgmknodes to remove dud /dev/mapper entries. (libdevmapper update reqd). | ||||
|   Add LVM1-style colon output to vgdisplay. | ||||
|   lvchange --refresh to reload active LVs. | ||||
|   Add string display to memory leak dump. | ||||
|   Add locking flags & memlock option. | ||||
|   Add list_versions to library. | ||||
|   Ignore open hidden LVs when checking if deactivation is OK. | ||||
|   Suppress move percentage when device inactive. | ||||
|   Add lv_info_by_lvid. | ||||
|   Various tidy-ups to the build process. | ||||
|   Rebaseline internal verbose level. | ||||
|   Add --nolocking option for read operations if locking is failing. | ||||
|   Add option to compile into a library. | ||||
|   When compiled without libdevmapper, only print warning message once. | ||||
|   Fix lvreduce PV extent calculations. | ||||
|   Fix DESTDIR to work with configure path overrides. | ||||
|   Always use / as config file separator & rename internal config file variables. | ||||
|   Add support for tagging PV/VG/LVs and hosts. | ||||
|   Fix rare bug in recognition of long cmdline argument forms. | ||||
|   Add basic internationalisation infrastructure. | ||||
|   Don't recurse symlinked dirs such as /dev/fd on 2.6 kernels. | ||||
|   Update autoconf files. | ||||
|   Add sysfs block device filtering for 2.6 kernels. | ||||
|   Update refs for move to sources.redhat.com. | ||||
|  | ||||
| Friday 14th November 2003 | ||||
| ========================= | ||||
| Some bug fixes & minor enhancements, including: | ||||
|   Backwards compatibility with LVM1 metadata improved. | ||||
|   Missing man pages written. | ||||
|   Tool error codes made more consistent. | ||||
|   vgmknodes written. | ||||
|   O_DIRECT can be turned off if it doesn't work in your kernel. | ||||
|   dumpconfig to display the active configuration file | ||||
|  | ||||
| You need to update libdevmapper before using 'vgmknodes' or 'vgscan --mknodes'. | ||||
| If your root filesystem is on an LV, you should run one of those two | ||||
| commands to fix up the special files in /dev in your real root filesystem  | ||||
| after finishing with your initrd.  Also, remember you can use | ||||
| 'vgchange --ignorelockingfailure' on your initrd if the tool fails because | ||||
| it can't write a lock file to a read-only filesystem. | ||||
|  | ||||
| Wednesday 30th April 2003 | ||||
| ========================= | ||||
| A pvmove implementation is now available for the new metadata format. | ||||
|  | ||||
| When running a command that allocates space (e.g. lvcreate), you can now | ||||
| restrict not only which disk(s) may be used but also the Physical Extents  | ||||
| on those disks.  e.g. lvcreate -L 10 vg1 /dev/hda6:1000-2000:3000-4000 | ||||
|  | ||||
|  | ||||
| Monday 18th November 2002 | ||||
| ======================== | ||||
|  | ||||
| The new format of LVM metadata is ready for you to test! | ||||
|   We expect it to be more efficient and more robust than the original format. | ||||
|   It's more compact and supports transactional changes and replication. | ||||
|   Should things go wrong on a system, it's human-readable (and editable). | ||||
|  | ||||
| Please report any problems you find to the mailing list,  | ||||
| linux-lvm@sistina.com.  The software has NOT yet been thoroughly | ||||
| tested and so quite possibly there'll still be some bugs in it. | ||||
| Be aware of the disclaimer in the COPYING file. | ||||
|  | ||||
| While testing, we recommend turning logging on in the configuration file  | ||||
| to provide us with diagnostic information: | ||||
|   log { | ||||
|         file="/tmp/lvm2.log" | ||||
| 	level=7 | ||||
| 	activation=1 | ||||
|   } | ||||
|  | ||||
| You should schedule regular backups of your configuration file and | ||||
| metadata backups and archives (normally kept under /etc/lvm). | ||||
|  | ||||
| Please read docs/example.conf and "man lvm.conf" to find out more about  | ||||
| the configuration file. | ||||
|  | ||||
| To convert an existing volume group called vg1 to the new format using | ||||
| the default settings, use "vgconvert -M2 vg1".  See "man vgconvert". | ||||
|  | ||||
| -M (or --metadatatype in its long form) is a new flag to indicate which | ||||
| format of metadata the command should use for anything it creates. | ||||
| Currently, the valid types are "lvm1" and "lvm2" and they can be | ||||
| abbreviated to "1" and "2" respectively.  The default value for this | ||||
| flag can be changed in the global section in the config file. | ||||
|  | ||||
| Backwards-compatible support for the original LVM1 metadata format is | ||||
| maintained, but it can be moved into a shared library or removed | ||||
| completely with configure's --with-lvm1 option. | ||||
|  | ||||
| Under LVM2, the basic unit of metadata is the volume group.  Different | ||||
| volume groups can use different formats of metadata - vg1 could use | ||||
| the original LVM1 format while vg2 used the new format - but you can't | ||||
| mix formats within a volume group.  So to add a PV to an LVM2-format | ||||
| volume group you must run "pvcreate -M2" on it, followed by "vgextend". | ||||
|  | ||||
| With LVM2-format metadata, lvextend will let you specify striping | ||||
| parameters.  So an LV could consist of two or more "segments" - the | ||||
| first segment could have 3 stripes while the second segment has just 2. | ||||
|  | ||||
| LVM2 maintains a backup of the current metadata for each volume group | ||||
| in /etc/lvm/backup, and puts copies of previous versions in | ||||
| /etc/lvm/archive.  "vgcfgbackup" and "vgcfgrestore" can be used to | ||||
| create and restore from these files.  If you fully understand what  | ||||
| you're doing, metadata can be changed by editing a copy of a current | ||||
| backup file and using vgcfgrestore to reload it. | ||||
|  | ||||
| Please read the pvcreate man page for more information on the new | ||||
| format for metadata. | ||||
|  | ||||
| All tools that can change things have a --test flag which can be used | ||||
| to check the effect  of a set of cmdline args without really making the | ||||
| changes. | ||||
|  | ||||
|  | ||||
| What's not finished? | ||||
| ==================== | ||||
| The internal cache.  If you turn on debugging output you'll see lots of | ||||
| repeated messages, many of which will eventually get optimised out. | ||||
|  | ||||
| --test sometimes causes a command to fail (e.g. vgconvert --test) even  | ||||
| though the real command would work: again, fixing this is waiting for  | ||||
| the work on the cache. | ||||
|  | ||||
| Several of the tools do not yet contain the logic to handle full | ||||
| recovery: combinations of pvcreate and vgcfgrestore may sometimes be | ||||
| needed to restore metadata if a tool gets interrupted or crashes or | ||||
| finds something unexpected.  This applies particularly to tools that | ||||
| work on more than one volume group at once (e.g. vgsplit). | ||||
|  | ||||
| Display output.  Some metadata information cannot yet be displayed. | ||||
|  | ||||
| Recovery tools to salvage "lost" metadata directly from the disks: | ||||
| but we hope the new format will mean such tools are hardly ever needed! | ||||
|  | ||||
							
								
								
									
										90
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| 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. | ||||
|  | ||||
							
								
								
									
										1082
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1082
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										560
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										560
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,10 @@ | ||||
| #! /bin/sh | ||||
| # Configuration validation subroutine script, version 1.1. | ||||
| #   Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. | ||||
| # Configuration validation subroutine script. | ||||
| #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | ||||
| #   2000, 2001, 2002, 2003 Free Software Foundation, Inc. | ||||
|  | ||||
| timestamp='2003-06-17' | ||||
|  | ||||
| # This file is (in principle) common to ALL GNU software. | ||||
| # The presence of a machine in this file suggests that SOME GNU software | ||||
| # can handle that machine.  It does not imply ALL GNU software can. | ||||
| @@ -25,6 +29,9 @@ | ||||
| # configuration script generated by Autoconf, you may include it under | ||||
| # the same distribution terms that you use for the rest of that program. | ||||
|  | ||||
| # Please send patches to <config-patches@gnu.org>.  Submit a context | ||||
| # diff and a properly formatted ChangeLog entry. | ||||
| # | ||||
| # Configuration subroutine to validate and canonicalize a configuration type. | ||||
| # Supply the specified configuration type as an argument. | ||||
| # If it is invalid, we print an error message on stderr and exit with code 1. | ||||
| @@ -45,30 +52,73 @@ | ||||
| #	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM | ||||
| # It is wrong to echo any other type of specification. | ||||
|  | ||||
| if [ x$1 = x ] | ||||
| then | ||||
| 	echo Configuration name missing. 1>&2 | ||||
| 	echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 | ||||
| 	echo "or     $0 ALIAS" 1>&2 | ||||
| 	echo where ALIAS is a recognized configuration type. 1>&2 | ||||
| 	exit 1 | ||||
| fi | ||||
| me=`echo "$0" | sed -e 's,.*/,,'` | ||||
|  | ||||
| # First pass through any local machine types. | ||||
| case $1 in | ||||
| 	*local*) | ||||
| 		echo $1 | ||||
| 		exit 0 | ||||
| 		;; | ||||
| 	*) | ||||
| 	;; | ||||
| usage="\ | ||||
| Usage: $0 [OPTION] CPU-MFR-OPSYS | ||||
|        $0 [OPTION] ALIAS | ||||
|  | ||||
| Canonicalize a configuration name. | ||||
|  | ||||
| Operation modes: | ||||
|   -h, --help         print this help, then exit | ||||
|   -t, --time-stamp   print date of last modification, then exit | ||||
|   -v, --version      print version number, then exit | ||||
|  | ||||
| Report bugs and patches to <config-patches@gnu.org>." | ||||
|  | ||||
| version="\ | ||||
| GNU config.sub ($timestamp) | ||||
|  | ||||
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 | ||||
| Free Software Foundation, Inc. | ||||
|  | ||||
| This is free software; see the source for copying conditions.  There is NO | ||||
| warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | ||||
|  | ||||
| help=" | ||||
| Try \`$me --help' for more information." | ||||
|  | ||||
| # Parse command line | ||||
| while test $# -gt 0 ; do | ||||
|   case $1 in | ||||
|     --time-stamp | --time* | -t ) | ||||
|        echo "$timestamp" ; exit 0 ;; | ||||
|     --version | -v ) | ||||
|        echo "$version" ; exit 0 ;; | ||||
|     --help | --h* | -h ) | ||||
|        echo "$usage"; exit 0 ;; | ||||
|     -- )     # Stop option processing | ||||
|        shift; break ;; | ||||
|     - )	# Use stdin as input. | ||||
|        break ;; | ||||
|     -* ) | ||||
|        echo "$me: invalid option $1$help" | ||||
|        exit 1 ;; | ||||
|  | ||||
|     *local*) | ||||
|        # First pass through any local machine types. | ||||
|        echo $1 | ||||
|        exit 0;; | ||||
|  | ||||
|     * ) | ||||
|        break ;; | ||||
|   esac | ||||
| done | ||||
|  | ||||
| case $# in | ||||
|  0) echo "$me: missing argument$help" >&2 | ||||
|     exit 1;; | ||||
|  1) ;; | ||||
|  *) echo "$me: too many arguments$help" >&2 | ||||
|     exit 1;; | ||||
| esac | ||||
|  | ||||
| # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). | ||||
| # Here we must recognize all the valid KERNEL-OS combinations. | ||||
| maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | ||||
| case $maybe_os in | ||||
|   linux-gnu*) | ||||
|   nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) | ||||
|     os=-$maybe_os | ||||
|     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` | ||||
|     ;; | ||||
| @@ -94,7 +144,7 @@ case $os in | ||||
| 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ | ||||
| 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ | ||||
| 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ | ||||
| 	-apple) | ||||
| 	-apple | -axis) | ||||
| 		os= | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
| @@ -105,9 +155,17 @@ case $os in | ||||
| 	-scout) | ||||
| 		;; | ||||
| 	-wrs) | ||||
| 		os=vxworks | ||||
| 		os=-vxworks | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
| 	-chorusos*) | ||||
| 		os=-chorusos | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
|  	-chorusrdb) | ||||
|  		os=-chorusrdb | ||||
| 		basic_machine=$1 | ||||
|  		;; | ||||
| 	-hiux*) | ||||
| 		os=-hiuxwe2 | ||||
| 		;; | ||||
| @@ -156,33 +214,72 @@ case $os in | ||||
| 	-psos*) | ||||
| 		os=-psos | ||||
| 		;; | ||||
| 	-mint | -mint[0-9]*) | ||||
| 		basic_machine=m68k-atari | ||||
| 		os=-mint | ||||
| 		;; | ||||
| esac | ||||
|  | ||||
| # Decode aliases for certain CPU-COMPANY combinations. | ||||
| case $basic_machine in | ||||
| 	# Recognize the basic CPU types without company name. | ||||
| 	# Some are omitted here because they have special meanings below. | ||||
| 	tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ | ||||
| 		| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ | ||||
| 		| 580 | i960 | h8300 \ | ||||
| 		| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ | ||||
| 		| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \ | ||||
| 		| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ | ||||
| 		| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ | ||||
| 		| mips64orion | mips64orionel | mipstx39 | mipstx39el \ | ||||
| 		| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ | ||||
| 		| mips64vr5000 | miprs64vr5000el | mcore \ | ||||
| 		| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ | ||||
| 		| thumb | d10v) | ||||
| 	1750a | 580 \ | ||||
| 	| a29k \ | ||||
| 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | ||||
| 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | ||||
| 	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | ||||
| 	| c4x | clipper \ | ||||
| 	| d10v | d30v | dlx | dsp16xx \ | ||||
| 	| fr30 | frv \ | ||||
| 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | ||||
| 	| i370 | i860 | i960 | ia64 \ | ||||
| 	| ip2k \ | ||||
| 	| m32r | m68000 | m68k | m88k | mcore \ | ||||
| 	| mips | mipsbe | mipseb | mipsel | mipsle \ | ||||
| 	| mips16 \ | ||||
| 	| mips64 | mips64el \ | ||||
| 	| mips64vr | mips64vrel \ | ||||
| 	| mips64orion | mips64orionel \ | ||||
| 	| mips64vr4100 | mips64vr4100el \ | ||||
| 	| mips64vr4300 | mips64vr4300el \ | ||||
| 	| mips64vr5000 | mips64vr5000el \ | ||||
| 	| mipsisa32 | mipsisa32el \ | ||||
| 	| mipsisa32r2 | mipsisa32r2el \ | ||||
| 	| mipsisa64 | mipsisa64el \ | ||||
| 	| mipsisa64sb1 | mipsisa64sb1el \ | ||||
| 	| mipsisa64sr71k | mipsisa64sr71kel \ | ||||
| 	| mipstx39 | mipstx39el \ | ||||
| 	| mn10200 | mn10300 \ | ||||
| 	| msp430 \ | ||||
| 	| ns16k | ns32k \ | ||||
| 	| openrisc | or32 \ | ||||
| 	| pdp10 | pdp11 | pj | pjl \ | ||||
| 	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | ||||
| 	| pyramid \ | ||||
| 	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | ||||
| 	| sh64 | sh64le \ | ||||
| 	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | ||||
| 	| strongarm \ | ||||
| 	| tahoe | thumb | tic4x | tic80 | tron \ | ||||
| 	| v850 | v850e \ | ||||
| 	| we32k \ | ||||
| 	| x86 | xscale | xstormy16 | xtensa \ | ||||
| 	| z8k) | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		;; | ||||
| 	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65) | ||||
| 	m6811 | m68hc11 | m6812 | m68hc12) | ||||
| 		# Motorola 68HC11/12. | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		os=-none | ||||
| 		;; | ||||
| 	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) | ||||
| 		;; | ||||
|  | ||||
| 	# We use `pc' rather than `unknown' | ||||
| 	# because (1) that's what they normally are, and | ||||
| 	# (2) the word "unknown" tends to confuse beginning users. | ||||
| 	i[34567]86) | ||||
| 	i*86 | x86_64) | ||||
| 	  basic_machine=$basic_machine-pc | ||||
| 	  ;; | ||||
| 	# Object if more than one company name word. | ||||
| @@ -191,24 +288,60 @@ case $basic_machine in | ||||
| 		exit 1 | ||||
| 		;; | ||||
| 	# Recognize the basic CPU types with company name. | ||||
| 	# FIXME: clean up the formatting here. | ||||
| 	vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ | ||||
| 	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ | ||||
| 	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ | ||||
| 	      | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ | ||||
| 	      | xmp-* | ymp-* \ | ||||
| 	      | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ | ||||
| 	      | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \ | ||||
| 	      | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | ||||
| 	      | clipper-* | orion-* \ | ||||
| 	      | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ | ||||
| 	      | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ | ||||
| 	      | mips64el-* | mips64orion-* | mips64orionel-* \ | ||||
| 	      | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ | ||||
| 	      | mipstx39-* | mipstx39el-* | mcore-* \ | ||||
| 	      | f301-* | armv*-* | t3e-* \ | ||||
| 	      | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ | ||||
| 	      | thumb-* | v850-* | d30v-* | tic30-* | c30-* ) | ||||
| 	580-* \ | ||||
| 	| a29k-* \ | ||||
| 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | ||||
| 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | ||||
| 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | ||||
| 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \ | ||||
| 	| avr-* \ | ||||
| 	| bs2000-* \ | ||||
| 	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | ||||
| 	| clipper-* | cydra-* \ | ||||
| 	| d10v-* | d30v-* | dlx-* \ | ||||
| 	| elxsi-* \ | ||||
| 	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | ||||
| 	| h8300-* | h8500-* \ | ||||
| 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | ||||
| 	| i*86-* | i860-* | i960-* | ia64-* \ | ||||
| 	| ip2k-* \ | ||||
| 	| m32r-* \ | ||||
| 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | ||||
| 	| m88110-* | m88k-* | mcore-* \ | ||||
| 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | ||||
| 	| mips16-* \ | ||||
| 	| mips64-* | mips64el-* \ | ||||
| 	| mips64vr-* | mips64vrel-* \ | ||||
| 	| mips64orion-* | mips64orionel-* \ | ||||
| 	| mips64vr4100-* | mips64vr4100el-* \ | ||||
| 	| mips64vr4300-* | mips64vr4300el-* \ | ||||
| 	| mips64vr5000-* | mips64vr5000el-* \ | ||||
| 	| mipsisa32-* | mipsisa32el-* \ | ||||
| 	| mipsisa32r2-* | mipsisa32r2el-* \ | ||||
| 	| mipsisa64-* | mipsisa64el-* \ | ||||
| 	| mipsisa64sb1-* | mipsisa64sb1el-* \ | ||||
| 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \ | ||||
| 	| mipstx39-* | mipstx39el-* \ | ||||
| 	| msp430-* \ | ||||
| 	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | ||||
| 	| orion-* \ | ||||
| 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | ||||
| 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | ||||
| 	| pyramid-* \ | ||||
| 	| romp-* | rs6000-* \ | ||||
| 	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | ||||
| 	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | ||||
| 	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | ||||
| 	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | ||||
| 	| tahoe-* | thumb-* \ | ||||
| 	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | ||||
| 	| tron-* \ | ||||
| 	| v850-* | v850e-* | vax-* \ | ||||
| 	| we32k-* \ | ||||
| 	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | ||||
| 	| xtensa-* \ | ||||
| 	| ymp-* \ | ||||
| 	| z8k-*) | ||||
| 		;; | ||||
| 	# Recognize the various machine names and aliases which stand | ||||
| 	# for a CPU type and a company and sometimes even an OS. | ||||
| @@ -240,19 +373,22 @@ case $basic_machine in | ||||
| 		basic_machine=a29k-none | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| 	amd64) | ||||
| 		basic_machine=x86_64-pc | ||||
| 		;; | ||||
| 	amdahl) | ||||
| 		basic_machine=580-amdahl | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	amiga | amiga-*) | ||||
| 		basic_machine=m68k-cbm | ||||
| 		basic_machine=m68k-unknown | ||||
| 		;; | ||||
| 	amigaos | amigados) | ||||
| 		basic_machine=m68k-cbm | ||||
| 		basic_machine=m68k-unknown | ||||
| 		os=-amigaos | ||||
| 		;; | ||||
| 	amigaunix | amix) | ||||
| 		basic_machine=m68k-cbm | ||||
| 		basic_machine=m68k-unknown | ||||
| 		os=-sysv4 | ||||
| 		;; | ||||
| 	apollo68) | ||||
| @@ -271,6 +407,10 @@ case $basic_machine in | ||||
| 		basic_machine=ns32k-sequent | ||||
| 		os=-dynix | ||||
| 		;; | ||||
| 	c90) | ||||
| 		basic_machine=c90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	convex-c1) | ||||
| 		basic_machine=c1-convex | ||||
| 		os=-bsd | ||||
| @@ -291,27 +431,30 @@ case $basic_machine in | ||||
| 		basic_machine=c38-convex | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| 	cray | ymp) | ||||
| 		basic_machine=ymp-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	cray2) | ||||
| 		basic_machine=cray2-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	[ctj]90-cray) | ||||
| 		basic_machine=c90-cray | ||||
| 	cray | j90) | ||||
| 		basic_machine=j90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	crds | unos) | ||||
| 		basic_machine=m68k-crds | ||||
| 		;; | ||||
| 	cris | cris-* | etrax*) | ||||
| 		basic_machine=cris-axis | ||||
| 		;; | ||||
| 	da30 | da30-*) | ||||
| 		basic_machine=m68k-da30 | ||||
| 		;; | ||||
| 	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) | ||||
| 		basic_machine=mips-dec | ||||
| 		;; | ||||
| 	decsystem10* | dec10*) | ||||
| 		basic_machine=pdp10-dec | ||||
| 		os=-tops10 | ||||
| 		;; | ||||
| 	decsystem20* | dec20*) | ||||
| 		basic_machine=pdp10-dec | ||||
| 		os=-tops20 | ||||
| 		;; | ||||
| 	delta | 3300 | motorola-3300 | motorola-delta \ | ||||
| 	      | 3300-motorola | delta-motorola) | ||||
| 		basic_machine=m68k-motorola | ||||
| @@ -353,6 +496,10 @@ case $basic_machine in | ||||
| 		basic_machine=tron-gmicro | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	go32) | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-go32 | ||||
| 		;; | ||||
| 	h3050r* | hiux*) | ||||
| 		basic_machine=hppa1.1-hitachi | ||||
| 		os=-hiuxwe2 | ||||
| @@ -426,22 +573,21 @@ case $basic_machine in | ||||
| 		;; | ||||
| 	i370-ibm* | ibm*) | ||||
| 		basic_machine=i370-ibm | ||||
| 		os=-mvs | ||||
| 		;; | ||||
| # I'm not sure what "Sysv32" means.  Should this be sysv3.2? | ||||
| 	i[34567]86v32) | ||||
| 	i*86v32) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | ||||
| 		os=-sysv32 | ||||
| 		;; | ||||
| 	i[34567]86v4*) | ||||
| 	i*86v4*) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | ||||
| 		os=-sysv4 | ||||
| 		;; | ||||
| 	i[34567]86v) | ||||
| 	i*86v) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	i[34567]86sol2) | ||||
| 	i*86sol2) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | ||||
| 		os=-solaris2 | ||||
| 		;; | ||||
| @@ -453,14 +599,6 @@ case $basic_machine in | ||||
| 		basic_machine=i386-unknown | ||||
| 		os=-vsta | ||||
| 		;; | ||||
| 	i386-go32 | go32) | ||||
| 		basic_machine=i386-unknown | ||||
| 		os=-go32 | ||||
| 		;; | ||||
| 	i386-mingw32 | mingw32) | ||||
| 		basic_machine=i386-unknown | ||||
| 		os=-mingw32 | ||||
| 		;; | ||||
| 	iris | iris4d) | ||||
| 		basic_machine=mips-sgi | ||||
| 		case $os in | ||||
| @@ -486,35 +624,43 @@ case $basic_machine in | ||||
| 		basic_machine=ns32k-utek | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	mingw32) | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-mingw32 | ||||
| 		;; | ||||
| 	miniframe) | ||||
| 		basic_machine=m68000-convergent | ||||
| 		;; | ||||
| 	*mint | *MiNT) | ||||
| 	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) | ||||
| 		basic_machine=m68k-atari | ||||
| 		os=-mint | ||||
| 		;; | ||||
| 	mipsel*-linux*) | ||||
| 		basic_machine=mipsel-unknown | ||||
| 		os=-linux-gnu | ||||
| 		;; | ||||
| 	mips*-linux*) | ||||
| 		basic_machine=mips-unknown | ||||
| 		os=-linux-gnu | ||||
| 		;; | ||||
| 	mips3*-*) | ||||
| 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` | ||||
| 		;; | ||||
| 	mips3*) | ||||
| 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown | ||||
| 		;; | ||||
| 	mmix*) | ||||
| 		basic_machine=mmix-knuth | ||||
| 		os=-mmixware | ||||
| 		;; | ||||
| 	monitor) | ||||
| 		basic_machine=m68k-rom68k | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	morphos) | ||||
| 		basic_machine=powerpc-unknown | ||||
| 		os=-morphos | ||||
| 		;; | ||||
| 	msdos) | ||||
| 		basic_machine=i386-unknown | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-msdos | ||||
| 		;; | ||||
| 	mvs) | ||||
| 		basic_machine=i370-ibm | ||||
| 		os=-mvs | ||||
| 		;; | ||||
| 	ncr3000) | ||||
| 		basic_machine=i486-ncr | ||||
| 		os=-sysv4 | ||||
| @@ -524,7 +670,7 @@ case $basic_machine in | ||||
| 		os=-netbsd | ||||
| 		;; | ||||
| 	netwinder) | ||||
| 		basic_machine=armv4l-corel | ||||
| 		basic_machine=armv4l-rebel | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	news | news700 | news800 | news900) | ||||
| @@ -572,13 +718,28 @@ case $basic_machine in | ||||
| 		basic_machine=i960-intel | ||||
| 		os=-mon960 | ||||
| 		;; | ||||
| 	nonstopux) | ||||
| 		basic_machine=mips-compaq | ||||
| 		os=-nonstopux | ||||
| 		;; | ||||
| 	np1) | ||||
| 		basic_machine=np1-gould | ||||
| 		;; | ||||
| 	nv1) | ||||
| 		basic_machine=nv1-cray | ||||
| 		os=-unicosmp | ||||
| 		;; | ||||
| 	nsr-tandem) | ||||
| 		basic_machine=nsr-tandem | ||||
| 		;; | ||||
| 	op50n-* | op60c-*) | ||||
| 		basic_machine=hppa1.1-oki | ||||
| 		os=-proelf | ||||
| 		;; | ||||
| 	or32 | or32-*) | ||||
| 		basic_machine=or32-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	OSE68000 | ose68000) | ||||
| 		basic_machine=m68000-ericsson | ||||
| 		os=-ose | ||||
| @@ -601,45 +762,65 @@ case $basic_machine in | ||||
| 	pbb) | ||||
| 		basic_machine=m68k-tti | ||||
| 		;; | ||||
|         pc532 | pc532-*) | ||||
| 	pc532 | pc532-*) | ||||
| 		basic_machine=ns32k-pc532 | ||||
| 		;; | ||||
| 	pentium | p5 | k5 | k6 | nexen) | ||||
| 	pentium | p5 | k5 | k6 | nexgen | viac3) | ||||
| 		basic_machine=i586-pc | ||||
| 		;; | ||||
| 	pentiumpro | p6 | 6x86) | ||||
| 	pentiumpro | p6 | 6x86 | athlon | athlon_*) | ||||
| 		basic_machine=i686-pc | ||||
| 		;; | ||||
| 	pentiumii | pentium2) | ||||
| 	pentiumii | pentium2 | pentiumiii | pentium3) | ||||
| 		basic_machine=i686-pc | ||||
| 		;; | ||||
| 	pentium4) | ||||
| 		basic_machine=i786-pc | ||||
| 		;; | ||||
| 	pentium-* | p5-* | k5-* | k6-* | nexen-*) | ||||
| 	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) | ||||
| 		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	pentiumpro-* | p6-* | 6x86-*) | ||||
| 	pentiumpro-* | p6-* | 6x86-* | athlon-*) | ||||
| 		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	pentiumii-* | pentium2-*) | ||||
| 	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) | ||||
| 		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	pentium4-*) | ||||
| 		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	pn) | ||||
| 		basic_machine=pn-gould | ||||
| 		;; | ||||
| 	power)	basic_machine=rs6000-ibm | ||||
| 	power)	basic_machine=power-ibm | ||||
| 		;; | ||||
| 	ppc)	basic_machine=powerpc-unknown | ||||
| 	        ;; | ||||
| 		;; | ||||
| 	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	ppcle | powerpclittle | ppc-le | powerpc-little) | ||||
| 		basic_machine=powerpcle-unknown | ||||
| 	        ;; | ||||
| 		;; | ||||
| 	ppcle-* | powerpclittle-*) | ||||
| 		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	ppc64)	basic_machine=powerpc64-unknown | ||||
| 		;; | ||||
| 	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	ppc64le | powerpc64little | ppc64-le | powerpc64-little) | ||||
| 		basic_machine=powerpc64le-unknown | ||||
| 		;; | ||||
| 	ppc64le-* | powerpc64little-*) | ||||
| 		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	ps2) | ||||
| 		basic_machine=i386-ibm | ||||
| 		;; | ||||
| 	pw32) | ||||
| 		basic_machine=i586-unknown | ||||
| 		os=-pw32 | ||||
| 		;; | ||||
| 	rom68k) | ||||
| 		basic_machine=m68k-rom68k | ||||
| 		os=-coff | ||||
| @@ -650,10 +831,26 @@ case $basic_machine in | ||||
| 	rtpc | rtpc-*) | ||||
| 		basic_machine=romp-ibm | ||||
| 		;; | ||||
| 	s390 | s390-*) | ||||
| 		basic_machine=s390-ibm | ||||
| 		;; | ||||
| 	s390x | s390x-*) | ||||
| 		basic_machine=s390x-ibm | ||||
| 		;; | ||||
| 	sa29200) | ||||
| 		basic_machine=a29k-amd | ||||
| 		os=-udi | ||||
| 		;; | ||||
| 	sb1) | ||||
| 		basic_machine=mipsisa64sb1-unknown | ||||
| 		;; | ||||
| 	sb1el) | ||||
| 		basic_machine=mipsisa64sb1el-unknown | ||||
| 		;; | ||||
| 	sei) | ||||
| 		basic_machine=mips-sei | ||||
| 		os=-seiux | ||||
| 		;; | ||||
| 	sequent) | ||||
| 		basic_machine=i386-sequent | ||||
| 		;; | ||||
| @@ -661,7 +858,10 @@ case $basic_machine in | ||||
| 		basic_machine=sh-hitachi | ||||
| 		os=-hms | ||||
| 		;; | ||||
| 	sparclite-wrs) | ||||
| 	sh64) | ||||
| 		basic_machine=sh64-unknown | ||||
| 		;; | ||||
| 	sparclite-wrs | simso-wrs) | ||||
| 		basic_machine=sparclite-wrs | ||||
| 		os=-vxworks | ||||
| 		;; | ||||
| @@ -719,20 +919,44 @@ case $basic_machine in | ||||
| 	sun386 | sun386i | roadrunner) | ||||
| 		basic_machine=i386-sun | ||||
| 		;; | ||||
| 	sv1) | ||||
| 		basic_machine=sv1-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	symmetry) | ||||
| 		basic_machine=i386-sequent | ||||
| 		os=-dynix | ||||
| 		;; | ||||
| 	t3e) | ||||
| 		basic_machine=t3e-cray | ||||
| 		basic_machine=alphaev5-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	t90) | ||||
| 		basic_machine=t90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	tic54x | c54x*) | ||||
| 		basic_machine=tic54x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic55x | c55x*) | ||||
| 		basic_machine=tic55x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic6x | c6x*) | ||||
| 		basic_machine=tic6x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tx39) | ||||
| 		basic_machine=mipstx39-unknown | ||||
| 		;; | ||||
| 	tx39el) | ||||
| 		basic_machine=mipstx39el-unknown | ||||
| 		;; | ||||
| 	toad1) | ||||
| 		basic_machine=pdp10-xkl | ||||
| 		os=-tops20 | ||||
| 		;; | ||||
| 	tower | tower-32) | ||||
| 		basic_machine=m68k-ncr | ||||
| 		;; | ||||
| @@ -757,8 +981,8 @@ case $basic_machine in | ||||
| 		os=-vms | ||||
| 		;; | ||||
| 	vpp*|vx|vx-*) | ||||
|                basic_machine=f301-fujitsu | ||||
|                ;; | ||||
| 		basic_machine=f301-fujitsu | ||||
| 		;; | ||||
| 	vxworks960) | ||||
| 		basic_machine=i960-wrs | ||||
| 		os=-vxworks | ||||
| @@ -779,13 +1003,13 @@ case $basic_machine in | ||||
| 		basic_machine=hppa1.1-winbond | ||||
| 		os=-proelf | ||||
| 		;; | ||||
| 	xmp) | ||||
| 		basic_machine=xmp-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
|         xps | xps100) | ||||
| 	xps | xps100) | ||||
| 		basic_machine=xps100-honeywell | ||||
| 		;; | ||||
| 	ymp) | ||||
| 		basic_machine=ymp-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	z8k-*-coff) | ||||
| 		basic_machine=z8k-unknown | ||||
| 		os=-sim | ||||
| @@ -806,13 +1030,6 @@ case $basic_machine in | ||||
| 	op60c) | ||||
| 		basic_machine=hppa1.1-oki | ||||
| 		;; | ||||
| 	mips) | ||||
| 		if [ x$os = x-linux-gnu ]; then | ||||
| 			basic_machine=mips-unknown | ||||
| 		else | ||||
| 			basic_machine=mips-mips | ||||
| 		fi | ||||
| 		;; | ||||
| 	romp) | ||||
| 		basic_machine=romp-ibm | ||||
| 		;; | ||||
| @@ -822,16 +1039,26 @@ case $basic_machine in | ||||
| 	vax) | ||||
| 		basic_machine=vax-dec | ||||
| 		;; | ||||
| 	pdp10) | ||||
| 		# there are many clones, so DEC is not a safe bet | ||||
| 		basic_machine=pdp10-unknown | ||||
| 		;; | ||||
| 	pdp11) | ||||
| 		basic_machine=pdp11-dec | ||||
| 		;; | ||||
| 	we32k) | ||||
| 		basic_machine=we32k-att | ||||
| 		;; | ||||
| 	sparc | sparcv9) | ||||
| 	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) | ||||
| 		basic_machine=sh-unknown | ||||
| 		;; | ||||
| 	sh64) | ||||
| 		basic_machine=sh64-unknown | ||||
| 		;; | ||||
| 	sparc | sparcv9 | sparcv9b) | ||||
| 		basic_machine=sparc-sun | ||||
| 		;; | ||||
|         cydra) | ||||
| 	cydra) | ||||
| 		basic_machine=cydra-cydrome | ||||
| 		;; | ||||
| 	orion) | ||||
| @@ -846,9 +1073,8 @@ case $basic_machine in | ||||
| 	pmac | pmac-mpw) | ||||
| 		basic_machine=powerpc-apple | ||||
| 		;; | ||||
| 	c4x*) | ||||
| 		basic_machine=c4x-none | ||||
| 		os=-coff | ||||
| 	*-unknown) | ||||
| 		# Make sure to match an already-canonicalized machine name. | ||||
| 		;; | ||||
| 	*) | ||||
| 		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 | ||||
| @@ -906,14 +1132,34 @@ case $os in | ||||
| 	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | ||||
| 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | ||||
| 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | ||||
| 	      | -chorusos* | -chorusrdb* \ | ||||
| 	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | ||||
| 	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | ||||
| 	      | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*) | ||||
| 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | ||||
| 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | ||||
| 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | ||||
| 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | ||||
| 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | ||||
| 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) | ||||
| 	# Remember, each alternative MUST END IN *, to match a version number. | ||||
| 		;; | ||||
| 	-qnx*) | ||||
| 		case $basic_machine in | ||||
| 		    x86-* | i*86-*) | ||||
| 			;; | ||||
| 		    *) | ||||
| 			os=-nto$os | ||||
| 			;; | ||||
| 		esac | ||||
| 		;; | ||||
| 	-nto-qnx*) | ||||
| 		;; | ||||
| 	-nto*) | ||||
| 		os=`echo $os | sed -e 's|nto|nto-qnx|'` | ||||
| 		;; | ||||
| 	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | ||||
| 	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | ||||
| 	      | -macos* | -mpw* | -magic* | -mon960* | -lnews*) | ||||
| 	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) | ||||
| 		;; | ||||
| 	-mac*) | ||||
| 		os=`echo $os | sed -e 's|mac|macos|'` | ||||
| @@ -927,6 +1173,12 @@ case $os in | ||||
| 	-sunos6*) | ||||
| 		os=`echo $os | sed -e 's|sunos6|solaris3|'` | ||||
| 		;; | ||||
| 	-opened*) | ||||
| 		os=-openedition | ||||
| 		;; | ||||
| 	-wince*) | ||||
| 		os=-wince | ||||
| 		;; | ||||
| 	-osfrose*) | ||||
| 		os=-osfrose | ||||
| 		;; | ||||
| @@ -942,14 +1194,23 @@ case $os in | ||||
| 	-acis*) | ||||
| 		os=-aos | ||||
| 		;; | ||||
| 	-atheos*) | ||||
| 		os=-atheos | ||||
| 		;; | ||||
| 	-386bsd) | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| 	-ctix* | -uts*) | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	-nova*) | ||||
| 		os=-rtmk-nova | ||||
| 		;; | ||||
| 	-ns2 ) | ||||
| 	        os=-nextstep2 | ||||
| 		os=-nextstep2 | ||||
| 		;; | ||||
| 	-nsk*) | ||||
| 		os=-nsk | ||||
| 		;; | ||||
| 	# Preserve the version number of sinix5. | ||||
| 	-sinix5.*) | ||||
| @@ -985,8 +1246,14 @@ case $os in | ||||
| 	-xenix) | ||||
| 		os=-xenix | ||||
| 		;; | ||||
|         -*mint | -*MiNT) | ||||
| 	        os=-mint | ||||
| 	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) | ||||
| 		os=-mint | ||||
| 		;; | ||||
| 	-aros*) | ||||
| 		os=-aros | ||||
| 		;; | ||||
| 	-kaos*) | ||||
| 		os=-kaos | ||||
| 		;; | ||||
| 	-none) | ||||
| 		;; | ||||
| @@ -1013,13 +1280,20 @@ case $basic_machine in | ||||
| 	*-acorn) | ||||
| 		os=-riscix1.2 | ||||
| 		;; | ||||
| 	arm*-corel) | ||||
| 	arm*-rebel) | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	arm*-semi) | ||||
| 		os=-aout | ||||
| 		;; | ||||
|         pdp11-*) | ||||
|     c4x-* | tic4x-*) | ||||
|         os=-coff | ||||
|         ;; | ||||
| 	# This must come before the *-dec entry. | ||||
| 	pdp10-*) | ||||
| 		os=-tops20 | ||||
| 		;; | ||||
| 	pdp11-*) | ||||
| 		os=-none | ||||
| 		;; | ||||
| 	*-dec | vax-*) | ||||
| @@ -1046,6 +1320,9 @@ case $basic_machine in | ||||
| 	mips*-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	or32-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	*-tti)	# must be before sparc entry or we get the wrong os. | ||||
| 		os=-sysv3 | ||||
| 		;; | ||||
| @@ -1109,25 +1386,25 @@ case $basic_machine in | ||||
| 	*-next) | ||||
| 		os=-nextstep3 | ||||
| 		;; | ||||
|         *-gould) | ||||
| 	*-gould) | ||||
| 		os=-sysv | ||||
| 		;; | ||||
|         *-highlevel) | ||||
| 	*-highlevel) | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| 	*-encore) | ||||
| 		os=-bsd | ||||
| 		;; | ||||
|         *-sgi) | ||||
| 	*-sgi) | ||||
| 		os=-irix | ||||
| 		;; | ||||
|         *-siemens) | ||||
| 	*-siemens) | ||||
| 		os=-sysv4 | ||||
| 		;; | ||||
| 	*-masscomp) | ||||
| 		os=-rtu | ||||
| 		;; | ||||
| 	f301-fujitsu) | ||||
| 	f30[01]-fujitsu | f700-fujitsu) | ||||
| 		os=-uxpv | ||||
| 		;; | ||||
| 	*-rom68k) | ||||
| @@ -1187,13 +1464,13 @@ case $basic_machine in | ||||
| 			-genix*) | ||||
| 				vendor=ns | ||||
| 				;; | ||||
| 			-mvs*) | ||||
| 			-mvs* | -opened*) | ||||
| 				vendor=ibm | ||||
| 				;; | ||||
| 			-ptx*) | ||||
| 				vendor=sequent | ||||
| 				;; | ||||
| 			-vxsim* | -vxworks*) | ||||
| 			-vxsim* | -vxworks* | -windiss*) | ||||
| 				vendor=wrs | ||||
| 				;; | ||||
| 			-aux*) | ||||
| @@ -1205,12 +1482,23 @@ case $basic_machine in | ||||
| 			-mpw* | -macos*) | ||||
| 				vendor=apple | ||||
| 				;; | ||||
| 			-*mint | -*MiNT) | ||||
| 			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) | ||||
| 				vendor=atari | ||||
| 				;; | ||||
| 			-vos*) | ||||
| 				vendor=stratus | ||||
| 				;; | ||||
| 		esac | ||||
| 		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` | ||||
| 		;; | ||||
| esac | ||||
|  | ||||
| echo $basic_machine$os | ||||
| exit 0 | ||||
|  | ||||
| # Local variables: | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
| # time-stamp-start: "timestamp='" | ||||
| # time-stamp-format: "%:y-%02m-%02d" | ||||
| # time-stamp-end: "'" | ||||
| # End: | ||||
|   | ||||
| @@ -1,19 +1,38 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # install - install a program, script, or datafile | ||||
| # This comes from X11R5 (mit/util/scripts/install.sh). | ||||
|  | ||||
| scriptversion=2003-06-13.21 | ||||
|  | ||||
| # 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 | ||||
| @@ -23,13 +42,11 @@ | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
|  | ||||
|  | ||||
| # set DOITPROG to echo to test this script | ||||
|  | ||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||
| doit="${DOITPROG-}" | ||||
|  | ||||
|  | ||||
| # put in absolute paths if you don't have them in your path; or use env. vars. | ||||
|  | ||||
| mvprog="${MVPROG-mv}" | ||||
| @@ -41,211 +58,229 @@ stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| transformbasename="" | ||||
| transform_arg="" | ||||
| transformbasename= | ||||
| transform_arg= | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd="" | ||||
| chgrpcmd="" | ||||
| stripcmd="" | ||||
| chowncmd= | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
| rmcmd="$rmprog -f" | ||||
| mvcmd="$mvprog" | ||||
| src="" | ||||
| dst="" | ||||
| dir_arg="" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
|  | ||||
| while [ x"$1" != x ]; do | ||||
|     case $1 in | ||||
| 	-c) instcmd="$cpprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| usage="Usage: $0 [OPTION]... SRCFILE DSTFILE | ||||
|    or: $0 -d DIR1 DIR2... | ||||
|  | ||||
| 	-d) dir_arg=true | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. | ||||
| In the second, create the directory path DIR. | ||||
|  | ||||
| 	-m) chmodcmd="$chmodprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| Options: | ||||
| -b=TRANSFORMBASENAME | ||||
| -c         copy source (using $cpprog) instead of moving (using $mvprog). | ||||
| -d         create directories instead of installing files. | ||||
| -g GROUP   $chgrp installed files to GROUP. | ||||
| -m MODE    $chmod installed files to MODE. | ||||
| -o USER    $chown installed files to USER. | ||||
| -s         strip installed files (using $stripprog). | ||||
| -t=TRANSFORM | ||||
| --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 -n "$1"; do | ||||
|   case $1 in | ||||
|     -b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-s) stripcmd="$stripprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -c) instcmd=$cpprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -d) dir_arg=true | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -g) chgrpcmd="$chgrpprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	*)  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 | ||||
|     --help) echo "$usage"; exit 0;; | ||||
|  | ||||
|     -m) chmodcmd="$chmodprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -o) chowncmd="$chownprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -s) stripcmd=$stripprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     --version) echo "$0 $scriptversion"; exit 0;; | ||||
|  | ||||
|     *)  if test -z "$src"; then | ||||
|           src=$1 | ||||
|         else | ||||
|           # this colon is to work around a 386BSD /bin/sh bug | ||||
|           : | ||||
|           dst=$1 | ||||
|         fi | ||||
|         shift | ||||
|         continue;; | ||||
|   esac | ||||
| done | ||||
|  | ||||
| if [ x"$src" = x ] | ||||
| then | ||||
| 	echo "install:	no input file specified" | ||||
| 	exit 1 | ||||
| else | ||||
| 	true | ||||
| if test -z "$src"; then | ||||
|   echo "$0: no input file specified." >&2 | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ]; then | ||||
| 	dst=$src | ||||
| 	src="" | ||||
| 	 | ||||
| 	if [ -d $dst ]; then | ||||
| 		instcmd=: | ||||
| 		chmodcmd="" | ||||
| 	else | ||||
| 		instcmd=mkdir | ||||
| 	fi | ||||
| if test -n "$dir_arg"; then | ||||
|   dst=$src | ||||
|   src= | ||||
|  | ||||
|   if test -d "$dst"; then | ||||
|     instcmd=: | ||||
|     chmodcmd= | ||||
|   else | ||||
|     instcmd=$mkdirprog | ||||
|   fi | ||||
| else | ||||
|   # 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 test ! -f "$src" && test ! -d "$src"; then | ||||
|     echo "$0: $src does not exist." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
| # 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 test -z "$dst"; then | ||||
|     echo "$0: no destination specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
| 	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 | ||||
|   # If destination is a directory, append the input filename; won't work | ||||
|   # if double slashes aren't ignored. | ||||
|   if test -d "$dst"; then | ||||
|     dst=$dst/`basename "$src"` | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| ## this sed command emulates the dirname command | ||||
| dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | ||||
| 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 | ||||
| # (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}}" | ||||
| if test ! -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}" | ||||
|   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='' | ||||
|   pathcomp= | ||||
|  | ||||
| while [ $# -ne 0 ] ; do | ||||
| 	pathcomp="${pathcomp}${1}" | ||||
| 	shift | ||||
|  | ||||
| 	if [ ! -d "${pathcomp}" ] ; | ||||
|         then | ||||
| 		$mkdirprog "${pathcomp}" | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| 	pathcomp="${pathcomp}/" | ||||
| done | ||||
|   while test $# -ne 0 ; do | ||||
|     pathcomp=$pathcomp$1 | ||||
|     shift | ||||
|     test -d "$pathcomp" || $mkdirprog "$pathcomp" | ||||
|     pathcomp=$pathcomp/ | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ] | ||||
| then | ||||
| 	$doit $instcmd $dst && | ||||
| if test -n "$dir_arg"; then | ||||
|   $doit $instcmd "$dst" \ | ||||
|     && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ | ||||
|     && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ | ||||
|     && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ | ||||
|     && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } | ||||
|  | ||||
| 	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 we're going to rename the final executable, determine the name now. | ||||
|   if test -z "$transformarg"; then | ||||
|     dstfile=`basename "$dst"` | ||||
|   else | ||||
|     dstfile=`basename "$dst" $transformbasename \ | ||||
|              | sed $transformarg`$transformbasename | ||||
|   fi | ||||
|  | ||||
| # If we're going to rename the final executable, determine the name now. | ||||
|   # don't allow the sed command to completely eliminate the filename. | ||||
|   test -z "$dstfile" && dstfile=`basename "$dst"` | ||||
|  | ||||
| 	if [ x"$transformarg" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	else | ||||
| 		dstfile=`basename $dst $transformbasename |  | ||||
| 			sed $transformarg`$transformbasename | ||||
| 	fi | ||||
|   # Make a couple of temp file names in the proper directory. | ||||
|   dsttmp=$dstdir/_inst.$$_ | ||||
|   rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
| # don't allow the sed command to completely eliminate the filename | ||||
|   # Trap to clean up those temp files at exit. | ||||
|   trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
| 	if [ x"$dstfile" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|   # Move or copy the file name to the temp name | ||||
|   $doit $instcmd "$src" "$dsttmp" && | ||||
|  | ||||
| # Make a temp file name in the proper directory. | ||||
|   # 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 $instcmd $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 "$dsttmp"; } && | ||||
|  | ||||
| 	dsttmp=$dstdir/#inst.$$# | ||||
|  | ||||
| # Move or copy the file name to the temp name | ||||
|  | ||||
| 	$doit $instcmd $src $dsttmp && | ||||
|  | ||||
| 	trap "rm -f ${dsttmp}" 0 && | ||||
|  | ||||
| # 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 $instcmd $src $dsttmp" command. | ||||
|  | ||||
| 	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 rename the file to the real destination. | ||||
|  | ||||
| 	$doit $rmcmd -f $dstdir/$dstfile && | ||||
| 	$doit $mvcmd $dsttmp $dstdir/$dstfile  | ||||
|   # 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 "$dstdir/$dstfile"; then | ||||
|       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ | ||||
|       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ | ||||
|       || { | ||||
| 	  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 | ||||
| 	  (exit 1); exit | ||||
|       } | ||||
|     else | ||||
|       : | ||||
|     fi | ||||
|   } && | ||||
|  | ||||
|   # Now rename the file to the real destination. | ||||
|   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" | ||||
| fi && | ||||
|  | ||||
| # The final little trick to "correctly" pass the exit status to the exit trap. | ||||
| { | ||||
|   (exit 0); exit | ||||
| } | ||||
|  | ||||
| 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: | ||||
|   | ||||
							
								
								
									
										594
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										594
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,594 @@ | ||||
| ## | ||||
| ## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved. | ||||
| ## Copyright (C) 2004 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 | ||||
| ################################################################################ | ||||
|  | ||||
| AC_PREREQ(2.53) | ||||
| ################################################################################ | ||||
| dnl -- Process this file with autoconf to produce a configure script. | ||||
| AC_INIT(lib/device/dev-cache.h) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the directory where autoconf has auxilary files | ||||
| AC_CONFIG_AUX_DIR(autoconf)  | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Get system type | ||||
| AC_CANONICAL_SYSTEM | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		CFLAGS="$CFLAGS" | ||||
| 		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" | ||||
| 		SOFLAG="-shared" | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=yes | ||||
| 		SELINUX=yes | ||||
| 		CLUSTER=internal | ||||
| 		FSADM=no ;; | ||||
| 	darwin*) | ||||
| 		CFLAGS="$CFLAGS -no-cpp-precomp -fno-common" | ||||
| 		COPTIMISE_FLAG="-O2" | ||||
| 		CLDFLAGS="$CLDFLAGS" | ||||
| 		CLDWHOLEARCHIVE="-all_load" | ||||
| 		CLDNOWHOLEARCHIVE= | ||||
| 		LDDEPS="$LDDEPS" | ||||
| 		LDFLAGS="$LDFLAGS" | ||||
| 		SOFLAG="-dynamiclib" | ||||
| 		DEVMAPPER=no | ||||
| 		ODIRECT=no | ||||
| 		SELINUX=no | ||||
| 		CLUSTER=none | ||||
| 		FSADM=no ;; | ||||
| esac | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for programs. | ||||
| AC_PROG_AWK | ||||
| AC_PROG_CC | ||||
| AC_PROG_INSTALL | ||||
| AC_PROG_LN_S | ||||
| AC_PROG_MAKE_SET | ||||
| AC_PROG_RANLIB | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for header files. | ||||
| AC_HEADER_DIRENT | ||||
| AC_HEADER_STDC | ||||
| AC_HEADER_SYS_WAIT | ||||
| AC_HEADER_TIME | ||||
|  | ||||
| AC_CHECK_HEADERS(fcntl.h limits.h locale.h stddef.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h,,AC_MSG_ERROR(bailing out)) | ||||
| AC_CHECK_HEADERS(assert.h ctype.h libgen.h signal.h stdio.h sys/mman.h sys/resource.h sys/stat.h sys/types.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 | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for typedefs, structures, and compiler characteristics. | ||||
| AC_C_CONST | ||||
| AC_C_INLINE | ||||
| AC_TYPE_OFF_T | ||||
| AC_TYPE_PID_T | ||||
| AC_TYPE_SIZE_T | ||||
| AC_TYPE_MODE_T | ||||
| AC_STRUCT_ST_RDEV | ||||
| AC_STRUCT_TM | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for functions | ||||
| AC_CHECK_FUNCS(gethostname getpagesize memset munmap setlocale strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul,,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 | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Prefix is /usr by default, the exec_prefix default is setup later | ||||
| AC_PREFIX_DEFAULT(/usr) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Parallel make jobs? | ||||
| AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) | ||||
|  | ||||
| ################################################################################ | ||||
| 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 ], | ||||
|   [ 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="$withval" ]) | ||||
| AC_MSG_RESULT($GROUP) | ||||
|  | ||||
| if test x$GROUP != x; then | ||||
| 	GROUP="-g $GROUP" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DLVM1_FALLBACK" | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DLVM1_INTERNAL" | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DPOOL_INTERNAL" | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DCLUSTER_LOCKING_INTERNAL" | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL" | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DMIRRORED_INTERNAL" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enables staticly-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 -- Enable readline | ||||
| AC_MSG_CHECKING(whether to enable readline) | ||||
| AC_ARG_ENABLE(readline, [  --enable-readline       Enable readline support], | ||||
| READLINE=$enableval, READLINE=no) | ||||
| AC_MSG_RESULT($READLINE) | ||||
|  | ||||
| if test x$READLINE = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DREADLINE_SUPPORT" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| 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 -- 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= | ||||
| 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 -- Disable devmapper | ||||
| AC_MSG_CHECKING(whether to use device-mapper) | ||||
| AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable device-mapper interaction], | ||||
| DEVMAPPER=$enableval) | ||||
| AC_MSG_RESULT($DEVMAPPER) | ||||
|  | ||||
| if test x$DEVMAPPER = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| 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 | ||||
| 	CFLAGS="$CFLAGS -DO_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) | ||||
|  | ||||
| if test x$CMDLIB = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DCMDLIB" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable fsadm | ||||
| AC_MSG_CHECKING(whether to build fsadm) | ||||
| AC_ARG_ENABLE(fsadm, [  --enable-fsadm          Enable fsadm], | ||||
| FSADM=$enableval) | ||||
| AC_MSG_RESULT($FSADM) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Mess with default exec_prefix | ||||
| if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; | ||||
|  then  exec_prefix=""; | ||||
| fi; | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for library functions. | ||||
| AC_PROG_GCC_TRADITIONAL | ||||
| AC_TYPE_SIGNAL | ||||
| AC_FUNC_VPRINTF | ||||
| AC_CHECK_FUNCS(mkdir rmdir uname,,AC_MSG_ERROR(bailing out)) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for termcap (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, , | ||||
| 		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 | ||||
| 	CFLAGS="$CFLAGS -DHAVE_LIBDL" | ||||
| 	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 -- Check for is_selinux_enabled | ||||
| if test x$SELINUX = xyes; then | ||||
| 	AC_MSG_CHECKING(for is_selinux_enabled function) | ||||
| 	AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no) | ||||
| 	AC_MSG_RESULT($HAVE_SELINUX) | ||||
|  | ||||
| 	if test x$HAVE_SELINUX = xyes; then | ||||
| 		CFLAGS="$CFLAGS -DHAVE_SELINUX" | ||||
| 		LIBS="-lselinux $LIBS" | ||||
| 	else | ||||
| 		AC_MSG_WARN(Disabling selinux) | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for getopt | ||||
| AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG") | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for readline (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_CHECK_LIB(readline, readline, , | ||||
| 		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). | ||||
| ) | ||||
| 	) | ||||
| 	AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES") | ||||
| 		 | ||||
| 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 | ||||
| 	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' ]) | ||||
|  | ||||
| ################################################################################ | ||||
| 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$FSADM = xyes; then | ||||
| 	AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out)) | ||||
| 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$DEVMAPPER = xyes; then | ||||
| 	AC_CHECK_HEADERS(libdevmapper.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 | ||||
|  | ||||
| ################################################################################ | ||||
| if test "-f VERSION"; then | ||||
|   LVM_VERSION="\"`cat VERSION`\"" | ||||
| else | ||||
|   LVM_VERSION="Unknown" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_SUBST(JOBS) | ||||
| AC_SUBST(STATIC_LINK) | ||||
| AC_SUBST(LVM1) | ||||
| AC_SUBST(POOL) | ||||
| AC_SUBST(SNAPSHOTS) | ||||
| AC_SUBST(MIRRORS) | ||||
| AC_SUBST(OWNER) | ||||
| AC_SUBST(GROUP) | ||||
| AC_SUBST(CFLAGS) | ||||
| AC_SUBST(COPTIMISE_FLAG) | ||||
| AC_SUBST(CLDFLAGS) | ||||
| AC_SUBST(CLDWHOLEARCHIVE) | ||||
| AC_SUBST(CLDNOWHOLEARCHIVE) | ||||
| AC_SUBST(LDDEPS) | ||||
| AC_SUBST(LDFLAGS) | ||||
| AC_SUBST(SOFLAG) | ||||
| AC_SUBST(LIBS) | ||||
| AC_SUBST(LVM_VERSION) | ||||
| AC_SUBST(LVM1_FALLBACK) | ||||
| AC_SUBST(DEBUG) | ||||
| AC_SUBST(DEVMAPPER) | ||||
| AC_SUBST(HAVE_LIBDL) | ||||
| AC_SUBST(HAVE_SELINUX) | ||||
| AC_SUBST(CMDLIB) | ||||
| AC_SUBST(MSGFMT) | ||||
| AC_SUBST(LOCALEDIR) | ||||
| AC_SUBST(CONFDIR) | ||||
| AC_SUBST(STATICDIR) | ||||
| AC_SUBST(INTL_PACKAGE) | ||||
| AC_SUBST(INTL) | ||||
| AC_SUBST(CLVMD) | ||||
| AC_SUBST(CLUSTER) | ||||
| AC_SUBST(FSADM) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- First and last lines should not contain files to generate in order to  | ||||
| dnl -- keep utility scripts running properly | ||||
| AC_OUTPUT( 								\ | ||||
| Makefile								\ | ||||
| make.tmpl								\ | ||||
| daemons/Makefile							\ | ||||
| daemons/clvmd/Makefile							\ | ||||
| doc/Makefile								\ | ||||
| include/Makefile						 	\ | ||||
| lib/Makefile							 	\ | ||||
| lib/format1/Makefile						 	\ | ||||
| lib/format_pool/Makefile						\ | ||||
| lib/locking/Makefile							\ | ||||
| lib/mirror/Makefile							\ | ||||
| lib/snapshot/Makefile							\ | ||||
| man/Makefile							 	\ | ||||
| po/Makefile								\ | ||||
| tools/Makefile							 	\ | ||||
| tools/version.h								\ | ||||
| tools/fsadm/Makefile							\ | ||||
| test/mm/Makefile							\ | ||||
| test/device/Makefile							\ | ||||
| test/format1/Makefile							\ | ||||
| test/regex/Makefile                                                     \ | ||||
| test/filters/Makefile                                                   \ | ||||
| ) | ||||
|  | ||||
| if test x$ODIRECT != xyes; then | ||||
|   AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up) | ||||
| fi | ||||
|  | ||||
| if test x$FSADM == xyes; then | ||||
|   AC_MSG_WARN(fsadm support is untested) | ||||
| fi | ||||
							
								
								
									
										23
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # | ||||
| # Copyright (C) 2004 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@ | ||||
|  | ||||
| ifneq ("@CLVMD@", "none") | ||||
|   SUBDIRS = clvmd | ||||
| endif | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
							
								
								
									
										73
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| # | ||||
| # Copyright (C) 2004 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@ | ||||
|  | ||||
| SOURCES = \ | ||||
| 	clvmd-command.c  \ | ||||
| 	clvmd.c          \ | ||||
| 	libclvm.c        \ | ||||
| 	lvm-functions.c  \ | ||||
| 	system-lv.c | ||||
|  | ||||
| ifeq ("@CLVMD@", "gulm") | ||||
| 	GULM = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "cman") | ||||
| 	CMAN = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "all") | ||||
| 	GULM = yes | ||||
| 	CMAN = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("$(GULM)", "yes") | ||||
| 	SOURCES += clvmd-gulm.c tcp-comms.c | ||||
| 	LMLIBS += -lccs -lgulm | ||||
| 	CFLAGS += -DUSE_GULM | ||||
| endif | ||||
|  | ||||
| ifeq ("$(CMAN)", "yes") | ||||
| 	SOURCES += clvmd-cman.c | ||||
| 	LMLIBS += -ldlm | ||||
| 	CFLAGS += -DUSE_CMAN | ||||
| endif | ||||
|  | ||||
| TARGETS = \ | ||||
| 	clvmd | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| CFLAGS += -D_REENTRANT -fno-strict-aliasing | ||||
| LIBS += -ldevmapper -llvm -lpthread | ||||
|  | ||||
| INSTALL_TARGETS = \ | ||||
| 	install_clvmd | ||||
|  | ||||
| clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a | ||||
| 	$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| .PHONY: install_clvmd | ||||
|  | ||||
| install_clvmd: $(TARGETS) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) clvmd \ | ||||
| 		$(sbindir)/clvmd | ||||
|  | ||||
| install: $(INSTALL_TARGETS) | ||||
|  | ||||
| install_cluster: $(INSTALL_TARGETS) | ||||
|  | ||||
							
								
								
									
										65
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| /* 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 */ | ||||
|  | ||||
| /* 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 | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										532
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,532 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| #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 "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "libdlm.h" | ||||
| #include "log.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #define LOCKSPACE_NAME "clvmd" | ||||
|  | ||||
| static int cluster_sock; | ||||
| static int num_nodes; | ||||
| static struct cl_cluster_node *nodes = NULL; | ||||
| static int count_nodes; /* size of allocated nodes array */ | ||||
| static int max_updown_nodes = 50;	/* Current size of the allocated array */ | ||||
| /* Node up/down status, indexed by nodeid */ | ||||
| static int *node_updown = NULL; | ||||
| static dlm_lshandle_t *lockspace; | ||||
|  | ||||
| static void count_clvmds_running(void); | ||||
| static void get_members(void); | ||||
| static int nodeid_from_csid(char *csid); | ||||
| static int name_from_nodeid(int nodeid, char *name); | ||||
|  | ||||
| struct lock_wait { | ||||
| 	pthread_cond_t cond; | ||||
| 	pthread_mutex_t mutex; | ||||
| 	struct dlm_lksb lksb; | ||||
| }; | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	struct sockaddr_cl saddr; | ||||
| 	int port = CLUSTER_PORT_CLVMD; | ||||
|  | ||||
| 	/* Open the cluster communication socket */ | ||||
| 	cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT); | ||||
| 	if (cluster_sock == -1) { | ||||
| 		syslog(LOG_ERR, "Can't open cman cluster manager socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Bind to our port number on the cluster. | ||||
| 	   Writes to this will block if the cluster loses quorum */ | ||||
| 	saddr.scl_family = AF_CLUSTER; | ||||
| 	saddr.scl_port = port; | ||||
|  | ||||
| 	if (bind | ||||
| 	    (cluster_sock, (struct sockaddr *) &saddr, | ||||
| 	     sizeof(struct sockaddr_cl))) { | ||||
| 		syslog(LOG_ERR, "Can't bind cluster socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the cluster members list */ | ||||
| 	get_members(); | ||||
| 	count_clvmds_running(); | ||||
|  | ||||
| 	/* 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); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd() | ||||
| { | ||||
| 	return cluster_sock; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	return num_nodes; | ||||
| } | ||||
|  | ||||
| /* send_message with the fd check removed */ | ||||
| static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext) | ||||
| { | ||||
| 	struct iovec iov[2]; | ||||
| 	struct msghdr msg; | ||||
| 	struct sockaddr_cl saddr; | ||||
| 	int len = 0; | ||||
|  | ||||
| 	msg.msg_control = NULL; | ||||
| 	msg.msg_controllen = 0; | ||||
| 	msg.msg_iovlen = 1; | ||||
| 	msg.msg_iov = iov; | ||||
| 	msg.msg_flags = 0; | ||||
| 	iov[0].iov_len = msglen; | ||||
| 	iov[0].iov_base = buf; | ||||
|  | ||||
| 	saddr.scl_family = AF_CLUSTER; | ||||
| 	saddr.scl_port = CLUSTER_PORT_CLVMD; | ||||
| 	if (csid) { | ||||
| 		msg.msg_name = &saddr; | ||||
| 		msg.msg_namelen = sizeof(saddr); | ||||
| 		memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
| 	} else {		/* Cluster broadcast */ | ||||
|  | ||||
| 		msg.msg_name = NULL; | ||||
| 		msg.msg_namelen = 0; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		len = sendmsg(cluster_sock, &msg, 0); | ||||
| 		if (len < 0 && errno != EAGAIN) | ||||
| 			log_error(errtext); | ||||
|  | ||||
| 	} while (len == -1 && errno == EAGAIN); | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	int i; | ||||
| 	memset(csid, 0, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (nodes[i].us) | ||||
| 			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Call a callback routine for each node that known (down mean not running a clvmd) */ | ||||
| static int _cluster_do_node_callback(struct local_client *client, | ||||
| 			     void (*callback) (struct local_client *, char *, | ||||
| 					       int)) | ||||
| { | ||||
| 	int i; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	for (i = 0; i < _get_num_nodes(); i++) { | ||||
| 		callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]); | ||||
| 		if (!node_updown[nodes[i].node_id]) | ||||
| 			somedown = -1; | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Process OOB message from the cluster socket, | ||||
|    this currently just means that a node has stopped listening on our port */ | ||||
| static void process_oob_msg(char *buf, int len, int nodeid) | ||||
| { | ||||
| 	char namebuf[256]; | ||||
| 	switch (buf[0]) { | ||||
|         case CLUSTER_OOB_MSG_PORTCLOSED: | ||||
| 		name_from_nodeid(nodeid, namebuf); | ||||
| 		log_notice("clvmd on node %s has died\n", namebuf); | ||||
| 		DEBUGLOG("Got OOB message, removing node %s\n", namebuf); | ||||
|  | ||||
| 		node_updown[nodeid] = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case CLUSTER_OOB_MSG_STATECHANGE: | ||||
| 		DEBUGLOG("Got OOB message, Cluster state change\n"); | ||||
| 		get_members(); | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* ERROR */ | ||||
| 		DEBUGLOG("Got unknown OOB message: %d\n", buf[0]); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			struct local_client **new_client) | ||||
| { | ||||
| 	struct iovec iov[2]; | ||||
| 	struct msghdr msg; | ||||
| 	struct sockaddr_cl saddr; | ||||
|  | ||||
| 	/* We never return a new client */ | ||||
| 	*new_client = NULL; | ||||
|  | ||||
| 	msg.msg_control = NULL; | ||||
| 	msg.msg_controllen = 0; | ||||
| 	msg.msg_iovlen = 1; | ||||
| 	msg.msg_iov = iov; | ||||
| 	msg.msg_name = &saddr; | ||||
| 	msg.msg_flags = 0; | ||||
| 	msg.msg_namelen = sizeof(saddr); | ||||
| 	iov[0].iov_len = len; | ||||
| 	iov[0].iov_base = buf; | ||||
|  | ||||
| 	len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK); | ||||
| 	if (len < 0 && errno == EAGAIN) | ||||
| 		return len; | ||||
|  | ||||
| 	DEBUGLOG("Read on cluster socket, len = %d\n", len); | ||||
|  | ||||
| 	/* A real error */ | ||||
| 	if (len < 0) { | ||||
| 		log_error("read error on cluster socket: %m"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* EOF - we have left the cluster */ | ||||
| 	if (len == 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* Is it OOB? probably a node gone down */ | ||||
| 	if (msg.msg_flags & MSG_OOB) { | ||||
| 		process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid); | ||||
|  | ||||
| 		/* Tell the upper layer to ignore this message */ | ||||
| 		len = -1; | ||||
| 		errno = EAGAIN; | ||||
| 	} | ||||
| 	else { | ||||
| 		memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid)); | ||||
| 		/* Send it back to clvmd */ | ||||
| 		process_message(client, buf, len, csid); | ||||
| 	} | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| static void _add_up_node(char *csid) | ||||
| { | ||||
| 	/* It's up ! */ | ||||
| 	int nodeid = nodeid_from_csid(csid); | ||||
|  | ||||
| 	if (nodeid >= max_updown_nodes) { | ||||
| 	        int new_size = nodeid + 10; | ||||
| 		int *new_updown = realloc(node_updown, new_size); | ||||
|  | ||||
| 		if (new_updown) { | ||||
| 			node_updown = new_updown; | ||||
| 			max_updown_nodes = new_size; | ||||
| 			DEBUGLOG("realloced more space for nodes. now %d\n", | ||||
| 				 max_updown_nodes); | ||||
| 		} else { | ||||
| 			log_error | ||||
| 			    ("Realloc failed. Node status for clvmd will be wrong. quitting\n"); | ||||
| 			exit(999); | ||||
| 		} | ||||
| 	} | ||||
| 	node_updown[nodeid] = 1; | ||||
| 	DEBUGLOG("Added new node %d to updown list\n", nodeid); | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown() | ||||
| { | ||||
| 	unlock_all(); | ||||
| 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 	close(cluster_sock); | ||||
| } | ||||
|  | ||||
| static int is_listening(int nodeid) | ||||
| { | ||||
| 	struct cl_listen_request rq; | ||||
| 	int status; | ||||
|  | ||||
| 	rq.port = CLUSTER_PORT_CLVMD; | ||||
| 	rq.nodeid = nodeid; | ||||
|  | ||||
| 	do { | ||||
| 		status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq); | ||||
| 		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++) { | ||||
| 		node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get a list of active cluster members */ | ||||
| static void get_members() | ||||
| { | ||||
| 	struct cl_cluster_nodelist nodelist; | ||||
|  | ||||
| 	num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0); | ||||
| 	if (num_nodes == -1) { | ||||
| 		log_error("Unable to get node count"); | ||||
| 	} else { | ||||
| 	        /* 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 cl_cluster_node)); | ||||
| 			if (!nodes) { | ||||
| 			        log_error("Unable to allocate nodes array\n"); | ||||
| 				exit(5); | ||||
| 			} | ||||
| 		} | ||||
| 		nodelist.max_members = count_nodes; | ||||
| 		nodelist.nodes = nodes; | ||||
|  | ||||
| 		num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist); | ||||
| 		if (num_nodes <= 0) { | ||||
| 		        log_error("Unable to get node details"); | ||||
| 			exit(6); | ||||
| 		} | ||||
|  | ||||
| 		/* Sanity check struct */ | ||||
| 		if (nodes[0].size != sizeof(struct cl_cluster_node)) { | ||||
| 			log_error | ||||
| 			    ("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n"); | ||||
| 			exit(10); | ||||
| 		} | ||||
|  | ||||
| 		if (node_updown == NULL) { | ||||
| 			node_updown = | ||||
| 			    (int *) malloc(sizeof(int) * | ||||
| 					   max(num_nodes, max_updown_nodes)); | ||||
| 			memset(node_updown, 0, | ||||
| 			       sizeof(int) * max(num_nodes, max_updown_nodes)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Convert a node name to a CSID */ | ||||
| static int _csid_from_name(char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (strcmp(name, nodes[i].name) == 0) { | ||||
| 			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node name */ | ||||
| static int _name_from_csid(char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) { | ||||
| 			strcpy(name, nodes[i].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].node_id) { | ||||
| 			strcpy(name, nodes[i].name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node ID */ | ||||
| static int nodeid_from_csid(char *csid) | ||||
| { | ||||
|         int nodeid; | ||||
|  | ||||
| 	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	return nodeid; | ||||
| } | ||||
|  | ||||
| static int _is_quorate() | ||||
| { | ||||
| 	return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0); | ||||
| } | ||||
|  | ||||
| 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 struct cluster_ops _cluster_cman_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, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.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; | ||||
| } | ||||
							
								
								
									
										285
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,285 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  | ||||
| */ | ||||
|  | ||||
| #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 "list.h" | ||||
| #include "hash.h" | ||||
| #include "locking.h" | ||||
| #include "log.h" | ||||
| #include "lvm-functions.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
| #include "libdlm.h" | ||||
|  | ||||
| /* 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) { | ||||
| 			buflen = arglen + 200; | ||||
| 			*buf = realloc(*buf, buflen); | ||||
| 		} | ||||
| 		uname(&nodeinfo); | ||||
| 		*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s", | ||||
| 				       nodeinfo.nodename, args, | ||||
| 				       nodeinfo.release); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		/* Check to see if the VG is in use by LVM1 */ | ||||
| 		status = do_check_lvm1(&args[2]); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		/* This is the biggie */ | ||||
| 		lock_cmd = args[0]; | ||||
| 		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, | ||||
| 					 "Internal lvm error, check syslog"); | ||||
| 			return EIO; | ||||
| 		} | ||||
| 		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, strerror(status)); | ||||
| 	} | ||||
|  | ||||
| 	return status; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int lock_vg(struct local_client *client) | ||||
| { | ||||
|     struct 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 hash_table *)client->bits.localsock.private; | ||||
|     } | ||||
|     else { | ||||
| 	lock_hash = hash_create(3); | ||||
| 	if (!lock_hash) | ||||
| 	    return ENOMEM; | ||||
| 	client->bits.localsock.private = (void *)lock_hash; | ||||
|     } | ||||
|  | ||||
|     lock_cmd = args[0]; | ||||
|     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)hash_lookup(lock_hash, lockname); | ||||
| 	if (lkid == 0) | ||||
| 	    return EINVAL; | ||||
|  | ||||
| 	status = sync_unlock(lockname, lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    hash_remove(lock_hash, lockname); | ||||
|     } | ||||
|     else { | ||||
|  | ||||
| 	status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    hash_insert(lock_hash, lockname, (void *)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 *) lockid; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
|        	        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; | ||||
|  | ||||
| 	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: | ||||
| 		/* 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 hash_node *v; | ||||
| 	struct hash_table *lock_hash = | ||||
| 	    (struct hash_table *)client->bits.localsock.private; | ||||
|  | ||||
| 	hash_iterate(v, lock_hash) { | ||||
| 		int lkid = (int)(long)hash_get_data(lock_hash, v); | ||||
|  | ||||
| 		DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid); | ||||
| 		sync_unlock("DUMMY", lkid); | ||||
| 	} | ||||
|  | ||||
| 	hash_destroy(lock_hash); | ||||
| 	client->bits.localsock.private = 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										69
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| /* | ||||
|  * 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) (void *buf, int msglen, char *csid, | ||||
| 				const char *errtext); | ||||
| 	int (*name_from_csid) (char *csid, char *name); | ||||
| 	int (*csid_from_name) (char *csid, char *name); | ||||
| 	int (*get_num_nodes) (void); | ||||
| 	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len, | ||||
| 			       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 *, | ||||
| 						      char *csid, int node_up)); | ||||
| 	int (*is_quorate) (void); | ||||
|  | ||||
| 	void (*get_our_csid) (char *csid); | ||||
| 	void (*add_up_node) (char *csid); | ||||
| 	void (*cluster_closedown) (void); | ||||
|  | ||||
| 	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 "cnxman-socket.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_CLUSTER_MEMBER_NAME_LEN | ||||
| struct cluster_ops *init_cman_cluster(void); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										959
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										959
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,959 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  2002-2003  All rights reserved. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* This provides the interface between clvmd and gulm as the cluster | ||||
|  * and lock manager. | ||||
|  * | ||||
|  * It also provides the "liblm" functions too as it's hard (and pointless) | ||||
|  * to seperate them out when using gulm. | ||||
|  * | ||||
|  * What it does /not/ provide is the communications between clvmd daemons | ||||
|  * on the cluster nodes. That is done in tcp-comms.c | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #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 "ccs.h" | ||||
| #include "list.h" | ||||
| #include "locking.h" | ||||
| #include "log.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "hash.h" | ||||
| #include "clvmd-gulm.h" | ||||
| #include "libgulm.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| /* Hash list of nodes in the cluster */ | ||||
| static struct hash_table *node_hash; | ||||
|  | ||||
| /* hash list of outstanding lock requests */ | ||||
| static struct hash_table *lock_hash; | ||||
|  | ||||
| /* Copy of the current core state */ | ||||
| static uint8_t current_corestate; | ||||
|  | ||||
| /* Number of active nodes */ | ||||
| static int num_nodes; | ||||
|  | ||||
| static char *cluster_name; | ||||
|  | ||||
| static pthread_mutex_t lock_start_mutex; | ||||
| static volatile int lock_start_flag; | ||||
|  | ||||
| struct node_info | ||||
| { | ||||
|     enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state; | ||||
|     char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| }; | ||||
|  | ||||
| struct lock_wait | ||||
| { | ||||
|     pthread_cond_t cond; | ||||
|     pthread_mutex_t mutex; | ||||
|     int status; | ||||
| }; | ||||
|  | ||||
| /* Forward */ | ||||
| static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			       struct local_client **new_client); | ||||
| static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			       struct local_client **new_client); | ||||
| static int get_all_cluster_nodes(void); | ||||
| static int _csid_from_name(char *csid, char *name); | ||||
| static void _cluster_closedown(void); | ||||
|  | ||||
| /* In tcp-comms.c */ | ||||
| extern struct hash_table *sock_hash; | ||||
|  | ||||
| static int add_internal_client(int fd, fd_callback_t callback) | ||||
| { | ||||
|     struct local_client *client; | ||||
|  | ||||
|     DEBUGLOG("Add_internal_client, fd = %d\n", fd); | ||||
|  | ||||
|     /* Add a GULM file descriptor it to the main loop */ | ||||
|     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); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* Gulm library handle */ | ||||
| static gulm_interface_p gulm_if; | ||||
| static lg_core_callbacks_t core_callbacks; | ||||
| static lg_lockspace_callbacks_t lock_callbacks; | ||||
|  | ||||
| static void badsig_handler(int sig) | ||||
| { | ||||
|     DEBUGLOG("got sig %d\n", sig); | ||||
|     _cluster_closedown(); | ||||
|     exit(0); | ||||
| } | ||||
|  | ||||
| static void sighup_handler(int sig) | ||||
| { | ||||
|     DEBUGLOG("got SIGHUP\n"); | ||||
|  | ||||
|     /* Re-read CCS node list */ | ||||
|     get_all_cluster_nodes(); | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
|     int status; | ||||
|     int ccs_h; | ||||
|     int port = 0; | ||||
|     char *portstr; | ||||
|  | ||||
|     /* Get cluster name from CCS */ | ||||
|     ccs_h = ccs_force_connect(NULL, 0); | ||||
|     if (ccs_h < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Cannot login in to CCSD server\n"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     ccs_get(ccs_h, "//cluster/@name", &cluster_name); | ||||
|     DEBUGLOG("got cluster name %s\n", cluster_name); | ||||
|  | ||||
|     if (!ccs_get(ccs_h, "//cluster/clvm/@port", &portstr)) | ||||
|     { | ||||
| 	port = atoi(portstr); | ||||
| 	free(portstr); | ||||
| 	DEBUGLOG("got port number %d\n", port); | ||||
|  | ||||
| 	if (port <= 0 && port >= 65536) | ||||
| 	    port = 0; | ||||
|     } | ||||
|  | ||||
|     ccs_disconnect(ccs_h); | ||||
|  | ||||
|     /* Block locking until we are logged in */ | ||||
|     pthread_mutex_init(&lock_start_mutex, NULL); | ||||
|     pthread_mutex_lock(&lock_start_mutex); | ||||
|     lock_start_flag = 1; | ||||
|  | ||||
|     node_hash = hash_create(100); | ||||
|     lock_hash = hash_create(10); | ||||
|  | ||||
|     /* Get all nodes from CCS */ | ||||
|     if (get_all_cluster_nodes()) | ||||
| 	return -1; | ||||
|  | ||||
|     /* Initialise GULM library */ | ||||
|     status = lg_initialize(&gulm_if, cluster_name, "clvmd"); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("lg_initialize failed: %d\n", status); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* Connect to core - we are not "important" :-) */ | ||||
|     status = lg_core_login(gulm_if, 0); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("lg_core_login failed: %d\n", status); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* Initialise the inter-node comms */ | ||||
|     status = init_comms(port); | ||||
|     if (status) | ||||
| 	return status; | ||||
|  | ||||
|     /* Add core FD to the list */ | ||||
|     status = add_internal_client(lg_core_selector(gulm_if), read_from_core_sock); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("can't allocate client space\n"); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* Connect to the lock server */ | ||||
|     if (lg_lock_login(gulm_if, "CLVM")) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Cannot login in to LOCK server\n"); | ||||
| 	DEBUGLOG("Cannot login in to LOCK server\n"); | ||||
| 	exit(88); | ||||
|     } | ||||
|  | ||||
|     /* Add lockspace FD to the list */ | ||||
|     status = add_internal_client(lg_lock_selector(gulm_if), read_from_lock_sock); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("can't allocate client space\n"); | ||||
| 	exit(status); | ||||
|     } | ||||
|  | ||||
|     /* Request a list of nodes, we can;t really do anything until | ||||
|        this comes back */ | ||||
|     status = lg_core_nodelist(gulm_if); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("lg_core_nodelist failed: %d\n", status); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* So I can kill it without taking GULM down too */ | ||||
|     signal(SIGINT, badsig_handler); | ||||
|     signal(SIGTERM, badsig_handler); | ||||
|  | ||||
|     /* Re-read the node list on SIGHUP */ | ||||
|     signal(SIGHUP, sighup_handler); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
|     DEBUGLOG("cluster_closedown\n"); | ||||
|     lg_lock_logout(gulm_if); | ||||
|     lg_core_logout(gulm_if); | ||||
|     lg_release(gulm_if); | ||||
| } | ||||
|  | ||||
| /* Expire locks for a named node, or us */ | ||||
| #define GIO_KEY_SIZE 46 | ||||
| static void drop_expired_locks(char *nodename) | ||||
| { | ||||
|     struct utsname nodeinfo; | ||||
|     uint8_t mask[GIO_KEY_SIZE]; | ||||
|  | ||||
|     memset(mask, 0xff, GIO_KEY_SIZE); | ||||
|  | ||||
|     if (!nodename) | ||||
|     { | ||||
| 	uname(&nodeinfo); | ||||
| 	nodename = nodeinfo.nodename; | ||||
|     } | ||||
|  | ||||
|     if (lg_lock_drop_exp(gulm_if, nodename, mask, GIO_KEY_SIZE)) | ||||
|     { | ||||
| 	DEBUGLOG("Error calling lg_lock_drop_exp()\n"); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			       struct local_client **new_client) | ||||
| { | ||||
|     int status; | ||||
|  | ||||
|     *new_client = NULL; | ||||
|     status = lg_core_handle_messages(gulm_if, &core_callbacks, NULL); | ||||
|     return status<0 ? status : 1; | ||||
| } | ||||
|  | ||||
| static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			       struct local_client **new_client) | ||||
| { | ||||
|     int status; | ||||
|  | ||||
|     *new_client = NULL; | ||||
|     status = lg_lock_handle_messages(gulm_if, &lock_callbacks, NULL); | ||||
|     return status<0 ? status : 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* CORE callback routines */ | ||||
| static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t rank, uint8_t corestate) | ||||
| { | ||||
|    DEBUGLOG("CORE Got a Login reply.  gen:%lld err:%d rank:%d corestate:%d\n", | ||||
|          gen, error, rank, corestate); | ||||
|  | ||||
|    if (error) | ||||
|        exit(error); | ||||
|  | ||||
|    current_corestate = corestate; | ||||
|    return 0; | ||||
| } | ||||
|  | ||||
| static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate) | ||||
| { | ||||
|     if (nodestate == lg_core_Logged_in) | ||||
|     { | ||||
| 	/* Don't clobber NODE_CLVMD state */ | ||||
| 	if (ninfo->state != NODE_CLVMD) | ||||
| 	{ | ||||
| 	    if (ninfo->state == NODE_UNKNOWN || | ||||
| 		ninfo->state == NODE_DOWN) | ||||
| 		num_nodes++; | ||||
|  | ||||
| 	    ninfo->state = NODE_UP; | ||||
| 	} | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	if (nodestate == lg_core_Expired || | ||||
| 	    nodestate == lg_core_Fenced || | ||||
| 	    nodestate == lg_core_Logged_out) | ||||
| 	{ | ||||
| 	    if (ninfo->state != NODE_DOWN) | ||||
| 		num_nodes--; | ||||
| 	    ninfo->state = NODE_DOWN; | ||||
| 	    tcp_remove_client(csid); | ||||
| 	} | ||||
|     } | ||||
|     DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n", | ||||
| 	     ninfo->name, ninfo->state, num_nodes); | ||||
| } | ||||
|  | ||||
| static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state) | ||||
| { | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN); | ||||
|     if (!ninfo) | ||||
|     { | ||||
| 	/* If we can't find that node then re-read the config file in case it | ||||
| 	   was added after we were started */ | ||||
| 	DEBUGLOG("Node %s not found, re-reading config file\n", name); | ||||
| 	get_all_cluster_nodes(); | ||||
|  | ||||
| 	/* Now try again */ | ||||
| 	ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN); | ||||
| 	if (!ninfo) | ||||
| 	{ | ||||
| 	    DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name); | ||||
| 	    return NULL; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     set_node_state(ninfo, (char *)&ip, state); | ||||
|  | ||||
|     return ninfo; | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	get_our_gulm_csid(csid); | ||||
| } | ||||
|  | ||||
| static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *ip, uint8_t state) | ||||
| { | ||||
|     DEBUGLOG("CORE nodelist\n"); | ||||
|  | ||||
|     if (type == lglcb_start) | ||||
|     { | ||||
| 	DEBUGLOG("Got Nodelist, start\n"); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	if (type == lglcb_item) | ||||
| 	{ | ||||
| 	    DEBUGLOG("Got nodelist, item: %s, %#x\n", name, state); | ||||
|  | ||||
| 	    add_or_set_node(name, ip, state); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    if (type == lglcb_stop) | ||||
| 	    { | ||||
| 		char ourcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 		DEBUGLOG("Got Nodelist, stop\n"); | ||||
| 		clvmd_cluster_init_completed(); | ||||
|  | ||||
| 		/* Mark ourself as up */ | ||||
| 		_get_our_csid(ourcsid); | ||||
| 		gulm_add_up_node(ourcsid); | ||||
| 	    } | ||||
| 	    else | ||||
| 	    { | ||||
| 		DEBUGLOG("Unknown lglcb_t %#x\n", type); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername) | ||||
| { | ||||
|     DEBUGLOG("CORE Got statechange  corestate:%#x mastername:%s\n", | ||||
| 	     corestate, mastername); | ||||
|  | ||||
|     current_corestate = corestate; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int core_nodechange(void *misc, char *nodename, struct in6_addr *nodeip, uint8_t nodestate) | ||||
| { | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     DEBUGLOG("CORE node change, name=%s, state = %d\n", nodename, nodestate); | ||||
|  | ||||
|     /* If we don't get nodeip here, try a lookup by name */ | ||||
|     if (!nodeip) | ||||
| 	_csid_from_name((char *)nodeip, nodename); | ||||
|     if (!nodeip) | ||||
| 	return 0; | ||||
|  | ||||
|     ninfo = add_or_set_node(nodename, nodeip, nodestate); | ||||
|     if (!ninfo) | ||||
| 	return 0; | ||||
|  | ||||
|     /* Check if we need to drop any expired locks */ | ||||
|     if (ninfo->state == NODE_DOWN) | ||||
|     { | ||||
| 	drop_expired_locks(nodename); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| static int core_error(void *misc, uint32_t err) | ||||
| { | ||||
|     DEBUGLOG("CORE error: %d\n", err); | ||||
|     // Not sure what happens here | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* LOCK callback routines */ | ||||
| static int lock_login_reply(void *misc, uint32_t error, uint8_t which) | ||||
| { | ||||
|     DEBUGLOG("LOCK Got a Login reply.  err:%d which:%d\n", | ||||
| 	     error, which); | ||||
|  | ||||
|     if (error) | ||||
| 	exit(error); | ||||
|  | ||||
|     /* Drop any expired locks for us that might be hanging around */ | ||||
|     drop_expired_locks(NULL); | ||||
|  | ||||
|     /* Enable locking operations in other threads */ | ||||
|     if (lock_start_flag) | ||||
|     { | ||||
| 	lock_start_flag = 0; | ||||
| 	pthread_mutex_unlock(&lock_start_mutex); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen, | ||||
| 			   uint64_t subid, uint64_t start, uint64_t stop, | ||||
| 			   uint8_t state, uint32_t flags, uint32_t error, | ||||
| 			   uint8_t *LVB, uint16_t LVBlen) | ||||
| { | ||||
|     struct lock_wait *lwait; | ||||
|  | ||||
|     DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error); | ||||
|  | ||||
|     lwait = hash_lookup(lock_hash, key); | ||||
|     if (!lwait) | ||||
|     { | ||||
| 	DEBUGLOG("Can't find hash entry for resource %s\n", key); | ||||
| 	return 0; | ||||
|     } | ||||
|     lwait->status = error; | ||||
|     pthread_mutex_lock(&lwait->mutex); | ||||
|     pthread_cond_signal(&lwait->cond); | ||||
|     pthread_mutex_unlock(&lwait->mutex); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| static int lock_error(void *misc, uint32_t err) | ||||
| { | ||||
|     DEBUGLOG("LOCK error: %d\n", err); | ||||
|     // Not sure what happens here | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* CORE callbacks */ | ||||
| static lg_core_callbacks_t core_callbacks = { | ||||
|     .login_reply  = core_login_reply, | ||||
|     .nodelist     = core_nodelist, | ||||
|     .statechange  = core_statechange, | ||||
|     .nodechange   = core_nodechange, | ||||
|     .error        = core_error, | ||||
| }; | ||||
|  | ||||
| /* LOCK callbacks */ | ||||
| static lg_lockspace_callbacks_t lock_callbacks = { | ||||
|     .login_reply   = lock_login_reply, | ||||
|     .lock_state    = lock_lock_state, | ||||
|     .error         = lock_error, | ||||
| }; | ||||
|  | ||||
| /* Allow tcp-comms to loop round the list of active nodes */ | ||||
| int get_next_node_csid(void **context, char *csid) | ||||
| { | ||||
|     struct node_info *ninfo = NULL; | ||||
|  | ||||
|     /* First node */ | ||||
|     if (!*context) | ||||
|     { | ||||
| 	*context = hash_get_first(node_hash); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	*context = hash_get_next(node_hash, *context); | ||||
|     } | ||||
|     if (*context) | ||||
| 	ninfo = hash_get_data(node_hash, *context); | ||||
|  | ||||
|     /* Find a node that is UP */ | ||||
|     while (*context && ninfo->state == NODE_DOWN) | ||||
|     { | ||||
| 	*context = hash_get_next(node_hash, *context); | ||||
| 	if (*context) | ||||
| 	{ | ||||
| 	    ninfo = hash_get_data(node_hash, *context); | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (!*context || ninfo->state == NODE_DOWN) | ||||
|     { | ||||
| 	return 0; | ||||
|     } | ||||
|  | ||||
|     memcpy(csid, hash_get_key(node_hash, *context), GULM_MAX_CSID_LEN); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| int gulm_name_from_csid(char *csid, char *name) | ||||
| { | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!ninfo) | ||||
|     { | ||||
|         sprintf(name, "UNKNOWN %s", print_csid(csid)); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     strcpy(name, ninfo->name); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _csid_from_name(char *csid, char *name) | ||||
| { | ||||
|     struct hash_node *hn; | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     hash_iterate(hn, node_hash) | ||||
|     { | ||||
| 	ninfo = hash_get_data(node_hash, hn); | ||||
| 	if (strcmp(ninfo->name, name) == 0) | ||||
| 	{ | ||||
| 	    memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN); | ||||
| 	    return 0; | ||||
| 	} | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
|     DEBUGLOG("num_nodes = %d\n", num_nodes); | ||||
|     return num_nodes; | ||||
| } | ||||
|  | ||||
| /* Node is now known to be running a clvmd */ | ||||
| void gulm_add_up_node(char *csid) | ||||
| { | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!ninfo) | ||||
| 	return; | ||||
|  | ||||
|     ninfo->state = NODE_CLVMD; | ||||
|     return; | ||||
|  | ||||
| } | ||||
| /* Node is now known to be NOT running a clvmd */ | ||||
| void add_down_node(char *csid) | ||||
| { | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!ninfo) | ||||
| 	return; | ||||
|  | ||||
|     /* Only set it to UP if it was previously known to be | ||||
|        running clvmd - gulm may set it DOWN quite soon */ | ||||
|     if (ninfo->state == NODE_CLVMD) | ||||
| 	ninfo->state = NODE_UP; | ||||
|     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 *, char *csid, int node_up)) | ||||
| { | ||||
|     struct hash_node *hn; | ||||
|     struct node_info *ninfo; | ||||
|  | ||||
|     hash_iterate(hn, node_hash) | ||||
|     { | ||||
| 	char csid[GULM_MAX_CSID_LEN]; | ||||
| 	struct local_client *client; | ||||
|  | ||||
| 	ninfo = hash_get_data(node_hash, hn); | ||||
| 	memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN); | ||||
|  | ||||
| 	DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state); | ||||
|  | ||||
| 	client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	if (client) | ||||
| 	    callback(master_client, csid, ninfo->state == NODE_CLVMD); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* Convert gulm error codes to unix errno numbers */ | ||||
| static int gulm_to_errno(int gulm_ret) | ||||
| { | ||||
|     switch (gulm_ret) | ||||
|     { | ||||
|     case lg_err_TryFailed: | ||||
| 	errno = EAGAIN; | ||||
| 	break; | ||||
|  | ||||
|     case lg_err_AlreadyPend: | ||||
| 	errno = EBUSY; | ||||
|  | ||||
| 	/* More?? */ | ||||
|     default: | ||||
| 	errno = EINVAL; | ||||
|     } | ||||
|  | ||||
|     return gulm_ret ? -1 : 0; | ||||
| } | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
|     int status; | ||||
|     struct lock_wait lwait; | ||||
|  | ||||
|     /* Wait until the lock module is ready */ | ||||
|     if (lock_start_flag) | ||||
|     { | ||||
| 	pthread_mutex_lock(&lock_start_mutex); | ||||
| 	pthread_mutex_unlock(&lock_start_mutex); | ||||
|     } | ||||
|  | ||||
|     pthread_cond_init(&lwait.cond, NULL); | ||||
|     pthread_mutex_init(&lwait.mutex, NULL); | ||||
|     pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
|     /* This needs to be converted from DLM/LVM2 value for GULM */ | ||||
|     if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try; | ||||
|  | ||||
|     hash_insert(lock_hash, resource, &lwait); | ||||
|     DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode); | ||||
|  | ||||
|     status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1, | ||||
| 			       0, 0, 0, | ||||
| 			       mode, flags, NULL, 0); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("lg_lock_state returned %d\n", status); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* Wait for it to complete */ | ||||
|     pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
|     pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
|     hash_remove(lock_hash, resource); | ||||
|     DEBUGLOG("lock-resource returning %d\n", lwait.status); | ||||
|  | ||||
|     return gulm_to_errno(lwait.status); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _unlock_resource(char *resource, int lockid) | ||||
| { | ||||
|     int status; | ||||
|     struct lock_wait lwait; | ||||
|  | ||||
|     pthread_cond_init(&lwait.cond, NULL); | ||||
|     pthread_mutex_init(&lwait.mutex, NULL); | ||||
|     pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
|     hash_insert(lock_hash, resource, &lwait); | ||||
|  | ||||
|     DEBUGLOG("unlock_resource %s\n", resource); | ||||
|     status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1, | ||||
| 			       0, 0, 0, | ||||
| 			       lg_lock_state_Unlock, 0, NULL, 0); | ||||
|  | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("lg_lock_state(unlock) returned %d\n", status); | ||||
| 	return status; | ||||
|     } | ||||
|  | ||||
|     /* Wait for it to complete */ | ||||
|  | ||||
|     pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
|     pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
|     hash_remove(lock_hash, resource); | ||||
|  | ||||
|     return gulm_to_errno(lwait.status); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* These two locking functions MUST be called in a seperate thread from | ||||
|    the clvmd main loop because they expect to be woken up by it. | ||||
|  | ||||
|    These are abstractions around the real locking functions (above) | ||||
|    as we need to emulate the DLM's EX/PW/CW interaction with GULM using | ||||
|    two locks. | ||||
|    To aid unlocking, we store the lock mode in the lockid (as GULM | ||||
|    doesn't use this). | ||||
| */ | ||||
| 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, lg_lock_state_Exclusive, flags, lockid); | ||||
| 	if (status) | ||||
| 	    goto out; | ||||
|  | ||||
| 	/* If we can't get this lock then bail out */ | ||||
| 	status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid); | ||||
|         if (status == lg_err_TryFailed) | ||||
|         { | ||||
|            _unlock_resource(lock1, *lockid); | ||||
|            status = -1; | ||||
|            errno = EAGAIN; | ||||
|         } | ||||
| 	break; | ||||
|  | ||||
|     case LCK_READ: | ||||
| 	status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid); | ||||
| 	break; | ||||
|  | ||||
|     case LCK_WRITE: | ||||
| 	status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, 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); | ||||
|  | ||||
|     /* The held lock mode is in the lock id */ | ||||
|     assert(lockid == LCK_EXCL || | ||||
| 	   lockid == LCK_READ || | ||||
| 	   lockid == LCK_WRITE); | ||||
|  | ||||
|     switch (lockid) | ||||
|     { | ||||
|     case LCK_EXCL: | ||||
| 	status = _unlock_resource(lock1, lockid); | ||||
| 	if (status) | ||||
| 	    goto out; | ||||
| 	status = _unlock_resource(lock2, lockid); | ||||
| 	break; | ||||
|  | ||||
|     case LCK_READ: | ||||
| 	status = _unlock_resource(lock1, lockid); | ||||
| 	break; | ||||
|  | ||||
|     case LCK_WRITE: | ||||
| 	status = _unlock_resource(lock2, lockid); | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|  out: | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| static int _is_quorate() | ||||
| { | ||||
|     if (current_corestate == lg_core_Slave || | ||||
| 	current_corestate == lg_core_Master || | ||||
| 	current_corestate == lg_core_Client) | ||||
| 	return 1; | ||||
|     else | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Get all the cluster node names & IPs from CCS and | ||||
|    add them to our node list so we know who to talk to. | ||||
|    Called when we start up and if we get sent SIGHUP. | ||||
| */ | ||||
| static int get_all_cluster_nodes() | ||||
| { | ||||
|     int ctree; | ||||
|     char *nodename; | ||||
|     int error; | ||||
|     int i; | ||||
|  | ||||
|     /* Open the config file */ | ||||
|     ctree = ccs_force_connect(NULL, 1); | ||||
|     if (ctree < 0) | ||||
|     { | ||||
| 	log_error("Error connecting to CCS"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     for (i=1;;i++) | ||||
|     { | ||||
| 	char nodekey[256]; | ||||
| 	char nodeip[GULM_MAX_CSID_LEN]; | ||||
| 	int  clvmflag = 1; | ||||
| 	char *clvmflagstr; | ||||
| 	char key[256]; | ||||
|  | ||||
| 	sprintf(nodekey, "//cluster/clusternodes/clusternode[%d]/@name", i); | ||||
| 	error = ccs_get(ctree, nodekey, &nodename); | ||||
| 	if (error) | ||||
| 	    break; | ||||
|  | ||||
| 	sprintf(key, "//cluster/clusternodes/clusternode[@name=\"%s\"]/clvm", nodename); | ||||
| 	if (!ccs_get(ctree, key, &clvmflagstr)) | ||||
| 	{ | ||||
| 	    clvmflag = atoi(clvmflagstr); | ||||
| 	    free(clvmflagstr); | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("Got node %s from ccs(clvmflag = %d)\n", nodename, clvmflag); | ||||
| 	if ((get_ip_address(nodename, nodeip) == 0) && clvmflag) | ||||
| 	{ | ||||
| 	    struct node_info *ninfo; | ||||
|  | ||||
| 	    /* If it's not in the list, then add it */ | ||||
| 	    ninfo = hash_lookup_binary(node_hash, nodeip, GULM_MAX_CSID_LEN); | ||||
| 	    if (!ninfo) | ||||
| 	    { | ||||
| 		ninfo = malloc(sizeof(struct node_info)); | ||||
| 		if (!ninfo) | ||||
| 		{ | ||||
| 		    syslog(LOG_ERR, "Cannot alloc memory for node info\n"); | ||||
| 		    ccs_disconnect(ctree); | ||||
| 		    return -1; | ||||
| 		} | ||||
| 		strcpy(ninfo->name, nodename); | ||||
|  | ||||
| 		ninfo->state = NODE_DOWN; | ||||
| 		hash_insert_binary(node_hash, nodeip, GULM_MAX_CSID_LEN, ninfo); | ||||
| 	    } | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    DEBUGLOG("node %s has clvm disabled\n", nodename); | ||||
| 	} | ||||
| 	free(nodename); | ||||
|     } | ||||
|  | ||||
|     /* Finished with config file */ | ||||
|     ccs_disconnect(ctree); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_init_completed(void) | ||||
| { | ||||
| 	clvmd_cluster_init_completed(); | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	return get_main_gulm_cluster_fd(); | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client) | ||||
| { | ||||
| 	return cluster_fd_gulm_callback(fd, buf, len, csid, new_client); | ||||
| } | ||||
|  | ||||
| static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext) | ||||
| { | ||||
| 	return gulm_cluster_send_message(buf, msglen, csid, errtext); | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_gulm_ops = { | ||||
| 	.cluster_init_completed   = _cluster_init_completed, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = gulm_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              = gulm_add_up_node, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_gulm_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_gulm_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										12
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
| 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(char *node, char *addr); | ||||
| extern void tcp_remove_client(char *csid); | ||||
| extern int alloc_client(int fd, char *csid, struct local_client **new_client); | ||||
|  | ||||
| void gulm_add_up_node(char *csid); | ||||
| int gulm_name_from_csid(char *csid, char *name); | ||||
							
								
								
									
										1778
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1778
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										123
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| /* | ||||
|  * 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; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * 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, | ||||
| 			      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; | ||||
|  | ||||
| 	union { | ||||
| 		struct localsock_bits localsock; | ||||
| 		struct pipe_bits pipe; | ||||
| 		struct netsock_bits net; | ||||
| 	} bits; | ||||
| }; | ||||
| #define DEBUG | ||||
| #ifdef DEBUG | ||||
| #define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args) | ||||
| #else | ||||
| #define DEBUGLOG(fmt, args...) | ||||
| #endif | ||||
|  | ||||
| #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, char *buf, int len, char *csid); | ||||
|  | ||||
| int sync_lock(const char *resource, int mode, int flags, int *lockid); | ||||
| int sync_unlock(const char *resource, int lockid); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										226
									
								
								daemons/clvmd/cnxman-socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								daemons/clvmd/cnxman-socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved. | ||||
| **  Copyright (C) 2004 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. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* CMAN socket interface header, | ||||
|    may be include by user or kernel code */ | ||||
|  | ||||
| #ifndef __CNXMAN_SOCKET_H | ||||
| #define __CNXMAN_SOCKET_H | ||||
|  | ||||
| /* A currently unused number. TIPC also uses this number and you're unlikely | ||||
|    to be using both. | ||||
|  */ | ||||
| #define AF_CLUSTER 30 | ||||
| #define PF_CLUSTER AF_CLUSTER | ||||
|  | ||||
| /* Protocol(socket) types */ | ||||
| #define CLPROTO_MASTER 2 | ||||
| #define CLPROTO_CLIENT 3 | ||||
|  | ||||
| /* ioctls -- should register these properly */ | ||||
| #define SIOCCLUSTER_NOTIFY            _IOW('x', 0x01, int) | ||||
| #define SIOCCLUSTER_REMOVENOTIFY      _IO( 'x', 0x02) | ||||
| #define SIOCCLUSTER_GETMEMBERS        _IOR('x', 0x03, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SETEXPECTED_VOTES _IOW('x', 0x04, int) | ||||
| #define SIOCCLUSTER_ISQUORATE         _IO( 'x', 0x05) | ||||
| #define SIOCCLUSTER_ISLISTENING       _IOW('x', 0x06, struct cl_listen_request) | ||||
| #define SIOCCLUSTER_GETALLMEMBERS     _IOR('x', 0x07, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SET_VOTES         _IOW('x', 0x08, int) | ||||
| #define SIOCCLUSTER_GET_VERSION       _IOR('x', 0x09, struct cl_version) | ||||
| #define SIOCCLUSTER_SET_VERSION       _IOW('x', 0x0a, struct cl_version) | ||||
| #define SIOCCLUSTER_ISACTIVE          _IO( 'x', 0x0b) | ||||
| #define SIOCCLUSTER_KILLNODE          _IOW('x', 0x0c, int) | ||||
| #define SIOCCLUSTER_GET_JOINCOUNT     _IO( 'x', 0x0d) | ||||
| #define SIOCCLUSTER_SERVICE_REGISTER  _IOW('x', 0x0e, char) | ||||
| #define SIOCCLUSTER_SERVICE_UNREGISTER _IO('x', 0x0f) | ||||
| #define SIOCCLUSTER_SERVICE_JOIN      _IO( 'x', 0x10) | ||||
| #define SIOCCLUSTER_SERVICE_LEAVE     _IO( 'x', 0x20) | ||||
| #define SIOCCLUSTER_SERVICE_SETSIGNAL _IOW('x', 0x30, int) | ||||
| #define SIOCCLUSTER_SERVICE_STARTDONE _IOW('x', 0x40, unsigned int) | ||||
| #define SIOCCLUSTER_SERVICE_GETEVENT  _IOR('x', 0x50, struct cl_service_event) | ||||
| #define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SERVICE_GLOBALID  _IOR('x', 0x70, uint32_t) | ||||
| #define SIOCCLUSTER_SERVICE_SETLEVEL  _IOR('x', 0x80, int) | ||||
| #define SIOCCLUSTER_GETNODE	      _IOWR('x', 0x90, struct cl_cluster_node) | ||||
| #define SIOCCLUSTER_BARRIER           _IOW('x', 0x0a0, struct cl_barrier_info) | ||||
|  | ||||
| /* These were setsockopts */ | ||||
| #define SIOCCLUSTER_PASS_SOCKET       _IOW('x', 0x0b0, struct cl_passed_sock) | ||||
| #define SIOCCLUSTER_SET_NODENAME      _IOW('x', 0x0b1, char *) | ||||
| #define SIOCCLUSTER_SET_NODEID        _IOW('x', 0x0b2, int) | ||||
| #define SIOCCLUSTER_JOIN_CLUSTER      _IOW('x', 0x0b3, struct cl_join_cluster_info) | ||||
| #define SIOCCLUSTER_LEAVE_CLUSTER     _IOW('x', 0x0b4, int) | ||||
|  | ||||
|  | ||||
| /* Maximum size of a cluster message */ | ||||
| #define CMAN_MAX_CLUSTER_MESSAGE          1500 | ||||
| #define CMAN_MAX_CLUSTER_MEMBER_NAME_LEN   255 | ||||
| #define MAX_BARRIER_NAME_LEN           33 | ||||
| #define MAX_SA_ADDR_LEN                12 | ||||
| #define MAX_CLUSTER_NAME_LEN           16 | ||||
|  | ||||
| /* Well-known cluster port numbers */ | ||||
| #define CLUSTER_PORT_MEMBERSHIP  1	/* Mustn't block during cluster | ||||
| 					 * transitions! */ | ||||
| #define CLUSTER_PORT_SERVICES    2 | ||||
| #define CLUSTER_PORT_SYSMAN      10	/* Remote execution daemon */ | ||||
| #define CLUSTER_PORT_CLVMD       11	/* Cluster LVM daemon */ | ||||
| #define CLUSTER_PORT_SLM         12	/* LVM SLM (simple lock manager) */ | ||||
|  | ||||
| /* Port numbers above this will be blocked when the cluster is inquorate or in | ||||
|  * transition */ | ||||
| #define HIGH_PROTECTED_PORT      9 | ||||
|  | ||||
| /* Reasons for leaving the cluster */ | ||||
| #define CLUSTER_LEAVEFLAG_DOWN     0	/* Normal shutdown */ | ||||
| #define CLUSTER_LEAVEFLAG_KILLED   1 | ||||
| #define CLUSTER_LEAVEFLAG_PANIC    2 | ||||
| #define CLUSTER_LEAVEFLAG_REMOVED  3	/* This one can reduce quorum */ | ||||
| #define CLUSTER_LEAVEFLAG_REJECTED 4	/* Not allowed into the cluster in the | ||||
| 					 * first place */ | ||||
| #define CLUSTER_LEAVEFLAG_INCONSISTENT 5	/* Our view of the cluster is | ||||
| 						 * in a minority */ | ||||
| #define CLUSTER_LEAVEFLAG_DEAD         6	/* Discovered to be dead */ | ||||
| #define CLUSTER_LEAVEFLAG_FORCE     0x10	/* Forced by command-line */ | ||||
|  | ||||
| /* OOB messages sent to a local socket */ | ||||
| #define CLUSTER_OOB_MSG_PORTCLOSED  1 | ||||
| #define CLUSTER_OOB_MSG_STATECHANGE 2 | ||||
| #define CLUSTER_OOB_MSG_SERVICEEVENT 3 | ||||
|  | ||||
| /* Sendmsg flags, these are above the normal sendmsg flags so they don't | ||||
|  * interfere */ | ||||
| #define MSG_NOACK     0x010000	/* Don't need an ACK for this message */ | ||||
| #define MSG_QUEUE     0x020000	/* Queue the message for sending later */ | ||||
| #define MSG_MULTICAST 0x080000	/* Message was sent to all nodes in the cluster | ||||
| 				 */ | ||||
| #define MSG_ALLINT    0x100000	/* Send out of all interfaces */ | ||||
| #define MSG_REPLYEXP  0x200000	/* Reply is expected */ | ||||
|  | ||||
| typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER, | ||||
| 	       NODESTATE_DEAD } nodestate_t; | ||||
|  | ||||
|  | ||||
| struct sockaddr_cl { | ||||
| 	unsigned short scl_family; | ||||
| 	unsigned char scl_flags; | ||||
| 	unsigned char scl_port; | ||||
| 	int           scl_nodeid; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * This is how we pass the multicast & receive sockets into kernel space. | ||||
|  */ | ||||
| struct cl_passed_sock { | ||||
| 	int fd;			/* FD of master socket to do multicast on */ | ||||
| 	int number;		/* Socket number, to match up recvonly & bcast | ||||
| 				 * sockets */ | ||||
|         int multicast;          /* Is it multicast or receive ? */ | ||||
| }; | ||||
|  | ||||
| /* Cluster configuration info passed when we join the cluster */ | ||||
| struct cl_join_cluster_info { | ||||
| 	unsigned char votes; | ||||
| 	unsigned int expected_votes; | ||||
| 	unsigned int two_node; | ||||
| 	unsigned int config_version; | ||||
|  | ||||
|         char cluster_name[17]; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* This is the structure, per node, returned from the membership ioctl */ | ||||
| struct cl_cluster_node { | ||||
| 	unsigned int size; | ||||
| 	unsigned int node_id; | ||||
| 	unsigned int us; | ||||
| 	unsigned int leave_reason; | ||||
| 	unsigned int incarnation; | ||||
| 	nodestate_t state; | ||||
| 	char name[CMAN_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| 	unsigned char votes; | ||||
| }; | ||||
|  | ||||
| /* The struct passed to the membership ioctls */ | ||||
| struct cl_cluster_nodelist { | ||||
|         uint32_t max_members; | ||||
|         struct cl_cluster_node *nodes; | ||||
| }; | ||||
|  | ||||
| /* Structure passed to SIOCCLUSTER_ISLISTENING */ | ||||
| struct cl_listen_request { | ||||
| 	unsigned char port; | ||||
|         int           nodeid; | ||||
| }; | ||||
|  | ||||
| /* A Cluster PORTCLOSED message - received by a local user as an OOB message */ | ||||
| struct cl_portclosed_oob { | ||||
| 	unsigned char cmd;	/* CLUSTER_OOB_MSG_PORTCLOSED */ | ||||
| 	unsigned char port; | ||||
| }; | ||||
|  | ||||
| /* Get all version numbers or set the config version */ | ||||
| struct cl_version { | ||||
| 	unsigned int major; | ||||
| 	unsigned int minor; | ||||
| 	unsigned int patch; | ||||
| 	unsigned int config; | ||||
| }; | ||||
|  | ||||
| /* structure passed to barrier ioctls */ | ||||
| struct cl_barrier_info { | ||||
| 	char cmd; | ||||
| 	char name[MAX_BARRIER_NAME_LEN]; | ||||
| 	unsigned int flags; | ||||
| 	unsigned long arg; | ||||
| }; | ||||
|  | ||||
| typedef enum { SERVICE_EVENT_STOP, SERVICE_EVENT_START, SERVICE_EVENT_FINISH, | ||||
| 		SERVICE_EVENT_LEAVEDONE } service_event_t; | ||||
|  | ||||
| typedef enum { SERVICE_START_FAILED, SERVICE_START_JOIN, SERVICE_START_LEAVE } | ||||
| 		service_start_t; | ||||
|  | ||||
| struct cl_service_event { | ||||
| 	service_event_t type; | ||||
| 	service_start_t start_type; | ||||
| 	unsigned int event_id; | ||||
| 	unsigned int last_stop; | ||||
| 	unsigned int last_start; | ||||
| 	unsigned int last_finish; | ||||
| 	unsigned int node_count; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Commands to the barrier ioctl */ | ||||
| #define BARRIER_IOCTL_REGISTER 1 | ||||
| #define BARRIER_IOCTL_CHANGE   2 | ||||
| #define BARRIER_IOCTL_DELETE   3 | ||||
| #define BARRIER_IOCTL_WAIT     4 | ||||
|  | ||||
| /* Attributes of a barrier - bitmask */ | ||||
| #define BARRIER_ATTR_AUTODELETE 1 | ||||
| #define BARRIER_ATTR_MULTISTEP  2 | ||||
| #define BARRIER_ATTR_MANUAL     4 | ||||
| #define BARRIER_ATTR_ENABLED    8 | ||||
| #define BARRIER_ATTR_CALLBACK  16 | ||||
|  | ||||
| /* Attribute setting commands */ | ||||
| #define BARRIER_SETATTR_AUTODELETE 1 | ||||
| #define BARRIER_SETATTR_MULTISTEP  2 | ||||
| #define BARRIER_SETATTR_ENABLED    3 | ||||
| #define BARRIER_SETATTR_NODES      4 | ||||
| #define BARRIER_SETATTR_CALLBACK   5 | ||||
| #define BARRIER_SETATTR_TIMEOUT    6 | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										446
									
								
								daemons/clvmd/libclvm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										446
									
								
								daemons/clvmd/libclvm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,446 @@ | ||||
| /* | ||||
|  * Copyright (C) 1997-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 | ||||
|  */ | ||||
|  | ||||
| /* library functions for Cluster LVM Daemon */ | ||||
|  | ||||
| #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 <search.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "libclvm.h" | ||||
|  | ||||
| /* CLVM in hex! */ | ||||
| #define LVM_SIGNATURE 0x434C564D | ||||
|  | ||||
| #define MAX_CLUSTER_MEMBER_NAME_LEN 255 | ||||
|  | ||||
| /* NOTE: the LVMD uses the socket FD as the client ID, this means | ||||
|    that any client that calls fork() will inherit the context of | ||||
|    it's parent. */ | ||||
| static int clvmd_sock = -1; | ||||
|  | ||||
| static int open_local_sock(void) | ||||
| { | ||||
| 	int local_socket; | ||||
| 	struct sockaddr_un sockaddr; | ||||
|  | ||||
| 	/* Open local socket */ | ||||
| 	local_socket = socket(PF_UNIX, SOCK_STREAM, 0); | ||||
| 	if (local_socket < 0) { | ||||
| 		perror("Can't create local socket"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	fcntl(local_socket, F_SETFD, !FD_CLOEXEC); | ||||
|  | ||||
| 	strcpy(sockaddr.sun_path, CLVMD_SOCKNAME); | ||||
| 	sockaddr.sun_family = AF_UNIX; | ||||
| 	if (connect | ||||
| 	    (local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		close(local_socket); | ||||
|  | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return local_socket; | ||||
| } | ||||
|  | ||||
| /* Send a request and return the status */ | ||||
| static int send_request(char *inbuf, int inlen, char **retbuf) | ||||
| { | ||||
| 	char outbuf[PIPE_BUF]; | ||||
| 	struct clvm_header *outheader = (struct clvm_header *) outbuf; | ||||
| 	int len; | ||||
| 	int off; | ||||
| 	fd_set fds; | ||||
|  | ||||
| 	FD_ZERO(&fds); | ||||
| 	FD_SET(clvmd_sock, &fds); | ||||
|  | ||||
| 	/* Send it to CLVMD */ | ||||
| 	if (write(clvmd_sock, inbuf, inlen) != inlen) { | ||||
| 		perror("Error writing to CLVMD"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the response */ | ||||
| 	if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { | ||||
| 		perror("Error reading CLVMD"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (len == 0) { | ||||
| 		fprintf(stderr, "EOF reading CLVMD"); | ||||
| 		errno = ENOTCONN; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Allocate buffer */ | ||||
| 	*retbuf = malloc(len + outheader->arglen); | ||||
| 	if (!*retbuf) { | ||||
| 		errno = ENOMEM; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* 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, PIPE_BUF); | ||||
| 		if (len > 0) | ||||
| 			off += len; | ||||
| 	} | ||||
|  | ||||
| 	/* Was it an error ? */ | ||||
| 	if (outheader->status < 0) { | ||||
| 		errno = -outheader->status; | ||||
| 		return -2; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Build the structure header and parse-out wildcard node names */ | ||||
| static void build_header(struct clvm_header *head, int cmd, const char *node, | ||||
| 			 void *data, 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 */ | ||||
| int lvm_cluster_write(char cmd, char *node, void *data, int len) | ||||
| { | ||||
| 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1]; | ||||
| 	char *retbuf = NULL; | ||||
| 	int status; | ||||
| 	struct clvm_header *head = (struct clvm_header *) outbuf; | ||||
|  | ||||
| 	if (clvmd_sock == -1) | ||||
| 		clvmd_sock = open_local_sock(); | ||||
| 	if (clvmd_sock == -1) | ||||
| 		return -1; | ||||
|  | ||||
| 	build_header(head, cmd, node, data, len); | ||||
| 	memcpy(head->node + strlen(head->node) + 1, data, len); | ||||
|  | ||||
| 	status = | ||||
| 	    send_request(outbuf, | ||||
| 			 sizeof(struct clvm_header) + strlen(head->node) + len, | ||||
| 			 &retbuf); | ||||
| 	if (retbuf) | ||||
| 		free(retbuf); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* API: Send a message to a(or all) node(s) in the cluster | ||||
|    and wait for replies */ | ||||
| int lvm_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]; | ||||
| 	int *outptr; | ||||
| 	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 -1; | ||||
|  | ||||
| 	build_header(head, cmd, node, data, 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 == 0 || status == -2) { | ||||
| 		/* 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 */ | ||||
| 		outptr = | ||||
| 		    malloc(sizeof(lvm_response_t) * num_responses + | ||||
| 			   sizeof(int) * 2); | ||||
| 		if (!outptr) { | ||||
| 			if (retbuf) | ||||
| 				free(retbuf); | ||||
| 			errno = ENOMEM; | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		*response = (lvm_response_t *) (outptr + 2); | ||||
| 		outptr[0] = LVM_SIGNATURE; | ||||
| 		outptr[1] = num_responses; | ||||
| 		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; | ||||
|  | ||||
| 			rarray[i].status = *(int *) inptr; | ||||
| 			inptr += sizeof(int); | ||||
|  | ||||
| 			rarray[i].response = malloc(strlen(inptr) + 1); | ||||
| 			if (rarray[i].response == NULL) { | ||||
| 				/* Free up everything else and return error */ | ||||
| 				int j; | ||||
| 				for (j = 0; j < i; j++) | ||||
| 					free(rarray[i].response); | ||||
| 				free(outptr); | ||||
| 				errno = ENOMEM; | ||||
| 				return -1; | ||||
| 			} | ||||
|  | ||||
| 			strcpy(rarray[i].response, inptr); | ||||
| 			rarray[i].len = strlen(inptr); | ||||
| 			inptr += strlen(inptr) + 1; | ||||
| 			i++; | ||||
| 		} | ||||
| 		*num = num_responses; | ||||
| 		*response = rarray; | ||||
| 	} | ||||
|  | ||||
| 	if (retbuf) | ||||
| 		free(retbuf); | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* API: Free reply array */ | ||||
| int lvm_cluster_free_request(lvm_response_t * response) | ||||
| { | ||||
| 	int *ptr = (int *) response - 2; | ||||
| 	int i; | ||||
| 	int num; | ||||
|  | ||||
| 	/* Check it's ours to free */ | ||||
| 	if (response == NULL || *ptr != LVM_SIGNATURE) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	num = ptr[1]; | ||||
| 	for (i = 0; i < num; i++) { | ||||
| 		free(response[i].response); | ||||
| 	} | ||||
| 	free(ptr); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* These are a "higher-level" API providing black-box lock/unlock | ||||
|    functions for cluster LVM...maybe */ | ||||
|  | ||||
| /* Set by lock(), used by unlock() */ | ||||
| static int num_responses; | ||||
| static lvm_response_t *response; | ||||
|  | ||||
| int lvm_lock_for_cluster(char scope, char *name, int verbosity) | ||||
| { | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	char *args; | ||||
| 	int len; | ||||
|  | ||||
| 	if (name) { | ||||
| 		len = strlen(name) + 2; | ||||
| 		args = alloca(len); | ||||
| 		strcpy(args + 1, name); | ||||
| 	} else { | ||||
| 		len = 2; | ||||
| 		args = alloca(len); | ||||
| 		args[1] = '\0'; | ||||
| 	} | ||||
| 	args[0] = scope; | ||||
|  | ||||
| 	status = lvm_cluster_request(CLVMD_CMD_LOCK, | ||||
| 				     "", args, len, &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) { | ||||
| 			if (verbosity) | ||||
| 				fprintf(stderr, | ||||
| 					"clvmd not running on node %s\n", | ||||
| 					response[i].node); | ||||
| 			status = -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* If there was an error then free the memory now as the caller won't | ||||
| 	   want to do the unlock */ | ||||
| 	if (status) { | ||||
| 		int saved_errno = errno; | ||||
| 		lvm_cluster_free_request(response); | ||||
| 		num_responses = 0; | ||||
| 		errno = saved_errno; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| int lvm_unlock_for_cluster(char scope, char *name, int verbosity) | ||||
| { | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int len; | ||||
| 	int failed; | ||||
| 	int num_unlock_responses; | ||||
| 	char *args; | ||||
| 	lvm_response_t *unlock_response; | ||||
|  | ||||
| 	/* We failed - this should not have been called */ | ||||
| 	if (num_responses == 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (name) { | ||||
| 		len = strlen(name) + 2; | ||||
| 		args = alloca(len); | ||||
| 		strcpy(args + 1, name); | ||||
| 	} else { | ||||
| 		len = 2; | ||||
| 		args = alloca(len); | ||||
| 		args[1] = '\0'; | ||||
| 	} | ||||
| 	args[0] = scope; | ||||
|  | ||||
| 	/* See if it failed anywhere */ | ||||
| 	failed = 0; | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status != 0) | ||||
| 			failed++; | ||||
| 	} | ||||
|  | ||||
| 	/* If it failed on any nodes then we only unlock on | ||||
| 	   the nodes that succeeded */ | ||||
| 	if (failed) { | ||||
| 		for (i = 0; i < num_responses; i++) { | ||||
| 			/* Unlock the ones that succeeded */ | ||||
| 			if (response[i].status == 0) { | ||||
| 				status = lvm_cluster_request(CLVMD_CMD_UNLOCK, | ||||
| 							     response[i].node, | ||||
| 							     args, len, | ||||
| 							     &unlock_response, | ||||
| 							     &num_unlock_responses); | ||||
| 				if (status) { | ||||
| 					if (verbosity) | ||||
| 						fprintf(stderr, | ||||
| 							"cluster command to node %s failed: %s\n", | ||||
| 							response[i].node, | ||||
| 							strerror(errno)); | ||||
| 				} else if (unlock_response[0].status != 0) { | ||||
| 					if (verbosity > 1) | ||||
| 						fprintf(stderr, | ||||
| 							"unlock on node %s failed: %s\n", | ||||
| 							response[i].node, | ||||
| 							strerror(unlock_response | ||||
| 								 [0].status)); | ||||
| 				} | ||||
| 				lvm_cluster_free_request(unlock_response); | ||||
| 			} else { | ||||
| 				if (verbosity) | ||||
| 					fprintf(stderr, | ||||
| 						"command on node %s failed: '%s' - will be left locked\n", | ||||
| 						response[i].node, | ||||
| 						strerror(response[i].status)); | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* All OK, we can do a full cluster unlock */ | ||||
| 		status = lvm_cluster_request(CLVMD_CMD_UNLOCK, | ||||
| 					     "", | ||||
| 					     args, len, | ||||
| 					     &unlock_response, | ||||
| 					     &num_unlock_responses); | ||||
| 		if (status) { | ||||
| 			if (verbosity > 1) | ||||
| 				fprintf(stderr, "cluster command failed: %s\n", | ||||
| 					strerror(errno)); | ||||
| 		} else { | ||||
| 			for (i = 0; i < num_unlock_responses; i++) { | ||||
| 				if (unlock_response[i].status != 0) { | ||||
| 					if (verbosity > 1) | ||||
| 						fprintf(stderr, | ||||
| 							"unlock on node %s failed: %s\n", | ||||
| 							response[i].node, | ||||
| 							strerror(unlock_response | ||||
| 								 [0].status)); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		lvm_cluster_free_request(unlock_response); | ||||
| 	} | ||||
| 	lvm_cluster_free_request(response); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										36
									
								
								daemons/clvmd/libclvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								daemons/clvmd/libclvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * Copyright (C) 1997-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 _LIBCLVM_H | ||||
| #define _LIBCLVM_H | ||||
|  | ||||
| typedef struct lvm_response { | ||||
| 	char node[255]; | ||||
| 	char *response; | ||||
| 	int status; | ||||
| 	int len; | ||||
|  | ||||
| } lvm_response_t; | ||||
|  | ||||
| extern int lvm_cluster_request(char cmd, const char *node, void *data, int len, | ||||
| 			       lvm_response_t ** response, int *num); | ||||
| extern int lvm_cluster_write(char cmd, char *node, void *data, int len); | ||||
| extern int lvm_cluster_free_request(lvm_response_t * response); | ||||
|  | ||||
| /* The "high-level" API */ | ||||
| extern int lvm_lock_for_cluster(char scope, char *name, int verbosity); | ||||
| extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										463
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										463
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,463 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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 "libdlm.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| /* LVM2 headers */ | ||||
| #include "toolcontext.h" | ||||
| #include "log.h" | ||||
| #include "activate.h" | ||||
| #include "hash.h" | ||||
| #include "locking.h" | ||||
|  | ||||
| static struct cmd_context *cmd = NULL; | ||||
| static struct hash_table *lv_hash = NULL; | ||||
| static pthread_mutex_t lv_hash_lock; | ||||
|  | ||||
| struct lv_info { | ||||
| 	int lock_id; | ||||
| 	int lock_mode; | ||||
| }; | ||||
|  | ||||
| /* 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 = 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 hash_node *v; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	hash_iterate(v, lv_hash) { | ||||
| 		struct lv_info *lvi = hash_get_data(lv_hash, v); | ||||
|  | ||||
| 		sync_unlock(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 = 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); | ||||
| 			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 = 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); | ||||
| 		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, int mode) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
| 	int activate_lv; | ||||
| 	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; | ||||
|  | ||||
| 	/* OK, try to get the lock */ | ||||
| 	status = hold_lock(resource, mode, LKF_NOQUEUE); | ||||
| 	if (status) | ||||
| 		return errno; | ||||
|  | ||||
| 	/* If it's suspended then resume it */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, &lvi)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.suspended) | ||||
| 		if (!lv_resume(cmd, resource)) | ||||
| 			return EIO; | ||||
|  | ||||
| 	/* Now activate it */ | ||||
| 	if (!lv_activate(cmd, resource)) | ||||
| 		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_deactivate_lock, 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)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.exists) { | ||||
| 		if (!lv_suspend_if_active(cmd, resource)) { | ||||
| 			return EIO; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_deactivate_lv(char *resource) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1) { | ||||
| 		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; | ||||
|  | ||||
| 	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 = 0x%x, flags = %d\n", | ||||
| 		 resource, command, lock_flags); | ||||
|  | ||||
| 	if (!cmd->config_valid || config_files_changed(cmd)) { | ||||
| 		/* Reinitialise various settings inc. logging, filters */ | ||||
| 		if (!refresh_toolcontext(cmd)) { | ||||
| 			log_error("Updated config file invalid. Aborting."); | ||||
| 			return EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch (command) { | ||||
| 	case LCK_LV_EXCLUSIVE: | ||||
| 		status = do_activate_lv(resource, LKM_EXMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_SUSPEND: | ||||
| 		status = do_suspend_lv(resource); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_UNLOCK: | ||||
| 	case LCK_LV_RESUME:	/* if active */ | ||||
| 		status = do_resume_lv(resource); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_ACTIVATE: | ||||
| 		status = do_activate_lv(resource, LKM_CRMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_DEACTIVATE: | ||||
| 		status = do_deactivate_lv(resource); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		DEBUGLOG("Invalid LV command 0x%x\n", command); | ||||
| 		status = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	/* clean the pool for another command */ | ||||
| 	pool_empty(cmd->mem); | ||||
|  | ||||
| 	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 = 0x%x, flags = %d\n", | ||||
| 			 resource, command, 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) | ||||
| { | ||||
| 	/* Opposite of above, done on resume after a metadata update */ | ||||
| 	if (command == LCK_LV_RESUME) { | ||||
| 		int oldmode; | ||||
|  | ||||
| 		DEBUGLOG | ||||
| 		    ("post_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n", | ||||
| 		     resource, command, 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; | ||||
|  | ||||
| 			if (!lv_info_by_lvid(cmd, resource, &lvi)) | ||||
| 				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 un use by LVM1 so we don't stomp on it */ | ||||
| int do_check_lvm1(char *vgname) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	status = check_lvm1_vg_inactive(cmd, vgname); | ||||
|  | ||||
| 	return status == 1 ? 0 : EBUSY; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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]; | ||||
| 	char uuid[65]; | ||||
| 	char line[255]; | ||||
| 	FILE *lvs = | ||||
| 	    popen | ||||
| 	    ("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr", | ||||
| 	     "r"); | ||||
|  | ||||
| 	if (!lvs) | ||||
| 		return NULL; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), lvs)) { | ||||
| 	        if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) { | ||||
|  | ||||
| 			/* 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? */ | ||||
| 				/* 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	fclose(lvs); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void init_lvhash() | ||||
| { | ||||
| 	/* Create hash table for keeping LV locks & status */ | ||||
| 	lv_hash = hash_create(100); | ||||
| 	pthread_mutex_init(&lv_hash_lock, NULL); | ||||
| } | ||||
|  | ||||
| /* Called to initialise the LVM context of the daemon */ | ||||
| int init_lvm(void) | ||||
| { | ||||
| 	if (!(cmd = create_toolcontext(NULL))) { | ||||
| 		log_error("Failed to allocate command context"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */ | ||||
| 	init_syslog(LOG_DAEMON); | ||||
| 	init_debug(_LOG_ERR); | ||||
|  | ||||
| 	get_initial_state(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										35
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * 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(char *vgname); | ||||
| extern int init_lvm(void); | ||||
| extern void init_lvhash(void); | ||||
|  | ||||
| extern int hold_unlock(char *resource); | ||||
| extern int hold_lock(char *resource, int mode, int flags); | ||||
| extern void unlock_all(void); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										371
									
								
								daemons/clvmd/system-lv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										371
									
								
								daemons/clvmd/system-lv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,371 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| /* Routines dealing with the System LV */ | ||||
|  | ||||
| #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/mount.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 <dirent.h> | ||||
| #include <errno.h> | ||||
| #include <mntent.h> | ||||
|  | ||||
| #include "libdlm.h" | ||||
| #include "log.h" | ||||
| #include "list.h" | ||||
| #include "locking.h" | ||||
| #include "system-lv.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #ifdef HAVE_CCS | ||||
| #include "ccs.h" | ||||
| #endif | ||||
|  | ||||
| #define SYSTEM_LV_FILESYSTEM "ext2" | ||||
| #define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX" | ||||
|  | ||||
| extern char *config_filename(void); | ||||
|  | ||||
| static char system_lv_name[PATH_MAX] = { '\0' }; | ||||
| static char mount_point[PATH_MAX] = { '\0' }; | ||||
| static int mounted = 0; | ||||
| static int mounted_rw = 0; | ||||
| static int lockid; | ||||
| static const char *lock_name = "CLVM_SYSTEM_LV"; | ||||
|  | ||||
| /* Look in /proc/mounts or (as a last resort) /etc/mtab to | ||||
|    see if the system-lv is mounted. If it is mounted and we | ||||
|    think it's not then abort because we don't have the right | ||||
|    lock status and we don't know what other processes are doing with it. | ||||
|  | ||||
|    Returns 1 for mounted, 0 for not mounted so it matches the condition | ||||
|    of the "mounted" static variable above. | ||||
| */ | ||||
| static int is_really_mounted(void) | ||||
| { | ||||
| 	FILE *mountfile; | ||||
| 	struct mntent *ment; | ||||
|  | ||||
| 	mountfile = setmntent("/proc/mounts", "r"); | ||||
| 	if (!mountfile) { | ||||
| 		mountfile = setmntent("/etc/mtab", "r"); | ||||
| 		if (!mountfile) { | ||||
| 			log_error("Unable to open /proc/mounts or /etc/mtab"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Look for system LV name in the file */ | ||||
| 	do { | ||||
| 		ment = getmntent(mountfile); | ||||
| 		if (ment) { | ||||
| 			if (strcmp(ment->mnt_fsname, system_lv_name) == 0) { | ||||
| 				endmntent(mountfile); | ||||
| 				return 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	while (ment); | ||||
|  | ||||
| 	endmntent(mountfile); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Get the system LV name from the config file */ | ||||
| static int find_system_lv(void) | ||||
| { | ||||
| 	if (system_lv_name[0] == '\0') { | ||||
| #ifdef HAVE_CCS | ||||
| 		int error; | ||||
| 		ccs_node_t *ctree; | ||||
|  | ||||
| 		/* Read the cluster config file */ | ||||
| 		/* Open the config file */ | ||||
| 		error = open_ccs_file(&ctree, "clvm.ccs"); | ||||
| 		if (error) { | ||||
| 			perror("reading config file"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(system_lv_name, find_ccs_str(ctree, | ||||
| 						    "cluster/systemlv", '/', | ||||
| 						    "/dev/vg/system_lv")); | ||||
|  | ||||
| 		/* Finished with config file */ | ||||
| 		close_ccs_file(ctree); | ||||
| #else | ||||
| 		if (getenv("CLVMD_SYSTEM_LV")) | ||||
| 			strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV")); | ||||
| 		else | ||||
| 			return -1; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	/* See if it has been mounted outside our control */ | ||||
| 	if (is_really_mounted() != mounted) { | ||||
| 		log_error | ||||
| 		    ("The system LV state has been mounted/umounted outside the control of clvmd\n" | ||||
| 		     "it cannot not be used for cluster communications until this is fixed.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* No prizes */ | ||||
| int system_lv_umount(void) | ||||
| { | ||||
| 	if (!mounted) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (umount(mount_point) < 0) { | ||||
| 		log_error("umount of system LV (%s) failed: %m\n", | ||||
| 			  system_lv_name); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sync_unlock(lock_name, lockid); | ||||
| 	mounted = 0; | ||||
|  | ||||
| 	/* Remove the mount point */ | ||||
| 	rmdir(mount_point); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int system_lv_mount(int readwrite) | ||||
| { | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
| 	int fd; | ||||
|  | ||||
| 	if (find_system_lv()) { | ||||
| 		errno = EBUSY; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Is it already mounted suitably? */ | ||||
| 	if (mounted) { | ||||
| 		if (!readwrite || (readwrite && mounted_rw)) { | ||||
| 			return 0; | ||||
| 		} else { | ||||
| 			/* Mounted RO and we need RW */ | ||||
| 			if (system_lv_umount() < 0) | ||||
| 				return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Randomize the mount point */ | ||||
| 	strcpy(mount_point, SYSTEM_LV_MOUNTPOINT); | ||||
| 	fd = mkstemp(mount_point); | ||||
| 	if (fd < 0) { | ||||
| 		log_error("mkstemp for system LV mount point failed: %m\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Race condition here but there's no mkstemp for directories */ | ||||
| 	close(fd); | ||||
| 	unlink(mount_point); | ||||
| 	mkdir(mount_point, 0600); | ||||
|  | ||||
| 	/* Make sure we have a system-lv lock */ | ||||
| 	status = | ||||
| 	    sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0, | ||||
| 		      &lockid); | ||||
| 	if (status < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Mount it */ | ||||
| 	if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM, | ||||
| 		  MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS | ||||
| 		  | (readwrite ? 0 : MS_RDONLY), NULL) < 0) { | ||||
| 		/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to | ||||
| 		   write to it we try to make a filesystem in it and retry the mount */ | ||||
| 		if (errno == EINVAL && readwrite) { | ||||
| 			char cmd[256]; | ||||
|  | ||||
| 			log_error("Attempting mkfs on system LV device %s\n", | ||||
| 				  system_lv_name); | ||||
| 			snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s", | ||||
| 				 SYSTEM_LV_FILESYSTEM, system_lv_name); | ||||
| 			system(cmd); | ||||
|  | ||||
| 			if (mount | ||||
| 			    (system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM, | ||||
| 			     MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | | ||||
| 			     MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY), | ||||
| 			     NULL) == 0) | ||||
| 				goto mounted; | ||||
| 		} | ||||
|  | ||||
| 		saved_errno = errno; | ||||
| 		log_error("mount of system LV (%s, %s, %s) failed: %m\n", | ||||
| 			  system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM); | ||||
| 		sync_unlock(lock_name, lockid); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|       mounted: | ||||
| /* Set the internal flags */ | ||||
| 	mounted = 1; | ||||
| 	mounted_rw = readwrite; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Erase *all* files in the root directory of the system LV. | ||||
|    This *MUST* be called with an appropriate lock held! | ||||
|    The LV is left mounted RW because it is assumed that the | ||||
|    caller wants to write something here after clearing some space */ | ||||
| int system_lv_eraseall(void) | ||||
| { | ||||
| 	DIR *dir; | ||||
| 	struct dirent *ent; | ||||
| 	char fname[PATH_MAX]; | ||||
|  | ||||
| 	/* Must be mounted R/W */ | ||||
| 	system_lv_mount(1); | ||||
|  | ||||
| 	dir = opendir(mount_point); | ||||
| 	if (!dir) | ||||
| 		return -1; | ||||
|  | ||||
| 	while ((ent = readdir(dir))) { | ||||
| 		struct stat st; | ||||
| 		snprintf(fname, sizeof(fname), "%s/%s", mount_point, | ||||
| 			 ent->d_name); | ||||
|  | ||||
| 		if (stat(fname, &st)) { | ||||
| 			if (S_ISREG(st.st_mode)) | ||||
| 				unlink(fname); | ||||
| 		} | ||||
| 	} | ||||
| 	closedir(dir); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* This is a "high-level" routine - it mounts the system LV, writes | ||||
|    the data into a file named after this node and then umounts the LV | ||||
|    again */ | ||||
| int system_lv_write_data(char *data, ssize_t len) | ||||
| { | ||||
| 	struct utsname nodeinfo; | ||||
| 	char fname[PATH_MAX]; | ||||
| 	int outfile; | ||||
| 	ssize_t thiswrite; | ||||
| 	ssize_t written; | ||||
|  | ||||
| 	if (system_lv_mount(1)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Build the file name we are goingto use. */ | ||||
| 	uname(&nodeinfo); | ||||
| 	snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename); | ||||
|  | ||||
| 	/* Open the file for output */ | ||||
| 	outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600); | ||||
| 	if (outfile < 0) { | ||||
| 		int saved_errno = errno; | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	written = 0; | ||||
| 	do { | ||||
| 		thiswrite = write(outfile, data + written, len - written); | ||||
| 		if (thiswrite > 0) | ||||
| 			written += thiswrite; | ||||
|  | ||||
| 	} while (written < len && thiswrite > 0); | ||||
|  | ||||
| 	close(outfile); | ||||
|  | ||||
| 	system_lv_umount(); | ||||
| 	return (thiswrite < 0) ? -1 : 0; | ||||
| } | ||||
|  | ||||
| /* This is a "high-level" routine - it mounts the system LV, reads | ||||
|    the data from a named file and then umounts the LV | ||||
|    again */ | ||||
| int system_lv_read_data(char *fname_base, char *data, ssize_t *len) | ||||
| { | ||||
| 	char fname[PATH_MAX]; | ||||
| 	int outfile; | ||||
| 	struct stat st; | ||||
| 	ssize_t filesize; | ||||
| 	ssize_t thisread; | ||||
| 	ssize_t readbytes; | ||||
|  | ||||
| 	if (system_lv_mount(0)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Build the file name we are going to use. */ | ||||
| 	snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base); | ||||
|  | ||||
| 	/* Get the file size and stuff. Actually we only need the file size but | ||||
| 	   this will also check that the file exists */ | ||||
| 	if (stat(fname, &st) < 0) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		log_error("stat of file %s on system LV failed: %m\n", fname); | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	filesize = st.st_size; | ||||
|  | ||||
| 	outfile = open(fname, O_RDONLY); | ||||
| 	if (outfile < 0) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		log_error("open of file %s on system LV failed: %m\n", fname); | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	readbytes = 0; | ||||
| 	do { | ||||
| 		thisread = | ||||
| 		    read(outfile, data + readbytes, filesize - readbytes); | ||||
| 		if (thisread > 0) | ||||
| 			readbytes += thisread; | ||||
|  | ||||
| 	} while (readbytes < filesize && thisread > 0); | ||||
|  | ||||
| 	close(outfile); | ||||
|  | ||||
| 	system_lv_umount(); | ||||
|  | ||||
| 	*len = readbytes; | ||||
| 	return (thisread < 0) ? -1 : 0; | ||||
| } | ||||
							
								
								
									
										30
									
								
								daemons/clvmd/system-lv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								daemons/clvmd/system-lv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * 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 _CLVM_SYSTEM_LV_H | ||||
| #define _CLVM_SYSTEM_LV_H | ||||
|  | ||||
| /* Prototypes for System-LV functions */ | ||||
|  | ||||
| /* "low-level" functions */ | ||||
| extern int system_lv_umount(void); | ||||
| extern int system_lv_mount(int readwrite); | ||||
| extern int system_lv_eraseall(void); | ||||
|  | ||||
| /* "high-level" functions */ | ||||
| extern int system_lv_write_data(char *data, ssize_t len); | ||||
| extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										444
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,444 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  2002-2003  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. | ||||
| */ | ||||
|  | ||||
|  | ||||
| #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 "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "clvmd-gulm.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| #define DEFAULT_TCP_PORT 21064 | ||||
|  | ||||
| static int listen_fd = -1; | ||||
| static int tcp_port; | ||||
| struct 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 = hash_create(100); | ||||
|     tcp_port = 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)); | ||||
|     } | ||||
|  | ||||
|     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); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void tcp_remove_client(char *csid) | ||||
|  { | ||||
|     struct local_client *client; | ||||
|     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 */ | ||||
|     client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (client) | ||||
|     { | ||||
| 	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     } | ||||
|  | ||||
|     /* Look for a mangled one too */ | ||||
|     csid[0] ^= 0x80; | ||||
|  | ||||
|     client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (client) | ||||
|     { | ||||
| 	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     } | ||||
|  | ||||
|     /* Put it back as we found it */ | ||||
|     csid[0] ^= 0x80; | ||||
| } | ||||
|  | ||||
| int alloc_client(int fd, char *csid, struct local_client **new_client) | ||||
| { | ||||
|     struct local_client *client; | ||||
|  | ||||
|     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 (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 (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; | ||||
|         } | ||||
|     } | ||||
|     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, 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; | ||||
| } | ||||
|  | ||||
|  | ||||
| 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); | ||||
|     int status; | ||||
|  | ||||
|     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); | ||||
|  | ||||
|     status = read(client->fd, buf, len); | ||||
|  | ||||
|     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; | ||||
| 	hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN); | ||||
|  | ||||
| 	/* Tell cluster manager layer */ | ||||
| 	add_down_node(remcsid); | ||||
|     } | ||||
|     else { | ||||
| 	    /* Send it back to clvmd */ | ||||
| 	    process_message(client, buf, len, csid); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| static int connect_csid(char *csid, struct local_client **newclient) | ||||
| { | ||||
|     int fd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     int status; | ||||
|  | ||||
|     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) | ||||
|     { | ||||
| 	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; | ||||
|     } | ||||
|  | ||||
|     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, unsigned 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 = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!client) | ||||
|     { | ||||
| 	status = 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, 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(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(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; | ||||
| } | ||||
							
								
								
									
										12
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #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(char *); | ||||
| int get_main_gulm_cluster_fd(void); | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client); | ||||
| int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext); | ||||
| void get_our_gulm_csid(char *csid); | ||||
							
								
								
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| LVM2 requires the device-mapper kernel module (dm-mod).  This is | ||||
| available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and | ||||
| is distributed with linux 2.5 and above.  The LVM1 kernel module (lvm-mod) | ||||
| will not work with lvm2 packages.  dm-mod and lvm-mod may both be loaded | ||||
| in the kernel at the same time with no problems.  Without dm-mod, this | ||||
| package is pretty useless. | ||||
							
								
								
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| lvm2 (1.95.15-1) unstable; urgency=low | ||||
|    | ||||
|   * New upstream release. | ||||
|   * Remove undocumented manpage symlinks. | ||||
|   * Update description to be more informative.  (Closes: #173499) | ||||
|   * Add kernel-patch-device-mapper suggestion. | ||||
|   * Update standards version. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 16 Feb 2002 04:21:26 -0400 | ||||
|  | ||||
| lvm2 (1.95.11-1) unstable; urgency=low | ||||
|  | ||||
|   * New upstream release.  (Closes: #171436) | ||||
|   * Removed TODO and INTRO from debian/docs; added WHATS_NEW. | ||||
|   * Remove vgcfgrestore.8 undocumented symlink. | ||||
|   * Added a README.Debian, mentioning the device-mapper kernel module | ||||
|     requirement that lvm2 has.  (Closes: #171674, #163020) | ||||
|   * Get rid of debian/conffiles (debhelper's smart enough to figure that out). | ||||
|   * debian/copyright fix to appease lintian. | ||||
|   * Fix typo in tools/commands.h that caused /usr/sbin/; to be created. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  9 Dec 2002 02:51:02 -0400 | ||||
|  | ||||
| lvm2 (1.95.10-2) unstable; urgency=low | ||||
|  | ||||
|   * Fix software raid problems by ensuring lvm init script runs after | ||||
|     raidtools init script.  (Closes: #152569) | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Tue,  3 Sep 2002 04:05:43 -0400 | ||||
|  | ||||
| lvm2 (1.95.10-1) unstable; urgency=low | ||||
|  | ||||
|   * New upstream release (Beta 3.2). | ||||
|   * Change all references to /dev/device-mapper/control to | ||||
|     /dev/mapper/control. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun,  1 Sep 2002 18:55:12 -0400 | ||||
|  | ||||
| lvm2 (0.95.05-3) unstable; urgency=low | ||||
|  | ||||
|   * Get rid of awk dependency in init script.  (Closes: #146257) | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 12 May 2002 04:39:06 -0500 | ||||
|  | ||||
| lvm2 (0.95.05-2) unstable; urgency=low | ||||
|  | ||||
|   * Use ${shlibs:Depends} in Depends. | ||||
|   * Get rid of postinst/postrm scripts, use debhelper's init script instead. | ||||
|   * Add Conflicts against lvm10, lvm-common. | ||||
|   * Fix endian issues on big-endian machines. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Thu,  2 May 2002 23:53:53 -0500 | ||||
|  | ||||
| lvm2 (0.95.05-1) unstable; urgency=low | ||||
|  | ||||
|   * New release (Beta2). | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Thu, 25 Apr 2002 00:37:41 -0500 | ||||
|  | ||||
| lvm2 (0.95.04cvs20020306-1) unstable; urgency=low | ||||
|  | ||||
|   * CVS updated. | ||||
|   * Convert from debian native package. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Wed,  6 Mar 2002 00:43:21 -0500 | ||||
|  | ||||
| lvm2 (0.95.04cvs20020304) unstable; urgency=low | ||||
|  | ||||
|   * CVS updated. | ||||
|   * Enhance init script; create devmapper control device, etc. | ||||
|   * Add dmsetup as a suggestion. | ||||
|   * Add /etc/lvm/lvm.conf conffile. | ||||
|   * Add undocumented(7) for the commands missing manpages. | ||||
|    | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  4 Mar 2002 04:51:26 -0500 | ||||
|  | ||||
| lvm2 (0.95.02cvs20020220) unstable; urgency=low | ||||
|  | ||||
|   * Initial Release. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Wed, 20 Feb 2002 03:17:25 -0500 | ||||
|  | ||||
							
								
								
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| Source: lvm2 | ||||
| Section: admin | ||||
| Priority: optional | ||||
| Maintainer: Andres Salomon <dilinger@mp3revolution.net> | ||||
| Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev | ||||
| Standards-Version: 3.5.8.0 | ||||
|  | ||||
| Package: lvm2 | ||||
| Architecture: any | ||||
| Depends: ${shlibs:Depends} | ||||
| Conflicts: lvm10, lvm-common | ||||
| Replaces: lvm10, lvm-common | ||||
| Provides: lvm-binaries | ||||
| Suggests: dmsetup, kernel-patch-device-mapper | ||||
| Description: The Linux Logical Volume Manager | ||||
|  This is LVM2, the rewrite of The Linux Logical Volume Manager.  LVM | ||||
|  supports enterprise level volume management of disk and disk subsystems | ||||
|  by grouping arbitrary disks into volume groups. The total capacity of | ||||
|  volume groups can be allocated to logical volumes, which are accessed as | ||||
|  regular block devices. | ||||
|  . | ||||
|  LVM2 is currently stable, but has some unimplemented features (most notably, | ||||
|  pvmove and e2fsadm).  It is not yet recommended for production use.  It is | ||||
|  backwards-compatible with LVM1 (lvm10), and requires Linux kernel 2.4. | ||||
							
								
								
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on | ||||
| Wed, 20 Feb 2002 03:17:25 -0500. | ||||
|  | ||||
| It was downloaded from http://www.sistina.com/products_lvm.htm | ||||
|  | ||||
| Upstream Author: LVM Development Team | ||||
|  | ||||
| Copyright (c) 2001-2002 LVM Development Team | ||||
|  | ||||
| LVM2 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. | ||||
|  | ||||
| LVM2 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 | ||||
|  | ||||
| On Debian systems, the full text of the GPL can be found in | ||||
| /usr/share/common-licenses/GPL | ||||
							
								
								
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| etc/lvm | ||||
| usr/share/man/man5 | ||||
| usr/share/man/man8 | ||||
| sbin | ||||
							
								
								
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| BUGS | ||||
| README | ||||
| VERSION | ||||
| WHATS_NEW | ||||
| doc/* | ||||
							
								
								
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #! /bin/sh | ||||
| # | ||||
| # lvm2		This script handles LVM2 initialization/shutdown. | ||||
| # | ||||
| #		Written by Andres Salomon <dilinger@mp3revolution.net>. | ||||
| # | ||||
|  | ||||
| PATH=/sbin:/bin:/usr/sbin:/usr/bin | ||||
| NAME=lvm2 | ||||
| DESC=LVM | ||||
|  | ||||
| test -x /sbin/vgchange || exit 0 | ||||
| modprobe dm-mod >/dev/null 2>&1 | ||||
|  | ||||
| # Create necessary files in /dev for device-mapper | ||||
| create_devfiles() { | ||||
| 	DIR="/dev/mapper" | ||||
| 	FILE="$DIR/control" | ||||
| 	major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//') | ||||
| 	minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//') | ||||
|  | ||||
| 	if test ! -d $DIR; then | ||||
| 		mkdir --mode=755 $DIR >/dev/null 2>&1 | ||||
| 	fi | ||||
|  | ||||
| 	if test ! -c $FILE -a ! -z "$minor"; then | ||||
| 		mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1 | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| case "$1" in | ||||
|   start) | ||||
| 	echo -n "Initializing $DESC: " | ||||
| 	create_devfiles | ||||
| 	vgchange -a y | ||||
|  | ||||
| #	# Mount all LVM devices | ||||
| #	for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do | ||||
| #		MTPT=$( grep $vg /etc/fstab | awk '{print $2}' ) | ||||
| #		mount $MTPT | ||||
| #	done | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   stop) | ||||
| 	echo -n "Shutting down $DESC: " | ||||
| 	# We don't really try all that hard to shut it down; far too many | ||||
| 	# things that can keep it from successfully shutting down. | ||||
| 	vgchange -a n | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   restart|force-reload) | ||||
| 	echo -n "Restarting $DESC: " | ||||
| 	vgchange -a n | ||||
| 	sleep 1 | ||||
| 	vgchange -a y | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   *) | ||||
| 	echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2 | ||||
| 	exit 1 | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| exit 0 | ||||
							
								
								
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| debian/lvm2/usr/share/man/man5/lvm.conf.5 | ||||
| debian/lvm2/usr/share/man/man8/lvchange.8 | ||||
| debian/lvm2/usr/share/man/man8/lvcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/lvdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/lvextend.8 | ||||
| debian/lvm2/usr/share/man/man8/lvm.8 | ||||
| debian/lvm2/usr/share/man/man8/lvmchange.8 | ||||
| debian/lvm2/usr/share/man/man8/lvreduce.8 | ||||
| debian/lvm2/usr/share/man/man8/lvremove.8 | ||||
| debian/lvm2/usr/share/man/man8/lvrename.8 | ||||
| debian/lvm2/usr/share/man/man8/lvscan.8 | ||||
| debian/lvm2/usr/share/man/man8/pvchange.8 | ||||
| debian/lvm2/usr/share/man/man8/pvcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/pvdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/pvscan.8 | ||||
| debian/lvm2/usr/share/man/man8/vgcfgbackup.8 | ||||
| debian/lvm2/usr/share/man/man8/vgchange.8 | ||||
| debian/lvm2/usr/share/man/man8/vgck.8 | ||||
| debian/lvm2/usr/share/man/man8/vgcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/vgdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/vgextend.8 | ||||
| debian/lvm2/usr/share/man/man8/vgmerge.8 | ||||
| debian/lvm2/usr/share/man/man8/vgreduce.8 | ||||
| debian/lvm2/usr/share/man/man8/vgremove.8 | ||||
| debian/lvm2/usr/share/man/man8/vgrename.8 | ||||
| debian/lvm2/usr/share/man/man8/vgscan.8 | ||||
							
								
								
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| #!/usr/bin/make -f | ||||
| # Sample debian/rules that uses debhelper.  | ||||
| # GNU copyright 1997 by Joey Hess. | ||||
| # | ||||
| # This version is for a hypothetical package that builds an | ||||
| # architecture-dependant package, as well as an architecture-independent | ||||
| # package. | ||||
|  | ||||
| # Uncomment this to turn on verbose mode.  | ||||
| #export DH_VERBOSE=1 | ||||
|  | ||||
| # This is the debhelper compatibility version to use. | ||||
| export DH_COMPAT=3 | ||||
|  | ||||
| # These are used for cross-compiling and for saving the configure script | ||||
| # from having to guess our platform (since we know it already) | ||||
| DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) | ||||
| DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) | ||||
|  | ||||
| ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) | ||||
| 	CFLAGS += -g | ||||
| endif | ||||
| ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) | ||||
| 	INSTALL_PROGRAM += -s | ||||
| endif | ||||
|  | ||||
| configure: configure-stamp | ||||
| configure-stamp: | ||||
| 	dh_testdir | ||||
| 	# Add here commands to configure the package. | ||||
| 	./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info | ||||
|  | ||||
| 	touch configure-stamp | ||||
|  | ||||
| build-arch: configure-stamp build-arch-stamp | ||||
| build-arch-stamp: | ||||
| 	dh_testdir | ||||
|  | ||||
| 	# Add here command to compile/build the package. | ||||
| 	$(MAKE) | ||||
|  | ||||
| 	touch build-arch-stamp | ||||
|  | ||||
| build-indep: configure-stamp build-indep-stamp | ||||
| build-indep-stamp: | ||||
| 	dh_testdir | ||||
|  | ||||
| 	# Add here command to compile/build the arch indep package. | ||||
| 	# It's ok not to do anything here, if you don't need to build | ||||
| 	#  anything for this package. | ||||
| 	#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1 | ||||
|  | ||||
| 	touch build-indep-stamp | ||||
|  | ||||
| build: build-arch build-indep | ||||
|  | ||||
| clean: | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
| 	rm -f build-stamp configure-stamp | ||||
|  | ||||
| 	# Add here commands to clean up after the build process. | ||||
| 	-$(MAKE) distclean | ||||
| 	-test -r /usr/share/misc/config.sub && \ | ||||
| 	  cp -f /usr/share/misc/config.sub config.sub | ||||
| 	-test -r /usr/share/misc/config.guess && \ | ||||
| 	  cp -f /usr/share/misc/config.guess config.guess | ||||
|  | ||||
|  | ||||
| 	dh_clean | ||||
|  | ||||
| install: DH_OPTIONS= | ||||
| install: build | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
| 	dh_clean -k | ||||
| 	dh_installdirs | ||||
|  | ||||
| 	# Add here commands to install the package into debian/lvm2. | ||||
| 	$(MAKE) install prefix=$(CURDIR)/debian/lvm2 | ||||
| 	install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf | ||||
|  | ||||
|  | ||||
| # Build architecture-independent files here. | ||||
| # Pass -i to all debhelper commands in this target to reduce clutter. | ||||
| binary-indep: build install | ||||
| # nada. | ||||
|  | ||||
| # Build architecture-dependent files here. | ||||
| binary-arch: build install | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
|  | ||||
| #	dh_installdebconf | ||||
| 	dh_installdocs | ||||
| 	dh_installexamples | ||||
| #	dh_installlogrotate -a | ||||
| #	dh_installemacsen -a | ||||
| #	dh_installpam -a | ||||
| #	dh_installmime -a | ||||
| 	dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ." | ||||
| 	dh_installcron | ||||
| 	dh_installman | ||||
| 	dh_installinfo  | ||||
| 	dh_installchangelogs | ||||
| 	dh_strip | ||||
| 	dh_link | ||||
| 	dh_compress | ||||
| 	dh_fixperms | ||||
| 	dh_makeshlibs | ||||
| 	dh_installdeb | ||||
| #	dh_perl -a | ||||
| 	dh_shlibdeps | ||||
| 	dh_gencontrol | ||||
| 	dh_md5sums | ||||
| 	dh_builddeb | ||||
|  | ||||
| binary: binary-indep binary-arch | ||||
| .PHONY: build clean binary-indep binary-arch binary install configure | ||||
							
								
								
									
										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 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@ | ||||
|  | ||||
| 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! | ||||
							
								
								
									
										289
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | ||||
| # 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" ] | ||||
|  | ||||
|     # 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. | ||||
|  | ||||
|     # Remember to run vgscan after you change this parameter to ensure  | ||||
|     # that the cache file gets regenerated (see below). | ||||
|  | ||||
|     # 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 file is hidden in the /etc/lvm directory. | ||||
|     # It is safe to delete this file: the tools regenerate it. | ||||
|     cache = "/etc/lvm/.cache" | ||||
|  | ||||
|     # 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 | ||||
| } | ||||
|  | ||||
| # 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 | ||||
|  | ||||
|     # 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 file-based locking (1). | ||||
|     # Turn locking off by setting to 0 (dangerous: risks metadata corruption | ||||
|     # if LVM2 commands get run concurrently). | ||||
|     locking_type = 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" | ||||
| } | ||||
|  | ||||
| activation { | ||||
|     # Device used in place of missing stripes if activating incomplete volume. | ||||
|     # For now, you need to set this up yourself first (e.g. with 'dmsetup') | ||||
|     # For example, you could make it return I/O errors using the 'error'  | ||||
|     # target or make it return zeros. | ||||
|     missing_stripe_filler = "/dev/ioerror" | ||||
|  | ||||
|     # Size (in KB) of each copy operation when mirroring | ||||
|     mirror_region_size = 512 | ||||
|  | ||||
|     # 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", "@*" ] | ||||
| } | ||||
|  | ||||
|  | ||||
| #################### | ||||
| # Advanced section # | ||||
| #################### | ||||
|  | ||||
| # Metadata settings | ||||
| # | ||||
| # metadata { | ||||
|     # Default number of copies of metadata to hold on each PV.  0, 1 or 2. | ||||
|     # It's best to leave this at 2. | ||||
|     # You might want to override it from the command line with 0 or 1  | ||||
|     # when running pvcreate on new PVs which are to be added to large VGs. | ||||
|  | ||||
|     # pvmetadatacopies = 2 | ||||
|  | ||||
|     # 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" ] | ||||
| #} | ||||
|  | ||||
|  | ||||
							
								
								
									
										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' | ||||
|  | ||||
							
								
								
									
										46
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| 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 this 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 | ||||
							
								
								
									
										50
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| ../daemons/clvmd/clvm.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/bitset.h | ||||
| ../lib/datastruct/btree.h | ||||
| ../lib/datastruct/hash.h | ||||
| ../lib/datastruct/list.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/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/metadata/lv_alloc.h | ||||
| ../lib/metadata/metadata.h | ||||
| ../lib/metadata/segtype.h | ||||
| ../lib/mm/dbg_malloc.h | ||||
| ../lib/mm/memlock.h | ||||
| ../lib/mm/pool.h | ||||
| ../lib/mm/xlate.h | ||||
| ../lib/misc/crc.h | ||||
| ../lib/misc/intl.h | ||||
| ../lib/misc/lib.h | ||||
| ../lib/misc/lvm-file.h | ||||
| ../lib/misc/lvm-string.h | ||||
| ../lib/misc/selinux.h | ||||
| ../lib/misc/sharedlib.h | ||||
| ../lib/regex/matcher.h | ||||
| ../lib/report/report.h | ||||
| ../lib/uuid/uuid.h | ||||
| ../po/pogen.h | ||||
| ../tools/version.h | ||||
							
								
								
									
										43
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 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 | ||||
|  | ||||
| SHELL = /bin/sh | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| LN_S = @LN_S@ | ||||
|  | ||||
| .PHONY: clean distclean all install pofile install_cluster | ||||
|  | ||||
| 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 | ||||
|  | ||||
| clean: | ||||
|  | ||||
| install: | ||||
|  | ||||
| install_cluster: | ||||
|  | ||||
							
								
								
									
										146
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 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@ | ||||
|  | ||||
| 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/bitset.c \ | ||||
| 	datastruct/btree.c \ | ||||
| 	datastruct/hash.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/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 \ | ||||
| 	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_map.c \ | ||||
| 	metadata/segtype.c \ | ||||
| 	metadata/snapshot_manip.c \ | ||||
| 	misc/crc.c \ | ||||
| 	misc/lvm-file.c \ | ||||
| 	misc/lvm-string.c \ | ||||
| 	mm/dbg_malloc.c \ | ||||
| 	mm/memlock.c \ | ||||
| 	mm/pool.c \ | ||||
| 	regex/matcher.c \ | ||||
| 	regex/parse_rx.c \ | ||||
| 	regex/ttree.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 ("@HAVE_SELINUX@", "yes") | ||||
|   SOURCES += misc/selinux.c | ||||
| endif | ||||
|  | ||||
| LIB_STATIC = liblvm.a | ||||
|  | ||||
| $(SUBDIRS): $(LIB_STATIC) | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| Base library directory | ||||
							
								
								
									
										789
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										789
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,789 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "metadata.h" | ||||
| #include "activate.h" | ||||
| #include "memlock.h" | ||||
| #include "display.h" | ||||
| #include "fs.h" | ||||
| #include "lvm-file.h" | ||||
| #include "lvm-string.h" | ||||
| #include "pool.h" | ||||
| #include "toolcontext.h" | ||||
| #include "dev_manager.h" | ||||
| #include "str_list.h" | ||||
| #include "config.h" | ||||
|  | ||||
| #include <limits.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) | ||||
|  | ||||
| int lvm1_present(struct cmd_context *cmd) | ||||
| { | ||||
| 	char path[PATH_MAX]; | ||||
|  | ||||
| 	if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir) | ||||
| 	    < 0) { | ||||
| 		log_error("LVM1 proc global snprintf failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (path_exists(path)) | ||||
| 		return 1; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| #ifndef DEVMAPPER_SUPPORT | ||||
| void set_activation(int act) | ||||
| { | ||||
| 	static int warned = 0; | ||||
|  | ||||
| 	if (warned || !act) | ||||
| 		return; | ||||
|  | ||||
| 	log_error("Compiled without libdevmapper support. " | ||||
| 		  "Can't enable activation."); | ||||
|  | ||||
| 	warned = 1; | ||||
| } | ||||
| int activation(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int library_version(char *version, size_t size) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int driver_version(char *version, size_t size) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int target_present(const char *target_name) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_info(const struct logical_volume *lv, struct lvinfo *info, | ||||
| 	    int with_open_count) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info, int with_open_count) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_snapshot_percent(struct logical_volume *lv, float *percent) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent, | ||||
| 		      uint32_t *event_nr) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lvs_in_vg_activated(struct volume_group *vg) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lvs_in_vg_opened(struct volume_group *vg) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_suspend(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_resume(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			 int *activate_lv) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_activate(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void activation_exit(void) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| #else				/* DEVMAPPER_SUPPORT */ | ||||
|  | ||||
| static int _activation = 1; | ||||
|  | ||||
| void set_activation(int act) | ||||
| { | ||||
| 	if (act == _activation) | ||||
| 		return; | ||||
|  | ||||
| 	_activation = act; | ||||
| 	if (_activation) | ||||
| 		log_verbose("Activation enabled. Device-mapper kernel " | ||||
| 			    "driver will be used."); | ||||
| 	else | ||||
| 		log_verbose("Activation disabled. No device-mapper " | ||||
| 			    "interaction will be attempted."); | ||||
| } | ||||
|  | ||||
| int activation(void) | ||||
| { | ||||
| 	return _activation; | ||||
| } | ||||
|  | ||||
| static int _passes_activation_filter(struct cmd_context *cmd, | ||||
| 				     struct logical_volume *lv) | ||||
| { | ||||
| 	const struct config_node *cn; | ||||
| 	struct config_value *cv; | ||||
| 	char *str; | ||||
| 	char path[PATH_MAX]; | ||||
|  | ||||
| 	if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) { | ||||
| 		/* If no host tags defined, activate */ | ||||
| 		if (list_empty(&cmd->tags)) | ||||
| 			return 1; | ||||
|  | ||||
| 		/* If any host tag matches any LV or VG tag, activate */ | ||||
| 		if (str_list_match_list(&cmd->tags, &lv->tags) || | ||||
| 		    str_list_match_list(&cmd->tags, &lv->vg->tags)) | ||||
| 			return 1; | ||||
|  | ||||
| 		/* Don't activate */ | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	for (cv = cn->v; cv; cv = cv->next) { | ||||
| 		if (cv->type != CFG_STRING) { | ||||
| 			log_error("Ignoring invalid string in config file " | ||||
| 				  "activation/volume_list"); | ||||
| 			continue; | ||||
| 		} | ||||
| 		str = cv->v.str; | ||||
| 		if (!*str) { | ||||
| 			log_error("Ignoring empty string in config file " | ||||
| 				  "activation/volume_list"); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* Tag? */ | ||||
| 		if (*str == '@') { | ||||
| 			str++; | ||||
| 			if (!*str) { | ||||
| 				log_error("Ignoring empty tag in config file " | ||||
| 					  "activation/volume_list"); | ||||
| 				continue; | ||||
| 			} | ||||
| 			/* If any host tag matches any LV or VG tag, activate */ | ||||
| 			if (!strcmp(str, "*")) { | ||||
| 				if (str_list_match_list(&cmd->tags, &lv->tags) | ||||
| 				    || str_list_match_list(&cmd->tags, | ||||
| 							   &lv->vg->tags)) | ||||
| 					    return 1; | ||||
| 				else | ||||
| 					continue; | ||||
| 			} | ||||
| 			/* If supplied tag matches LV or VG tag, activate */ | ||||
| 			if (str_list_match_item(&lv->tags, str) || | ||||
| 			    str_list_match_item(&lv->vg->tags, str)) | ||||
| 				return 1; | ||||
| 			else | ||||
| 				continue; | ||||
| 		} | ||||
| 		if (!index(str, '/')) { | ||||
| 			/* vgname supplied */ | ||||
| 			if (!strcmp(str, lv->vg->name)) | ||||
| 				return 1; | ||||
| 			else | ||||
| 				continue; | ||||
| 		} | ||||
| 		/* vgname/lvname */ | ||||
| 		if (lvm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name, | ||||
| 				 lv->name) < 0) { | ||||
| 			log_error("lvm_snprintf error from %s/%s", lv->vg->name, | ||||
| 				  lv->name); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(path, str)) | ||||
| 			return 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int library_version(char *version, size_t size) | ||||
| { | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dm_get_library_version(version, size)) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int driver_version(char *version, size_t size) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	struct dm_task *dmt; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	log_very_verbose("Getting driver version"); | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_run(dmt)) | ||||
| 		log_error("Failed to get driver version"); | ||||
|  | ||||
| 	if (!dm_task_get_driver_version(dmt, version, size)) | ||||
| 		goto out; | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int target_present(const char *target_name) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_versions *target, *last_target; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	log_very_verbose("Getting target version for %s", target_name); | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_run(dmt)) { | ||||
| 		log_debug("Failed to get %s target version", target_name); | ||||
| 		/* Assume this was because LIST_VERSIONS isn't supported */ | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	target = dm_task_get_versions(dmt); | ||||
|  | ||||
| 	do { | ||||
| 		last_target = target; | ||||
|  | ||||
| 		if (!strcmp(target_name, target->name)) { | ||||
| 			r = 1; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		target = (void *) target + target->next; | ||||
| 	} while (last_target != target); | ||||
|  | ||||
|       out: | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if info structure populated, else 0 on failure. | ||||
|  */ | ||||
| static int _lv_info(const struct logical_volume *lv, int mknodes, | ||||
| 		    struct lvinfo *info, int with_open_count) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
| 	struct dm_info dminfo; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_info(dm, lv, mknodes, with_open_count, &dminfo))) | ||||
| 		stack; | ||||
|  | ||||
| 	info->exists = dminfo.exists; | ||||
| 	info->suspended = dminfo.suspended; | ||||
| 	info->open_count = dminfo.open_count; | ||||
| 	info->major = dminfo.major; | ||||
| 	info->minor = dminfo.minor; | ||||
| 	info->read_only = dminfo.read_only; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int lv_info(const struct logical_volume *lv, struct lvinfo *info, | ||||
| 	    int with_open_count) | ||||
| { | ||||
| 	return _lv_info(lv, 0, info, with_open_count); | ||||
| } | ||||
|  | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info, int with_open_count) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	return _lv_info(lv, 0, info, with_open_count); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if percent set, else 0 on failure. | ||||
|  */ | ||||
| int lv_snapshot_percent(struct logical_volume *lv, float *percent) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_snapshot_percent(dm, lv, percent))) | ||||
| 		stack; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* FIXME Merge with snapshot_percent */ | ||||
| int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent, | ||||
| 		      uint32_t *event_nr) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr))) | ||||
| 		stack; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _lv_active(struct logical_volume *lv) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 0)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return info.exists; | ||||
| } | ||||
|  | ||||
| static int _lv_open_count(struct logical_volume *lv) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 1)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return info.open_count; | ||||
| } | ||||
|  | ||||
| /* FIXME Need to detect and handle an lv rename */ | ||||
| static int _lv_activate_lv(struct logical_volume *lv) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_activate(dm, lv))) | ||||
| 		stack; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _lv_deactivate(struct logical_volume *lv) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_deactivate(dm, lv))) | ||||
| 		stack; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _lv_suspend_lv(struct logical_volume *lv) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dev_manager *dm; | ||||
|  | ||||
| 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(r = dev_manager_suspend(dm, lv))) | ||||
| 		stack; | ||||
|  | ||||
| 	dev_manager_destroy(dm); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * These two functions return the number of visible LVs in the state, | ||||
|  * or -1 on error. | ||||
|  */ | ||||
| int lvs_in_vg_activated(struct volume_group *vg) | ||||
| { | ||||
| 	struct list *lvh; | ||||
| 	struct logical_volume *lv; | ||||
| 	int count = 0; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	list_iterate(lvh, &vg->lvs) { | ||||
| 		lv = list_item(lvh, struct lv_list)->lv; | ||||
| 		if (lv->status & VISIBLE_LV) | ||||
| 			count += (_lv_active(lv) == 1); | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| int lvs_in_vg_opened(struct volume_group *vg) | ||||
| { | ||||
| 	struct list *lvh; | ||||
| 	struct logical_volume *lv; | ||||
| 	int count = 0; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 0; | ||||
|  | ||||
| 	list_iterate(lvh, &vg->lvs) { | ||||
| 		lv = list_item(lvh, struct lv_list)->lv; | ||||
| 		if (lv->status & VISIBLE_LV) | ||||
| 			count += (_lv_open_count(lv) > 0); | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		       int error_if_not_suspended) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (test_mode()) { | ||||
| 		_skip("Suspending '%s'.", lv->name); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists || info.suspended) | ||||
| 		return error_if_not_suspended ? 0 : 1; | ||||
|  | ||||
| 	memlock_inc(); | ||||
| 	if (!_lv_suspend_lv(lv)) { | ||||
| 		memlock_dec(); | ||||
| 		fs_unlock(); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Returns success if the device is not active */ | ||||
| int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_suspend(cmd, lvid_s, 0); | ||||
| } | ||||
|  | ||||
| int lv_suspend(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_suspend(cmd, lvid_s, 1); | ||||
| } | ||||
|  | ||||
| static int _lv_resume(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		      int error_if_not_active) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (test_mode()) { | ||||
| 		_skip("Resuming '%s'.", lv->name); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists || !info.suspended) | ||||
| 		return error_if_not_active ? 0 : 1; | ||||
|  | ||||
| 	if (!_lv_activate_lv(lv)) | ||||
| 		return 0; | ||||
|  | ||||
| 	memlock_dec(); | ||||
| 	fs_unlock(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Returns success if the device is not active */ | ||||
| int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_resume(cmd, lvid_s, 0); | ||||
| } | ||||
|  | ||||
| int lv_resume(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_resume(cmd, lvid_s, 1); | ||||
| } | ||||
|  | ||||
| int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
| 	struct lvinfo info; | ||||
| 	int r; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (test_mode()) { | ||||
| 		_skip("Deactivating '%s'.", lv->name); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 1)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (info.open_count && (lv->status & VISIBLE_LV)) { | ||||
| 		log_error("LV %s/%s in use: not removing", lv->vg->name, | ||||
| 			  lv->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	memlock_inc(); | ||||
| 	r = _lv_deactivate(lv); | ||||
| 	memlock_dec(); | ||||
| 	fs_unlock(); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* Test if LV passes filter */ | ||||
| int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			 int *activate_lv) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		goto activate; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!_passes_activation_filter(cmd, lv)) { | ||||
| 		log_verbose("Not activating %s/%s due to config file settings", | ||||
| 			    lv->vg->name, lv->name); | ||||
| 		*activate_lv = 0; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
|       activate: | ||||
| 	*activate_lv = 1; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
| 	struct lvinfo info; | ||||
| 	int r; | ||||
|  | ||||
| 	if (!activation()) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (filter && !_passes_activation_filter(cmd, lv)) { | ||||
| 		log_verbose("Not activating %s/%s due to config file settings", | ||||
| 			    lv->vg->name, lv->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (test_mode()) { | ||||
| 		_skip("Activating '%s'.", lv->name); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_info(lv, &info, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (info.exists && !info.suspended) | ||||
| 		return 1; | ||||
|  | ||||
| 	memlock_inc(); | ||||
| 	r = _lv_activate_lv(lv); | ||||
| 	memlock_dec(); | ||||
| 	fs_unlock(); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* Activate LV */ | ||||
| int lv_activate(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_activate(cmd, lvid_s, 0); | ||||
| } | ||||
|  | ||||
| /* Activate LV only if it passes filter */ | ||||
| int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s) | ||||
| { | ||||
| 	return _lv_activate(cmd, lvid_s, 1); | ||||
| } | ||||
|  | ||||
| int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
| 	int r = 1; | ||||
|  | ||||
| 	if (!lv) { | ||||
| 		r = dev_manager_mknodes(); | ||||
| 		fs_unlock(); | ||||
| 		return r; | ||||
| 	} | ||||
|  | ||||
| 	if (!_lv_info(lv, 1, &info, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (info.exists) | ||||
| 		r = dev_manager_lv_mknodes(lv); | ||||
| 	else | ||||
| 		r = dev_manager_lv_rmnodes(lv); | ||||
|  | ||||
| 	fs_unlock(); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void activation_exit(void) | ||||
| { | ||||
| 	dev_manager_exit(); | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										84
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef LVM_ACTIVATE_H | ||||
| #define LVM_ACTIVATE_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| #  include <libdevmapper.h> | ||||
| #endif | ||||
|  | ||||
| struct lvinfo { | ||||
| 	int exists; | ||||
| 	int suspended; | ||||
| 	unsigned int open_count; | ||||
| 	int major; | ||||
| 	int minor; | ||||
| 	int read_only; | ||||
| }; | ||||
|  | ||||
| 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 target_present(const char *target_name); | ||||
|  | ||||
| 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 lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s); | ||||
| 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(const struct logical_volume *lv, struct lvinfo *info, | ||||
| 	    int with_open_count); | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info, int with_open_count); | ||||
|  | ||||
| /* | ||||
|  * 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(struct logical_volume *lv, float *percent); | ||||
| int lv_mirror_percent(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_opened(struct volume_group *vg); | ||||
|  | ||||
| int lv_setup_cow_store(struct logical_volume *lv); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										2213
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2213
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										58
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| /* | ||||
|  * 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 _LVM_DEV_MANAGER_H | ||||
| #define _LVM_DEV_MANAGER_H | ||||
|  | ||||
| struct logical_volume; | ||||
| struct cmd_context; | ||||
| struct dev_manager; | ||||
| struct dm_info; | ||||
|  | ||||
| /* | ||||
|  * 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_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 dev_manager *dm, const struct logical_volume *lv, | ||||
| 		     int mknodes, int with_open_count, struct dm_info *info); | ||||
| int dev_manager_snapshot_percent(struct dev_manager *dm, | ||||
| 				 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 dev_manager_activate(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); | ||||
| int dev_manager_mknodes(void); | ||||
|  | ||||
| /* | ||||
|  * Put the desired changes into effect. | ||||
|  */ | ||||
| int dev_manager_execute(struct dev_manager *dm); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										359
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "fs.h" | ||||
| #include "toolcontext.h" | ||||
| #include "lvm-string.h" | ||||
| #include "lvm-file.h" | ||||
| #include "memlock.h" | ||||
|  | ||||
| #ifdef HAVE_SELINUX | ||||
| #  include "selinux.h" | ||||
| #endif | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <limits.h> | ||||
| #include <dirent.h> | ||||
| #include <libdevmapper.h> | ||||
|  | ||||
| static int _mk_dir(const char *dev_dir, const char *vg_name) | ||||
| { | ||||
| 	char vg_path[PATH_MAX]; | ||||
|  | ||||
| 	if (lvm_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 (lvm_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 (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 (lvm_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 (lvm_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 (lvm_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 (lvm_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 (lvm_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 (!set_selinux_context(lv_path)) { | ||||
|                 stack; | ||||
|                 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 (lvm_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)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
| 	case FS_DEL: | ||||
| 		if (!_rm_link(dev_dir, vg_name, lv_name) || | ||||
| 		    !_rm_dir(dev_dir, vg_name)) { | ||||
| 			stack; | ||||
| 			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 LIST_INIT(_fs_ops); | ||||
|  | ||||
| struct fs_op_parms { | ||||
| 	struct 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 = dbg_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); | ||||
|  | ||||
| 	list_add(&_fs_ops, &fsp->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _pop_fs_ops(void) | ||||
| { | ||||
| 	struct list *fsph, *fspht; | ||||
| 	struct fs_op_parms *fsp; | ||||
|  | ||||
| 	list_iterate_safe(fsph, fspht, &_fs_ops) { | ||||
| 		fsp = 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); | ||||
| 		list_del(&fsp->list); | ||||
| 		dbg_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)) { | ||||
| 			stack; | ||||
| 			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_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(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										32
									
								
								lib/activate/fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/activate/fs.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 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 _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_rename_lv(struct logical_volume *lv, | ||||
| 		 const char *dev, const char *old_name); | ||||
| void fs_unlock(void); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										25
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-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 _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); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										581
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										581
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,581 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "lvmcache.h" | ||||
| #include "hash.h" | ||||
| #include "toolcontext.h" | ||||
| #include "dev-cache.h" | ||||
| #include "metadata.h" | ||||
| #include "filter.h" | ||||
| #include "memlock.h" | ||||
| #include "str_list.h" | ||||
|  | ||||
| static struct hash_table *_pvid_hash = NULL; | ||||
| static struct hash_table *_vgid_hash = NULL; | ||||
| static struct hash_table *_vgname_hash = NULL; | ||||
| static struct hash_table *_lock_hash = NULL; | ||||
| static struct list _vginfos; | ||||
| static int _has_scanned = 0; | ||||
| static int _vgs_locked = 0; | ||||
|  | ||||
| int lvmcache_init(void) | ||||
| { | ||||
| 	list_init(&_vginfos); | ||||
|  | ||||
| 	if (!(_vgname_hash = hash_create(128))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(_vgid_hash = hash_create(128))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(_pvid_hash = hash_create(128))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(_lock_hash = hash_create(128))) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void lvmcache_lock_vgname(const char *vgname, int read_only) | ||||
| { | ||||
| 	if (!_lock_hash && !lvmcache_init()) { | ||||
| 		log_error("Internal cache initialisation failed"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!hash_insert(_lock_hash, vgname, (void *) 1)) | ||||
| 		log_error("Cache locking failure for %s", vgname); | ||||
|  | ||||
| 	_vgs_locked++; | ||||
| } | ||||
|  | ||||
| static int _vgname_is_locked(const char *vgname) __attribute__ ((unused)); | ||||
| static int _vgname_is_locked(const char *vgname) | ||||
| { | ||||
| 	if (!_lock_hash) | ||||
| 		return 0; | ||||
|  | ||||
| 	return hash_lookup(_lock_hash, vgname) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| void lvmcache_unlock_vgname(const char *vgname) | ||||
| { | ||||
| 	/* FIXME: Clear all CACHE_LOCKED flags in this vg */ | ||||
| 	hash_remove(_lock_hash, vgname); | ||||
|  | ||||
| 	/* FIXME Do this per-VG */ | ||||
| 	if (!--_vgs_locked) | ||||
| 		dev_close_all(); | ||||
| } | ||||
|  | ||||
| int vgs_locked(void) | ||||
| { | ||||
| 	return _vgs_locked; | ||||
| } | ||||
|  | ||||
| struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname) | ||||
| { | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
|  | ||||
| 	if (!_vgname_hash) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!(vginfo = hash_lookup(_vgname_hash, vgname))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return vginfo; | ||||
| } | ||||
|  | ||||
| const struct format_type *fmt_from_vgname(const char *vgname) | ||||
| { | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
|  | ||||
| 	if (!(vginfo = vginfo_from_vgname(vgname))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return vginfo->fmt; | ||||
| } | ||||
|  | ||||
| struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid) | ||||
| { | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
| 	char id[ID_LEN + 1]; | ||||
|  | ||||
| 	if (!_vgid_hash || !vgid) | ||||
| 		return NULL; | ||||
|  | ||||
| 	/* vgid not necessarily NULL-terminated */ | ||||
| 	strncpy(&id[0], vgid, ID_LEN); | ||||
| 	id[ID_LEN] = '\0'; | ||||
|  | ||||
| 	if (!(vginfo = hash_lookup(_vgid_hash, id))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return vginfo; | ||||
| } | ||||
|  | ||||
| struct lvmcache_info *info_from_pvid(const char *pvid) | ||||
| { | ||||
| 	struct lvmcache_info *info; | ||||
| 	char id[ID_LEN + 1]; | ||||
|  | ||||
| 	if (!_pvid_hash || !pvid) | ||||
| 		return NULL; | ||||
|  | ||||
| 	strncpy(&id[0], pvid, ID_LEN); | ||||
| 	id[ID_LEN] = '\0'; | ||||
|  | ||||
| 	if (!(info = hash_lookup(_pvid_hash, id))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return info; | ||||
| } | ||||
|  | ||||
| static void _rescan_entry(struct lvmcache_info *info) | ||||
| { | ||||
| 	struct label *label; | ||||
|  | ||||
| 	if (info->status & CACHE_INVALID) | ||||
| 		label_read(info->dev, &label); | ||||
| } | ||||
|  | ||||
| static int _scan_invalid(void) | ||||
| { | ||||
| 	hash_iter(_pvid_hash, (iterate_fn) _rescan_entry); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) | ||||
| { | ||||
| 	struct label *label; | ||||
| 	struct dev_iter *iter; | ||||
| 	struct device *dev; | ||||
| 	struct list *fmth; | ||||
| 	struct format_type *fmt; | ||||
|  | ||||
| 	static int _scanning_in_progress = 0; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	/* Avoid recursion when a PVID can't be found! */ | ||||
| 	if (_scanning_in_progress) | ||||
| 		return 0; | ||||
|  | ||||
| 	_scanning_in_progress = 1; | ||||
|  | ||||
| 	if (!_vgname_hash && !lvmcache_init()) { | ||||
| 		log_error("Internal cache initialisation failed"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (_has_scanned && !full_scan) { | ||||
| 		r = _scan_invalid(); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!(iter = dev_iter_create(cmd->filter))) { | ||||
| 		log_error("dev_iter creation failed"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	while ((dev = dev_iter_get(iter))) | ||||
| 		label_read(dev, &label); | ||||
|  | ||||
| 	dev_iter_destroy(iter); | ||||
|  | ||||
| 	_has_scanned = 1; | ||||
|  | ||||
| 	/* Perform any format-specific scanning e.g. text files */ | ||||
| 	list_iterate(fmth, &cmd->formats) { | ||||
| 		fmt = list_item(fmth, struct format_type); | ||||
| 		if (fmt->ops->scan && !fmt->ops->scan(fmt)) | ||||
| 			goto out; | ||||
| 	} | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	_scanning_in_progress = 0; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan) | ||||
| { | ||||
| 	struct list *vgnames; | ||||
| 	struct lvmcache_vginfo *vgi; | ||||
|  | ||||
| 	lvmcache_label_scan(cmd, full_scan); | ||||
|  | ||||
| 	if (!(vgnames = str_list_create(cmd->mem))) { | ||||
| 		log_error("vgnames list allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate_items(vgi, &_vginfos) { | ||||
| 		if (!str_list_add(cmd->mem, vgnames,  | ||||
| 				  pool_strdup(cmd->mem, vgi->vgname))) { | ||||
| 			log_error("strlist allocation failed"); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return vgnames; | ||||
| } | ||||
|  | ||||
| struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) | ||||
| { | ||||
| 	struct label *label; | ||||
| 	struct lvmcache_info *info; | ||||
|  | ||||
| 	/* Already cached ? */ | ||||
| 	if ((info = info_from_pvid((char *) pvid))) { | ||||
| 		if (label_read(info->dev, &label)) { | ||||
| 			info = (struct lvmcache_info *) label->info; | ||||
| 			if (id_equal(pvid, (struct id *) &info->dev->pvid)) | ||||
| 				return info->dev; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lvmcache_label_scan(cmd, 0); | ||||
|  | ||||
| 	/* Try again */ | ||||
| 	if ((info = info_from_pvid((char *) pvid))) { | ||||
| 		if (label_read(info->dev, &label)) { | ||||
| 			info = (struct lvmcache_info *) label->info; | ||||
| 			if (id_equal(pvid, (struct id *) &info->dev->pvid)) | ||||
| 				return info->dev; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (memlock()) | ||||
| 		return NULL; | ||||
|  | ||||
| 	lvmcache_label_scan(cmd, 1); | ||||
|  | ||||
| 	/* Try again */ | ||||
| 	if ((info = info_from_pvid((char *) pvid))) { | ||||
| 		if (label_read(info->dev, &label)) { | ||||
| 			info = (struct lvmcache_info *) label->info; | ||||
| 			if (id_equal(pvid, (struct id *) &info->dev->pvid)) | ||||
| 				return info->dev; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static void _drop_vginfo(struct lvmcache_info *info) | ||||
| { | ||||
| 	if (!list_empty(&info->list)) { | ||||
| 		list_del(&info->list); | ||||
| 		list_init(&info->list); | ||||
| 	} | ||||
|  | ||||
| 	if (info->vginfo && list_empty(&info->vginfo->infos)) { | ||||
| 		hash_remove(_vgname_hash, info->vginfo->vgname); | ||||
| 		if (info->vginfo->vgname) | ||||
| 			dbg_free(info->vginfo->vgname); | ||||
| 		if (*info->vginfo->vgid) | ||||
| 			hash_remove(_vgid_hash, info->vginfo->vgid); | ||||
| 		list_del(&info->vginfo->list); | ||||
| 		dbg_free(info->vginfo); | ||||
| 	} | ||||
|  | ||||
| 	info->vginfo = NULL; | ||||
| } | ||||
|  | ||||
| /* Unused | ||||
| void lvmcache_del(struct lvmcache_info *info) | ||||
| { | ||||
| 	if (info->dev->pvid[0] && _pvid_hash) | ||||
| 		hash_remove(_pvid_hash, info->dev->pvid); | ||||
|  | ||||
| 	_drop_vginfo(info); | ||||
|  | ||||
| 	info->label->labeller->ops->destroy_label(info->label->labeller, | ||||
| 						info->label);  | ||||
| 	dbg_free(info); | ||||
|  | ||||
| 	return; | ||||
| } */ | ||||
|  | ||||
| static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid) | ||||
| { | ||||
| 	if (!strcmp(info->dev->pvid, pvid)) | ||||
| 		return 1; | ||||
| 	if (*info->dev->pvid) { | ||||
| 		hash_remove(_pvid_hash, info->dev->pvid); | ||||
| 	} | ||||
| 	strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid)); | ||||
| 	if (!hash_insert(_pvid_hash, pvid, info)) { | ||||
| 		log_error("_lvmcache_update: pvid insertion failed: %s", pvid); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid) | ||||
| { | ||||
| 	if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid, | ||||
| 					       sizeof(info->vginfo->vgid))) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (info->vginfo && *info->vginfo->vgid) | ||||
| 		hash_remove(_vgid_hash, info->vginfo->vgid); | ||||
| 	if (!vgid) | ||||
| 		return 1; | ||||
|  | ||||
| 	strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid)); | ||||
| 	info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0'; | ||||
| 	if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) { | ||||
| 		log_error("_lvmcache_update: vgid hash insertion failed: %s", | ||||
| 			  info->vginfo->vgid); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname) | ||||
| { | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
|  | ||||
| 	/* If vgname is NULL and we don't already have a vgname,  | ||||
| 	 * assume ORPHAN - we want every entry to have a vginfo | ||||
| 	 * attached for scanning reasons. | ||||
| 	 */ | ||||
| 	if (!vgname && !info->vginfo) | ||||
| 		vgname = ORPHAN; | ||||
|  | ||||
| 	if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname))) | ||||
| 		return 1; | ||||
|  | ||||
| 	/* Remove existing vginfo entry */ | ||||
| 	_drop_vginfo(info); | ||||
|  | ||||
| 	/* Get existing vginfo or create new one */ | ||||
| 	if (!(vginfo = vginfo_from_vgname(vgname))) { | ||||
| 		if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) { | ||||
| 			log_error("lvmcache_update_vgname: list alloc failed"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		memset(vginfo, 0, sizeof(*vginfo)); | ||||
| 		if (!(vginfo->vgname = dbg_strdup(vgname))) { | ||||
| 			dbg_free(vginfo); | ||||
| 			log_error("cache vgname alloc failed for %s", vgname); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		list_init(&vginfo->infos); | ||||
| 		if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) { | ||||
| 			log_error("cache_update: vg hash insertion failed: %s", | ||||
| 				  vginfo->vgname); | ||||
| 			dbg_free(vginfo->vgname); | ||||
| 			dbg_free(vginfo); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		/* Ensure orphans appear last on list_iterate */ | ||||
| 		if (!*vgname) | ||||
| 			list_add(&_vginfos, &vginfo->list); | ||||
| 		else | ||||
| 			list_add_h(&_vginfos, &vginfo->list); | ||||
| 	} | ||||
|  | ||||
| 	info->vginfo = vginfo; | ||||
| 	list_add(&vginfo->infos, &info->list); | ||||
|  | ||||
| 	/* FIXME Check consistency of list! */ | ||||
| 	vginfo->fmt = info->fmt; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int lvmcache_update_vg(struct volume_group *vg) | ||||
| { | ||||
| 	struct list *pvh; | ||||
| 	struct physical_volume *pv; | ||||
| 	struct lvmcache_info *info; | ||||
| 	char pvid_s[ID_LEN + 1]; | ||||
| 	int vgid_updated = 0; | ||||
|  | ||||
| 	pvid_s[sizeof(pvid_s) - 1] = '\0'; | ||||
|  | ||||
| 	list_iterate(pvh, &vg->pvs) { | ||||
| 		pv = list_item(pvh, struct pv_list)->pv; | ||||
| 		strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1); | ||||
| 		/* FIXME Could pv->dev->pvid ever be different? */ | ||||
| 		if ((info = info_from_pvid(pvid_s))) { | ||||
| 			lvmcache_update_vgname(info, vg->name); | ||||
| 			if (!vgid_updated) { | ||||
| 				_lvmcache_update_vgid(info, (char *) &vg->id); | ||||
| 				vgid_updated = 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, | ||||
| 				   struct device *dev, | ||||
| 				   const char *vgname, const char *vgid) | ||||
| { | ||||
| 	struct label *label; | ||||
| 	struct lvmcache_info *existing, *info; | ||||
| 	char pvid_s[ID_LEN + 1]; | ||||
|  | ||||
| 	if (!_vgname_hash && !lvmcache_init()) { | ||||
| 		log_error("Internal cache initialisation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	strncpy(pvid_s, pvid, sizeof(pvid_s)); | ||||
| 	pvid_s[sizeof(pvid_s) - 1] = '\0'; | ||||
|  | ||||
| 	if (!(existing = info_from_pvid(pvid_s)) && | ||||
| 	    !(existing = info_from_pvid(dev->pvid))) { | ||||
| 		if (!(label = label_create(labeller))) { | ||||
| 			stack; | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		if (!(info = dbg_malloc(sizeof(*info)))) { | ||||
| 			log_error("lvmcache_info allocation failed"); | ||||
| 			label_destroy(label); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		memset(info, 0, sizeof(*info)); | ||||
|  | ||||
| 		label->info = info; | ||||
| 		info->label = label; | ||||
| 		list_init(&info->list); | ||||
| 		info->dev = dev; | ||||
| 	} else { | ||||
| 		if (existing->dev != dev) { | ||||
| 			/* Is the existing entry a duplicate pvid e.g. md ? */ | ||||
| 			if (MAJOR(existing->dev->dev) == md_major() && | ||||
| 			    MAJOR(dev->dev) != md_major()) { | ||||
| 				log_very_verbose("Ignoring duplicate PV %s on " | ||||
| 						 "%s - using md %s", | ||||
| 						 pvid, dev_name(dev), | ||||
| 						 dev_name(existing->dev)); | ||||
| 				return NULL; | ||||
| 			} else if (MAJOR(existing->dev->dev) != md_major() && | ||||
| 				   MAJOR(dev->dev) == md_major()) | ||||
| 				log_very_verbose("Duplicate PV %s on %s - " | ||||
| 						 "using md %s", pvid, | ||||
| 						 dev_name(existing->dev), | ||||
| 						 dev_name(dev)); | ||||
| 			else | ||||
| 				log_error("Found duplicate PV %s: using %s not " | ||||
| 					  "%s", pvid, dev_name(dev), | ||||
| 					  dev_name(existing->dev)); | ||||
| 		} | ||||
| 		info = existing; | ||||
| 		/* Has labeller changed? */ | ||||
| 		if (info->label->labeller != labeller) { | ||||
| 			label_destroy(info->label); | ||||
| 			if (!(info->label = label_create(labeller))) { | ||||
| 				/* FIXME leaves info without label! */ | ||||
| 				stack; | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			info->label->info = info; | ||||
| 		} | ||||
| 		label = info->label; | ||||
| 	} | ||||
|  | ||||
| 	info->fmt = (const struct format_type *) labeller->private; | ||||
| 	info->status |= CACHE_INVALID; | ||||
|  | ||||
| 	if (!_lvmcache_update_pvid(info, pvid_s)) { | ||||
| 		if (!existing) { | ||||
| 			dbg_free(info); | ||||
| 			label_destroy(label); | ||||
| 		} | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!lvmcache_update_vgname(info, vgname)) { | ||||
| 		if (!existing) { | ||||
| 			hash_remove(_pvid_hash, pvid_s); | ||||
| 			strcpy(info->dev->pvid, ""); | ||||
| 			dbg_free(info); | ||||
| 			label_destroy(label); | ||||
| 		} | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!_lvmcache_update_vgid(info, vgid)) | ||||
| 		/* Non-critical */ | ||||
| 		stack; | ||||
|  | ||||
| 	return info; | ||||
| } | ||||
|  | ||||
| static void _lvmcache_destroy_entry(struct lvmcache_info *info) | ||||
| { | ||||
| 	if (!list_empty(&info->list)) | ||||
| 		list_del(&info->list); | ||||
| 	strcpy(info->dev->pvid, ""); | ||||
| 	label_destroy(info->label); | ||||
| 	dbg_free(info); | ||||
| } | ||||
|  | ||||
| static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo) | ||||
| { | ||||
| 	if (vginfo->vgname) | ||||
| 		dbg_free(vginfo->vgname); | ||||
| 	dbg_free(vginfo); | ||||
| } | ||||
|  | ||||
| static void _lvmcache_destroy_lockname(int present) | ||||
| { | ||||
| 	/* Nothing to do */ | ||||
| } | ||||
|  | ||||
| void lvmcache_destroy(void) | ||||
| { | ||||
| 	_has_scanned = 0; | ||||
|  | ||||
| 	if (_vgid_hash) { | ||||
| 		hash_destroy(_vgid_hash); | ||||
| 		_vgid_hash = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (_pvid_hash) { | ||||
| 		hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry); | ||||
| 		hash_destroy(_pvid_hash); | ||||
| 		_pvid_hash = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (_vgname_hash) { | ||||
| 		hash_iter(_vgname_hash, | ||||
| 			  (iterate_fn) _lvmcache_destroy_vgnamelist); | ||||
| 		hash_destroy(_vgname_hash); | ||||
| 		_vgname_hash = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (_lock_hash) { | ||||
| 		hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname); | ||||
| 		hash_destroy(_lock_hash); | ||||
| 		_lock_hash = NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_init(&_vginfos); | ||||
| } | ||||
							
								
								
									
										87
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CACHE_H | ||||
| #define _LVM_CACHE_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
| #include "uuid.h" | ||||
| #include "label.h" | ||||
|  | ||||
| #define ORPHAN "" | ||||
|  | ||||
| #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; | ||||
|  | ||||
| struct lvmcache_vginfo { | ||||
| 	struct list list;	/* Join these vginfos together */ | ||||
| 	struct list infos;	/* List head for lvmcache_infos */ | ||||
| 	char *vgname;		/* "" == orphan */ | ||||
| 	char vgid[ID_LEN + 1]; | ||||
| 	const struct format_type *fmt; | ||||
| }; | ||||
|  | ||||
| struct lvmcache_info { | ||||
| 	struct list list;	/* Join VG members together */ | ||||
| 	struct list mdas;	/* list head for metadata areas */ | ||||
| 	struct 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(void); | ||||
|  | ||||
| /* Set full_scan to 1 to reread every filtered device label */ | ||||
| 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); | ||||
| void lvmcache_del(struct lvmcache_info *info); | ||||
|  | ||||
| /* Update things */ | ||||
| int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname); | ||||
| int lvmcache_update_vg(struct volume_group *vg); | ||||
|  | ||||
| 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); | ||||
| struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname); | ||||
| struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid); | ||||
| struct lvmcache_info *info_from_pvid(const char *pvid); | ||||
| struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid); | ||||
| int vgs_locked(void); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of vgnames */ | ||||
| /* Set full_scan to 1 to reread every filtered device label */ | ||||
| struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan); | ||||
|  | ||||
| #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 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 _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 | ||||
							
								
								
									
										1006
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1006
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										92
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TOOLCONTEXT_H | ||||
| #define _LVM_TOOLCONTEXT_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
| #include "pool.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; | ||||
| 	uint64_t unit_factor; | ||||
| 	char unit_type; | ||||
| 	const char *msg_prefix; | ||||
| 	int cmd_name;		/* Show command name? */ | ||||
|  | ||||
| 	int archive;		/* should we archive ? */ | ||||
| 	int backup;		/* should we backup ? */ | ||||
|  | ||||
| 	struct format_type *fmt; | ||||
|  | ||||
| 	mode_t umask; | ||||
| }; | ||||
|  | ||||
| struct config_tree; | ||||
|  | ||||
| /* FIXME Split into tool & library contexts */ | ||||
| /* command-instance-related variables needed by library */ | ||||
| struct cmd_context { | ||||
| 	struct pool *libmem;	/* For permanent config data */ | ||||
| 	struct 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 list formats;	/* Available formats */ | ||||
| 	struct list segtypes;	/* Available segment types */ | ||||
| 	const char *hostname; | ||||
| 	const char *kernel_vsn; | ||||
|  | ||||
| 	char *cmd_line; | ||||
| 	struct command *command; | ||||
| 	struct arg *args; | ||||
| 	char **argv; | ||||
|  | ||||
| 	struct dev_filter *filter; | ||||
| 	int dump_filter;	/* Dump filter when exiting? */ | ||||
|  | ||||
| 	struct list config_files; | ||||
| 	int config_valid; | ||||
| 	struct config_tree *cft; | ||||
| 	struct config_info default_settings; | ||||
| 	struct config_info current_settings; | ||||
|  | ||||
| 	/* List of defined tags */ | ||||
| 	struct list tags; | ||||
| 	int hosttags; | ||||
|  | ||||
| 	char sys_dir[PATH_MAX]; | ||||
| 	char dev_dir[PATH_MAX]; | ||||
| 	char proc_dir[PATH_MAX]; | ||||
| }; | ||||
|  | ||||
| struct cmd_context *create_toolcontext(struct arg *the_args); | ||||
| void destroy_toolcontext(struct cmd_context *cmd); | ||||
| int refresh_toolcontext(struct cmd_context *cmd); | ||||
| int config_files_changed(struct cmd_context *cmd); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										999
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										999
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,999 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "config.h" | ||||
| #include "crc.h" | ||||
| #include "pool.h" | ||||
| #include "device.h" | ||||
| #include "str_list.h" | ||||
| #include "toolcontext.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <sys/mman.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <ctype.h> | ||||
|  | ||||
| enum { | ||||
| 	TOK_INT, | ||||
| 	TOK_FLOAT, | ||||
| 	TOK_STRING, | ||||
| 	TOK_EQ, | ||||
| 	TOK_SECTION_B, | ||||
| 	TOK_SECTION_E, | ||||
| 	TOK_ARRAY_B, | ||||
| 	TOK_ARRAY_E, | ||||
| 	TOK_IDENTIFIER, | ||||
| 	TOK_COMMA, | ||||
| 	TOK_EOF | ||||
| }; | ||||
|  | ||||
| struct parser { | ||||
| 	char *fb, *fe;		/* file limits */ | ||||
|  | ||||
| 	int t;			/* token limits and type */ | ||||
| 	char *tb, *te; | ||||
|  | ||||
| 	int fd;			/* descriptor for file being parsed */ | ||||
| 	int line;		/* line number we are on */ | ||||
|  | ||||
| 	struct pool *mem; | ||||
| }; | ||||
|  | ||||
| struct cs { | ||||
| 	struct config_tree cft; | ||||
| 	struct pool *mem; | ||||
| 	time_t timestamp; | ||||
| 	char *filename; | ||||
| 	int exists; | ||||
| }; | ||||
|  | ||||
| static void _get_token(struct parser *p, int tok_prev); | ||||
| static void _eat_space(struct parser *p); | ||||
| static struct config_node *_file(struct parser *p); | ||||
| static struct config_node *_section(struct parser *p); | ||||
| static struct config_value *_value(struct parser *p); | ||||
| static struct config_value *_type(struct parser *p); | ||||
| static int _match_aux(struct parser *p, int t); | ||||
| static struct config_value *_create_value(struct parser *p); | ||||
| static struct config_node *_create_node(struct parser *p); | ||||
| static char *_dup_tok(struct parser *p); | ||||
|  | ||||
| static const int sep = '/'; | ||||
|  | ||||
| #define MAX_INDENT 32 | ||||
|  | ||||
| #define match(t) do {\ | ||||
|    if (!_match_aux(p, (t))) {\ | ||||
| 	log_error("Parse error at line %d: unexpected token", p->line); \ | ||||
|       return 0;\ | ||||
|    } \ | ||||
| } while(0); | ||||
|  | ||||
| static int _tok_match(const char *str, const char *b, const char *e) | ||||
| { | ||||
| 	while (*str && (b != e)) { | ||||
| 		if (*str++ != *b++) | ||||
| 			return 0; | ||||
| 	} | ||||
|  | ||||
| 	return !(*str || (b != e)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * public interface | ||||
|  */ | ||||
| struct config_tree *create_config_tree(const char *filename) | ||||
| { | ||||
| 	struct cs *c; | ||||
| 	struct pool *mem = pool_create("config", 10 * 1024); | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(c = pool_zalloc(mem, sizeof(*c)))) { | ||||
| 		stack; | ||||
| 		pool_destroy(mem); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	c->mem = mem; | ||||
| 	c->cft.root = (struct config_node *) NULL; | ||||
| 	c->timestamp = 0; | ||||
| 	c->exists = 0; | ||||
| 	if (filename) | ||||
| 		c->filename = pool_strdup(c->mem, filename); | ||||
| 	return &c->cft; | ||||
| } | ||||
|  | ||||
| void destroy_config_tree(struct config_tree *cft) | ||||
| { | ||||
| 	pool_destroy(((struct cs *) cft)->mem); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	struct cs *c = (struct cs *) cft; | ||||
| 	struct parser *p; | ||||
| 	int r = 0; | ||||
| 	int use_mmap = 1; | ||||
| 	off_t mmap_offset = 0; | ||||
|  | ||||
| 	if (!(p = pool_alloc(c->mem, sizeof(*p)))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	p->mem = c->mem; | ||||
|  | ||||
| 	/* Only use mmap with regular files */ | ||||
| 	if (!(dev->flags & DEV_REGULAR) || size2) | ||||
| 		use_mmap = 0; | ||||
|  | ||||
| 	if (use_mmap) { | ||||
| 		mmap_offset = offset % getpagesize(); | ||||
| 		/* memory map the file */ | ||||
| 		p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ, | ||||
| 			     MAP_PRIVATE, dev_fd(dev), offset - mmap_offset); | ||||
| 		if (p->fb == (caddr_t) (-1)) { | ||||
| 			log_sys_error("mmap", dev_name(dev)); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		p->fb = p->fb + mmap_offset; | ||||
| 	} else { | ||||
| 		if (!(p->fb = dbg_malloc(size + size2))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (!dev_read(dev, (uint64_t) offset, size, p->fb)) { | ||||
| 			log_error("Read from %s failed", dev_name(dev)); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		if (size2) { | ||||
| 			if (!dev_read(dev, (uint64_t) offset2, size2, | ||||
| 				      p->fb + size)) { | ||||
| 				log_error("Circular read from %s failed", | ||||
| 					  dev_name(dev)); | ||||
| 				goto out; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (checksum_fn && checksum != | ||||
| 	    (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size), | ||||
| 			 p->fb + size, size2))) { | ||||
| 		log_error("%s: Checksum error", dev_name(dev)); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	p->fe = p->fb + size + size2; | ||||
|  | ||||
| 	/* parse */ | ||||
| 	p->tb = p->te = p->fb; | ||||
| 	p->line = 1; | ||||
| 	_get_token(p, TOK_SECTION_E); | ||||
| 	if (!(cft->root = _file(p))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	if (!use_mmap) | ||||
| 		dbg_free(p->fb); | ||||
| 	else { | ||||
| 		/* unmap the file */ | ||||
| 		if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) { | ||||
| 			log_sys_error("munmap", dev_name(dev)); | ||||
| 			r = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int read_config_file(struct config_tree *cft) | ||||
| { | ||||
| 	struct cs *c = (struct cs *) cft; | ||||
| 	struct stat info; | ||||
| 	struct device *dev; | ||||
| 	int r = 1; | ||||
|  | ||||
| 	if (stat(c->filename, &info)) { | ||||
| 		log_sys_error("stat", c->filename); | ||||
| 		c->exists = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!S_ISREG(info.st_mode)) { | ||||
| 		log_error("%s is not a regular file", c->filename); | ||||
| 		c->exists = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	c->exists = 1; | ||||
|  | ||||
| 	if (info.st_size == 0) { | ||||
| 		log_verbose("%s is empty", c->filename); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dev = dev_create_file(c->filename, NULL, NULL))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0, | ||||
| 			   (checksum_fn_t) NULL, 0); | ||||
|  | ||||
| 	dev_close(dev); | ||||
|  | ||||
| 	c->timestamp = info.st_mtime; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| time_t config_file_timestamp(struct config_tree *cft) | ||||
| { | ||||
| 	struct cs *c = (struct cs *) cft; | ||||
|  | ||||
| 	return c->timestamp; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return 1 if config files ought to be reloaded | ||||
|  */ | ||||
| int config_file_changed(struct config_tree *cft) | ||||
| { | ||||
| 	struct cs *c = (struct cs *) cft; | ||||
| 	struct stat info; | ||||
|  | ||||
| 	if (!c->filename) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (stat(c->filename, &info) == -1) { | ||||
| 		/* Ignore a deleted config file: still use original data */ | ||||
| 		if (errno == ENOENT) { | ||||
| 			if (!c->exists) | ||||
| 				return 0; | ||||
| 			log_very_verbose("Config file %s has disappeared!", | ||||
| 					 c->filename); | ||||
| 			goto reload; | ||||
| 		} | ||||
| 		log_sys_error("stat", c->filename); | ||||
| 		log_error("Failed to reload configuration files"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!S_ISREG(info.st_mode)) { | ||||
| 		log_error("Configuration file %s is not a regular file", | ||||
| 			  c->filename); | ||||
| 		goto reload; | ||||
| 	} | ||||
|  | ||||
| 	/* Unchanged? */ | ||||
| 	if (c->timestamp == info.st_mtime) | ||||
| 		return 0; | ||||
|  | ||||
|       reload: | ||||
| 	log_verbose("Detected config file change to %s", c->filename); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _write_value(FILE *fp, struct config_value *v) | ||||
| { | ||||
| 	switch (v->type) { | ||||
| 	case CFG_STRING: | ||||
| 		fprintf(fp, "\"%s\"", v->v.str); | ||||
| 		break; | ||||
|  | ||||
| 	case CFG_FLOAT: | ||||
| 		fprintf(fp, "%f", v->v.r); | ||||
| 		break; | ||||
|  | ||||
| 	case CFG_INT: | ||||
| 		fprintf(fp, "%d", v->v.i); | ||||
| 		break; | ||||
|  | ||||
| 	case CFG_EMPTY_ARRAY: | ||||
| 		fprintf(fp, "[]"); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_error("_write_value: Unknown value type: %d", v->type); | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _write_config(struct config_node *n, FILE *fp, int level) | ||||
| { | ||||
| 	char space[MAX_INDENT + 1]; | ||||
| 	int l = (level < MAX_INDENT) ? level : MAX_INDENT; | ||||
| 	int i; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return 1; | ||||
|  | ||||
| 	for (i = 0; i < l; i++) | ||||
| 		space[i] = '\t'; | ||||
| 	space[i] = '\0'; | ||||
|  | ||||
| 	while (n) { | ||||
| 		fprintf(fp, "%s%s", space, n->key); | ||||
| 		if (!n->v) { | ||||
| 			/* it's a sub section */ | ||||
| 			fprintf(fp, " {\n"); | ||||
| 			_write_config(n->child, fp, level + 1); | ||||
| 			fprintf(fp, "%s}", space); | ||||
| 		} else { | ||||
| 			/* it's a value */ | ||||
| 			struct config_value *v = n->v; | ||||
| 			fprintf(fp, "="); | ||||
| 			if (v->next) { | ||||
| 				fprintf(fp, "["); | ||||
| 				while (v) { | ||||
| 					_write_value(fp, v); | ||||
| 					v = v->next; | ||||
| 					if (v) | ||||
| 						fprintf(fp, ", "); | ||||
| 				} | ||||
| 				fprintf(fp, "]"); | ||||
| 			} else | ||||
| 				_write_value(fp, v); | ||||
| 		} | ||||
| 		fprintf(fp, "\n"); | ||||
| 		n = n->sib; | ||||
| 	} | ||||
| 	/* FIXME: add error checking */ | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int write_config_file(struct config_tree *cft, const char *file) | ||||
| { | ||||
| 	int r = 1; | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	if (!file) { | ||||
| 		fp = stdout; | ||||
| 		file = "stdout"; | ||||
| 	} else if (!(fp = fopen(file, "w"))) { | ||||
| 		log_sys_error("open", file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_verbose("Dumping configuration to %s", file); | ||||
| 	if (!_write_config(cft->root, fp, 0)) { | ||||
| 		log_error("Failure while writing configuration"); | ||||
| 		r = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (fp != stdout) | ||||
| 		fclose(fp); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * parser | ||||
|  */ | ||||
| static struct config_node *_file(struct parser *p) | ||||
| { | ||||
| 	struct config_node *root = NULL, *n, *l = NULL; | ||||
| 	while (p->t != TOK_EOF) { | ||||
| 		if (!(n = _section(p))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (!root) | ||||
| 			root = n; | ||||
| 		else | ||||
| 			l->sib = n; | ||||
| 		l = n; | ||||
| 	} | ||||
| 	return root; | ||||
| } | ||||
|  | ||||
| static struct config_node *_section(struct parser *p) | ||||
| { | ||||
| 	/* IDENTIFIER '{' VALUE* '}' */ | ||||
| 	struct config_node *root, *n, *l = NULL; | ||||
| 	if (!(root = _create_node(p))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(root->key = _dup_tok(p))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	match(TOK_IDENTIFIER); | ||||
|  | ||||
| 	if (p->t == TOK_SECTION_B) { | ||||
| 		match(TOK_SECTION_B); | ||||
| 		while (p->t != TOK_SECTION_E) { | ||||
| 			if (!(n = _section(p))) { | ||||
| 				stack; | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			if (!root->child) | ||||
| 				root->child = n; | ||||
| 			else | ||||
| 				l->sib = n; | ||||
| 			l = n; | ||||
| 		} | ||||
| 		match(TOK_SECTION_E); | ||||
| 	} else { | ||||
| 		match(TOK_EQ); | ||||
| 		if (!(root->v = _value(p))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return root; | ||||
| } | ||||
|  | ||||
| static struct config_value *_value(struct parser *p) | ||||
| { | ||||
| 	/* '[' TYPE* ']' | TYPE */ | ||||
| 	struct config_value *h = NULL, *l, *ll = NULL; | ||||
| 	if (p->t == TOK_ARRAY_B) { | ||||
| 		match(TOK_ARRAY_B); | ||||
| 		while (p->t != TOK_ARRAY_E) { | ||||
| 			if (!(l = _type(p))) { | ||||
| 				stack; | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			if (!h) | ||||
| 				h = l; | ||||
| 			else | ||||
| 				ll->next = l; | ||||
| 			ll = l; | ||||
|  | ||||
| 			if (p->t == TOK_COMMA) | ||||
| 				match(TOK_COMMA); | ||||
| 		} | ||||
| 		match(TOK_ARRAY_E); | ||||
| 		/* | ||||
| 		 * Special case for an empty array. | ||||
| 		 */ | ||||
| 		if (!h) { | ||||
| 			if (!(h = _create_value(p))) | ||||
| 				return NULL; | ||||
|  | ||||
| 			h->type = CFG_EMPTY_ARRAY; | ||||
| 		} | ||||
|  | ||||
| 	} else | ||||
| 		h = _type(p); | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| static struct config_value *_type(struct parser *p) | ||||
| { | ||||
| 	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */ | ||||
| 	struct config_value *v = _create_value(p); | ||||
|  | ||||
| 	if (!v) | ||||
| 		return NULL; | ||||
|  | ||||
| 	switch (p->t) { | ||||
| 	case TOK_INT: | ||||
| 		v->type = CFG_INT; | ||||
| 		v->v.i = strtol(p->tb, NULL, 0);	/* FIXME: check error */ | ||||
| 		match(TOK_INT); | ||||
| 		break; | ||||
|  | ||||
| 	case TOK_FLOAT: | ||||
| 		v->type = CFG_FLOAT; | ||||
| 		v->v.r = strtod(p->tb, NULL);	/* FIXME: check error */ | ||||
| 		match(TOK_FLOAT); | ||||
| 		break; | ||||
|  | ||||
| 	case TOK_STRING: | ||||
| 		v->type = CFG_STRING; | ||||
|  | ||||
| 		p->tb++, p->te--;	/* strip "'s */ | ||||
| 		if (!(v->v.str = _dup_tok(p))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		p->te++; | ||||
| 		match(TOK_STRING); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_error("Parse error at line %d: expected a value", p->line); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| static int _match_aux(struct parser *p, int t) | ||||
| { | ||||
| 	if (p->t != t) | ||||
| 		return 0; | ||||
|  | ||||
| 	_get_token(p, t); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * tokeniser | ||||
|  */ | ||||
| static void _get_token(struct parser *p, int tok_prev) | ||||
| { | ||||
| 	int values_allowed = 0; | ||||
|  | ||||
| 	p->tb = p->te; | ||||
| 	_eat_space(p); | ||||
| 	if (p->tb == p->fe || !*p->tb) { | ||||
| 		p->t = TOK_EOF; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* Should next token be interpreted as value instead of identifier? */ | ||||
| 	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B || | ||||
| 	    tok_prev == TOK_COMMA) | ||||
| 		values_allowed = 1; | ||||
|  | ||||
| 	p->t = TOK_INT;		/* fudge so the fall through for | ||||
| 				   floats works */ | ||||
| 	switch (*p->te) { | ||||
| 	case '{': | ||||
| 		p->t = TOK_SECTION_B; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '}': | ||||
| 		p->t = TOK_SECTION_E; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '[': | ||||
| 		p->t = TOK_ARRAY_B; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case ']': | ||||
| 		p->t = TOK_ARRAY_E; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case ',': | ||||
| 		p->t = TOK_COMMA; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '=': | ||||
| 		p->t = TOK_EQ; | ||||
| 		p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '"': | ||||
| 		p->t = TOK_STRING; | ||||
| 		p->te++; | ||||
| 		while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) { | ||||
| 			if ((*p->te == '\\') && (p->te + 1 != p->fe) && | ||||
| 			    *(p->te + 1)) | ||||
| 				p->te++; | ||||
| 			p->te++; | ||||
| 		} | ||||
|  | ||||
| 		if ((p->te != p->fe) && (*p->te)) | ||||
| 			p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '\'': | ||||
| 		p->t = TOK_STRING; | ||||
| 		p->te++; | ||||
| 		while ((p->te != p->fe) && (*p->te) && (*p->te != '\'')) | ||||
| 			p->te++; | ||||
|  | ||||
| 		if ((p->te != p->fe) && (*p->te)) | ||||
| 			p->te++; | ||||
| 		break; | ||||
|  | ||||
| 	case '.': | ||||
| 		p->t = TOK_FLOAT; | ||||
| 	case '0': | ||||
| 	case '1': | ||||
| 	case '2': | ||||
| 	case '3': | ||||
| 	case '4': | ||||
| 	case '5': | ||||
| 	case '6': | ||||
| 	case '7': | ||||
| 	case '8': | ||||
| 	case '9': | ||||
| 	case '+': | ||||
| 	case '-': | ||||
| 		if (values_allowed) { | ||||
| 			p->te++; | ||||
| 			while ((p->te != p->fe) && (*p->te)) { | ||||
| 				if (*p->te == '.') { | ||||
| 					if (p->t == TOK_FLOAT) | ||||
| 						break; | ||||
| 					p->t = TOK_FLOAT; | ||||
| 				} else if (!isdigit((int) *p->te)) | ||||
| 					break; | ||||
| 				p->te++; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 	default: | ||||
| 		p->t = TOK_IDENTIFIER; | ||||
| 		while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) && | ||||
| 		       (*p->te != '#') && (*p->te != '=') && (*p->te != '{') && | ||||
| 		       (*p->te != '}')) | ||||
| 			p->te++; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void _eat_space(struct parser *p) | ||||
| { | ||||
| 	while ((p->tb != p->fe) && (*p->tb)) { | ||||
| 		if (*p->te == '#') { | ||||
| 			while ((p->te != p->fe) && (*p->te) && (*p->te != '\n')) | ||||
| 				p->te++; | ||||
| 			p->line++; | ||||
| 		} | ||||
|  | ||||
| 		else if (isspace(*p->te)) { | ||||
| 			while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) { | ||||
| 				if (*p->te == '\n') | ||||
| 					p->line++; | ||||
| 				p->te++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		else | ||||
| 			return; | ||||
|  | ||||
| 		p->tb = p->te; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * memory management | ||||
|  */ | ||||
| static struct config_value *_create_value(struct parser *p) | ||||
| { | ||||
| 	struct config_value *v = pool_alloc(p->mem, sizeof(*v)); | ||||
| 	memset(v, 0, sizeof(*v)); | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| static struct config_node *_create_node(struct parser *p) | ||||
| { | ||||
| 	struct config_node *n = pool_alloc(p->mem, sizeof(*n)); | ||||
| 	memset(n, 0, sizeof(*n)); | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static char *_dup_tok(struct parser *p) | ||||
| { | ||||
| 	size_t len = p->te - p->tb; | ||||
| 	char *str = pool_alloc(p->mem, len + 1); | ||||
| 	if (!str) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	strncpy(str, p->tb, len); | ||||
| 	str[len] = '\0'; | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * utility functions | ||||
|  */ | ||||
| struct config_node *find_config_node(const struct config_node *cn, | ||||
| 				     const char *path) | ||||
| { | ||||
| 	const char *e; | ||||
|  | ||||
| 	while (cn) { | ||||
| 		/* trim any leading slashes */ | ||||
| 		while (*path && (*path == sep)) | ||||
| 			path++; | ||||
|  | ||||
| 		/* find the end of this segment */ | ||||
| 		for (e = path; *e && (*e != sep); e++) ; | ||||
|  | ||||
| 		/* hunt for the node */ | ||||
| 		while (cn) { | ||||
| 			if (_tok_match(cn->key, path, e)) | ||||
| 				break; | ||||
|  | ||||
| 			cn = cn->sib; | ||||
| 		} | ||||
|  | ||||
| 		if (cn && *e) | ||||
| 			cn = cn->child; | ||||
| 		else | ||||
| 			break;	/* don't move into the last node */ | ||||
|  | ||||
| 		path = e; | ||||
| 	} | ||||
|  | ||||
| 	return (struct config_node *) cn; | ||||
| } | ||||
|  | ||||
| const char *find_config_str(const struct config_node *cn, | ||||
| 			    const char *path, const char *fail) | ||||
| { | ||||
| 	const struct config_node *n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (n && n->v->type == CFG_STRING) { | ||||
| 		if (*n->v->v.str) | ||||
| 			log_very_verbose("Setting %s to %s", path, n->v->v.str); | ||||
| 		return n->v->v.str; | ||||
| 	} | ||||
|  | ||||
| 	if (fail) | ||||
| 		log_very_verbose("%s not found in config: defaulting to %s", | ||||
| 				 path, fail); | ||||
| 	return fail; | ||||
| } | ||||
|  | ||||
| int find_config_int(const struct config_node *cn, const char *path, int fail) | ||||
| { | ||||
| 	const struct config_node *n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (n && n->v->type == CFG_INT) { | ||||
| 		log_very_verbose("Setting %s to %d", path, n->v->v.i); | ||||
| 		return n->v->v.i; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("%s not found in config: defaulting to %d", | ||||
| 			 path, fail); | ||||
| 	return fail; | ||||
| } | ||||
|  | ||||
| float find_config_float(const struct config_node *cn, const char *path, | ||||
| 			float fail) | ||||
| { | ||||
| 	const struct config_node *n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (n && n->v->type == CFG_FLOAT) { | ||||
| 		log_very_verbose("Setting %s to %f", path, n->v->v.r); | ||||
| 		return n->v->v.r; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("%s not found in config: defaulting to %f", | ||||
| 			 path, fail); | ||||
|  | ||||
| 	return fail; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int _str_in_array(const char *str, const char *values[]) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; values[i]; i++) | ||||
| 		if (!strcasecmp(str, values[i])) | ||||
| 			return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _str_to_bool(const char *str, int fail) | ||||
| { | ||||
| 	static const char *_true_values[] = { "y", "yes", "on", "true", NULL }; | ||||
| 	static const char *_false_values[] = | ||||
| 	    { "n", "no", "off", "false", NULL }; | ||||
|  | ||||
| 	if (_str_in_array(str, _true_values)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (_str_in_array(str, _false_values)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return fail; | ||||
| } | ||||
|  | ||||
| int find_config_bool(const struct config_node *cn, const char *path, int fail) | ||||
| { | ||||
| 	const struct config_node *n = find_config_node(cn, path); | ||||
| 	struct config_value *v; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return fail; | ||||
|  | ||||
| 	v = n->v; | ||||
|  | ||||
| 	switch (v->type) { | ||||
| 	case CFG_INT: | ||||
| 		return v->v.i ? 1 : 0; | ||||
|  | ||||
| 	case CFG_STRING: | ||||
| 		return _str_to_bool(v->v.str, fail); | ||||
| 	} | ||||
|  | ||||
| 	return fail; | ||||
| } | ||||
|  | ||||
| int get_config_uint32(const struct config_node *cn, const char *path, | ||||
| 		      uint32_t *result) | ||||
| { | ||||
| 	const struct config_node *n; | ||||
|  | ||||
| 	n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (!n || !n->v || n->v->type != CFG_INT) | ||||
| 		return 0; | ||||
|  | ||||
| 	*result = n->v->v.i; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int get_config_uint64(const struct config_node *cn, const char *path, | ||||
| 		      uint64_t *result) | ||||
| { | ||||
| 	const struct config_node *n; | ||||
|  | ||||
| 	n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (!n || !n->v || n->v->type != CFG_INT) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* FIXME Support 64-bit value! */ | ||||
| 	*result = (uint64_t) n->v->v.i; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int get_config_str(const struct config_node *cn, const char *path, | ||||
| 		   char **result) | ||||
| { | ||||
| 	const struct config_node *n; | ||||
|  | ||||
| 	n = find_config_node(cn, path); | ||||
|  | ||||
| 	if (!n || !n->v || n->v->type != CFG_STRING) | ||||
| 		return 0; | ||||
|  | ||||
| 	*result = n->v->v.str; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Insert cn2 after cn1 */ | ||||
| static void _insert_config_node(struct config_node **cn1, | ||||
| 				struct config_node *cn2) | ||||
| { | ||||
| 	if (!*cn1) { | ||||
| 		*cn1 = cn2; | ||||
| 		cn2->sib = NULL; | ||||
| 	} else { | ||||
| 		cn2->sib = (*cn1)->sib; | ||||
| 		(*cn1)->sib = cn2; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Merge section cn2 into section cn1 (which has the same name) | ||||
|  * overwriting any existing cn1 nodes with matching names. | ||||
|  */ | ||||
| static void _merge_section(struct config_node *cn1, struct config_node *cn2) | ||||
| { | ||||
| 	struct config_node *cn, *nextn, *oldn; | ||||
| 	struct config_value *cv; | ||||
|  | ||||
| 	for (cn = cn2->child; cn; cn = nextn) { | ||||
| 		nextn = cn->sib; | ||||
|  | ||||
| 		/* Skip "tags" */ | ||||
| 		if (!strcmp(cn->key, "tags")) | ||||
| 			continue; | ||||
|  | ||||
| 		/* Subsection? */ | ||||
| 		if (!cn->v) | ||||
| 			/* Ignore - we don't have any of these yet */ | ||||
| 			continue; | ||||
| 		/* Not already present? */ | ||||
| 		if (!(oldn = find_config_node(cn1->child, cn->key))) { | ||||
| 			_insert_config_node(&cn1->child, cn); | ||||
| 			continue; | ||||
| 		} | ||||
| 		/* Merge certain value lists */ | ||||
| 		if ((!strcmp(cn1->key, "activation") && | ||||
| 		     !strcmp(cn->key, "volume_list")) || | ||||
| 		    (!strcmp(cn1->key, "devices") && | ||||
| 		     (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) { | ||||
| 			cv = cn->v; | ||||
| 			while (cv->next) | ||||
| 				cv = cv->next; | ||||
| 			cv->next = oldn->v; | ||||
| 		} | ||||
|  | ||||
| 		/* Replace values */ | ||||
| 		oldn->v = cn->v; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _match_host_tags(struct list *tags, struct config_node *tn) | ||||
| { | ||||
| 	struct config_value *tv; | ||||
| 	const char *str; | ||||
|  | ||||
| 	for (tv = tn->v; tv; tv = tv->next) { | ||||
| 		if (tv->type != CFG_STRING) | ||||
| 			continue; | ||||
| 		str = tv->v.str; | ||||
| 		if (*str == '@') | ||||
| 			str++; | ||||
| 		if (!*str) | ||||
| 			continue; | ||||
| 		if (str_list_match_item(tags, str)) | ||||
| 			return 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Destructively merge a new config tree into an existing one */ | ||||
| int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft, | ||||
| 		      struct config_tree *newdata) | ||||
| { | ||||
| 	struct config_node *root = cft->root; | ||||
| 	struct config_node *cn, *nextn, *oldn, *tn, *cn2; | ||||
|  | ||||
| 	for (cn = newdata->root; cn; cn = nextn) { | ||||
| 		nextn = cn->sib; | ||||
| 		/* Ignore tags section */ | ||||
| 		if (!strcmp(cn->key, "tags")) | ||||
| 			continue; | ||||
| 		/* If there's a tags node, skip if host tags don't match */ | ||||
| 		if ((tn = find_config_node(cn->child, "tags"))) { | ||||
| 			if (!_match_host_tags(&cmd->tags, tn)) | ||||
| 				continue; | ||||
| 		} | ||||
| 		if (!(oldn = find_config_node(root, cn->key))) { | ||||
| 			_insert_config_node(&cft->root, cn); | ||||
| 			/* Remove any "tags" nodes */ | ||||
| 			for (cn2 = cn->child; cn2; cn2 = cn2->sib) { | ||||
| 				if (!strcmp(cn2->key, "tags")) { | ||||
| 					cn->child = cn2->sib; | ||||
| 					continue; | ||||
| 				} | ||||
| 				if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { | ||||
| 					cn2->sib = cn2->sib->sib; | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
| 		_merge_section(oldn, cn); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										96
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CONFIG_H | ||||
| #define _LVM_CONFIG_H | ||||
|  | ||||
| struct device; | ||||
| struct cmd_context; | ||||
|  | ||||
| enum { | ||||
| 	CFG_STRING, | ||||
| 	CFG_FLOAT, | ||||
| 	CFG_INT, | ||||
| 	CFG_EMPTY_ARRAY | ||||
| }; | ||||
|  | ||||
| struct config_value { | ||||
| 	int type; | ||||
| 	union { | ||||
| 		int 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 list list; | ||||
| 	struct config_tree *cft; | ||||
| }; | ||||
|  | ||||
| struct config_tree *create_config_tree(const char *filename); | ||||
| void destroy_config_tree(struct config_tree *cft); | ||||
|  | ||||
| typedef uint32_t (*checksum_fn_t) (uint32_t initial, 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); | ||||
| 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); | ||||
|  | ||||
| /* | ||||
|  * 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 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); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										109
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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_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_LOCK_DIR "/var/lock/lvm" | ||||
| #define DEFAULT_LOCKING_LIB "lvm2_locking.so" | ||||
|  | ||||
| #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_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 "/dev/ioerror" | ||||
| #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_HEADINGS 1 | ||||
| #define DEFAULT_REP_SEPARATOR " " | ||||
|  | ||||
| #define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent" | ||||
| #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_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,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_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" | ||||
|  | ||||
| #endif				/* _LVM_DEFAULTS_H */ | ||||
							
								
								
									
										86
									
								
								lib/datastruct/bitset.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								lib/datastruct/bitset.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "bitset.h" | ||||
|  | ||||
| /* FIXME: calculate this. */ | ||||
| #define INT_SHIFT 5 | ||||
|  | ||||
| bitset_t bitset_create(struct pool *mem, unsigned num_bits) | ||||
| { | ||||
| 	unsigned n = (num_bits / BITS_PER_INT) + 2; | ||||
| 	size_t size = sizeof(int) * n; | ||||
| 	unsigned *bs = pool_zalloc(mem, size); | ||||
|  | ||||
| 	if (!bs) | ||||
| 		return NULL; | ||||
|  | ||||
| 	*bs = num_bits; | ||||
| 	return bs; | ||||
| } | ||||
|  | ||||
| void bitset_destroy(bitset_t bs) | ||||
| { | ||||
| 	dbg_free(bs); | ||||
| } | ||||
|  | ||||
| void bit_union(bitset_t out, bitset_t in1, bitset_t in2) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = (in1[0] / BITS_PER_INT) + 1; i; i--) | ||||
| 		out[i] = in1[i] | in2[i]; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * FIXME: slow | ||||
|  */ | ||||
| static inline int _test_word(uint32_t test, int bit) | ||||
| { | ||||
| 	while (bit < BITS_PER_INT) { | ||||
| 		if (test & (0x1 << bit)) | ||||
| 			return bit; | ||||
| 		bit++; | ||||
| 	} | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int bit_get_next(bitset_t bs, int last_bit) | ||||
| { | ||||
| 	int bit, word; | ||||
| 	uint32_t test; | ||||
|  | ||||
| 	last_bit++;		/* otherwise we'll return the same bit again */ | ||||
|  | ||||
| 	while (last_bit < bs[0]) { | ||||
| 		word = last_bit >> INT_SHIFT; | ||||
| 		test = bs[word + 1]; | ||||
| 		bit = last_bit & (BITS_PER_INT - 1); | ||||
|  | ||||
| 		if ((bit = _test_word(test, bit)) >= 0) | ||||
| 			return (word * BITS_PER_INT) + bit; | ||||
|  | ||||
| 		last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) + | ||||
| 		    BITS_PER_INT; | ||||
| 	} | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int bit_get_first(bitset_t bs) | ||||
| { | ||||
| 	return bit_get_next(bs, -1); | ||||
| } | ||||
							
								
								
									
										52
									
								
								lib/datastruct/bitset.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/datastruct/bitset.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_BITSET_H | ||||
| #define _LVM_BITSET_H | ||||
|  | ||||
| #include "pool.h" | ||||
|  | ||||
| #include <limits.h> | ||||
|  | ||||
| typedef uint32_t *bitset_t; | ||||
|  | ||||
| bitset_t bitset_create(struct pool *mem, unsigned num_bits); | ||||
| void bitset_destroy(bitset_t bs); | ||||
|  | ||||
| void bit_union(bitset_t out, bitset_t in1, bitset_t in2); | ||||
| int bit_get_first(bitset_t bs); | ||||
| int bit_get_next(bitset_t bs, int last_bit); | ||||
|  | ||||
| #define BITS_PER_INT (sizeof(int) * CHAR_BIT) | ||||
|  | ||||
| #define bit(bs, i) \ | ||||
|    (bs[(i / BITS_PER_INT) + 1] & (0x1 << (i & (BITS_PER_INT - 1)))) | ||||
|  | ||||
| #define bit_set(bs, i) \ | ||||
|    (bs[(i / BITS_PER_INT) + 1] |= (0x1 << (i & (BITS_PER_INT - 1)))) | ||||
|  | ||||
| #define bit_clear(bs, i) \ | ||||
|    (bs[(i / BITS_PER_INT) + 1] &= ~(0x1 << (i & (BITS_PER_INT - 1)))) | ||||
|  | ||||
| #define bit_set_all(bs) \ | ||||
|    memset(bs + 1, -1, ((*bs / BITS_PER_INT) + 1) * sizeof(int)) | ||||
|  | ||||
| #define bit_clear_all(bs) \ | ||||
|    memset(bs + 1, 0, ((*bs / BITS_PER_INT) + 1) * sizeof(int)) | ||||
|  | ||||
| #define bit_copy(bs1, bs2) \ | ||||
|    memcpy(bs1 + 1, bs2 + 1, ((*bs1 / BITS_PER_INT) + 1) * sizeof(int)) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										138
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "btree.h" | ||||
|  | ||||
| struct node { | ||||
| 	uint32_t key; | ||||
| 	struct node *l, *r, *p; | ||||
|  | ||||
| 	void *data; | ||||
| }; | ||||
|  | ||||
| struct btree { | ||||
| 	struct pool *mem; | ||||
| 	struct node *root; | ||||
| }; | ||||
|  | ||||
| struct btree *btree_create(struct pool *mem) | ||||
| { | ||||
| 	struct btree *t = 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 **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 c; | ||||
| } | ||||
|  | ||||
| void *btree_lookup(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 = pool_alloc(t->mem, sizeof(*n)))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		n->key = key; | ||||
| 		n->data = data; | ||||
| 		n->l = n->r = NULL; | ||||
| 		n->p = p; | ||||
|  | ||||
| 		*c = n; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void *btree_get_data(struct btree_iter *it) | ||||
| { | ||||
| 	return ((struct node *) it)->data; | ||||
| } | ||||
|  | ||||
| static inline struct node *_left(struct node *n) | ||||
| { | ||||
| 	while (n->l) | ||||
| 		n = n->l; | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_first(struct btree *t) | ||||
| { | ||||
| 	if (!t->root) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return (struct btree_iter *) _left(t->root); | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_next(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; | ||||
| } | ||||
							
								
								
									
										34
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_BTREE_H | ||||
| #define _LVM_BTREE_H | ||||
|  | ||||
| #include "pool.h" | ||||
|  | ||||
| struct btree; | ||||
|  | ||||
| struct btree *btree_create(struct pool *mem); | ||||
|  | ||||
| void *btree_lookup(struct btree *t, uint32_t k); | ||||
| int btree_insert(struct btree *t, uint32_t k, void *data); | ||||
|  | ||||
| struct btree_iter; | ||||
| void *btree_get_data(struct btree_iter *it); | ||||
|  | ||||
| struct btree_iter *btree_first(struct btree *t); | ||||
| struct btree_iter *btree_next(struct btree_iter *it); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										262
									
								
								lib/datastruct/hash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								lib/datastruct/hash.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| struct hash_node { | ||||
| 	struct hash_node *next; | ||||
| 	void *data; | ||||
| 	int keylen; | ||||
| 	char key[0]; | ||||
| }; | ||||
|  | ||||
| struct hash_table { | ||||
| 	int num_nodes; | ||||
| 	int num_slots; | ||||
| 	struct hash_node **slots; | ||||
| }; | ||||
|  | ||||
| /* Permutation of the Integers 0 through 255 */ | ||||
| static unsigned char _nums[] = { | ||||
| 	1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51, | ||||
| 	87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, | ||||
| 	49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, | ||||
| 	12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172, | ||||
| 	144, | ||||
| 	176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254, | ||||
| 	178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54, | ||||
| 	221, | ||||
| 	102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93, | ||||
| 	166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189, | ||||
| 	121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185, | ||||
| 	194, | ||||
| 	193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232, | ||||
| 	139, | ||||
| 	6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, | ||||
| 	84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, | ||||
| 	43, | ||||
| 	249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, | ||||
| 	71, | ||||
| 	230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, | ||||
| 	109, | ||||
| 	44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184, | ||||
| 	163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120, | ||||
| 	209 | ||||
| }; | ||||
|  | ||||
| static struct hash_node *_create_node(const char *str, int len) | ||||
| { | ||||
| 	struct hash_node *n = dbg_malloc(sizeof(*n) + len); | ||||
|  | ||||
| 	if (n) { | ||||
| 		memcpy(n->key, str, len); | ||||
| 		n->keylen = len; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static unsigned _hash(const char *str, uint32_t len) | ||||
| { | ||||
| 	unsigned long h = 0, g, i; | ||||
|  | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		h <<= 4; | ||||
| 		h += _nums[(int) *str++]; | ||||
| 		g = h & ((unsigned long) 0xf << 16u); | ||||
| 		if (g) { | ||||
| 			h ^= g >> 16u; | ||||
| 			h ^= g >> 5u; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| struct hash_table *hash_create(unsigned size_hint) | ||||
| { | ||||
| 	size_t len; | ||||
| 	unsigned new_size = 16u; | ||||
| 	struct hash_table *hc = dbg_malloc(sizeof(*hc)); | ||||
|  | ||||
| 	if (!hc) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	memset(hc, 0, sizeof(*hc)); | ||||
|  | ||||
| 	/* round size hint up to a power of two */ | ||||
| 	while (new_size < size_hint) | ||||
| 		new_size = new_size << 1; | ||||
|  | ||||
| 	hc->num_slots = new_size; | ||||
| 	len = sizeof(*(hc->slots)) * new_size; | ||||
| 	if (!(hc->slots = dbg_malloc(len))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
| 	memset(hc->slots, 0, len); | ||||
| 	return hc; | ||||
|  | ||||
|       bad: | ||||
| 	dbg_free(hc->slots); | ||||
| 	dbg_free(hc); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _free_nodes(struct hash_table *t) | ||||
| { | ||||
| 	struct hash_node *c, *n; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < t->num_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = n) { | ||||
| 			n = c->next; | ||||
| 			dbg_free(c); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void hash_destroy(struct hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	dbg_free(t->slots); | ||||
| 	dbg_free(t); | ||||
| } | ||||
|  | ||||
| static inline struct hash_node **_find(struct hash_table *t, const char *key, | ||||
| 				       uint32_t len) | ||||
| { | ||||
| 	unsigned h = _hash(key, len) & (t->num_slots - 1); | ||||
| 	struct hash_node **c; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) | ||||
| 		if (!memcmp(key, (*c)->key, len)) | ||||
| 			break; | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| void *hash_lookup_binary(struct hash_table *t, const char *key, | ||||
| 			 uint32_t len) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key, len); | ||||
| 	return *c ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| int hash_insert_binary(struct hash_table *t, const char *key, | ||||
| 		       uint32_t len, void *data) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	if (*c) | ||||
| 		(*c)->data = data; | ||||
| 	else { | ||||
| 		struct hash_node *n = _create_node(key, len); | ||||
|  | ||||
| 		if (!n) | ||||
| 			return 0; | ||||
|  | ||||
| 		n->data = data; | ||||
| 		n->next = 0; | ||||
| 		*c = n; | ||||
| 		t->num_nodes++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void hash_remove_binary(struct hash_table *t, const char *key, | ||||
| 			uint32_t len) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	if (*c) { | ||||
| 		struct hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		dbg_free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void *hash_lookup(struct hash_table *t, const char *key) | ||||
| { | ||||
| 	return hash_lookup_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| int hash_insert(struct hash_table *t, const char *key, void *data) | ||||
| { | ||||
| 	return hash_insert_binary(t, key, strlen(key) + 1, data); | ||||
| } | ||||
|  | ||||
| void hash_remove(struct hash_table *t, const char *key) | ||||
| { | ||||
| 	hash_remove_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| unsigned hash_get_num_entries(struct hash_table *t) | ||||
| { | ||||
| 	return t->num_nodes; | ||||
| } | ||||
|  | ||||
| void hash_iter(struct hash_table *t, iterate_fn f) | ||||
| { | ||||
| 	struct hash_node *c; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < t->num_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = c->next) | ||||
| 			f(c->data); | ||||
| } | ||||
|  | ||||
| void hash_wipe(struct hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	memset(t->slots, 0, sizeof(struct hash_node *) * t->num_slots); | ||||
| 	t->num_nodes = 0; | ||||
| } | ||||
|  | ||||
| char *hash_get_key(struct hash_table *t, struct hash_node *n) | ||||
| { | ||||
| 	return n->key; | ||||
| } | ||||
|  | ||||
| void *hash_get_data(struct hash_table *t, struct hash_node *n) | ||||
| { | ||||
| 	return n->data; | ||||
| } | ||||
|  | ||||
| static struct hash_node *_next_slot(struct hash_table *t, unsigned s) | ||||
| { | ||||
| 	struct hash_node *c = NULL; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = s; i < t->num_slots && !c; i++) | ||||
| 		c = t->slots[i]; | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| struct hash_node *hash_get_first(struct hash_table *t) | ||||
| { | ||||
| 	return _next_slot(t, 0); | ||||
| } | ||||
|  | ||||
| struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n) | ||||
| { | ||||
| 	unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1); | ||||
| 	return n->next ? n->next : _next_slot(t, h + 1); | ||||
| } | ||||
							
								
								
									
										49
									
								
								lib/datastruct/hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lib/datastruct/hash.h
									
									
									
									
									
										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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_HASH_H | ||||
| #define _LVM_HASH_H | ||||
|  | ||||
| struct hash_table; | ||||
| struct hash_node; | ||||
|  | ||||
| typedef void (*iterate_fn) (void *data); | ||||
|  | ||||
| struct hash_table *hash_create(unsigned size_hint); | ||||
| void hash_destroy(struct hash_table *t); | ||||
| void hash_wipe(struct hash_table *t); | ||||
|  | ||||
| void *hash_lookup(struct hash_table *t, const char *key); | ||||
| int hash_insert(struct hash_table *t, const char *key, void *data); | ||||
| void hash_remove(struct hash_table *t, const char *key); | ||||
|  | ||||
| void *hash_lookup_binary(struct hash_table *t, const char *key, uint32_t len); | ||||
| int hash_insert_binary(struct hash_table *t, const char *key, uint32_t len, | ||||
| 		       void *data); | ||||
| void hash_remove_binary(struct hash_table *t, const char *key, uint32_t len); | ||||
|  | ||||
| unsigned hash_get_num_entries(struct hash_table *t); | ||||
| void hash_iter(struct hash_table *t, iterate_fn f); | ||||
|  | ||||
| char *hash_get_key(struct hash_table *t, struct hash_node *n); | ||||
| void *hash_get_data(struct hash_table *t, struct hash_node *n); | ||||
| struct hash_node *hash_get_first(struct hash_table *t); | ||||
| struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n); | ||||
|  | ||||
| #define hash_iterate(v, h) \ | ||||
| 	for (v = hash_get_first(h); v; \ | ||||
| 	     v = hash_get_next(h, v)) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										112
									
								
								lib/datastruct/list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/datastruct/list.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_LIST_H | ||||
| #define _LVM_LIST_H | ||||
|  | ||||
| #include <assert.h> | ||||
|  | ||||
| struct list { | ||||
| 	struct list *n, *p; | ||||
| }; | ||||
|  | ||||
| #define LIST_INIT(name)	struct list name = { &(name), &(name) } | ||||
|  | ||||
| static inline void list_init(struct list *head) | ||||
| { | ||||
| 	head->n = head->p = head; | ||||
| } | ||||
|  | ||||
| static inline void list_add(struct list *head, struct list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head; | ||||
| 	elem->p = head->p; | ||||
|  | ||||
| 	head->p->n = elem; | ||||
| 	head->p = elem; | ||||
| } | ||||
|  | ||||
| static inline void list_add_h(struct list *head, struct list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head->n; | ||||
| 	elem->p = head; | ||||
|  | ||||
| 	head->n->p = elem; | ||||
| 	head->n = elem; | ||||
| } | ||||
|  | ||||
| static inline void list_del(struct list *elem) | ||||
| { | ||||
| 	elem->n->p = elem->p; | ||||
| 	elem->p->n = elem->n; | ||||
| } | ||||
|  | ||||
| static inline int list_empty(struct list *head) | ||||
| { | ||||
| 	return head->n == head; | ||||
| } | ||||
|  | ||||
| static inline int list_end(struct list *head, struct list *elem) | ||||
| { | ||||
| 	return elem->n == head; | ||||
| } | ||||
|  | ||||
| static inline struct list *list_next(struct list *head, struct list *elem) | ||||
| { | ||||
| 	return (list_end(head, elem) ? NULL : elem->n); | ||||
| } | ||||
|  | ||||
| #define list_item(v, t) \ | ||||
|     ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) | ||||
|  | ||||
| #define list_struct_base(v, t, h) \ | ||||
|     ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h)) | ||||
|  | ||||
| /* Given a known element in a known structure, locate another */ | ||||
| #define struct_field(v, t, e, f) \ | ||||
|     (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f) | ||||
|  | ||||
| /* Given a known element in a known structure, locate the list head */ | ||||
| #define list_head(v, t, e) struct_field(v, t, e, list) | ||||
|  | ||||
| #define list_iterate(v, head) \ | ||||
| 	for (v = (head)->n; v != head; v = v->n) | ||||
|  | ||||
| #define list_uniterate(v, head, start) \ | ||||
| 	for (v = (start)->p; v != head; v = v->p) | ||||
|  | ||||
| #define list_iterate_safe(v, t, head) \ | ||||
| 	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) | ||||
|  | ||||
| #define list_iterate_items(v, head) \ | ||||
| 	for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \ | ||||
| 	     v = list_item(v->list.n, typeof(*v))) | ||||
|  | ||||
| static inline unsigned int list_size(const struct list *head) | ||||
| { | ||||
| 	unsigned int s = 0; | ||||
| 	const struct list *v; | ||||
|  | ||||
| 	list_iterate(v, head) | ||||
| 	    s++; | ||||
|  | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| #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 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 _LVM_TYPES_H | ||||
| #define _LVM_TYPES_H | ||||
|  | ||||
| #include "list.h" | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
| /* Define some portable printing types */ | ||||
| #define PRIsize_t "Zu" | ||||
|  | ||||
| struct str_list { | ||||
| 	struct list list; | ||||
| 	const char *str; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										128
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "str_list.h" | ||||
|  | ||||
| struct list *str_list_create(struct pool *mem) | ||||
| { | ||||
| 	struct list *sl; | ||||
|  | ||||
| 	if (!(sl = pool_alloc(mem, sizeof(struct list)))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_init(sl); | ||||
|  | ||||
| 	return sl; | ||||
| } | ||||
|  | ||||
| int str_list_add(struct pool *mem, struct list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sln; | ||||
|  | ||||
| 	if (!str) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Already in list? */ | ||||
| 	if (str_list_match_item(sll, str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(sln = pool_alloc(mem, sizeof(*sln)))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	sln->str = str; | ||||
| 	list_add(sll, &sln->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_del(struct list *sll, const char *str) | ||||
| { | ||||
| 	struct list *slh, *slht; | ||||
|  | ||||
| 	list_iterate_safe(slh, slht, sll) { | ||||
| 		if (!strcmp(str, list_item(slh, struct str_list)->str)) | ||||
| 			 list_del(slh); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_dup(struct pool *mem, struct list *sllnew, struct list *sllold) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	list_init(sllnew); | ||||
|  | ||||
| 	list_iterate_items(sl, sllold) { | ||||
| 		if (!str_list_add(mem, sllnew, strdup(sl->str))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is item on list? | ||||
|  */ | ||||
| int str_list_match_item(struct list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	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(struct list *sll, struct list *sll2) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	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(struct list *sll, struct list *sll2) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	if (list_size(sll) != list_size(sll2)) | ||||
| 		return 0; | ||||
|  | ||||
| 	list_iterate_items(sl, sll) | ||||
| 	    if (!str_list_match_item(sll2, sl->str)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										29
									
								
								lib/datastruct/str_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/datastruct/str_list.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-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 _LVM_STR_LIST_H | ||||
| #define _LVM_STR_LIST_H | ||||
|  | ||||
| #include "pool.h" | ||||
|  | ||||
| struct list *str_list_create(struct pool *mem); | ||||
| int str_list_add(struct pool *mem, struct list *sll, const char *str); | ||||
| int str_list_del(struct list *sll, const char *str); | ||||
| int str_list_match_item(struct list *sll, const char *str); | ||||
| int str_list_match_list(struct list *sll, struct list *sll2); | ||||
| int str_list_lists_equal(struct list *sll, struct list *sll2); | ||||
| int str_list_dup(struct pool *mem, struct list *sllnew, struct list *sllold); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										581
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										581
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,581 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "dev-cache.h" | ||||
| #include "pool.h" | ||||
| #include "hash.h" | ||||
| #include "list.h" | ||||
| #include "lvm-types.h" | ||||
| #include "btree.h" | ||||
| #include "filter.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 list list; | ||||
| 	char dir[0]; | ||||
| }; | ||||
|  | ||||
| static struct { | ||||
| 	struct pool *mem; | ||||
| 	struct hash_table *names; | ||||
| 	struct btree *devices; | ||||
|  | ||||
| 	int has_scanned; | ||||
| 	struct list dirs; | ||||
|  | ||||
| } _cache; | ||||
|  | ||||
| #define _alloc(x) pool_alloc(_cache.mem, (x)) | ||||
| #define _free(x) pool_free(_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 allocate = !dev; | ||||
|  | ||||
| 	if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) { | ||||
| 		log_error("struct device allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) { | ||||
| 		log_error("struct str_list allocation failed"); | ||||
| 		dbg_free(dev); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if (!(alias->str = dbg_strdup(filename))) { | ||||
| 		log_error("filename strdup failed"); | ||||
| 		if (allocate) { | ||||
| 			dbg_free(dev); | ||||
| 			dbg_free(alias); | ||||
| 		} | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	dev->flags = DEV_REGULAR; | ||||
| 	if (allocate) | ||||
| 		dev->flags |= DEV_ALLOCED; | ||||
| 	list_init(&dev->aliases); | ||||
| 	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)); | ||||
| 	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; | ||||
| 	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)); | ||||
| 	list_init(&dev->open_list); | ||||
|  | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| /* Return 1 if we prefer path1 else return 0 */ | ||||
| static int _compare_paths(const char *path0, const char *path1) | ||||
| { | ||||
| 	int slash0 = 0, slash1 = 0; | ||||
| 	const char *p; | ||||
| 	char p0[PATH_MAX], p1[PATH_MAX]; | ||||
| 	char *s0, *s1; | ||||
| 	struct stat stat0, stat1; | ||||
|  | ||||
| 	/* 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_error("lstat", p0); | ||||
| 			return 1; | ||||
| 		} | ||||
| 		if (lstat(p1, &stat1)) { | ||||
| 			log_sys_error("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 list *ah; | ||||
| 	const char *oldpath; | ||||
| 	int prefer_old = 1; | ||||
|  | ||||
| 	if (!sl) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Is name already there? */ | ||||
| 	list_iterate(ah, &dev->aliases) { | ||||
| 		if (!strcmp(list_item(ah, struct str_list)->str, path)) { | ||||
| 			stack; | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!(sl->str = pool_strdup(_cache.mem, path))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!list_empty(&dev->aliases)) { | ||||
| 		oldpath = 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) | ||||
| 		list_add(&dev->aliases, &sl->list); | ||||
| 	else | ||||
| 		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; | ||||
|  | ||||
| 	/* is this device already registered ? */ | ||||
| 	if (!(dev = (struct device *) btree_lookup(_cache.devices, | ||||
| 						   (uint32_t) d))) { | ||||
| 		/* create new device */ | ||||
| 		if (!(dev = _dev_create(d))) { | ||||
| 			stack; | ||||
| 			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 (!_add_alias(dev, path)) { | ||||
| 		log_err("Couldn't add alias to dev cache."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!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 = dbg_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))) { | ||||
| 				stack; | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			_collapse_slashes(path); | ||||
| 			r &= _insert(path, 1); | ||||
| 			dbg_free(path); | ||||
|  | ||||
| 			free(dirent[n]); | ||||
| 		} | ||||
| 		free(dirent); | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| 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)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		r = 1; | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static void _full_scan(void) | ||||
| { | ||||
| 	struct list *dh; | ||||
|  | ||||
| 	if (_cache.has_scanned) | ||||
| 		return; | ||||
|  | ||||
| 	list_iterate(dh, &_cache.dirs) { | ||||
| 		struct dir_list *dl = list_item(dh, struct dir_list); | ||||
| 		_insert_dir(dl->dir); | ||||
| 	}; | ||||
|  | ||||
| 	_cache.has_scanned = 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 { | ||||
| 		_cache.has_scanned = 0; | ||||
| 		_full_scan(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int dev_cache_init(void) | ||||
| { | ||||
| 	_cache.names = NULL; | ||||
|  | ||||
| 	if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(_cache.names = hash_create(128))) { | ||||
| 		stack; | ||||
| 		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; | ||||
| 	} | ||||
|  | ||||
| 	list_init(&_cache.dirs); | ||||
|  | ||||
| 	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 inline void _check_for_open_devices(void) | ||||
| { | ||||
| 	hash_iter(_cache.names, (iterate_fn) _check_closed); | ||||
| } | ||||
|  | ||||
| void dev_cache_exit(void) | ||||
| { | ||||
| 	if (_cache.names) | ||||
| 		_check_for_open_devices(); | ||||
|  | ||||
| 	if (_cache.mem) { | ||||
| 		pool_destroy(_cache.mem); | ||||
| 		_cache.mem = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (_cache.names) { | ||||
| 		hash_destroy(_cache.names); | ||||
| 		_cache.names = NULL; | ||||
| 	} | ||||
|  | ||||
| 	_cache.devices = NULL; | ||||
| 	_cache.has_scanned = 0; | ||||
| 	list_init(&_cache.dirs); | ||||
| } | ||||
|  | ||||
| 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); | ||||
| 	list_add(&_cache.dirs, &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; | ||||
|  | ||||
| 	while ((r = stat(name = 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 */ | ||||
| 		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 (list_size(&dev->aliases) > 1) { | ||||
| 			list_del(dev->aliases.n); | ||||
| 			if (!r) | ||||
| 				_insert(name, 0); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		log_error("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 *) hash_lookup(_cache.names, name); | ||||
|  | ||||
| 	/* If the entry's wrong, remove it */ | ||||
| 	if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) { | ||||
| 		hash_remove(_cache.names, name); | ||||
| 		d = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!d) { | ||||
| 		_insert(name, 0); | ||||
| 		d = (struct device *) hash_lookup(_cache.names, name); | ||||
| 	} | ||||
|  | ||||
| 	return (d && (!f || f->passes_filter(f, d))) ? d : NULL; | ||||
| } | ||||
|  | ||||
| struct dev_iter *dev_iter_create(struct dev_filter *f) | ||||
| { | ||||
| 	struct dev_iter *di = dbg_malloc(sizeof(*di)); | ||||
|  | ||||
| 	if (!di) { | ||||
| 		log_error("dev_iter allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	_full_scan(); | ||||
| 	di->current = btree_first(_cache.devices); | ||||
| 	di->filter = f; | ||||
|  | ||||
| 	return di; | ||||
| } | ||||
|  | ||||
| void dev_iter_destroy(struct dev_iter *iter) | ||||
| { | ||||
| 	dbg_free(iter); | ||||
| } | ||||
|  | ||||
| static inline 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 || | ||||
| 		    iter->filter->passes_filter(iter->filter, d)) | ||||
| 			return d; | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
							
								
								
									
										52
									
								
								lib/device/dev-cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/device/dev-cache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEV_CACHE_H | ||||
| #define _LVM_DEV_CACHE_H | ||||
|  | ||||
| #include "lvm-types.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. | ||||
|  */ | ||||
| int dev_cache_init(void); | ||||
| 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); | ||||
| struct device *dev_cache_get(const char *name, struct dev_filter *f); | ||||
|  | ||||
| /* | ||||
|  * Object for iterating through the cache. | ||||
|  */ | ||||
| struct dev_iter; | ||||
| struct dev_iter *dev_iter_create(struct dev_filter *f); | ||||
| void dev_iter_destroy(struct dev_iter *iter); | ||||
| struct device *dev_iter_get(struct dev_iter *iter); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										554
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										554
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,554 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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 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)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!block_size) | ||||
| 		block_size = 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) { | ||||
| 			stack; | ||||
| 			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; | ||||
| } | ||||
|  | ||||
| /*----------------------------------------------------------------- | ||||
|  * Public functions | ||||
|  *---------------------------------------------------------------*/ | ||||
|  | ||||
| int dev_get_size(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; | ||||
| } | ||||
|  | ||||
| /* 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); | ||||
| 		close(fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	close(fd); | ||||
| 	*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; | ||||
|  | ||||
| 	if (dev->fd >= 0) { | ||||
| 		if ((dev->flags & DEV_OPENED_RW) || | ||||
| 		    ((flags & O_ACCMODE) != O_RDWR)) { | ||||
| 			dev->open_count++; | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 		if (dev->open_count) { | ||||
| 			/* 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))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dev->flags & DEV_REGULAR) && | ||||
| 	    ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) { | ||||
| 		log_error("%s: stat failed: Has device name changed?", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifdef O_DIRECT_SUPPORT | ||||
| 	if (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) { | ||||
| 		log_sys_error("open", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	dev->open_count++; | ||||
| 	dev->flags &= ~DEV_ACCESSED_W; | ||||
| 	if ((flags & O_ACCMODE) == O_RDWR) | ||||
| 		dev->flags |= DEV_OPENED_RW; | ||||
| 	else | ||||
| 		dev->flags &= ~DEV_OPENED_RW; | ||||
|  | ||||
| 	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); | ||||
| 		dev->open_count = 0; | ||||
| 		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); | ||||
|  | ||||
| 	list_add(&_open_devices, &dev->open_list); | ||||
|  | ||||
| 	log_debug("Opened %s %s", dev_name(dev), | ||||
| 		  dev->flags & DEV_OPENED_RW ? "RW" : "RO"); | ||||
|  | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| static void _close(struct device *dev) | ||||
| { | ||||
| 	if (close(dev->fd)) | ||||
| 		log_sys_error("close", dev_name(dev)); | ||||
| 	dev->fd = -1; | ||||
| 	dev->block_size = -1; | ||||
| 	list_del(&dev->open_list); | ||||
|  | ||||
| 	log_debug("Closed %s", dev_name(dev)); | ||||
|  | ||||
| 	if (dev->flags & DEV_ALLOCED) { | ||||
| 		dbg_free((void *) list_item(dev->aliases.n, struct str_list)-> | ||||
| 			 str); | ||||
| 		dbg_free(dev->aliases.n); | ||||
| 		dbg_free(dev); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _dev_close(struct device *dev, int immediate) | ||||
| { | ||||
| 	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--; | ||||
|  | ||||
| 	/* FIXME lookup device in cache to get vgname and see if it's locked? */ | ||||
| 	if (immediate || (dev->open_count < 1 && !vgs_locked())) | ||||
| 		_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 list *doh, *doht; | ||||
| 	struct device *dev; | ||||
|  | ||||
| 	list_iterate_safe(doh, doht, &_open_devices) { | ||||
| 		dev = 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) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	where.dev = dev; | ||||
| 	where.start = offset; | ||||
| 	where.size = len; | ||||
|  | ||||
| 	return _aligned_io(&where, buffer, 0); | ||||
| } | ||||
|  | ||||
| /* 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) { | ||||
| 		stack; | ||||
| 		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) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	where.dev = dev; | ||||
| 	where.start = offset; | ||||
| 	where.size = len; | ||||
|  | ||||
| 	dev->flags |= DEV_ACCESSED_W; | ||||
|  | ||||
| 	return _aligned_io(&where, buffer, 1); | ||||
| } | ||||
|  | ||||
| int dev_zero(struct device *dev, uint64_t offset, size_t len) | ||||
| { | ||||
| 	size_t s; | ||||
| 	char buffer[4096]; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		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, 0, 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); | ||||
| } | ||||
							
								
								
									
										69
									
								
								lib/device/dev-md.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								lib/device/dev-md.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004 Luca Berra | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "metadata.h" | ||||
| #include "xlate.h" | ||||
|  | ||||
| /* Lifted from <linux/raid/md_p.h> because of difficulty including it */ | ||||
|  | ||||
| #define MD_SB_MAGIC 0xa92b4efc | ||||
| #define MD_RESERVED_BYTES (64 * 1024) | ||||
| #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) | ||||
| #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \ | ||||
| 				- MD_RESERVED_SECTORS) | ||||
|  | ||||
| /* | ||||
|  * Returns -1 on error | ||||
|  */ | ||||
| int dev_is_md(struct device *dev, uint64_t *sb) | ||||
| { | ||||
| 	int ret = 0; | ||||
|  | ||||
| #ifdef linux | ||||
|  | ||||
| 	uint64_t size, sb_offset; | ||||
| 	uint32_t md_magic; | ||||
|  | ||||
| 	if (!dev_get_size(dev, &size)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (size < MD_RESERVED_SECTORS * 2) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT; | ||||
|  | ||||
| 	/* Check if it is an md component device. */ | ||||
| 	if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) && | ||||
| 	    (md_magic == xlate32(MD_SB_MAGIC))) { | ||||
| 		if (sb) | ||||
| 			*sb = sb_offset; | ||||
| 		ret = 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| #endif | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
							
								
								
									
										282
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,282 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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; | ||||
| 	uint8_t buf[SECTOR_SIZE]; | ||||
| 	uint16_t *part_magic; | ||||
| 	struct partition *part; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_read(dev, 0, sizeof(buf), &buf)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME Check for other types of partition table too */ | ||||
|  | ||||
| 	/* Check for msdos partition table */ | ||||
| 	part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET); | ||||
| 	if ((*part_magic == xlate16(PART_MAGIC))) { | ||||
| 		part = (struct partition *) (buf + PART_OFFSET); | ||||
| 		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 = dbg_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 | ||||
							
								
								
									
										104
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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	/* dbg_malloc used */ | ||||
| #define DEV_OPENED_RW		0x00000008	/* Opened RW */ | ||||
|  | ||||
| /* | ||||
|  * All devices in LVM will be represented by one of these. | ||||
|  * pointer comparisons are valid. | ||||
|  */ | ||||
| struct device { | ||||
| 	struct 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 list open_list; | ||||
|  | ||||
| 	char pvid[ID_LEN + 1]; | ||||
| }; | ||||
|  | ||||
| struct device_list { | ||||
| 	struct 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 append, int quiet); | ||||
| int dev_close(struct device *dev); | ||||
| int dev_close_immediate(struct device *dev); | ||||
| void dev_close_all(void); | ||||
|  | ||||
| static inline int dev_fd(struct device *dev) | ||||
| { | ||||
| 	return dev->fd; | ||||
| } | ||||
|  | ||||
| int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); | ||||
| 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_zero(struct device *dev, uint64_t offset, size_t len); | ||||
| void dev_flush(struct device *dev); | ||||
|  | ||||
| struct device *dev_create_file(const char *filename, struct device *dev, | ||||
| 			       struct str_list *alias); | ||||
|  | ||||
| static inline const char *dev_name(const struct device *dev) | ||||
| { | ||||
| 	return (dev) ? list_item(dev->aliases.n, struct str_list)->str : | ||||
| 	    "unknown device"; | ||||
| } | ||||
|  | ||||
| /* 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); | ||||
|  | ||||
| /* FIXME Check partition type if appropriate */ | ||||
|  | ||||
| #define is_lvm_partition(a) 1 | ||||
| /* int is_lvm_partition(const char *name); */ | ||||
|  | ||||
| int is_partitioned_dev(struct device *dev); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										683
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										683
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,683 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "metadata.h" | ||||
| #include "display.h" | ||||
| #include "activate.h" | ||||
| #include "toolcontext.h" | ||||
| #include "segtype.h" | ||||
|  | ||||
| #define SIZE_BUF 128 | ||||
|  | ||||
| static struct { | ||||
| 	alloc_policy_t alloc; | ||||
| 	const char *str; | ||||
| } _policies[] = { | ||||
| 	{ | ||||
| 	ALLOC_CONTIGUOUS, "contiguous"}, { | ||||
| 	ALLOC_NORMAL, "normal"}, { | ||||
| 	ALLOC_ANYWHERE, "anywhere"}, { | ||||
| 	ALLOC_INHERIT, "inherit"} | ||||
| }; | ||||
|  | ||||
| static 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; | ||||
| #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; | ||||
| #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 */ | ||||
| const char *display_size(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 *size_str[][3] = { | ||||
| 		{" Terabyte", " TB", "T"}, | ||||
| 		{" Gigabyte", " GB", "G"}, | ||||
| 		{" Megabyte", " MB", "M"}, | ||||
| 		{" Kilobyte", " KB", "K"}, | ||||
| 		{"", "", ""}, | ||||
| 		{" Byte    ", " B ", "B"}, | ||||
| 		{" Units   ", " Un", "U"}, | ||||
| 		{" Sectors ", " Se", "S"}, | ||||
| 		{"         ", "   ", " "}, | ||||
| 	}; | ||||
|  | ||||
| 	if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) { | ||||
| 		log_error("no memory for size display buffer"); | ||||
| 		return ""; | ||||
| 	} | ||||
|  | ||||
| 	suffix = cmd->current_settings.suffix; | ||||
|  | ||||
| 	for (s = 0; s < 8; 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; | ||||
| 	} | ||||
|  | ||||
| 	if (s < 8) { | ||||
| 		byte = cmd->current_settings.unit_factor; | ||||
| 		size *= UINT64_C(512); | ||||
| 	} else { | ||||
| 		size /= 2; | ||||
| 		suffix = 1; | ||||
| 		if (cmd->current_settings.unit_type == 'H') | ||||
| 			units = UINT64_C(1000); | ||||
| 		else | ||||
| 			units = UINT64_C(1024); | ||||
| 		byte = 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; | ||||
| } | ||||
|  | ||||
| void pvdisplay_colons(struct physical_volume *pv) | ||||
| { | ||||
| 	char uuid[64]; | ||||
|  | ||||
| 	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", | ||||
| 		  dev_name(pv->dev), 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; | ||||
| } | ||||
|  | ||||
| /* FIXME Include label fields */ | ||||
| void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv, | ||||
| 		    void *handle) | ||||
| { | ||||
| 	char uuid[64]; | ||||
| 	const char *size; | ||||
|  | ||||
| 	uint32_t pe_free; | ||||
|  | ||||
| 	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", dev_name(pv->dev)); | ||||
| 	log_print("VG Name               %s%s", pv->vg_name, | ||||
| 		  pv->status & EXPORTED_VG ? " (exported)" : ""); | ||||
|  | ||||
| 	size = display_size(cmd, (uint64_t) pv->size, SIZE_SHORT); | ||||
| 	if (pv->pe_size && pv->pe_count) { | ||||
|  | ||||
| /******** FIXME display LVM on-disk data size | ||||
| 		size2 = display_size(pv->size, SIZE_SHORT); | ||||
| ********/ | ||||
|  | ||||
| 		log_print("PV Size               %s" " / not usable %s",	/*  [LVM: %s]", */ | ||||
| 			  size, | ||||
| 			  display_size(cmd, (pv->size - | ||||
| 					     pv->pe_count * pv->pe_size), | ||||
| 				       SIZE_SHORT)); | ||||
|  | ||||
| 	} 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(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		    struct physical_volume *pv, void *handle) | ||||
| { | ||||
| 	char uuid[64]; | ||||
|  | ||||
| 	if (!pv) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_print("PV Name               %s     ", dev_name(pv->dev)); | ||||
| 	/* 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(struct logical_volume *lv) | ||||
| { | ||||
| 	int inkernel; | ||||
| 	struct lvinfo info; | ||||
| 	inkernel = lv_info(lv, &info, 1) && 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, struct logical_volume *lv, | ||||
| 		   void *handle) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
| 	int inkernel, snap_active; | ||||
| 	char uuid[64]; | ||||
| 	struct snapshot *snap = NULL; | ||||
| 	struct list *slh, *snaplist; | ||||
| 	float snap_percent;	/* fused, fsize; */ | ||||
|  | ||||
| 	if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	inkernel = lv_info(lv, &info, 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"); | ||||
|  | ||||
| 		snaplist = find_snapshots(lv); | ||||
| 		list_iterate(slh, snaplist) { | ||||
| 			snap = list_item(slh, struct snapshot_list)->snapshot; | ||||
| 			snap_active = lv_snapshot_percent(snap->cow, | ||||
| 							  &snap_percent); | ||||
| 			if (!snap_active || snap_percent < 0 || | ||||
| 			    snap_percent >= 100) snap_active = 0; | ||||
| 			log_print("                       %s%s/%s [%s]", | ||||
| 				  lv->vg->cmd->dev_dir, lv->vg->name, | ||||
| 				  snap->cow->name, | ||||
| 				  (snap_active > 0) ? "active" : "INACTIVE"); | ||||
| 		} | ||||
| 		snap = NULL; | ||||
| 	} else if ((snap = find_cow(lv))) { | ||||
| 		snap_active = lv_snapshot_percent(lv, &snap_percent); | ||||
| 		if (!snap_active || 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->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 ? snap->origin->size : lv->size, | ||||
| 			       SIZE_SHORT)); | ||||
|  | ||||
| 	log_print("Current LE             %u", | ||||
| 		  snap ? snap->origin->le_count : lv->le_count); | ||||
|  | ||||
| /********** FIXME allocation | ||||
|     log_print("Allocated LE           %u", lv->allocated_le); | ||||
| **********/ | ||||
|  | ||||
| 	log_print("Segments               %u", list_size(&lv->segments)); | ||||
|  | ||||
| /********* FIXME Stripes & stripesize for each segment | ||||
| 	log_print("Stripe size (KByte)    %u", lv->stripesize / 2); | ||||
| ***********/ | ||||
|  | ||||
| 	if (snap) { | ||||
| 		if (snap_percent == -1) | ||||
| 			snap_percent = 100; | ||||
|  | ||||
| 		log_print("Snapshot chunk size    %s", | ||||
| 			  display_size(cmd, (uint64_t) snap->chunk_size, | ||||
| 				       SIZE_SHORT)); | ||||
|  | ||||
| /* | ||||
| 	size = display_size(lv->size, SIZE_SHORT); | ||||
| 	sscanf(size, "%f", &fsize); | ||||
| 	fused = fsize * snap_percent / 100; | ||||
| */ | ||||
| 		log_print("Allocated to snapshot  %.2f%% ",	/* [%.2f/%s]", */ | ||||
| 			  snap_percent);	/*, fused, size); */ | ||||
| 		/* dbg_free(size); */ | ||||
| 	} | ||||
|  | ||||
| /********** FIXME Snapshot | ||||
| 	size = ??? | ||||
| 	log_print("Allocated to COW-table %s", size); | ||||
| 	dbg_free(size); | ||||
|     } | ||||
| ******************/ | ||||
|  | ||||
| 	log_print("Allocation             %s", get_alloc_string(lv->alloc)); | ||||
| 	log_print("Read ahead sectors     %u", lv->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->area[s].type) { | ||||
| 	case AREA_PV: | ||||
| 		log_print("%sPhysical volume\t%s", pre, | ||||
| 			  seg->area[s].u.pv.pv ? | ||||
| 			  dev_name(seg->area[s].u.pv.pv->dev) : "Missing"); | ||||
|  | ||||
| 		if (seg->area[s].u.pv.pv) | ||||
| 			log_print("%sPhysical extents\t%d to %d", pre, | ||||
| 				  seg->area[s].u.pv.pe, | ||||
| 				  seg->area[s].u.pv.pe + seg->area_len - 1); | ||||
| 		break; | ||||
| 	case AREA_LV: | ||||
| 		log_print("%sLogical volume\t%s", pre, | ||||
| 			  seg->area[s].u.lv.lv ? | ||||
| 			  seg->area[s].u.lv.lv->name : "Missing"); | ||||
|  | ||||
| 		if (seg->area[s].u.lv.lv) | ||||
| 			log_print("%sLogical extents\t%d to %d", pre, | ||||
| 				  seg->area[s].u.lv.le, | ||||
| 				  seg->area[s].u.lv.le + seg->area_len - 1); | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int lvdisplay_segments(struct logical_volume *lv) | ||||
| { | ||||
| 	struct lv_segment *seg; | ||||
|  | ||||
| 	log_print("--- Segments ---"); | ||||
|  | ||||
| 	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(struct volume_group *vg) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void vgdisplay_full(struct volume_group *vg) | ||||
| { | ||||
| 	uint32_t access; | ||||
| 	uint32_t active_pvs; | ||||
| 	char uuid[64]; | ||||
|  | ||||
| 	if (vg->status & PARTIAL_VG) | ||||
| 		active_pvs = list_size(&vg->pvs); | ||||
| 	else | ||||
| 		active_pvs = vg->pv_count; | ||||
|  | ||||
| 	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", | ||||
| 			  list_size(&vg->fid->metadata_areas)); | ||||
| 		log_print("Metadata Sequence No  %d", vg->seqno); | ||||
| 	} | ||||
| 	access = vg->status & (LVM_READ | LVM_WRITE); | ||||
| 	log_print("VG Access             %s%s%s%s", | ||||
| 		  access == (LVM_READ | LVM_WRITE) ? "read/write" : "", | ||||
| 		  access == LVM_READ ? "read" : "", | ||||
| 		  access == LVM_WRITE ? "write" : "", | ||||
| 		  access == 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->status & CLUSTERED) { | ||||
| 		log_print("Clustered             yes"); | ||||
| 		log_print("Shared                %s", | ||||
| 			  vg->status & SHARED ? "yes" : "no"); | ||||
| 	} | ||||
| 	log_print("MAX LV                %u", vg->max_lv); | ||||
| 	log_print("Cur LV                %u", vg->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), SIZE_SHORT))); | ||||
|       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, | ||||
| 			       SIZE_SHORT)); | ||||
|  | ||||
| 	log_print("PE Size               %s", | ||||
| 		  display_size(vg->cmd, (uint64_t) vg->extent_size, | ||||
| 			       SIZE_SHORT)); | ||||
|  | ||||
| 	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, SIZE_SHORT)); | ||||
|  | ||||
| 	log_print("Free  PE / Size       %u / %s", vg->free_count, | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->free_count * vg->extent_size, | ||||
| 			       SIZE_SHORT)); | ||||
|  | ||||
| 	if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { | ||||
| 		stack; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("VG UUID               %s", uuid); | ||||
| 	log_print(" "); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void vgdisplay_colons(struct volume_group *vg) | ||||
| { | ||||
| 	uint32_t active_pvs; | ||||
| 	const char *access; | ||||
| 	char uuid[64]; | ||||
|  | ||||
| 	if (vg->status & PARTIAL_VG) | ||||
| 		active_pvs = list_size(&vg->pvs); | ||||
| 	else | ||||
| 		active_pvs = vg->pv_count; | ||||
|  | ||||
| 	switch (vg->status & (LVM_READ | LVM_WRITE)) { | ||||
| 		case LVM_READ | LVM_WRITE: | ||||
| 			access = "r/w"; | ||||
| 			break; | ||||
| 		case LVM_READ: | ||||
| 			access = "r"; | ||||
| 			break; | ||||
| 		case LVM_WRITE: | ||||
| 			access = "w"; | ||||
| 			break; | ||||
| 		default: | ||||
| 			access = ""; | ||||
| 	} | ||||
|  | ||||
| 	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, | ||||
| 		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(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, | ||||
| 			       SIZE_SHORT), | ||||
| 		  display_size(vg->cmd, | ||||
| 			       ((uint64_t) vg->extent_count - | ||||
| 				vg->free_count) * vg->extent_size, | ||||
| 			       SIZE_SHORT), | ||||
| 		  display_size(vg->cmd, | ||||
| 			       (uint64_t) vg->free_count * vg->extent_size, | ||||
| 			       SIZE_SHORT)); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void display_formats(struct cmd_context *cmd) | ||||
| { | ||||
| 	struct format_type *fmt; | ||||
|  | ||||
| 	list_iterate_items(fmt, &cmd->formats) { | ||||
| 		log_print("%s", fmt->name); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void display_segtypes(struct cmd_context *cmd) | ||||
| { | ||||
| 	struct segment_type *segtype; | ||||
|  | ||||
| 	list_iterate_items(segtype, &cmd->segtypes) { | ||||
| 		log_print("%s", segtype->name); | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										57
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DISPLAY_H | ||||
| #define _LVM_DISPLAY_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t; | ||||
|  | ||||
| uint64_t units_to_bytes(const char *units, char *unit_type); | ||||
|  | ||||
| /* Specify size in KB */ | ||||
| const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl); | ||||
| char *display_uuid(char *uuidstr); | ||||
| void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre); | ||||
|  | ||||
| void pvdisplay_colons(struct physical_volume *pv); | ||||
| void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv, | ||||
| 		    void *handle); | ||||
| int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		    struct physical_volume *pv, void *handle); | ||||
|  | ||||
| void lvdisplay_colons(struct logical_volume *lv); | ||||
| int lvdisplay_segments(struct logical_volume *lv); | ||||
| int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 		   void *handle); | ||||
|  | ||||
| void vgdisplay_extents(struct volume_group *vg); | ||||
| void vgdisplay_full(struct volume_group *vg); | ||||
| void vgdisplay_colons(struct volume_group *vg); | ||||
| void vgdisplay_short(struct volume_group *vg); | ||||
|  | ||||
| void display_formats(struct cmd_context *cmd); | ||||
| void display_segtypes(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); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										103
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| /* | ||||
|  * 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 "lib.h" | ||||
| #include "pool.h" | ||||
| #include "list.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" | ||||
|  | ||||
| static const char *_name(const struct lv_segment *seg) | ||||
| { | ||||
| 	return seg->segtype->name; | ||||
| } | ||||
|  | ||||
| static int _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 _compose_target_line(struct dev_manager *dm, struct pool *mem, | ||||
| 				struct config_tree *cft, void **target_state, | ||||
| 				struct lv_segment *seg, char *params, | ||||
| 				size_t paramsize, const char **target, int *pos, | ||||
| 				uint32_t *pvmove_mirror_count) | ||||
| { | ||||
| 	/*   error */ | ||||
|  | ||||
| 	*target = "error"; | ||||
| 	*params = '\0'; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _target_present(void) | ||||
| { | ||||
| 	static int checked = 0; | ||||
| 	static int present = 0; | ||||
|  | ||||
| 	if (!checked) | ||||
| 		present = target_present("error"); | ||||
|  | ||||
| 	checked = 1; | ||||
| 	return present; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void _destroy(const struct segment_type *segtype) | ||||
| { | ||||
| 	dbg_free((void *) segtype); | ||||
| } | ||||
|  | ||||
| static struct segtype_handler _error_ops = { | ||||
| 	name:_name, | ||||
| 	merge_segments:_merge_segments, | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| 	compose_target_line:_compose_target_line, | ||||
| 	target_present:_target_present, | ||||
| #endif | ||||
| 	destroy:_destroy, | ||||
| }; | ||||
|  | ||||
| struct segment_type *init_error_segtype(struct cmd_context *cmd) | ||||
| { | ||||
| 	struct segment_type *segtype = dbg_malloc(sizeof(*segtype)); | ||||
|  | ||||
| 	if (!segtype) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	segtype->cmd = cmd; | ||||
| 	segtype->ops = &_error_ops; | ||||
| 	segtype->name = "error"; | ||||
| 	segtype->private = NULL; | ||||
| 	segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL; | ||||
|  | ||||
| 	log_very_verbose("Initialised segtype: %s", segtype->name); | ||||
|  | ||||
| 	return segtype; | ||||
| } | ||||
							
								
								
									
										77
									
								
								lib/filters/filter-composite.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lib/filters/filter-composite.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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 _destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct dev_filter **filters = (struct dev_filter **) f->private; | ||||
|  | ||||
| 	while (*filters) { | ||||
| 		(*filters)->destroy(*filters); | ||||
| 		filters++; | ||||
| 	} | ||||
|  | ||||
| 	dbg_free(f->private); | ||||
| 	dbg_free(f); | ||||
| } | ||||
|  | ||||
| struct dev_filter *composite_filter_create(int n, struct dev_filter **filters) | ||||
| { | ||||
| 	struct dev_filter **filters_copy, *cft; | ||||
|  | ||||
| 	if (!filters) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(filters_copy = dbg_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 = dbg_malloc(sizeof(*cft)))) { | ||||
| 		log_error("compsoite filters allocation failed"); | ||||
| 		dbg_free(filters_copy); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	cft->passes_filter = _and_p; | ||||
| 	cft->destroy = _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 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 _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 | ||||
							
								
								
									
										80
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "filter-md.h" | ||||
| #include "metadata.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 * 1024) | ||||
| #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) | ||||
| #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \ | ||||
| 				- MD_RESERVED_SECTORS) | ||||
|  | ||||
| static int _ignore_md(struct dev_filter *f, 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) | ||||
| { | ||||
| 	dbg_free(f); | ||||
| } | ||||
|  | ||||
| struct dev_filter *md_filter_create(void) | ||||
| { | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!(f = dbg_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 | ||||
|  | ||||
							
								
								
									
										274
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "config.h" | ||||
| #include "dev-cache.h" | ||||
| #include "hash.h" | ||||
| #include "filter-persistent.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| struct pfilter { | ||||
| 	char *file; | ||||
| 	struct hash_table *devices; | ||||
| 	struct dev_filter *real; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * entries in the table can be in one of these | ||||
|  * states. | ||||
|  */ | ||||
| #define PF_BAD_DEVICE ((void *) 1) | ||||
| #define PF_GOOD_DEVICE ((void *) 2) | ||||
|  | ||||
| static int _init_hash(struct pfilter *pf) | ||||
| { | ||||
| 	if (pf->devices) | ||||
| 		hash_destroy(pf->devices); | ||||
|  | ||||
| 	if (!(pf->devices = hash_create(128))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int persistent_filter_wipe(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	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 (!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 pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	int r = 0; | ||||
| 	struct config_tree *cft; | ||||
|  | ||||
| 	if (!(cft = create_config_tree(pf->file))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!read_config_file(cft)) { | ||||
| 		stack; | ||||
| 		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 (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: | ||||
| 	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; | ||||
| 	struct hash_node *n; | ||||
|  | ||||
| 	for (n = hash_get_first(pf->devices); n; | ||||
| 	     n = hash_get_next(pf->devices, n)) { | ||||
| 		d = hash_get_data(pf->devices, n); | ||||
|  | ||||
| 		if (d != data) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!first) | ||||
| 			fprintf(fp, ",\n"); | ||||
| 		else { | ||||
| 			fprintf(fp, "\t%s=[\n", path); | ||||
| 			first = 0; | ||||
| 		} | ||||
|  | ||||
| 		fprintf(fp, "\t\t\"%s\"", hash_get_key(pf->devices, n)); | ||||
| 	} | ||||
|  | ||||
| 	if (!first) | ||||
| 		fprintf(fp, "\n\t]\n"); | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int persistent_filter_dump(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	if (!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); | ||||
|  | ||||
| 	fp = fopen(pf->file, "w"); | ||||
| 	if (!fp) { | ||||
| 		if (errno != EROFS) | ||||
| 			log_sys_error("fopen", pf->file); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	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"); | ||||
| 	fclose(fp); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _lookup_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
| 	void *l = hash_lookup(pf->devices, dev_name(dev)); | ||||
| 	struct str_list *sl; | ||||
| 	struct list *ah; | ||||
|  | ||||
| 	if (!l) { | ||||
| 		l = pf->real->passes_filter(pf->real, dev) ? | ||||
| 		    PF_GOOD_DEVICE : PF_BAD_DEVICE; | ||||
|  | ||||
| 		list_iterate(ah, &dev->aliases) { | ||||
| 			sl = list_item(ah, struct str_list); | ||||
| 			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 _destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct pfilter *pf = (struct pfilter *) f->private; | ||||
|  | ||||
| 	hash_destroy(pf->devices); | ||||
| 	dbg_free(pf->file); | ||||
| 	pf->real->destroy(pf->real); | ||||
| 	dbg_free(pf); | ||||
| 	dbg_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 = dbg_malloc(sizeof(*pf)))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	memset(pf, 0, sizeof(*pf)); | ||||
|  | ||||
| 	if (!(pf->file = dbg_malloc(strlen(file) + 1))) { | ||||
| 		stack; | ||||
| 		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 = dbg_malloc(sizeof(*f)))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	f->passes_filter = _lookup_p; | ||||
| 	f->destroy = _destroy; | ||||
| 	f->private = pf; | ||||
|  | ||||
| 	return f; | ||||
|  | ||||
|       bad: | ||||
| 	dbg_free(pf->file); | ||||
| 	if (pf->devices) | ||||
| 		hash_destroy(pf->devices); | ||||
| 	dbg_free(pf); | ||||
| 	dbg_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 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 _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); | ||||
| int persistent_filter_dump(struct dev_filter *f); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										241
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "pool.h" | ||||
| #include "filter-regex.h" | ||||
| #include "matcher.h" | ||||
| #include "device.h" | ||||
| #include "bitset.h" | ||||
| #include "list.h" | ||||
|  | ||||
| struct rfilter { | ||||
| 	struct pool *mem; | ||||
| 	bitset_t accept; | ||||
| 	struct matcher *engine; | ||||
| }; | ||||
|  | ||||
| static int _extract_pattern(struct pool *mem, const char *pat, | ||||
| 			    char **regex, bitset_t accept, int ix) | ||||
| { | ||||
| 	char sep, *r, *ptr; | ||||
|  | ||||
| 	/* | ||||
| 	 * is this an accept or reject pattern | ||||
| 	 */ | ||||
| 	switch (*pat) { | ||||
| 	case 'a': | ||||
| 		bit_set(accept, ix); | ||||
| 		break; | ||||
|  | ||||
| 	case 'r': | ||||
| 		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 = pool_strdup(mem, pat))) { | ||||
| 		stack; | ||||
| 		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 pool *scratch; | ||||
| 	struct config_value *v; | ||||
| 	char **regex; | ||||
| 	unsigned count = 0; | ||||
| 	int i, r = 0; | ||||
|  | ||||
| 	if (!(scratch = pool_create("filter matcher", 1024))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * count how many patterns we have. | ||||
| 	 */ | ||||
| 	for (v = val; v; v = v->next) { | ||||
|  | ||||
| 		if (v->type != CFG_STRING) { | ||||
| 			log_info("filter patterns must be enclosed in quotes"); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		count++; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * allocate space for them | ||||
| 	 */ | ||||
| 	if (!(regex = pool_alloc(scratch, sizeof(*regex) * count))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * create the accept/reject bitset | ||||
| 	 */ | ||||
| 	rf->accept = 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_info("invalid filter pattern"); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 	/* | ||||
| 	 * build the matcher. | ||||
| 	 */ | ||||
| 	if (!(rf->engine = matcher_create(rf->mem, (const char **) regex, | ||||
| 					  count))) | ||||
| 		stack; | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	pool_destroy(scratch); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _accept_p(struct dev_filter *f, struct device *dev) | ||||
| { | ||||
| 	struct list *ah; | ||||
| 	int m, first = 1, rejected = 0; | ||||
| 	struct rfilter *rf = (struct rfilter *) f->private; | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	list_iterate(ah, &dev->aliases) { | ||||
| 		sl = list_item(ah, struct str_list); | ||||
| 		m = matcher_run(rf->engine, sl->str); | ||||
|  | ||||
| 		if (m >= 0) { | ||||
| 			if (bit(rf->accept, m)) { | ||||
|  | ||||
| 				if (!first) { | ||||
| 					log_debug("%s: New preferred name", | ||||
| 						  sl->str); | ||||
| 					list_del(&sl->list); | ||||
| 					list_add_h(&dev->aliases, &sl->list); | ||||
| 				} | ||||
|  | ||||
| 				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 _destroy(struct dev_filter *f) | ||||
| { | ||||
| 	struct rfilter *rf = (struct rfilter *) f->private; | ||||
| 	pool_destroy(rf->mem); | ||||
| } | ||||
|  | ||||
| struct dev_filter *regex_filter_create(struct config_value *patterns) | ||||
| { | ||||
| 	struct pool *mem = pool_create("filter regex", 10 * 1024); | ||||
| 	struct rfilter *rf; | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(rf = pool_alloc(mem, sizeof(*rf)))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	rf->mem = mem; | ||||
|  | ||||
| 	if (!_build_matcher(rf, patterns)) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(f = pool_zalloc(mem, sizeof(*f)))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	f->passes_filter = _accept_p; | ||||
| 	f->destroy = _destroy; | ||||
| 	f->private = rf; | ||||
| 	return f; | ||||
|  | ||||
|       bad: | ||||
| 	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 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 _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 | ||||
							
								
								
									
										306
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,306 @@ | ||||
| /* | ||||
|  * 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 "lib.h" | ||||
| #include "filter-sysfs.h" | ||||
| #include "lvm-string.h" | ||||
| #include "pool.h" | ||||
|  | ||||
| #ifdef linux | ||||
|  | ||||
| #include <dirent.h> | ||||
|  | ||||
| static int _locate_sysfs_blocks(const char *proc, char *path, size_t len) | ||||
| { | ||||
| 	char proc_mounts[PATH_MAX]; | ||||
| 	int r = 0; | ||||
| 	FILE *fp; | ||||
| 	char *split[4], buffer[PATH_MAX + 16]; | ||||
|  | ||||
| 	if (!*proc) { | ||||
| 		log_verbose("No proc filesystem found: skipping sysfs filter"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 		 | ||||
| 	if (lvm_snprintf(proc_mounts, sizeof(proc_mounts), | ||||
| 			 "%s/mounts", proc) < 0) { | ||||
| 		log_error("Failed to create /proc/mounts string"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(fp = fopen(proc_mounts, "r"))) { | ||||
| 		log_sys_error("fopen %s", proc_mounts); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(buffer, sizeof(buffer), fp)) { | ||||
| 		if (split_words(buffer, 4, split) == 4 && | ||||
| 		    !strcmp(split[2], "sysfs")) { | ||||
| 			if (lvm_snprintf(path, len, "%s/%s", split[1], | ||||
| 					 "block") >= 0) { | ||||
| 				r = 1; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /*---------------------------------------------------------------- | ||||
|  * 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 pool *mem; | ||||
| 	const char *sys_block; | ||||
| 	int initialised; | ||||
| 	struct entry *slots[SET_BUCKETS]; | ||||
| }; | ||||
|  | ||||
| static struct dev_set *_dev_set_create(struct pool *mem, const char *sys_block) | ||||
| { | ||||
| 	struct dev_set *ds; | ||||
|  | ||||
| 	if (!(ds = pool_zalloc(mem, sizeof(*ds)))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	ds->mem = mem; | ||||
| 	ds->sys_block = pool_strdup(mem, sys_block); | ||||
| 	ds->initialised = 0; | ||||
|  | ||||
| 	return ds; | ||||
| } | ||||
|  | ||||
| static inline 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 = 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); | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Recurse through sysfs directories, inserting any devs found. | ||||
|  */ | ||||
| static int _read_devs(struct dev_set *ds, const char *dir) | ||||
| { | ||||
|         struct dirent *d; | ||||
|         DIR *dr; | ||||
| 	unsigned char dtype; | ||||
| 	struct stat info; | ||||
| 	char path[PATH_MAX]; | ||||
| 	dev_t dev; | ||||
| 	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 (lvm_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; | ||||
| 		} | ||||
|  | ||||
| 		dtype = d->d_type; | ||||
|  | ||||
| 		if (dtype == DT_UNKNOWN) { | ||||
| 			if (lstat(path, &info) >= 0) { | ||||
| 				if (S_ISLNK(info.st_mode)) | ||||
| 					dtype = DT_LNK; | ||||
| 				else if (S_ISDIR(info.st_mode)) | ||||
| 					dtype = DT_DIR; | ||||
| 				else if (S_ISREG(info.st_mode)) | ||||
| 					dtype = DT_REG; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (dtype == DT_DIR) { | ||||
| 			if (!_read_devs(ds, path)) { | ||||
| 				r = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ((dtype == DT_REG && !strcmp(d->d_name, "dev"))) | ||||
| 			if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) { | ||||
| 				r = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 	} | ||||
|  | ||||
|         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->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; | ||||
| 	pool_destroy(ds->mem); | ||||
| } | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *proc) | ||||
| { | ||||
| 	char sys_block[PATH_MAX]; | ||||
| 	struct pool *mem; | ||||
| 	struct dev_set *ds; | ||||
| 	struct dev_filter *f; | ||||
|  | ||||
| 	if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!(mem = pool_create("sysfs", 256))) { | ||||
| 		log_error("sysfs pool creation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(ds = _dev_set_create(mem, sys_block))) { | ||||
| 		log_error("sysfs dev_set creation failed"); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(f = pool_zalloc(mem, sizeof(*f)))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	f->passes_filter = _accept_p; | ||||
| 	f->destroy = _destroy; | ||||
| 	f->private = ds; | ||||
| 	return f; | ||||
|  | ||||
|  bad: | ||||
| 	pool_destroy(mem); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *proc) | ||||
| { | ||||
| 	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 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 _LVM_FILTER_SYSFS_H | ||||
| #define _LVM_FILTER_SYSFS_H | ||||
|  | ||||
| #include "config.h" | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| struct dev_filter *sysfs_filter_create(const char *proc); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										263
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "dev-cache.h" | ||||
| #include "filter.h" | ||||
| #include "lvm-string.h" | ||||
| #include "config.h" | ||||
| #include "metadata.h" | ||||
|  | ||||
| #include <dirent.h> | ||||
| #include <unistd.h> | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| #define NUMBER_OF_MAJORS 4096 | ||||
|  | ||||
| /* FIXME Make this sparse */ | ||||
| /* 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; | ||||
|  | ||||
| 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 */ | ||||
| 	{NULL, 0} | ||||
| }; | ||||
|  | ||||
| static int _passes_lvm_type_device_filter(struct dev_filter *f, | ||||
| 					  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; | ||||
| 	} | ||||
|  | ||||
| 	/* Check it's accessible */ | ||||
| 	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) { | ||||
| 		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 (lvm_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; | ||||
|  | ||||
| 		/* 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"); | ||||
| 				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); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if (!cv->v.i) { | ||||
| 				log_error("Zero partition count invalid for " | ||||
| 					  "%s in devices/types in config file", | ||||
| 					  name); | ||||
| 				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; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	fclose(pd); | ||||
| 	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 = dbg_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)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| void lvm_type_filter_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	dbg_free(f); | ||||
| 	return; | ||||
| } | ||||
							
								
								
									
										42
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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