mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			1245 Commits
		
	
	
		
			dev-dct-cm
			...
			v1_00_19
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9812657777 | ||
|  | 0b09312fc6 | ||
|  | d0a7ac6b74 | ||
|  | ff9a238fbd | ||
|  | 359fffa5f1 | ||
|  | 5bf92ced1a | ||
|  | 340bcc7b45 | ||
|  | ef03742bd4 | ||
|  | 20431ec16d | ||
|  | becba8157b | ||
|  | 51fd3bb0eb | ||
|  | 4bbd3acb4e | ||
|  | 3bc930ea7b | ||
|  | d1b26f8e86 | ||
|  | fdf15caaff | ||
|  | c7b4a53c0b | ||
|  | af78dc0308 | ||
|  | 5ad39493c4 | ||
|  | 61f597b408 | ||
|  | 2162825240 | ||
|  | 2b780e70d1 | ||
|  | a3823f818e | ||
|  | 1f7c47bcaf | ||
|  | ec53c365a2 | ||
|  | 793ad1f2d4 | ||
|  | 9bc733b76c | ||
|  | 21b28f0217 | ||
|  | d3e23caa52 | ||
|  | 9e7518de67 | ||
|  | 679f0047aa | ||
|  | d77d5ce14b | ||
|  | 33ec22a2af | ||
|  | 353053225f | ||
|  | b7f3d6f7f7 | ||
|  | e34577499d | ||
|  | 4cf8960c0c | ||
|  | 1f93ea0675 | ||
|  | 25b705c3a8 | ||
|  | 0725588731 | ||
|  | fc5c61cc8b | ||
|  | ac282e63c6 | ||
|  | c3941941ce | ||
|  | 46cdd53323 | ||
|  | 3ff3e302c3 | ||
|  | f2ceecf95c | ||
|  | 9314c7c881 | ||
|  | 54abb2c572 | ||
|  | 8fa3bdd025 | ||
|  | 5e7a308528 | ||
|  | 7952177786 | ||
|  | 9afbe49c84 | ||
|  | 9f06ba2db3 | ||
|  | fe55bfddcf | ||
|  | c0842e6444 | ||
|  | 3fed20d06a | ||
|  | 5e8f2e2c04 | ||
|  | e4df99ea84 | ||
|  | b3276f5f11 | ||
|  | 32667ca256 | ||
|  | bed122a170 | ||
|  | 14adc9b875 | ||
|  | a8778bbc5a | ||
|  | a54e641f44 | ||
|  | 5c99efe87a | ||
|  | 7da1d731ff | ||
|  | af9828e819 | ||
|  | 7a27136142 | ||
|  | 012ad2d423 | ||
|  | ef3bdbf4da | ||
|  | b3bb698f7b | ||
|  | 1ed5d1e4c1 | ||
|  | bdee01a03d | ||
|  | 458f7376d7 | ||
|  | cb3a00e027 | ||
|  | 482eb1f3fb | ||
|  | 6e0f638f5e | ||
|  | bab349047d | ||
|  | 28ea6b8de8 | ||
|  | 9d51bbdae8 | ||
|  | d622f79533 | ||
|  | 04c8515ad1 | ||
|  | 53bc4251d1 | ||
|  | a5a751f02f | ||
|  | 66ed5f82c4 | ||
|  | c802a9e6aa | ||
|  | 880f210946 | ||
|  | 4f9f7eb6a6 | ||
|  | f910c4a8e7 | ||
|  | 529686d965 | ||
|  | 84dfd1536f | ||
|  | 85dedc324c | ||
|  | d639237411 | ||
|  | 449aaf75f1 | ||
|  | b1fda66caa | ||
|  | 66a8e90fd9 | ||
|  | 37b487d191 | ||
|  | 6c59fe3577 | ||
|  | 1cbb70c992 | ||
|  | e06b39f882 | ||
|  | 2602b1493e | ||
|  | 989d14502d | ||
|  | f78a550282 | ||
|  | 54a1abb284 | ||
|  | 97b492a8e2 | ||
|  | 0873bd14a9 | ||
|  | eff6ba429a | ||
|  | 8c18064be4 | ||
|  | 44a1ac0cf3 | ||
|  | 28dc8d88dd | ||
|  | 2c0c2b64ba | ||
|  | bd3e0f5248 | ||
|  | cd52d98938 | ||
|  | 894c70e7f8 | ||
|  | 51d70c2edd | ||
|  | 7d4b355240 | ||
|  | 3b56193b98 | ||
|  | b16045b57d | ||
|  | 9e8b0fca5b | ||
|  | 35cf1b3b5b | ||
|  | 83f788af57 | ||
|  | 2ffe378d3f | ||
|  | 38b33a4a5e | ||
|  | 60bf9ed0a0 | ||
|  | 16adf4de1b | ||
|  | 80de983023 | ||
|  | 8703ca623f | ||
|  | 286253a73f | ||
|  | bd806a41df | ||
|  | b89c4e9002 | ||
|  | 6dbf31c0c3 | ||
|  | 060c45d8a1 | ||
|  | 33d3e82e4d | ||
|  | 4bb074514d | ||
|  | e3f8892003 | ||
|  | 9d00ad5f18 | ||
|  | dae4344850 | ||
|  | aa7f3fabe2 | ||
|  | f93434a8ce | ||
|  | 25dee56be9 | ||
|  | ce9a3f3797 | ||
|  | 11e384920a | ||
|  | a0a1f1e536 | ||
|  | 3b3d0ea9eb | ||
|  | 2f4d78286d | ||
|  | 677dc6f985 | ||
|  | d52057e732 | ||
|  | fa2a1cb1fb | ||
|  | 19a0fb04ad | ||
|  | 947352f2fe | ||
|  | adcbedb686 | ||
|  | 7732f92acd | ||
|  | ad8a001688 | ||
|  | 9121eada08 | ||
|  | 49bd4d25a2 | ||
|  | d80b4129c6 | ||
|  | 7edb4172d5 | ||
|  | c3a4677990 | ||
|  | 5cbb893a3b | ||
|  | f28a2a432b | ||
|  | 03b75a2d27 | ||
|  | 859fe69083 | ||
|  | f6f2205ddb | ||
|  | 0f9a03ef61 | ||
|  | 9aa417c084 | ||
|  | 7b70952f5d | ||
|  | edd3d07b49 | ||
|  | 5293d0a4ec | ||
|  | 3c8c7beae1 | ||
|  | 9c3ba9fdcd | ||
|  | fb1748fb0f | ||
|  | 0a109fbd03 | ||
|  | 5cf64db74e | ||
|  | 488cc94f36 | ||
|  | e15846bf79 | ||
|  | 752bd00674 | ||
|  | 7fadfcbe32 | ||
|  | 41141e75bb | ||
|  | 50f641e627 | ||
|  | c7883fd093 | ||
|  | 4fcb24b2b1 | ||
|  | 5003557935 | ||
|  | bdf1ba84da | ||
|  | b0b4def983 | ||
|  | cc184bbe9e | ||
|  | ad30c830aa | ||
|  | 1d791a8af4 | ||
|  | e63c51cd97 | ||
|  | f202e32908 | ||
|  | 26e1a08e82 | ||
|  | 4d5119d435 | ||
|  | 75e34ea62e | ||
|  | 0a183d6274 | ||
|  | 21d8060aea | ||
|  | 9cbe906f60 | ||
|  | 8ce4137399 | ||
|  | 5f8a139347 | ||
|  | 9bb009a3fe | ||
|  | 726d65923f | ||
|  | 8a6be4cb2d | ||
|  | 10b06beb8e | ||
|  | 81318c7968 | ||
|  | 47a2c1c6e5 | ||
|  | 39cee65c6b | ||
|  | 8582ec724e | ||
|  | b0139682e8 | ||
|  | d39c475a6d | ||
|  | 48f38354c6 | ||
|  | cd5a920ed5 | ||
|  | 71bc1f378d | ||
|  | 0ee6c31cff | ||
|  | af89a9971e | ||
|  | c718a8ef72 | ||
|  | 8c8ad0faf0 | ||
|  | 314d5bbb7f | ||
|  | 102255757a | ||
|  | 914067a0d0 | ||
|  | 06e3ae2536 | ||
|  | 7f9b252556 | ||
|  | 3d700e243f | ||
|  | bcfc78ce11 | ||
|  | 09241765d5 | ||
|  | 671c83c265 | ||
|  | 772d28b766 | ||
|  | c26fcea58d | ||
|  | 1e5e26dbff | ||
|  | 742fc54864 | ||
|  | 49738f43c0 | ||
|  | 9f85f61010 | ||
|  | 239f422039 | ||
|  | 67af3c37be | ||
|  | a9442385c4 | ||
|  | 8c9cd10b8b | ||
|  | 72542059dd | ||
|  | a843fc6d40 | ||
|  | 4beed60c08 | ||
|  | 4049c1e480 | ||
|  | 8449314da2 | ||
|  | 63ad057028 | ||
|  | e720464330 | ||
|  | 24036afef9 | ||
|  | c78fa1a1bc | ||
|  | faa8b9022c | ||
|  | 729bafef7a | ||
|  | 590b028632 | ||
|  | 8150d00f36 | ||
|  | 060065926f | ||
|  | 70babe8a28 | ||
|  | c36e09664f | ||
|  | a9672246f3 | ||
|  | ff571884e9 | ||
|  | 475138bceb | ||
|  | 4a8af199c2 | ||
|  | bdabf5db72 | ||
|  | 6a5f21b34e | ||
|  | d608be103c | ||
|  | 374bb5d18a | ||
|  | 031d6c25ff | ||
|  | 223fb7b075 | ||
|  | a746741971 | ||
|  | 120faf2a58 | ||
|  | 990bca0dc6 | ||
|  | 3406472db7 | ||
|  | 1bd733c9f6 | ||
|  | 238c7f982e | ||
|  | fcb81147cb | ||
|  | 1915b73783 | ||
|  | ee79e621fb | ||
|  | d203275a3b | ||
|  | 9e8a996222 | ||
|  | 0126b0b3ed | ||
|  | 458928612c | ||
|  | e33f88e28d | ||
|  | be570bbf9e | ||
|  | f59b4be110 | ||
|  | 37336e41be | ||
|  | d24a1a3f0a | ||
|  | f7258955bd | ||
|  | 2a1eae5d6f | ||
|  | 50ee0a4adb | ||
|  | 955a26584e | ||
|  | 1d3e407c8f | ||
|  | cb809c4596 | ||
|  | 53bbe2888e | ||
|  | 7246f476a5 | ||
|  | 0785d1c390 | ||
|  | 85d2c49d14 | ||
|  | 8b77d62b7f | ||
|  | 373058a32a | ||
|  | e6293c2c8c | ||
|  | eff181c959 | ||
|  | 54752c2305 | ||
|  | b4753c044f | ||
|  | 26493424ae | ||
|  | 0282fd1332 | ||
|  | b9a019a08b | ||
|  | 66f6a0e687 | ||
|  | 2dd1b9f97d | ||
|  | 89615f3045 | ||
|  | 7e46192f67 | ||
|  | e78d985cdf | ||
|  | e8c4bf56fe | ||
|  | e6aa7d323d | ||
|  | fca8e25929 | ||
|  | 8e8ac286b4 | ||
|  | 7d9770b9a2 | ||
|  | 1996230460 | ||
|  | de7897a864 | ||
|  | e2884dcdb7 | ||
|  | 544a53a42b | ||
|  | 2e4787bfc8 | ||
|  | 1829eeb171 | ||
|  | c7488e3c4a | ||
|  | 3bf9606383 | ||
|  | 4f43f18f0a | ||
|  | 5b7f197397 | ||
|  | 018141c97f | ||
|  | 4d7813e57c | ||
|  | 605c60208f | ||
|  | 884fafcc30 | ||
|  | 56baa90320 | ||
|  | 6bb20ee09e | ||
|  | 541356430c | ||
|  | 2f4d91fd69 | ||
|  | f58c5e6b30 | ||
|  | 0311d0132c | ||
|  | c946c97402 | ||
|  | 84a6f51318 | ||
|  | 24a1501b0d | ||
|  | 383b6f5fcc | ||
|  | 633dd7ff9b | ||
|  | 580624fad6 | ||
|  | a8190f7efa | ||
|  | dd2157534b | ||
|  | 38a90e7669 | ||
|  | 6bfc526dcd | ||
|  | aadb8a7405 | ||
|  | 27082bf77e | ||
|  | a2903c80cd | ||
|  | 9a77c5369c | ||
|  | 3c30741a19 | ||
|  | 7028ad4ec0 | ||
|  | 8de750c6aa | ||
|  | 04f98de9ee | ||
|  | a1a019784b | ||
|  | 4aeeae77bd | ||
|  | 651cfc2b78 | ||
|  | 2ef8af25e2 | ||
|  | 0b13852a5b | ||
|  | 13427578c9 | ||
|  | d89ca2087e | ||
|  | 8b0ea9fba6 | ||
|  | 9f0b653d5a | ||
|  | 659a339233 | ||
|  | 4c29f177a0 | ||
|  | d664e63d55 | ||
|  | 2493509dbe | ||
|  | 1c8b27f554 | ||
|  | 68297b7186 | ||
|  | 34dd8d0a91 | ||
|  | 81c44790d5 | ||
|  | d557b335cf | ||
|  | e2adc28cff | ||
|  | 0fef6a6ecc | ||
|  | f2fd4b8a1f | ||
|  | 95bd5605a8 | ||
|  | 497cca7eca | ||
|  | 54f78feedd | ||
|  | 76408e53ae | ||
|  | be19e74d30 | ||
|  | dac578a775 | ||
|  | 04732ce74b | ||
|  | a6c95a2374 | ||
|  | f68622abe9 | ||
|  | 83a9a7bdb2 | ||
|  | 6500afc0ca | ||
|  | c69b7ecc96 | ||
|  | 615ef1e2d2 | ||
|  | cf69a0cd7f | ||
|  | 06e892fb33 | ||
|  | e6c5dd6865 | ||
|  | 247efdebdb | ||
|  | 76f3792287 | ||
|  | 64d8e2c727 | ||
|  | ead0bd9cb0 | ||
|  | 66fc13b2ec | ||
|  | f3af4128b0 | ||
|  | 0e43107c87 | ||
|  | 1ee3e7997e | ||
|  | 50fd61d91f | ||
|  | e4cdc051a9 | ||
|  | 778e846e96 | ||
|  | a27759b647 | ||
|  | b75eceab41 | ||
|  | e748a5d5f4 | ||
|  | 99c5a3ae46 | ||
|  | 51da710f5a | ||
|  | 569d69b3d2 | ||
|  | 059a6b1d90 | ||
|  | 990af7548a | ||
|  | a38aefdfc8 | ||
|  | 3bcb12e7d1 | ||
|  | 7904ecb462 | ||
|  | 9ba4d45109 | ||
|  | 56b8afe19d | ||
|  | f7aed9a94c | ||
|  | e12a7e881d | ||
|  | 5afb65325d | ||
|  | 135f520f32 | ||
|  | bc251f4ff6 | ||
|  | b8769751f6 | ||
|  | eff96d839e | ||
|  | aa34c23807 | ||
|  | 195acdac8c | ||
|  | 903e03c56c | ||
|  | 0892767b8a | ||
|  | 83ebfa772c | ||
|  | 1583641322 | ||
|  | 9510e2c256 | ||
|  | a9dbabe07e | ||
|  | 12884008fa | ||
|  | 02543bad1c | ||
|  | a8c56a5251 | ||
|  | 4e5a855f3f | ||
|  | 7e497a951e | ||
|  | cd08eabbfa | ||
|  | f7e62d9f81 | ||
|  | 9a3761e86e | ||
|  | 3619a68693 | ||
|  | efaf3c3bf9 | ||
|  | 0e4e6a6f67 | ||
|  | 42458e6278 | ||
|  | 41ec995377 | ||
|  | 4f37599326 | ||
|  | 4144520e5c | ||
|  | 6c4800546c | ||
|  | 733733c8a7 | ||
|  | 2aa67cc946 | ||
|  | 9385981a9d | ||
|  | fff780035d | ||
|  | 46127e673d | ||
|  | 70df59b224 | ||
|  | 0fdbaa803f | ||
|  | 6af1830eff | ||
|  | 6f860e2bd5 | ||
|  | 20a492f7ee | ||
|  | 63875e7591 | ||
|  | 0ad98cabde | ||
|  | 668879d2e1 | ||
|  | 2e09783302 | ||
|  | 49734114b3 | ||
|  | 950d9d6ee7 | ||
|  | f7974aee2e | ||
|  | c870a82621 | ||
|  | 984929a001 | ||
|  | 7f9e2c1db8 | ||
|  | 324e8389dc | ||
|  | 6f448c5a38 | ||
|  | ec43efbb20 | ||
|  | 3ed065de37 | ||
|  | 8152f0d72c | ||
|  | f8047f4736 | ||
|  | b93c66dc2d | ||
|  | ac877b3065 | ||
|  | dee8abfdde | ||
|  | cef3841d73 | ||
|  | 3cd5e8a041 | ||
|  | 515b5f866e | ||
|  | 321f62bf92 | ||
|  | f94fa47b52 | ||
|  | c502f8a722 | ||
|  | 59b4868ac3 | ||
|  | 3634e12cce | ||
|  | 6d45445391 | ||
|  | 4f47e268cc | ||
|  | 0035b31cdb | ||
|  | f2565aee03 | ||
|  | 5bd85668dd | ||
|  | 20f990b6ce | ||
|  | 6821379586 | ||
|  | 73b040eb49 | ||
|  | 49aa4b2e1e | ||
|  | 972241c74c | ||
|  | 680750e3c2 | ||
|  | 5e7d4d9d15 | ||
|  | 1e57e60613 | ||
|  | 3ac7ce605a | ||
|  | b720dea9f0 | ||
|  | c80722aefe | ||
|  | a84fa69f28 | ||
|  | e33781e59f | ||
|  | 8824bc7ece | ||
|  | c2e3b0e448 | ||
|  | f61a38e85a | ||
|  | d23e948216 | ||
|  | 58bdaa31f0 | ||
|  | b6491d88a6 | ||
|  | f6061ba62e | ||
|  | 427899ddce | ||
|  | c4ab7d2dbd | ||
|  | 0fd2ba033f | ||
|  | ed38939a93 | ||
|  | c7ee26ce5a | ||
|  | 909b8cb303 | ||
|  | b0277370cf | ||
|  | 2ec8656bea | ||
|  | b2ef256910 | ||
|  | 63d6ce95db | ||
|  | a9532b189c | ||
|  | 844545411f | ||
|  | 4e23a2b9b8 | ||
|  | 5deba027eb | ||
|  | fc8b7efc6f | ||
|  | a1c2d9c0f3 | ||
|  | 4ca49a0501 | ||
|  | 493c53d090 | ||
|  | b27e956d35 | ||
|  | 35ebed75c6 | ||
|  | 7bfdb5f77f | ||
|  | 8d8c02317f | ||
|  | a34482feab | ||
|  | cbdc8fd4a6 | ||
|  | 8d3afaa53c | ||
|  | 7ced9ef3df | ||
|  | e8a9ae7e80 | ||
|  | 73a88ab3d3 | ||
|  | aaed82738a | ||
|  | de7f7b96db | ||
|  | 1a669b3e68 | ||
|  | 333af9b13a | ||
|  | a5bca5e240 | ||
|  | c885633e02 | ||
|  | ca7e20b7ca | ||
|  | 545e11a3d7 | ||
|  | 44f5287664 | ||
|  | cf510897f1 | ||
|  | 1d171345f8 | ||
|  | 4fa7e1cd49 | ||
|  | acd008298e | ||
|  | 83a8021515 | ||
|  | cf88dfb1db | ||
|  | 8937c4b481 | ||
|  | cc6af10a4d | ||
|  | 6d94578955 | ||
|  | 08442ab71e | ||
|  | 10d91d213f | ||
|  | b7a3b06994 | ||
|  | 5f12c37f23 | ||
|  | 585edebccd | ||
|  | 9921c62234 | ||
|  | 1ac76d2e16 | ||
|  | 6e983bf400 | ||
|  | 6a8fd4fa6e | ||
|  | 3698eaa2d2 | ||
|  | 8d97ca433c | ||
|  | 23cc65e537 | ||
|  | 2f5a3c2bbe | ||
|  | f6485616cd | ||
|  | 6544fb43d9 | ||
|  | a954b32dcc | ||
|  | 426dc7836c | ||
|  | ff941ffc16 | ||
|  | a063c201df | ||
|  | e2be3fa0aa | ||
|  | 609da6fb50 | ||
|  | fc9f3ccec3 | ||
|  | f7baa67a0a | ||
|  | e8d78c2cdb | ||
|  | 9d33366092 | ||
|  | f5d61515c2 | ||
|  | 711a04a972 | ||
|  | e5b470a3f1 | ||
|  | 31820e1e22 | ||
|  | 4849e8cd6d | ||
|  | 77e3b460aa | ||
|  | b5321001f8 | ||
|  | 38eba9f5ea | ||
|  | ea6f399454 | ||
|  | f8bf2d7b7d | ||
|  | c4856caebb | ||
|  | fc1030bb22 | ||
|  | 9eb6cad8dc | ||
|  | 0fa2a78dce | ||
|  | a56fa1558b | ||
|  | 261c73a997 | ||
|  | 929c1333ca | ||
|  | 286a79d94d | ||
|  | 8b951f99da | ||
|  | abb449bca0 | ||
|  | bd084028d1 | ||
|  | 138a27570b | ||
|  | c2ed40a74f | ||
|  | a7e7a00cab | ||
|  | 64a31ab3cd | ||
|  | 71958bc0f1 | ||
|  | 366ec35612 | ||
|  | 3738f6e8ae | ||
|  | 051a8e2af1 | ||
|  | 2f43f28d5e | ||
|  | b64769754b | ||
|  | a97daa18d1 | ||
|  | b6556dce8b | ||
|  | aa8d8bc8b5 | ||
|  | 0800dcfdc4 | ||
|  | 12b0101e94 | ||
|  | 021b391a02 | ||
|  | d11e2b6057 | ||
|  | 264d90e7e5 | ||
|  | f9f3da9e78 | ||
|  | 6435b49153 | ||
|  | f9aa2941cf | ||
|  | 5a933d4bee | ||
|  | 5536aea0df | ||
|  | 976666d216 | ||
|  | 9a5bcd4392 | ||
|  | 812060a118 | ||
|  | 089b5052e6 | ||
|  | 874e5d72f4 | ||
|  | 6b11de1329 | ||
|  | 2245a7ad8d | ||
|  | ee5ec1b870 | ||
|  | 74ccfe851b | ||
|  | e1c24bd5a2 | ||
|  | 1349b79728 | ||
|  | d294d7604c | ||
|  | 01df2cf464 | ||
|  | 45b7322488 | ||
|  | b3055e992f | ||
|  | 3da548565c | ||
|  | a975e85548 | ||
|  | c4b5ade752 | ||
|  | a4b61b0794 | ||
|  | f6011184b8 | ||
|  | 74de118c6e | ||
|  | 9c25e77c17 | ||
|  | 440113e67e | ||
|  | a11b60c445 | ||
|  | a6052681ad | ||
|  | 482d50536a | ||
|  | 25c79a4fcd | ||
|  | 02946144ac | ||
|  | 71a360e9a3 | ||
|  | f7912d88b1 | ||
|  | 975101d7d2 | ||
|  | ef58c5ff55 | ||
|  | e10221804a | ||
|  | 284ed9ee0e | ||
|  | 5d7b961997 | ||
|  | c699a5c4b4 | ||
|  | 1f4ceb89cf | ||
|  | 0934ca0040 | ||
|  | 4738f892c2 | ||
|  | 33004fcf33 | ||
|  | 34d214c166 | ||
|  | a56cd92a1e | ||
|  | 7251348507 | ||
|  | 01cd5c84d6 | ||
|  | e210599fa6 | ||
|  | dbe7cee7e9 | ||
|  | 7370d88ceb | ||
|  | 34458e0c57 | ||
|  | 05c8c3abf2 | ||
|  | e9d464b4d3 | ||
|  | 6968c3ab9b | ||
|  | 131a8a9650 | ||
|  | 379ecbf9a9 | ||
|  | 7b9dfa9a28 | ||
|  | fbd0f5eed2 | ||
|  | 5970f904ae | ||
|  | 8cbcb2868d | ||
|  | 8ff2a4b026 | ||
|  | ae14d205a5 | ||
|  | ec5d560ec5 | ||
|  | fb543b53c0 | ||
|  | 39c16422e2 | ||
|  | 4d5b273ebe | ||
|  | ed6a860fad | ||
|  | 423e579292 | ||
|  | ee11aa9e75 | ||
|  | c46d20fa92 | ||
|  | dc8d17574c | ||
|  | 5c17cd04c8 | ||
|  | 67ada02076 | ||
|  | 32d94c2eaf | ||
|  | 687b39a12a | ||
|  | 705af407bf | ||
|  | 080052da2e | ||
|  | ef735fd92a | ||
|  | 17c16dcafc | ||
|  | a89b3018fb | ||
|  | 851e2ebd32 | ||
|  | 1225ce7fe8 | ||
|  | 7e77a31b96 | ||
|  | d146b9002f | ||
|  | 1f9d567b23 | ||
|  | ed1b3a023c | ||
|  | 1ca18f501a | ||
|  | 49588ccd98 | ||
|  | 098dedc092 | ||
|  | b06f6b9545 | ||
|  | ba3cb94999 | ||
|  | 74c67fbf4b | ||
|  | 32b46e4910 | ||
|  | ecf5539ed2 | ||
|  | ac9db4e4d5 | ||
|  | 0eb96094b0 | ||
|  | 30b3ac7dc5 | ||
|  | 0092790c7d | ||
|  | 28909d8a51 | ||
|  | b20cfbb7b6 | ||
|  | 97639bd0a8 | ||
|  | 161ec73c96 | ||
|  | 957d6bea15 | ||
|  | f8b6e5b414 | ||
|  | 1ab450870e | ||
|  | de45f4884c | ||
|  | 5da1f3e7c8 | ||
|  | 983014952b | ||
|  | 55298019a3 | ||
|  | a1ffc3f271 | ||
|  | 2fb60aa997 | ||
|  | f5ec76537a | ||
|  | 728491fd2b | ||
|  | d9d3f2b9e4 | ||
|  | 3fe4864f65 | ||
|  | 0b156f22a4 | ||
|  | 35b1d93813 | ||
|  | d770851ac0 | ||
|  | 989e7b1033 | ||
|  | c4e0eb7b49 | ||
|  | 71f5d0dac7 | ||
|  | 561b0c4381 | ||
|  | 995fbc7330 | ||
|  | 10ab8949c4 | ||
|  | c441202fea | ||
|  | ca261b0bee | ||
|  | 52f3709f67 | ||
|  | c2ca6187fe | ||
|  | 671a13d295 | ||
|  | 14c3e2eccf | ||
|  | 08e5b852c2 | ||
|  | 1c9606c824 | ||
|  | 3cd47b5c9b | ||
|  | aedc729087 | ||
|  | 5f7cfa3fa9 | ||
|  | 0083f30af5 | ||
|  | 4a06f05ef5 | ||
|  | 8f37cadce8 | ||
|  | a11603ca6c | ||
|  | 86274842e9 | ||
|  | cf9c955a44 | ||
|  | 55d828c35f | ||
|  | cdff28aca6 | ||
|  | b9da39274f | ||
|  | c379aa5782 | ||
|  | 9dcabac9dd | ||
|  | 794f3a2b9f | ||
|  | 2066121b7c | ||
|  | 0c4067f143 | ||
|  | 8aa69243b7 | ||
|  | 8697263bde | ||
|  | ea25c4f65c | ||
|  | 82ac3ebd7e | ||
|  | 13cb94909c | ||
|  | b57ca2a763 | ||
|  | 83c49e9745 | ||
|  | e15771d78d | ||
|  | 6edc4920ba | ||
|  | 302bb1bd93 | ||
|  | 529b1bceee | ||
|  | 42cd47d32e | ||
|  | 711d884c2e | ||
|  | 183d1c4674 | ||
|  | faed63a0bb | ||
|  | 53bff262f8 | ||
|  | 3251a708e4 | ||
|  | b5dbdbf7b2 | ||
|  | a9649e92c9 | ||
|  | b561f1fa8b | ||
|  | cecd7491b5 | ||
|  | 55a66322b5 | ||
|  | 155c31a2d7 | ||
|  | a89ce91089 | ||
|  | b897fe6700 | ||
|  | 548a351b06 | ||
|  | 4b1da57ca1 | ||
|  | 529aec7f25 | ||
|  | 1661e545cb | ||
|  | ec71d08878 | ||
|  | ac258b7dd7 | ||
|  | 0f57876233 | ||
|  | 1d25a3693d | ||
|  | 45fa428bf1 | ||
|  | 177fa80f1a | ||
|  | 3261261bfe | ||
|  | d4de7934f8 | ||
|  | c3475af809 | ||
|  | b12f707812 | ||
|  | 22c0c34d60 | ||
|  | a60b66f230 | ||
|  | 83f6e93628 | ||
|  | 222b5f0229 | ||
|  | 30aa383e26 | ||
|  | 676b401294 | ||
|  | ebf57159de | ||
|  | 199d2aafec | ||
|  | 81952f56fd | ||
|  | c5bac82b43 | ||
|  | 081b86109c | ||
|  | 8ac2028a75 | ||
|  | 264fed1c9f | ||
|  | dd59f7b2c7 | ||
|  | 9245a760db | ||
|  | b61b32bbc3 | ||
|  | 09b3914f5d | ||
|  | fe644e4c9e | ||
|  | 7b09bf2156 | ||
|  | 987d0aae66 | ||
|  | 9cbcbc1c22 | ||
|  | cfc4e2bc60 | ||
|  | a03405fa81 | ||
|  | d5c9ccbe6e | ||
|  | e52772d65f | ||
|  | 1e3259e728 | ||
|  | e905a20a60 | ||
|  | 88e2be7a33 | ||
|  | 8939131600 | ||
|  | ba37ebff8b | ||
|  | 28f4cb7e07 | ||
|  | db1e7102cd | ||
|  | 07eb7a5830 | ||
|  | b7c6c685fa | ||
|  | 212134df70 | ||
|  | 6eeb5528f5 | ||
|  | 54fad845c9 | ||
|  | d6c0de6fc7 | ||
|  | 649c8649f7 | ||
|  | da2f53d1b1 | ||
|  | 405139e3b8 | ||
|  | 4f8d347171 | ||
|  | bf0db4876c | ||
|  | 47a14884d6 | ||
|  | 3a7bbc8b08 | ||
|  | 1b1d65372c | ||
|  | fd2faaa16e | ||
|  | 0609cdb9ea | ||
|  | d3bb140f89 | ||
|  | b31dc66628 | ||
|  | 09476171a6 | ||
|  | 33dee813b5 | ||
|  | bb4e73c40b | ||
|  | b1f23ffa94 | ||
|  | b0e8cec1e7 | ||
|  | 5077ae19bc | ||
|  | 0d8447bf59 | ||
|  | c6cf08a274 | ||
|  | dc49ae519e | ||
|  | 904539476a | ||
|  | 3fbf02dc82 | ||
|  | c9392a840d | ||
|  | d164e8ab72 | ||
|  | 6dc62c9fb6 | ||
|  | 87a9684d66 | ||
|  | 94525e2f44 | ||
|  | b408b1b3b9 | ||
|  | 27c2f09e32 | ||
|  | 19bc4d3349 | ||
|  | f2b6c424d6 | ||
|  | a49d4453e9 | ||
|  | 65e50087b9 | ||
|  | 2d90f759d9 | ||
|  | 4230ac7674 | ||
|  | d96e9182e9 | ||
|  | 68c87b9616 | ||
|  | 7f8e9a0b6d | ||
|  | 81a229f2a5 | ||
|  | 8be7ae2733 | ||
|  | 846bca4cb1 | ||
|  | f36f353789 | ||
|  | 939a2731ed | ||
|  | 835dab97ff | ||
|  | fa904b53be | ||
|  | 0ec52dddce | ||
|  | c289355a3a | ||
|  | 02a13a5a18 | ||
|  | 6cf2a0281b | ||
|  | 120d35f9af | ||
|  | 2b15d5e7b3 | ||
|  | fc167bd3f0 | ||
|  | 91b04abf05 | ||
|  | 77faac8740 | ||
|  | 43b3d54855 | ||
|  | 69e9b85700 | ||
|  | 0b6d132759 | ||
|  | 7c233c6c0c | ||
|  | c35b290fa4 | ||
|  | 3d95cfb367 | ||
|  | b90fc3a56e | ||
|  | 1ef3fdccf5 | ||
|  | 02b7f77bd8 | ||
|  | 0ac7ead922 | ||
|  | da9d0e03ce | ||
|  | 120f65f672 | ||
|  | 200a14caa4 | ||
|  | 35bf6da8e2 | ||
|  | f08f70276c | ||
|  | 1ae50fd95b | ||
|  | 40512beb47 | ||
|  | 0d7f9b2c94 | ||
|  | 52f42140a7 | ||
|  | 3f6c50297f | ||
|  | f72d80afc5 | ||
|  | 7c5cb13b22 | ||
|  | d728750eb2 | ||
|  | 02a70e5667 | ||
|  | 44e51ea5fa | ||
|  | 87e201460a | ||
|  | 039bd945e2 | ||
|  | e9e52d2b4b | ||
|  | 2bf92e7399 | ||
|  | 5b0df241f0 | ||
|  | 76f5b05eff | ||
|  | 40fb6c998f | ||
|  | 33f50a342d | ||
|  | 81523ab68a | ||
|  | 2bf8cc62cf | ||
|  | 1ae8247af3 | ||
|  | 5ef32227ec | ||
|  | 6456e773bd | ||
|  | 234fe53ca3 | ||
|  | 7c93e7a7b3 | ||
|  | 8afc6c7f4b | ||
|  | 4609d0fa3a | ||
|  | d452c035c6 | ||
|  | 45113c8f5a | ||
|  | 0acdd3c62b | ||
|  | 96d7d0a33e | ||
|  | b6b280267b | ||
|  | 6e6d253b1a | ||
|  | d92c105db2 | ||
|  | 906db728d6 | ||
|  | c4b7411565 | ||
|  | de06396046 | ||
|  | ee6bfeb8e3 | ||
|  | 058347321f | ||
|  | feefe49324 | ||
|  | 187381a9a2 | ||
|  | 993dfa4368 | ||
|  | 7e35a16440 | ||
|  | e4eeb15926 | ||
|  | 634e0db26d | ||
|  | 56855c23e1 | ||
|  | 0b00f742e3 | ||
|  | b7ab3f673c | ||
|  | be04ea1e35 | ||
|  | 1f8e695802 | ||
|  | 2d82b2c64f | ||
|  | d076caf473 | ||
|  | c7abdefa31 | ||
|  | ba772c0bca | ||
|  | 5bad234119 | ||
|  | c7e7baaf23 | ||
|  | 36658a671b | ||
|  | 045f2e10ba | ||
|  | fb5a7db66d | ||
|  | ba7d33982e | ||
|  | c62279a755 | ||
|  | 17fa1a7ffb | ||
|  | e89ceac351 | ||
|  | 0b8c30c109 | ||
|  | 9ab0f463cc | ||
|  | 6433dda7b8 | ||
|  | fa7a2f4be4 | ||
|  | ba90e16505 | ||
|  | 008f710203 | ||
|  | df2740f126 | ||
|  | 2db89d143e | ||
|  | 0525d49da3 | ||
|  | e2b0745882 | ||
|  | 92e804fc50 | ||
|  | 67abf45576 | ||
|  | d2c9c814e7 | ||
|  | 22f8881a64 | ||
|  | 4ab20322fe | ||
|  | 5370eeecea | ||
|  | ba71cb5dd7 | ||
|  | 9aad6c2c52 | ||
|  | 4d9627f20c | ||
|  | c142492e91 | ||
|  | 6bf8d9e207 | ||
|  | 4f9a6168c1 | ||
|  | 38397f99aa | ||
|  | f8686d0e75 | ||
|  | 549e3c8f9d | ||
|  | bb56225b95 | ||
|  | f00be261ba | ||
|  | 9cd94f26d0 | ||
|  | 4d8f5c80a7 | ||
|  | 24a23acc3d | ||
|  | ca8703cfd8 | ||
|  | 6dcbb5b2f8 | ||
|  | a84fdddb2a | ||
|  | 38bb2f8ceb | ||
|  | 23f5ef4345 | ||
|  | ef8a2a9054 | ||
|  | 96103d0e36 | ||
|  | ff5f6748df | ||
|  | 1c1fd6c366 | ||
|  | 32d37d00cb | ||
|  | 82f6cda966 | ||
|  | f1ff8ff0d0 | ||
|  | 756c72902f | ||
|  | 73f8f0bbd0 | ||
|  | 18ed528f5d | ||
|  | 8fd2f136bc | ||
|  | 0524b1bf67 | ||
|  | 15716f65ce | ||
|  | d46bdba332 | ||
|  | 760728110a | ||
|  | 12d0a194ca | ||
|  | 4104543508 | ||
|  | 5c211db015 | ||
|  | 2dc6180f8d | ||
|  | e222a34b69 | ||
|  | ef17d95063 | ||
|  | 853502e5d7 | ||
|  | c18e297e77 | ||
|  | c5a49599ba | ||
|  | df9da9edf5 | ||
|  | e2200fd050 | ||
|  | c6207f5d9c | ||
|  | 4302b7ff6b | ||
|  | 50a7923438 | ||
|  | ab416445c8 | ||
|  | a54698d43c | ||
|  | c5a77cc1c0 | ||
|  | a9ffa811fc | ||
|  | 080a2608e0 | ||
|  | 57f2e83d6a | ||
|  | 5b030139d3 | ||
|  | 0da1ff42d1 | ||
|  | 2c599b7baa | ||
|  | 5c8af8d21a | ||
|  | 026f3cfde2 | ||
|  | f6349180e8 | ||
|  | aa6421921c | ||
|  | 7d41d2dab2 | ||
|  | f0b4d18f93 | ||
|  | 6750f06e10 | ||
|  | b2bd38fa9e | ||
|  | 3482a01e22 | ||
|  | 6335467552 | ||
|  | 4a39e65b62 | ||
|  | c50a23e918 | ||
|  | 1e76b72b98 | ||
|  | b94cf39eef | ||
|  | fef254ffff | ||
|  | e5495863a2 | ||
|  | 3b4df2abf0 | ||
|  | aef2aee6a4 | ||
|  | d0d9519149 | ||
|  | 685df1d2c5 | ||
|  | 08e6b6f2e7 | ||
|  | 66c887d0f3 | ||
|  | 22e9960697 | ||
|  | 64aa6e1f2d | ||
|  | 7a93ed9d04 | ||
|  | a905e922e9 | ||
|  | f9f08fc720 | ||
|  | 8d402d76d0 | ||
|  | 46fda6281c | ||
|  | a14dbe1ea6 | ||
|  | 18810a4c16 | ||
|  | 147bc80dba | ||
|  | c7a484195a | ||
|  | 4968eb6503 | ||
|  | a6f2d698a9 | ||
|  | ea5ed93ea5 | ||
|  | e1140134c6 | ||
|  | 5ed11e012e | ||
|  | 5380bd39ca | ||
|  | 2ee2685688 | ||
|  | 782002245b | ||
|  | 7fc0905843 | ||
|  | 72ecb99e54 | ||
|  | c863507d08 | ||
|  | cff86c9093 | ||
|  | 0479dfcc54 | ||
|  | 68dd67f21c | ||
|  | 540f6858b5 | ||
|  | b61e791a4f | ||
|  | d0986f9482 | ||
|  | 112cb0dc28 | ||
|  | 0d3d7fdcf2 | ||
|  | 5d6b89ef3b | ||
|  | ed0b26c09e | ||
|  | ae292bd920 | ||
|  | 6c85a90723 | ||
|  | 852592066c | ||
|  | 96e1bc9b44 | ||
|  | b41d81ed31 | ||
|  | e241ec2244 | ||
|  | 16e1f1a94c | ||
|  | 7a68c42b26 | ||
|  | 37ccc2e118 | ||
|  | 4192fe1ab2 | ||
|  | d5c743d7bb | ||
|  | 11814d63e8 | ||
|  | b753656d50 | ||
|  | f7e87611fc | ||
|  | 1fb0e1900e | ||
|  | 954a9731e0 | ||
|  | 65c3364ad8 | ||
|  | 3d72b7dccc | ||
|  | 13ee569f06 | ||
|  | d79ef23a75 | ||
|  | 5d0797d4ba | ||
|  | 47a8d7475f | ||
|  | 4939053121 | ||
|  | b525bf554e | ||
|  | f00285d2b2 | ||
|  | 040f8d6eda | ||
|  | 66d905325c | ||
|  | 8b0cd95e73 | ||
|  | d867cca6d9 | ||
|  | a28f736369 | ||
|  | 5c3a71cc59 | ||
|  | cef6dadb08 | ||
|  | 36be817a3e | ||
|  | 02f571f081 | ||
|  | 157159e487 | ||
|  | 02ada9f800 | ||
|  | 6fcf9a97bb | ||
|  | 17a5d8799f | ||
|  | 31f3fe7a22 | ||
|  | 89e46d3d83 | ||
|  | 885795e67d | ||
|  | 92bfb53dd4 | ||
|  | 4cecbeb115 | ||
|  | 5971480f55 | ||
|  | 05bebea511 | ||
|  | 76fa6c5cfb | ||
|  | 633b68b518 | ||
|  | 6913d8e995 | ||
|  | f3654e6f8d | ||
|  | d685dbcf22 | ||
|  | 6a57fa079e | ||
|  | 0a91d145ba | ||
|  | c2866e799d | ||
|  | d8cffcaae7 | ||
|  | 30abca7be2 | ||
|  | edce87f3fb | ||
|  | 66bac98fc2 | ||
|  | 59156de92b | ||
|  | e0d7d10600 | ||
|  | daaf862257 | ||
|  | 9de53d4b59 | ||
|  | f1571e2d46 | ||
|  | bd28d06298 | ||
|  | a24e4655eb | ||
|  | 20a6c8d8e5 | ||
|  | 98d264faf4 | ||
|  | 321902a9b5 | ||
|  | 8df5d06f9a | ||
|  | e69ea529cc | ||
|  | 15405b1119 | ||
|  | d2f97ce2da | ||
|  | 543ca631e9 | ||
|  | f184886db1 | ||
|  | 8432ab4324 | ||
|  | 6c05b37ca3 | ||
|  | 35f4beeb47 | ||
|  | cbad7caa68 | ||
|  | b0388a4012 | ||
|  | df3fab4d55 | ||
|  | da49f88a03 | ||
|  | e28feceb06 | ||
|  | 50496a164d | ||
|  | 6f1dce1572 | ||
|  | 6847776ae7 | ||
|  | 67bd53bdd8 | ||
|  | e735abfdfd | ||
|  | 1de93a2d6d | ||
|  | 36f9e7c742 | ||
|  | 9462763bbb | ||
|  | 4ae0880ea6 | ||
|  | 6ae2b6c835 | ||
|  | a0f180fd48 | ||
|  | bf1cf89914 | ||
|  | 297a047fb4 | ||
|  | 52ffc15ffc | ||
|  | e478c9c693 | ||
|  | d004f28074 | ||
|  | bc68ed8b1d | ||
|  | 04555ae650 | ||
|  | e8f62085be | ||
|  | f430bffe2a | ||
|  | 1f0520634f | ||
|  | 902d4c31fb | ||
|  | 17364ac09f | ||
|  | 0b889f8f81 | ||
|  | 40e349ff35 | ||
|  | c943b1b1df | ||
|  | 912bc1d4e1 | ||
|  | cacb1533a3 | ||
|  | f0feaca9d7 | ||
|  | b6656f171b | ||
|  | 6206ab3931 | ||
|  | c35fc58b1f | ||
|  | deed8abed7 | ||
|  | 7151ad23f0 | ||
|  | 0166d938af | ||
|  | 6194aeddb0 | ||
|  | 903dbf2c30 | ||
|  | 9380f9ff57 | ||
|  | 259ed95486 | ||
|  | 2ebc92681e | ||
|  | 195a1ffe13 | ||
|  | a8c2978185 | ||
|  | 140f97a457 | ||
|  | 7f94445a1e | ||
|  | 82a89aec65 | ||
|  | 7e95110232 | ||
|  | ec4aaaad89 | ||
|  | 1b790fde24 | ||
|  | aaccea731e | ||
|  | 29e31d7610 | ||
|  | aa51f4a98f | ||
|  | e6ccd12f00 | ||
|  | b134315df1 | ||
|  | 7f34dffa13 | ||
|  | fa239e78c9 | ||
|  | 707a6c4d6a | ||
|  | e5da303b43 | ||
|  | 84ccd66331 | ||
|  | ad8cc2baea | ||
|  | 7c4cf70309 | ||
|  | c3211e9b4f | ||
|  | 268d94c983 | ||
|  | 0bcacbba58 | ||
|  | 8cdc26add9 | ||
|  | e0b2238886 | ||
|  | 369a2e4029 | ||
|  | c4089e3b51 | ||
|  | 9e2e9bc5b8 | ||
|  | a9e44426ed | 
							
								
								
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Library General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if you | ||||
| distribute copies of the software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, the source code distributed need not include | ||||
| anything that is normally distributed (in either source or binary | ||||
| form) with the major components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program subject to | ||||
| these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
|  | ||||
| 			    NO WARRANTY | ||||
|  | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
| 	    How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
|  | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year  name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Library General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										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. | ||||
|  | ||||
							
								
								
									
										48
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| # | ||||
| # 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 | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS += lib/format1 \ | ||||
| 	     lib/format_pool \ | ||||
| 	     lib/mirror \ | ||||
| 	     lib/snapshot \ | ||||
| 	     po \ | ||||
| 	     test/mm test/device test/format1 test/regex test/filters | ||||
| endif | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| lib: include | ||||
| tools: lib | ||||
| po: lib tools | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| po.pofile: lib.pofile tools.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://ftp.sistina.com/pub/LVM2/tools/ | ||||
|   ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
| 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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										220
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| Version 2.00.17 - | ||||
| ============================= | ||||
|   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! | ||||
|  | ||||
							
								
								
									
										63
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| Version 1.00.18 | ||||
| ============================= | ||||
|   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: | ||||
|   | ||||
							
								
								
									
										402
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,402 @@ | ||||
| ## | ||||
| ##    Copyright 1999-2000 Sistina Software, Inc. | ||||
| ## | ||||
| ##    This is free software released under the GNU General Public License. | ||||
| ##    There is no warranty for this software.  See the file COPYING for | ||||
| ##    details. | ||||
| ## | ||||
| ##    See the file CONTRIBUTORS for a list of contributors. | ||||
| ## | ||||
| ##    This file is maintained by: | ||||
| ##      AJ Lewis <lewis@sistina.com> | ||||
| ##  | ||||
| ##    File name: configure.in | ||||
| ## | ||||
| ##    Description: Input file for autoconf.  Generates the configure script  | ||||
| ##                 that tries to keep everything nice and portable.  It also | ||||
| ##                 simplifies distribution package building considerably. | ||||
| ################################################################################ | ||||
|  | ||||
| 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 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_CHECK_HEADERS(fcntl.h malloc.h sys/ioctl.h unistd.h) | ||||
|  | ||||
| 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_STRUCT_ST_RDEV | ||||
| AC_HEADER_TIME | ||||
|  | ||||
| dnl Get system type | ||||
| AC_CANONICAL_SYSTEM | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		CFLAGS=  | ||||
| 		CLDFLAGS="-Wl,--version-script,.export.sym" | ||||
| 		CLDWHOLEARCHIVE="-Wl,-whole-archive" | ||||
| 		CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" | ||||
| 		LD_DEPS=".export.sym" | ||||
| 		LD_FLAGS="-Wl,--export-dynamic" | ||||
| 		SOFLAG="-shared" | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=yes ;; | ||||
| 	darwin*) | ||||
| 		CFLAGS="-no-cpp-precomp -fno-common" | ||||
| 		CLDFLAGS= | ||||
| 		CLDWHOLEARCHIVE="-all_load" | ||||
| 		CLDNOWHOLEARCHIVE= | ||||
| 		LD_DEPS= | ||||
| 		LD_FLAGS= | ||||
| 		SOFLAG="-dynamiclib" | ||||
| 		DEVMAPPER=no | ||||
| 		ODIRECT=no ;; | ||||
| esac | ||||
|  | ||||
| dnl -- prefix is /usr by default, the exec_prefix default is setup later | ||||
| AC_PREFIX_DEFAULT(/usr) | ||||
|  | ||||
| OWNER="root" | ||||
| GROUP="root" | ||||
|  | ||||
| dnl -- setup the ownership of the files | ||||
| AC_ARG_WITH(user, | ||||
|   [  --with-user=USER        Set the owner of installed files ], | ||||
|   [ OWNER="$withval" ]) | ||||
|  | ||||
| if test x$OWNER != x; then | ||||
| 	OWNER="-o $OWNER" | ||||
| fi | ||||
|  | ||||
| dnl -- setup the group ownership of the files | ||||
| AC_ARG_WITH(group, | ||||
|   [  --with-group=GROUP      Set the group owner of installed files ], | ||||
|   [ GROUP="$withval" ]) | ||||
|  | ||||
| if test x$GROUP != x; then | ||||
| 	GROUP="-g $GROUP" | ||||
| fi | ||||
|  | ||||
| dnl -- LVM1 tool fallback option | ||||
| 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) | ||||
|  | ||||
| if test x$LVM1_FALLBACK = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DLVM1_FALLBACK" | ||||
| fi | ||||
|  | ||||
| dnl -- format1 inclusion type | ||||
| AC_ARG_WITH(lvm1, | ||||
|   [  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ LVM1="$withval" ], | ||||
|   [ LVM1="internal" ]) | ||||
|  | ||||
| if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-lvm1 parameter invalid | ||||
| ) | ||||
|  exit | ||||
| fi; | ||||
|  | ||||
| if test x$LVM1 = xinternal; then | ||||
| 	CFLAGS="$CFLAGS -DLVM1_INTERNAL" | ||||
| fi | ||||
|  | ||||
| dnl -- format_pool inclusion type | ||||
| AC_ARG_WITH(pool, | ||||
|   [  --with-pool=TYPE        GFS pool read-only support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ POOL="$withval" ], | ||||
|   [ POOL="internal" ]) | ||||
|  | ||||
| if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-pool parameter invalid | ||||
| ) | ||||
|  exit | ||||
| fi; | ||||
|  | ||||
| if test x$POOL = xinternal; then | ||||
| 	CFLAGS="$CFLAGS -DPOOL_INTERNAL" | ||||
| fi | ||||
|  | ||||
|  | ||||
| AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) | ||||
|  | ||||
| dnl -- snapshots inclusion type | ||||
| AC_ARG_WITH(snapshots, | ||||
|   [  --with-snapshots=TYPE   Snapshot support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ SNAPSHOTS="$withval" ], | ||||
|   [ SNAPSHOTS="internal" ]) | ||||
|  | ||||
| if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-snapshots parameter invalid | ||||
| ) | ||||
|  exit | ||||
| fi; | ||||
|  | ||||
| if test x$SNAPSHOTS = xinternal; then | ||||
| 	CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL" | ||||
| fi | ||||
|  | ||||
| dnl -- mirrors inclusion type | ||||
| AC_ARG_WITH(mirrors, | ||||
|   [  --with-mirrors=TYPE     Mirror support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ MIRRORS="$withval" ], | ||||
|   [ MIRRORS="internal" ]) | ||||
|  | ||||
| if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-mirrors parameter invalid | ||||
| ) | ||||
|  exit | ||||
| fi; | ||||
|  | ||||
| if test x$MIRRORS = xinternal; then | ||||
| 	CFLAGS="$CFLAGS -DMIRRORED_INTERNAL" | ||||
| fi | ||||
|  | ||||
| dnl Enables staticly-linked tools | ||||
| 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) | ||||
|  | ||||
| dnl Enable readline | ||||
| AC_ARG_ENABLE(readline, [  --enable-readline       Enable readline support],  \ | ||||
| READLINE=$enableval, READLINE=no) | ||||
|  | ||||
| if test x$READLINE = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DREADLINE_SUPPORT" | ||||
| fi | ||||
|  | ||||
| echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6 | ||||
| dnl Enable Debugging | ||||
| AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debugging],  \ | ||||
| DEBUG=yes, DEBUG=no) | ||||
| echo "$ac_t""$DEBUG" 1>&6 | ||||
|  | ||||
| echo $ac_n "checking whether to enable device-mapper""... $ac_c" 1>&6 | ||||
| dnl Disable devmapper | ||||
| AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable device-mapper interaction],  \ | ||||
| DEVMAPPER=no) | ||||
| echo "$ac_t""$DEVMAPPER" 1>&6 | ||||
|  | ||||
| if test x$DEVMAPPER = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT" | ||||
| fi | ||||
|  | ||||
| echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6 | ||||
| dnl Disable O_DIRECT | ||||
| AC_ARG_ENABLE(o_direct, [  --disable-o_direct      Disable O_DIRECT],  \ | ||||
| ODIRECT=no) | ||||
| echo "$ac_t""$ODIRECT" 1>&6 | ||||
|  | ||||
| if test x$ODIRECT = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT" | ||||
| fi | ||||
|  | ||||
| echo $ac_n "checking whether to compile liblvm2cmd.so""... $ac_c" 1>&6 | ||||
| dnl Enable cmdlib | ||||
| AC_ARG_ENABLE(cmdlib, [  --enable-cmdlib         Build shared command library],  \ | ||||
| CMDLIB=yes, CMDLIB=no) | ||||
| echo "$ac_t""$CMDLIB" 1>&6 | ||||
|  | ||||
| if test x$CMDLIB = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DCMDLIB" | ||||
| fi | ||||
|  | ||||
| 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) | ||||
|  | ||||
| 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. | ||||
| ) | ||||
| 	exit | ||||
| 	) | ||||
| fi | ||||
|  | ||||
| dnl Check for dlopen | ||||
| AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no) | ||||
|  | ||||
| if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; 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$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ | ||||
|       \) -a "x$STATIC_LINK" = xyes ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| Features cannot be 'shared' when building statically | ||||
| ) | ||||
|  exit | ||||
| fi | ||||
|  | ||||
| dnl Check for is_selinux_enabled | ||||
| AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no) | ||||
|  | ||||
| if test x$HAVE_SELINUX = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DHAVE_SELINUX" | ||||
| 	LIBS="-lselinux $LIBS" | ||||
| 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). | ||||
| ) | ||||
| 		exit | ||||
| 	) | ||||
| 	AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES") | ||||
| 		 | ||||
| fi | ||||
|  | ||||
| echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6 | ||||
| dnl Internationalisation stuff | ||||
| AC_ARG_ENABLE(nls, [  --enable-nls            Enable Native Language Support],\ | ||||
| 		INTL=yes, INTL=no) | ||||
| echo "$ac_t""$INTL" 1>&6 | ||||
|  | ||||
| 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 | ||||
| 		) | ||||
| 		exit   | ||||
| 	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' ]) | ||||
|  | ||||
|  | ||||
| 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(CLDFLAGS) | ||||
| AC_SUBST(CLDWHOLEARCHIVE) | ||||
| AC_SUBST(CLDNOWHOLEARCHIVE) | ||||
| AC_SUBST(LD_DEPS) | ||||
| AC_SUBST(LD_FLAGS) | ||||
| 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) | ||||
|  | ||||
| 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                                                               \ | ||||
| doc/Makefile								\ | ||||
| include/Makefile						 	\ | ||||
| lib/Makefile							 	\ | ||||
| lib/format1/Makefile						 	\ | ||||
| lib/format_pool/Makefile						\ | ||||
| lib/mirror/Makefile							\ | ||||
| lib/snapshot/Makefile							\ | ||||
| man/Makefile							 	\ | ||||
| po/Makefile								\ | ||||
| tools/Makefile							 	\ | ||||
| tools/version.h								\ | ||||
| test/mm/Makefile							\ | ||||
| test/device/Makefile							\ | ||||
| test/format1/Makefile							\ | ||||
| test/regex/Makefile                                                     \ | ||||
| test/filters/Makefile                                                   \ | ||||
| ) | ||||
|  | ||||
| if test x$ODIRECT != xyes; then | ||||
|   echo | ||||
|   echo Warning: O_DIRECT disabled. | ||||
|   echo Use of pvmove may cause machine to lock up under low memory conditions. | ||||
|   echo | ||||
| fi | ||||
							
								
								
									
										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 ../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! | ||||
							
								
								
									
										283
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| # 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. | ||||
|  | ||||
|     # 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 | ||||
| +----------+---------+--------+ | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										48
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								include/.symlinks
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| ../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/segtypes.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 | ||||
							
								
								
									
										41
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| # | ||||
| # 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@ | ||||
|  | ||||
| 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: | ||||
|  | ||||
| .PHONY: clean distclean all install pofile | ||||
|  | ||||
							
								
								
									
										140
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| # | ||||
| # 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/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/segtypes.c \ | ||||
| 	metadata/snapshot_manip.c \ | ||||
| 	misc/crc.c \ | ||||
| 	misc/lvm-file.c \ | ||||
| 	misc/lvm-string.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 ("@SNAPSHOTS@", "internal") | ||||
|   SOURCES += snapshot/snapshot.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@MIRRORS@", "internal") | ||||
|   SOURCES += mirror/mirrored.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@DEBUG@", "yes") | ||||
|   SOURCES += mm/dbg_malloc.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 ../make.tmpl | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| Base library directory | ||||
							
								
								
									
										787
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										787
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,787 @@ | ||||
| /* | ||||
|  * 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) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info) | ||||
| { | ||||
| 	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 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, &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) | ||||
| { | ||||
| 	return _lv_info(lv, 0, info); | ||||
| } | ||||
|  | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info) | ||||
| { | ||||
| 	struct logical_volume *lv; | ||||
|  | ||||
| 	if (!(lv = lv_from_lvid(cmd, lvid_s))) | ||||
| 		return 0; | ||||
|  | ||||
| 	return _lv_info(lv, 0, info); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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)) { | ||||
| 		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)) { | ||||
| 		stack; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return info.exists; | ||||
| } | ||||
|  | ||||
| static int _lv_open_count(struct logical_volume *lv) | ||||
| { | ||||
| 	struct lvinfo info; | ||||
|  | ||||
| 	if (!lv_info(lv, &info)) { | ||||
| 		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)) { | ||||
| 		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)) { | ||||
| 		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)) { | ||||
| 		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)) { | ||||
| 		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)) { | ||||
| 		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 | ||||
							
								
								
									
										83
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| /* | ||||
|  * 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 lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, | ||||
| 		    struct lvinfo *info); | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
							
								
								
									
										2261
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2261
									
								
								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, 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, 0555)) { | ||||
| 		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; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Removing directory %s", vg_path); | ||||
|  | ||||
| 	if (is_empty_dir(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) | ||||
| 			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 | ||||
							
								
								
									
										1005
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1005
									
								
								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(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,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,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 | ||||
							
								
								
									
										240
									
								
								lib/datastruct/hash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								lib/datastruct/hash.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,240 @@ | ||||
| /* | ||||
|  * 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; | ||||
| 	char key[1]; | ||||
| }; | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	/* remember sizeof(n) includes an extra char from key[1], | ||||
| 	   so not adding 1 to the strlen as you would expect */ | ||||
| 	struct hash_node *n = dbg_malloc(sizeof(*n) + strlen(str)); | ||||
|  | ||||
| 	if (n) | ||||
| 		strcpy(n->key, str); | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static unsigned _hash(const char *str) | ||||
| { | ||||
| 	unsigned long h = 0, g; | ||||
| 	while (*str) { | ||||
| 		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 struct hash_node **_find(struct hash_table *t, const char *key) | ||||
| { | ||||
| 	unsigned h = _hash(key) & (t->num_slots - 1); | ||||
| 	struct hash_node **c; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) | ||||
| 		if (!strcmp(key, (*c)->key)) | ||||
| 			break; | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| void *hash_lookup(struct hash_table *t, const char *key) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key); | ||||
| 	return *c ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| int hash_insert(struct hash_table *t, const char *key, void *data) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key); | ||||
|  | ||||
| 	if (*c) | ||||
| 		(*c)->data = data; | ||||
| 	else { | ||||
| 		struct hash_node *n = _create_node(key); | ||||
|  | ||||
| 		if (!n) | ||||
| 			return 0; | ||||
|  | ||||
| 		n->data = data; | ||||
| 		n->next = 0; | ||||
| 		*c = n; | ||||
| 		t->num_nodes++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void hash_remove(struct hash_table *t, const char *key) | ||||
| { | ||||
| 	struct hash_node **c = _find(t, key); | ||||
|  | ||||
| 	if (*c) { | ||||
| 		struct hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		dbg_free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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) & (t->num_slots - 1); | ||||
| 	return n->next ? n->next : _next_slot(t, h + 1); | ||||
| } | ||||
							
								
								
									
										45
									
								
								lib/datastruct/hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								lib/datastruct/hash.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  * 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); | ||||
| void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len); | ||||
| int hash_insert(struct hash_table *t, const char *key, void *data); | ||||
| void hash_remove(struct hash_table *t, const char *key); | ||||
|  | ||||
| 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 | ||||
							
								
								
									
										579
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								lib/device/dev-cache.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,579 @@ | ||||
| /* | ||||
|  * 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; | ||||
| 	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->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(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 | ||||
							
								
								
									
										500
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										500
									
								
								lib/device/dev-io.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,500 @@ | ||||
| /* | ||||
|  * 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_sys_error("lseek", dev_name(where->dev)); | ||||
| 		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) | ||||
| 			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) | ||||
| { | ||||
| 	int s; | ||||
|  | ||||
| 	if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) { | ||||
| 		log_sys_error("ioctl BLKBSZGET", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*size = (unsigned int) s; | ||||
| 	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(struct device *dev, uint64_t *size) | ||||
| { | ||||
| 	int fd; | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	log_very_verbose("Getting size of %s", name); | ||||
| 	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); | ||||
| 		close(fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*size >>= BLKSIZE_SHIFT;	/* Convert to sectors */ | ||||
| 	close(fd); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int dev_get_sectsize(struct device *dev, uint32_t *size) | ||||
| { | ||||
| 	int fd; | ||||
| 	int s; | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	log_very_verbose("Getting size of %s", name); | ||||
| 	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; | ||||
| 	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) { | ||||
| 		dev->open_count++; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
|  | ||||
| 	if ((dev->fd = open(name, flags, 0777)) < 0) { | ||||
| 		log_sys_error("open", name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	dev->open_count = 1; | ||||
| 	dev->flags &= ~DEV_ACCESSED_W; | ||||
|  | ||||
| 	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(dev); | ||||
| 		dev->fd = -1; | ||||
| 		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", dev_name(dev)); | ||||
|  | ||||
| 	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; | ||||
| 	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 | ||||
|  | ||||
| 	/* FIXME lookup device in cache to get vgname and see if it's locked? */ | ||||
| 	if (--dev->open_count < 1 && (immediate || !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) | ||||
| 		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) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = dev_write(dev, dev->end, len, buffer); | ||||
| 	dev->end += (uint64_t) len; | ||||
|  | ||||
| #ifndef O_DIRECT_SUPPORT | ||||
| 	dev_flush(dev); | ||||
| #endif | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) | ||||
| { | ||||
| 	struct device_area where; | ||||
|  | ||||
| 	if (!dev->open_count) | ||||
| 		return 0; | ||||
|  | ||||
| 	where.dev = dev; | ||||
| 	where.start = offset; | ||||
| 	where.size = len; | ||||
|  | ||||
| 	dev->flags |= DEV_ACCESSED_W; | ||||
|  | ||||
| 	return _aligned_io(&where, buffer, 1); | ||||
| } | ||||
|  | ||||
| int dev_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; | ||||
|  | ||||
| 	/* FIXME: Always display error */ | ||||
| 	return (len == 0); | ||||
| } | ||||
							
								
								
									
										206
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								lib/device/device.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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> | ||||
|  | ||||
| #include "dbg_malloc.h" | ||||
| #include "log.h" | ||||
| #include "dev-cache.h" | ||||
| #include "metadata.h" | ||||
| #include "device.h" | ||||
|  | ||||
| int _get_partition_type(struct dev_filter *filter, struct device *d); | ||||
|  | ||||
| #define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev)) | ||||
|  | ||||
| int is_whole_disk(struct dev_filter *filter, struct device *d) | ||||
| { | ||||
| 	return (MINOR_PART(dm, d)) ? 0 : 1; | ||||
| } | ||||
|  | ||||
| int is_extended_partition(struct dev_mgr *dm, struct device *d) | ||||
| { | ||||
| 	return (MINOR_PART(dm, 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 | ||||
							
								
								
									
										103
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/device/device.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
|  | ||||
| /* | ||||
|  * 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; | ||||
| 	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(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); | ||||
|  | ||||
| /* FIXME Check partition type if appropriate */ | ||||
|  | ||||
| #define is_lvm_partition(a) 1 | ||||
|  | ||||
| /* | ||||
| static inline int is_lvm_partition(const char *name) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| */ | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										664
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								lib/display/display.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,664 @@ | ||||
| /* | ||||
|  * 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 "segtypes.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) && 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) && 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; | ||||
| } | ||||
							
								
								
									
										54
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								lib/display/display.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| /* | ||||
|  * 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); | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
							
								
								
									
										101
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								lib/error/errseg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* | ||||
|  * 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 "segtypes.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; | ||||
|  | ||||
| 	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 | ||||
							
								
								
									
										98
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/filters/filter-md.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| /* | ||||
|  * 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) | ||||
| { | ||||
| 	uint64_t size, sector; | ||||
| 	uint32_t md_magic; | ||||
|  | ||||
| 	if (!dev_get_size(dev, &size)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (size < MD_RESERVED_SECTORS * 2) | ||||
| 		/* | ||||
| 		 * We could ignore it since it is obviously too | ||||
| 		 * small, but that's not our job. | ||||
| 		 */ | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	sector = MD_NEW_SIZE_SECTORS(size); | ||||
|  | ||||
| 	/* Check if it is an md component device. */ | ||||
| 	if (dev_read(dev, sector << SECTOR_SHIFT, sizeof(uint32_t), &md_magic)) { | ||||
| 		if (md_magic == MD_SB_MAGIC) { | ||||
| 			log_debug("%s: Skipping md component device", | ||||
| 				  dev_name(dev)); | ||||
| 			if (!dev_close(dev)) | ||||
| 				stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	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 | ||||
|  | ||||
							
								
								
									
										277
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								lib/filters/filter-persistent.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | ||||
| /* | ||||
|  * 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); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (l == PF_BAD_DEVICE) { | ||||
| 		log_debug("%s: Skipping (cached)", dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} else | ||||
| 		return 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 | ||||
							
								
								
									
										238
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								lib/filters/filter-regex.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | ||||
| /* | ||||
|  * 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(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; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * 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(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 | ||||
							
								
								
									
										288
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								lib/filters/filter-sysfs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,288 @@ | ||||
| /* | ||||
|  * 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; | ||||
| 	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; | ||||
| 		} | ||||
|  | ||||
| 		if (d->d_type == DT_DIR) { | ||||
| 			if (!_read_devs(ds, path)) { | ||||
| 				r = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ((d->d_type == 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; | ||||
|  | ||||
| 	return _set_lookup(ds, dev->dev); | ||||
| } | ||||
|  | ||||
| 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(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 | ||||
							
								
								
									
										228
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								lib/filters/filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| /* | ||||
|  * 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 <dirent.h> | ||||
| #include <unistd.h> | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| #define NUMBER_OF_MAJORS 256 | ||||
|  | ||||
| typedef struct { | ||||
| 	const char *name; | ||||
| 	const int max_partitions; | ||||
| } device_info_t; | ||||
|  | ||||
| static int _md_major = -1; | ||||
|  | ||||
| int md_major(void) | ||||
| { | ||||
| 	return _md_major; | ||||
| } | ||||
|  | ||||
| /* This list can be supplemented with devices/types in the config file */ | ||||
| static const device_info_t device_info[] = { | ||||
| 	{"ide", 16},		/* IDE disk */ | ||||
| 	{"sd", 16},		/* SCSI disk */ | ||||
| 	{"md", 16},		/* Multiple Disk driver (SoftRAID) */ | ||||
| 	{"loop", 16},		/* 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 */ | ||||
| 	{"power2", 16},		/* EMC Powerpath */ | ||||
| 	{"i2o_block", 16},	/* i2o Block Disk */ | ||||
| 	{NULL, 0} | ||||
| }; | ||||
|  | ||||
| static int _passes_lvm_type_device_filter(struct dev_filter *f, | ||||
| 					  struct device *dev) | ||||
| { | ||||
| 	int fd; | ||||
| 	const char *name = dev_name(dev); | ||||
|  | ||||
| 	/* Is this a recognised device type? */ | ||||
| 	if (!(((int *) f->private)[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 ((fd = open(name, O_RDONLY)) < 0) { | ||||
| 		log_debug("%s: Skipping: open failed: %s", name, | ||||
| 			  strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	close(fd); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	int *max_partitions_by_major; | ||||
| 	char *name; | ||||
|  | ||||
| 	if (!(max_partitions_by_major = | ||||
| 	      dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) { | ||||
| 		log_error("Filter failed to allocate max_partitions_by_major"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	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 max_partitions_by_major; | ||||
| 	} | ||||
|  | ||||
| 	if (lvm_snprintf(proc_devices, sizeof(proc_devices), | ||||
| 			 "%s/devices", proc) < 0) { | ||||
| 		log_error("Failed to create /proc/devices string"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(pd = fopen(proc_devices, "r"))) { | ||||
| 		log_sys_error("fopen", proc_devices); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS); | ||||
| 	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 (max_partitions_by_major[line_maj] || !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 NULL; | ||||
| 			} | ||||
| 			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 NULL; | ||||
| 			} | ||||
| 			if (!cv->v.i) { | ||||
| 				log_error("Zero partition count invalid for " | ||||
| 					  "%s in devices/types in config file", | ||||
| 					  name); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			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 max_partitions_by_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; | ||||
|  | ||||
| 	if (!(f->private = _scan_proc_dev(proc, cn))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| void lvm_type_filter_destroy(struct dev_filter *f) | ||||
| { | ||||
| 	dbg_free(f->private); | ||||
| 	dbg_free(f); | ||||
| 	return; | ||||
| } | ||||
							
								
								
									
										38
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/filters/filter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * 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 | ||||
| #  include <linux/kdev_t.h> | ||||
| #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); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1
									
								
								lib/format1/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								lib/format1/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| init_format | ||||
							
								
								
									
										38
									
								
								lib/format1/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/format1/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| # | ||||
| # Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of 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 =\ | ||||
| 	disk-rep.c \ | ||||
| 	format1.c \ | ||||
| 	import-export.c \ | ||||
| 	import-extents.c \ | ||||
| 	layout.c \ | ||||
| 	lvm1-label.c \ | ||||
| 	vg_number.c | ||||
|  | ||||
| LIB_SHARED = liblvm2format1.so | ||||
|  | ||||
| include ../../make.tmpl | ||||
|  | ||||
| .PHONY: install | ||||
|  | ||||
| install: liblvm2format1.so | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/liblvm2format1.so.$(LIB_VERSION) | ||||
| 	$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so | ||||
|  | ||||
							
								
								
									
										720
									
								
								lib/format1/disk-rep.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										720
									
								
								lib/format1/disk-rep.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,720 @@ | ||||
| /* | ||||
|  * 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 "disk-rep.h" | ||||
| #include "pool.h" | ||||
| #include "xlate.h" | ||||
| #include "filter.h" | ||||
| #include "lvmcache.h" | ||||
|  | ||||
| #include <fcntl.h> | ||||
|  | ||||
| #define fail do {stack; return 0;} while(0) | ||||
| #define xx16(v) disk->v = xlate16(disk->v) | ||||
| #define xx32(v) disk->v = xlate32(disk->v) | ||||
| #define xx64(v) disk->v = xlate64(disk->v) | ||||
|  | ||||
| /* | ||||
|  * Functions to perform the endian conversion | ||||
|  * between disk and core.  The same code works | ||||
|  * both ways of course. | ||||
|  */ | ||||
| static void _xlate_pvd(struct pv_disk *disk) | ||||
| { | ||||
| 	xx16(version); | ||||
|  | ||||
| 	xx32(pv_on_disk.base); | ||||
| 	xx32(pv_on_disk.size); | ||||
| 	xx32(vg_on_disk.base); | ||||
| 	xx32(vg_on_disk.size); | ||||
| 	xx32(pv_uuidlist_on_disk.base); | ||||
| 	xx32(pv_uuidlist_on_disk.size); | ||||
| 	xx32(lv_on_disk.base); | ||||
| 	xx32(lv_on_disk.size); | ||||
| 	xx32(pe_on_disk.base); | ||||
| 	xx32(pe_on_disk.size); | ||||
|  | ||||
| 	xx32(pv_major); | ||||
| 	xx32(pv_number); | ||||
| 	xx32(pv_status); | ||||
| 	xx32(pv_allocatable); | ||||
| 	xx32(pv_size); | ||||
| 	xx32(lv_cur); | ||||
| 	xx32(pe_size); | ||||
| 	xx32(pe_total); | ||||
| 	xx32(pe_allocated); | ||||
| 	xx32(pe_start); | ||||
| } | ||||
|  | ||||
| static void _xlate_lvd(struct lv_disk *disk) | ||||
| { | ||||
| 	xx32(lv_access); | ||||
| 	xx32(lv_status); | ||||
| 	xx32(lv_open); | ||||
| 	xx32(lv_dev); | ||||
| 	xx32(lv_number); | ||||
| 	xx32(lv_mirror_copies); | ||||
| 	xx32(lv_recovery); | ||||
| 	xx32(lv_schedule); | ||||
| 	xx32(lv_size); | ||||
| 	xx32(lv_snapshot_minor); | ||||
| 	xx16(lv_chunk_size); | ||||
| 	xx16(dummy); | ||||
| 	xx32(lv_allocated_le); | ||||
| 	xx32(lv_stripes); | ||||
| 	xx32(lv_stripesize); | ||||
| 	xx32(lv_badblock); | ||||
| 	xx32(lv_allocation); | ||||
| 	xx32(lv_io_timeout); | ||||
| 	xx32(lv_read_ahead); | ||||
| } | ||||
|  | ||||
| static void _xlate_vgd(struct vg_disk *disk) | ||||
| { | ||||
| 	xx32(vg_number); | ||||
| 	xx32(vg_access); | ||||
| 	xx32(vg_status); | ||||
| 	xx32(lv_max); | ||||
| 	xx32(lv_cur); | ||||
| 	xx32(lv_open); | ||||
| 	xx32(pv_max); | ||||
| 	xx32(pv_cur); | ||||
| 	xx32(pv_act); | ||||
| 	xx32(dummy); | ||||
| 	xx32(vgda); | ||||
| 	xx32(pe_size); | ||||
| 	xx32(pe_total); | ||||
| 	xx32(pe_allocated); | ||||
| 	xx32(pvg_total); | ||||
| } | ||||
|  | ||||
| static void _xlate_extents(struct pe_disk *extents, uint32_t count) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		extents[i].lv_num = xlate16(extents[i].lv_num); | ||||
| 		extents[i].le_num = xlate16(extents[i].le_num); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Handle both minor metadata formats. | ||||
|  */ | ||||
| static int _munge_formats(struct pv_disk *pvd) | ||||
| { | ||||
| 	uint32_t pe_start; | ||||
| 	int b, e; | ||||
|  | ||||
| 	switch (pvd->version) { | ||||
| 	case 1: | ||||
| 		pvd->pe_start = ((pvd->pe_on_disk.base + | ||||
| 				  pvd->pe_on_disk.size) >> SECTOR_SHIFT); | ||||
| 		break; | ||||
|  | ||||
| 	case 2: | ||||
| 		pvd->version = 1; | ||||
| 		pe_start = pvd->pe_start << SECTOR_SHIFT; | ||||
| 		pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|         /* UUID too long? */ | ||||
|         if (pvd->pv_uuid[ID_LEN]) { | ||||
| 		/* Retain ID_LEN chars from end */ | ||||
|                 for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) { | ||||
|                         if (!pvd->pv_uuid[e]) { | ||||
|                                 e--; | ||||
|                                 break; | ||||
|                         } | ||||
|                 } | ||||
| 		for (b = 0; b < ID_LEN; b++) { | ||||
| 			pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN]; | ||||
| 			/* FIXME Remove all invalid chars */ | ||||
| 			if (pvd->pv_uuid[b] == '/') | ||||
| 				pvd->pv_uuid[b] = '#'; | ||||
| 		} | ||||
| 		memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN); | ||||
|         } | ||||
|  | ||||
| 	/* If UUID is missing, create one */ | ||||
| 	if (pvd->pv_uuid[0] == '\0') | ||||
| 		uuid_from_num(pvd->pv_uuid, pvd->pv_number); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /*  | ||||
|  * If exported, remove "PV_EXP" from end of VG name  | ||||
|  */ | ||||
| static void _munge_exported_vg(struct pv_disk *pvd) | ||||
| { | ||||
| 	int l; | ||||
| 	size_t s; | ||||
|  | ||||
| 	/* Return if PV not in a VG */ | ||||
| 	if ((!*pvd->vg_name)) | ||||
| 		return; | ||||
| 	/* FIXME also check vgd->status & VG_EXPORTED? */ | ||||
|  | ||||
| 	l = strlen(pvd->vg_name); | ||||
| 	s = sizeof(EXPORTED_TAG); | ||||
| 	if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) { | ||||
| 		pvd->vg_name[l - s + 1] = '\0'; | ||||
|                 pvd->pv_status |= VG_EXPORTED; | ||||
|         } | ||||
| } | ||||
|  | ||||
| int munge_pvd(struct device *dev, struct pv_disk *pvd) | ||||
| { | ||||
| 	_xlate_pvd(pvd); | ||||
|  | ||||
| 	if (pvd->id[0] != 'H' || pvd->id[1] != 'M') { | ||||
| 		log_very_verbose("%s does not have a valid LVM1 PV identifier", | ||||
| 				 dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_munge_formats(pvd)) { | ||||
| 		log_very_verbose("format1: Unknown metadata version %d " | ||||
| 				 "found on %s", pvd->version, dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* If VG is exported, set VG name back to the real name */ | ||||
| 	_munge_exported_vg(pvd); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_pvd(struct device *dev, struct pv_disk *pvd) | ||||
| { | ||||
| 	if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) { | ||||
| 		log_very_verbose("Failed to read PV data from %s", | ||||
| 				 dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return munge_pvd(dev, pvd); | ||||
| } | ||||
|  | ||||
| static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) | ||||
| { | ||||
| 	if (!dev_read(dev, pos, sizeof(*disk), disk)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_lvd(disk); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_vgd(struct disk_list *data) | ||||
| { | ||||
| 	struct vg_disk *vgd = &data->vgd; | ||||
| 	uint64_t pos = data->pvd.vg_on_disk.base; | ||||
| 	if (!dev_read(data->dev, pos, sizeof(*vgd), vgd)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_vgd(vgd); | ||||
|  | ||||
| 	if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV)) | ||||
| 		fail; | ||||
| 		 | ||||
| 	/* If UUID is missing, create one */ | ||||
| 	if (vgd->vg_uuid[0] == '\0') | ||||
| 		uuid_from_num(vgd->vg_uuid, vgd->vg_number); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_uuids(struct disk_list *data) | ||||
| { | ||||
| 	int num_read = 0; | ||||
| 	struct uuid_list *ul; | ||||
| 	char buffer[NAME_LEN]; | ||||
| 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; | ||||
| 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; | ||||
|  | ||||
| 	while (pos < end && num_read < data->vgd.pv_cur) { | ||||
| 		if (!dev_read(data->dev, pos, sizeof(buffer), buffer)) | ||||
| 			fail; | ||||
|  | ||||
| 		if (!(ul = pool_alloc(data->mem, sizeof(*ul)))) | ||||
| 			fail; | ||||
|  | ||||
| 		memcpy(ul->uuid, buffer, NAME_LEN); | ||||
| 		ul->uuid[NAME_LEN - 1] = '\0'; | ||||
|  | ||||
| 		list_add(&data->uuids, &ul->list); | ||||
|  | ||||
| 		pos += NAME_LEN; | ||||
| 		num_read++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static inline int _check_lvd(struct lv_disk *lvd) | ||||
| { | ||||
| 	return !(lvd->lv_name[0] == '\0'); | ||||
| } | ||||
|  | ||||
| static int _read_lvs(struct disk_list *data) | ||||
| { | ||||
| 	unsigned int i, read = 0; | ||||
| 	uint64_t pos; | ||||
| 	struct lvd_list *ll; | ||||
| 	struct vg_disk *vgd = &data->vgd; | ||||
|  | ||||
| 	for (i = 0; (i < vgd->lv_max) && (read < vgd->lv_cur); i++) { | ||||
| 		pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); | ||||
| 		ll = pool_alloc(data->mem, sizeof(*ll)); | ||||
|  | ||||
| 		if (!ll) | ||||
| 			fail; | ||||
|  | ||||
| 		if (!_read_lvd(data->dev, pos, &ll->lvd)) | ||||
| 			fail; | ||||
|  | ||||
| 		if (!_check_lvd(&ll->lvd)) | ||||
| 			continue; | ||||
|  | ||||
| 		read++; | ||||
| 		list_add(&data->lvds, &ll->list); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_extents(struct disk_list *data) | ||||
| { | ||||
| 	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; | ||||
| 	struct pe_disk *extents = pool_alloc(data->mem, len); | ||||
| 	uint64_t pos = data->pvd.pe_on_disk.base; | ||||
|  | ||||
| 	if (!extents) | ||||
| 		fail; | ||||
|  | ||||
| 	if (!dev_read(data->dev, pos, len, extents)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_extents(extents, data->pvd.pe_total); | ||||
| 	data->extents = extents; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct disk_list *__read_disk(const struct format_type *fmt, | ||||
| 				     struct device *dev, struct pool *mem, | ||||
| 				     const char *vg_name) | ||||
| { | ||||
| 	struct disk_list *dl = pool_alloc(mem, sizeof(*dl)); | ||||
| 	const char *name = dev_name(dev); | ||||
| 	struct lvmcache_info *info; | ||||
|  | ||||
| 	if (!dl) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	dl->dev = dev; | ||||
| 	dl->mem = mem; | ||||
| 	list_init(&dl->uuids); | ||||
| 	list_init(&dl->lvds); | ||||
|  | ||||
| 	if (!_read_pvd(dev, &dl->pvd)) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev, | ||||
| 				  dl->pvd.vg_name, NULL))) | ||||
| 		stack; | ||||
| 	else { | ||||
| 		info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT; | ||||
| 		list_init(&info->mdas); | ||||
| 		info->status &= ~CACHE_INVALID; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * is it an orphan ? | ||||
| 	 */ | ||||
| 	if (!*dl->pvd.vg_name) { | ||||
| 		log_very_verbose("%s is not a member of any format1 VG", name); | ||||
|  | ||||
| 		/* Update VG cache */ | ||||
| 		/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */ | ||||
|  | ||||
| 		return (vg_name) ? NULL : dl; | ||||
| 	} | ||||
|  | ||||
| 	if (!_read_vgd(dl)) { | ||||
| 		log_error("Failed to read VG data from PV (%s)", name); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	/* Update VG cache with what we found */ | ||||
| 	/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */ | ||||
|  | ||||
| 	if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) { | ||||
| 		log_very_verbose("%s is not a member of the VG %s", | ||||
| 				 name, vg_name); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!_read_uuids(dl)) { | ||||
| 		log_error("Failed to read PV uuid list from %s", name); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!_read_lvs(dl)) { | ||||
| 		log_error("Failed to read LV's from %s", name); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!_read_extents(dl)) { | ||||
| 		log_error("Failed to read extents from %s", name); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Found %s in %sVG %s", name, | ||||
| 			 (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "", | ||||
| 			 dl->pvd.vg_name); | ||||
|  | ||||
| 	return dl; | ||||
|  | ||||
|       bad: | ||||
| 	pool_free(dl->mem, dl); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, | ||||
| 			    struct pool *mem, const char *vg_name) | ||||
| { | ||||
| 	struct disk_list *r; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	r = __read_disk(fmt, dev, mem, vg_name); | ||||
|  | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static void _add_pv_to_list(struct list *head, struct disk_list *data) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct pv_disk *pvd; | ||||
|  | ||||
| 	list_iterate(pvdh, head) { | ||||
| 		pvd = &list_item(pvdh, struct disk_list)->pvd; | ||||
| 		if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid, | ||||
| 			     sizeof(pvd->pv_uuid))) { | ||||
| 			if (MAJOR(data->dev->dev) != md_major()) { | ||||
| 				log_very_verbose("Ignoring duplicate PV %s on " | ||||
| 						 "%s", pvd->pv_uuid, | ||||
| 						 dev_name(data->dev)); | ||||
| 				return; | ||||
| 			} | ||||
| 			log_very_verbose("Duplicate PV %s - using md %s", | ||||
| 					 pvd->pv_uuid, dev_name(data->dev)); | ||||
| 			list_del(pvdh); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	list_add(head, &data->list); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Build a list of pv_d's structures, allocated from mem. | ||||
|  * We keep track of the first object allocated form the pool | ||||
|  * so we can free off all the memory if something goes wrong. | ||||
|  */ | ||||
| int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, | ||||
| 		   struct dev_filter *filter, struct pool *mem, | ||||
| 		   struct list *head) | ||||
| { | ||||
| 	struct dev_iter *iter; | ||||
| 	struct device *dev; | ||||
| 	struct disk_list *data = NULL; | ||||
| 	struct list *vgih; | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
|  | ||||
| 	/* Fast path if we already saw this VG and cached the list of PVs */ | ||||
| 	if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) && | ||||
| 	    vginfo->infos.n) { | ||||
| 		list_iterate(vgih, &vginfo->infos) { | ||||
| 			dev = list_item(vgih, struct lvmcache_info)->dev; | ||||
| 			if (dev && !(data = read_disk(fmt, dev, mem, vg_name))) | ||||
| 				break; | ||||
| 			_add_pv_to_list(head, data); | ||||
| 		} | ||||
|  | ||||
| 		/* Did we find the whole VG? */ | ||||
| 		if (!vg_name || !*vg_name || | ||||
| 		    (data && *data->pvd.vg_name && | ||||
| 		     list_size(head) == data->vgd.pv_cur)) | ||||
| 			return 1; | ||||
|  | ||||
| 		/* Failed */ | ||||
| 		list_init(head); | ||||
| 		/* vgcache_del(vg_name); */ | ||||
| 	} | ||||
|  | ||||
| 	if (!(iter = dev_iter_create(filter))) { | ||||
| 		log_error("read_pvs_in_vg: dev_iter_create failed"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Otherwise do a complete scan */ | ||||
| 	for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { | ||||
| 		if ((data = read_disk(fmt, dev, mem, vg_name))) { | ||||
| 			_add_pv_to_list(head, data); | ||||
| 		} | ||||
| 	} | ||||
| 	dev_iter_destroy(iter); | ||||
|  | ||||
| 	if (list_empty(head)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_vgd(struct disk_list *data) | ||||
| { | ||||
| 	struct vg_disk *vgd = &data->vgd; | ||||
| 	uint64_t pos = data->pvd.vg_on_disk.base; | ||||
|  | ||||
| 	_xlate_vgd(vgd); | ||||
| 	if (!dev_write(data->dev, pos, sizeof(*vgd), vgd)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_vgd(vgd); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_uuids(struct disk_list *data) | ||||
| { | ||||
| 	struct uuid_list *ul; | ||||
| 	struct list *uh; | ||||
| 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; | ||||
| 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; | ||||
|  | ||||
| 	list_iterate(uh, &data->uuids) { | ||||
| 		if (pos >= end) { | ||||
| 			log_error("Too many uuids to fit on %s", | ||||
| 				  dev_name(data->dev)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		ul = list_item(uh, struct uuid_list); | ||||
| 		if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid)) | ||||
| 			fail; | ||||
|  | ||||
| 		pos += NAME_LEN; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) | ||||
| { | ||||
| 	_xlate_lvd(disk); | ||||
| 	if (!dev_write(dev, pos, sizeof(*disk), disk)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_lvd(disk); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_lvs(struct disk_list *data) | ||||
| { | ||||
| 	struct list *lvh; | ||||
| 	uint64_t pos, offset; | ||||
|  | ||||
| 	pos = data->pvd.lv_on_disk.base; | ||||
|  | ||||
| 	if (!dev_zero(data->dev, pos, data->pvd.lv_on_disk.size)) { | ||||
| 		log_error("Couldn't zero lv area on device '%s'", | ||||
| 			  dev_name(data->dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate(lvh, &data->lvds) { | ||||
| 		struct lvd_list *ll = list_item(lvh, struct lvd_list); | ||||
|  | ||||
| 		offset = sizeof(struct lv_disk) * ll->lvd.lv_number; | ||||
| 		if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) { | ||||
| 			log_error("lv_number %d too large", ll->lvd.lv_number); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (!_write_lvd(data->dev, pos + offset, &ll->lvd)) | ||||
| 			fail; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_extents(struct disk_list *data) | ||||
| { | ||||
| 	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; | ||||
| 	struct pe_disk *extents = data->extents; | ||||
| 	uint64_t pos = data->pvd.pe_on_disk.base; | ||||
|  | ||||
| 	_xlate_extents(extents, data->pvd.pe_total); | ||||
| 	if (!dev_write(data->dev, pos, len, extents)) | ||||
| 		fail; | ||||
|  | ||||
| 	_xlate_extents(extents, data->pvd.pe_total); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _write_pvd(struct disk_list *data) | ||||
| { | ||||
| 	char *buf; | ||||
| 	uint64_t pos = data->pvd.pv_on_disk.base; | ||||
| 	size_t size = data->pvd.pv_on_disk.size; | ||||
|  | ||||
| 	if (size < sizeof(struct pv_disk)) { | ||||
| 		log_error("Invalid PV structure size."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Make sure that the gap between the PV structure and | ||||
| 	   the next one is zeroed in order to make non LVM tools | ||||
| 	   happy (idea from AED) */ | ||||
| 	buf = dbg_malloc(size); | ||||
| 	if (!buf) { | ||||
| 		log_err("Couldn't allocate temporary PV buffer."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	memset(buf, 0, size); | ||||
| 	memcpy(buf, &data->pvd, sizeof(struct pv_disk)); | ||||
|  | ||||
| 	_xlate_pvd((struct pv_disk *) buf); | ||||
| 	if (!dev_write(data->dev, pos, size, buf)) { | ||||
| 		dbg_free(buf); | ||||
| 		fail; | ||||
| 	} | ||||
|  | ||||
| 	dbg_free(buf); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * assumes the device has been opened. | ||||
|  */ | ||||
| static int __write_all_pvd(const struct format_type *fmt, | ||||
| 			   struct disk_list *data) | ||||
| { | ||||
| 	const char *pv_name = dev_name(data->dev); | ||||
|  | ||||
| 	if (!_write_pvd(data)) { | ||||
| 		log_error("Failed to write PV structure onto %s", pv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */ | ||||
| 	/* | ||||
| 	 * Stop here for orphan pv's. | ||||
| 	 */ | ||||
| 	if (data->pvd.vg_name[0] == '\0') { | ||||
| 		/* if (!test_mode()) | ||||
| 		   vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */ | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	/* if (!test_mode()) | ||||
| 	   vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, | ||||
| 	   fmt); */ | ||||
|  | ||||
| 	if (!_write_vgd(data)) { | ||||
| 		log_error("Failed to write VG data to %s", pv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_write_uuids(data)) { | ||||
| 		log_error("Failed to write PV uuid list to %s", pv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_write_lvs(data)) { | ||||
| 		log_error("Failed to write LV's to %s", pv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_write_extents(data)) { | ||||
| 		log_error("Failed to write extents to %s", pv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * opens the device and hands to the above fn. | ||||
|  */ | ||||
| static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	if (!dev_open(data->dev)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	r = __write_all_pvd(fmt, data); | ||||
|  | ||||
| 	if (!dev_close(data->dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Writes all the given pv's to disk.  Does very | ||||
|  * little sanity checking, so make sure correct | ||||
|  * data is passed to here. | ||||
|  */ | ||||
| int write_disks(const struct format_type *fmt, struct list *pvs) | ||||
| { | ||||
| 	struct list *pvh; | ||||
| 	struct disk_list *dl; | ||||
|  | ||||
| 	list_iterate(pvh, pvs) { | ||||
| 		dl = list_item(pvh, struct disk_list); | ||||
| 		if (!(_write_all_pvd(fmt, dl))) | ||||
| 			fail; | ||||
|  | ||||
| 		log_very_verbose("Successfully wrote data to %s", | ||||
| 				 dev_name(dl->dev)); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										248
									
								
								lib/format1/disk-rep.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								lib/format1/disk-rep.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,248 @@ | ||||
| /* | ||||
|  * 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 DISK_REP_FORMAT1_H | ||||
| #define DISK_REP_FORMAT1_H | ||||
|  | ||||
| #include "lvm-types.h" | ||||
| #include "metadata.h" | ||||
| #include "pool.h" | ||||
| #include "toolcontext.h" | ||||
|  | ||||
| #define MAX_PV 256 | ||||
| #define MAX_LV 256 | ||||
| #define MAX_VG 99 | ||||
|  | ||||
| #define LVM_BLK_MAJOR 58 | ||||
|  | ||||
| #define MAX_PV_SIZE	((uint32_t) -1)	/* 2TB in sectors - 1 */ | ||||
| #define MIN_PE_SIZE	(8192L >> SECTOR_SHIFT)	/* 8 KB in sectors */ | ||||
| #define MAX_PE_SIZE	(16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L) | ||||
| #define PE_SIZE_PV_SIZE_REL 5	/* PV size must be at least 5 times PE size */ | ||||
| #define	MAX_LE_TOTAL	65534	/* 2^16 - 2 */ | ||||
| #define	MAX_PE_TOTAL	((uint32_t) -2) | ||||
|  | ||||
| #define UNMAPPED_EXTENT 0 | ||||
|  | ||||
| /* volume group */ | ||||
| #define	VG_ACTIVE            0x01	/* vg_status */ | ||||
| #define	VG_EXPORTED          0x02	/*     "     */ | ||||
| #define	VG_EXTENDABLE        0x04	/*     "     */ | ||||
|  | ||||
| #define	VG_READ              0x01	/* vg_access */ | ||||
| #define	VG_WRITE             0x02	/*     "     */ | ||||
| #define	VG_CLUSTERED         0x04	/*     "     */ | ||||
| #define	VG_SHARED            0x08	/*     "     */ | ||||
|  | ||||
| /* logical volume */ | ||||
| #define	LV_ACTIVE            0x01	/* lv_status */ | ||||
| #define	LV_SPINDOWN          0x02	/*     "     */ | ||||
| #define LV_PERSISTENT_MINOR  0x04	/*     "     */ | ||||
|  | ||||
| #define	LV_READ              0x01	/* lv_access */ | ||||
| #define	LV_WRITE             0x02	/*     "     */ | ||||
| #define	LV_SNAPSHOT          0x04	/*     "     */ | ||||
| #define	LV_SNAPSHOT_ORG      0x08	/*     "     */ | ||||
|  | ||||
| #define	LV_BADBLOCK_ON       0x01	/* lv_badblock */ | ||||
|  | ||||
| #define	LV_STRICT            0x01	/* lv_allocation */ | ||||
| #define	LV_CONTIGUOUS        0x02	/*       "       */ | ||||
|  | ||||
| /* physical volume */ | ||||
| #define	PV_ACTIVE            0x01	/* pv_status */ | ||||
| #define	PV_ALLOCATABLE       0x02	/* pv_allocatable */ | ||||
|  | ||||
| #define EXPORTED_TAG "PV_EXP"	/* Identifier for exported PV */ | ||||
| #define IMPORTED_TAG "PV_IMP"	/* Identifier for imported PV */ | ||||
|  | ||||
| struct data_area { | ||||
| 	uint32_t base; | ||||
| 	uint32_t size; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| struct pv_disk { | ||||
| 	uint8_t id[2]; | ||||
| 	uint16_t version;	/* lvm version */ | ||||
| 	struct data_area pv_on_disk; | ||||
| 	struct data_area vg_on_disk; | ||||
| 	struct data_area pv_uuidlist_on_disk; | ||||
| 	struct data_area lv_on_disk; | ||||
| 	struct data_area pe_on_disk; | ||||
| 	uint8_t pv_uuid[NAME_LEN]; | ||||
| 	uint8_t vg_name[NAME_LEN]; | ||||
| 	uint8_t system_id[NAME_LEN];	/* for vgexport/vgimport */ | ||||
| 	uint32_t pv_major; | ||||
| 	uint32_t pv_number; | ||||
| 	uint32_t pv_status; | ||||
| 	uint32_t pv_allocatable; | ||||
| 	uint32_t pv_size; | ||||
| 	uint32_t lv_cur; | ||||
| 	uint32_t pe_size; | ||||
| 	uint32_t pe_total; | ||||
| 	uint32_t pe_allocated; | ||||
|  | ||||
| 	/* only present on version == 2 pv's */ | ||||
| 	uint32_t pe_start; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| struct lv_disk { | ||||
| 	uint8_t lv_name[NAME_LEN]; | ||||
| 	uint8_t vg_name[NAME_LEN]; | ||||
| 	uint32_t lv_access; | ||||
| 	uint32_t lv_status; | ||||
| 	uint32_t lv_open; | ||||
| 	uint32_t lv_dev; | ||||
| 	uint32_t lv_number; | ||||
| 	uint32_t lv_mirror_copies;	/* for future use */ | ||||
| 	uint32_t lv_recovery;	/*       "        */ | ||||
| 	uint32_t lv_schedule;	/*       "        */ | ||||
| 	uint32_t lv_size; | ||||
| 	uint32_t lv_snapshot_minor;	/* minor number of original */ | ||||
| 	uint16_t lv_chunk_size;	/* chunk size of snapshot */ | ||||
| 	uint16_t dummy; | ||||
| 	uint32_t lv_allocated_le; | ||||
| 	uint32_t lv_stripes; | ||||
| 	uint32_t lv_stripesize; | ||||
| 	uint32_t lv_badblock;	/* for future use */ | ||||
| 	uint32_t lv_allocation; | ||||
| 	uint32_t lv_io_timeout;	/* for future use */ | ||||
| 	uint32_t lv_read_ahead; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| struct vg_disk { | ||||
| 	uint8_t vg_uuid[ID_LEN];	/* volume group UUID */ | ||||
| 	uint8_t vg_name_dummy[NAME_LEN - ID_LEN];	/* rest of v1 VG name */ | ||||
| 	uint32_t vg_number;	/* volume group number */ | ||||
| 	uint32_t vg_access;	/* read/write */ | ||||
| 	uint32_t vg_status;	/* active or not */ | ||||
| 	uint32_t lv_max;	/* maximum logical volumes */ | ||||
| 	uint32_t lv_cur;	/* current logical volumes */ | ||||
| 	uint32_t lv_open;	/* open logical volumes */ | ||||
| 	uint32_t pv_max;	/* maximum physical volumes */ | ||||
| 	uint32_t pv_cur;	/* current physical volumes FU */ | ||||
| 	uint32_t pv_act;	/* active physical volumes */ | ||||
| 	uint32_t dummy; | ||||
| 	uint32_t vgda;		/* volume group descriptor arrays FU */ | ||||
| 	uint32_t pe_size;	/* physical extent size in sectors */ | ||||
| 	uint32_t pe_total;	/* total of physical extents */ | ||||
| 	uint32_t pe_allocated;	/* allocated physical extents */ | ||||
| 	uint32_t pvg_total;	/* physical volume groups FU */ | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| struct pe_disk { | ||||
| 	uint16_t lv_num; | ||||
| 	uint16_t le_num; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| struct uuid_list { | ||||
| 	struct list list; | ||||
| 	char uuid[NAME_LEN]; | ||||
| }; | ||||
|  | ||||
| struct lvd_list { | ||||
| 	struct list list; | ||||
| 	struct lv_disk lvd; | ||||
| }; | ||||
|  | ||||
| struct disk_list { | ||||
| 	struct list list; | ||||
| 	struct pool *mem; | ||||
| 	struct device *dev; | ||||
|  | ||||
| 	struct pv_disk pvd; | ||||
| 	struct vg_disk vgd; | ||||
| 	struct list uuids; | ||||
| 	struct list lvds; | ||||
| 	struct pe_disk *extents; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Layout constants. | ||||
|  */ | ||||
| #define METADATA_ALIGN 4096UL | ||||
|  | ||||
| #define	METADATA_BASE 0UL | ||||
| #define	PV_SIZE 1024UL | ||||
| #define	VG_SIZE 4096UL | ||||
|  | ||||
| /* | ||||
|  * Functions to calculate layout info. | ||||
|  */ | ||||
| int calculate_layout(struct disk_list *dl); | ||||
| int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, | ||||
| 			   uint32_t max_extent_count, uint64_t pe_start); | ||||
|  | ||||
| /* | ||||
|  * Low level io routines which read/write | ||||
|  * disk_lists. | ||||
|  */ | ||||
|  | ||||
| struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, | ||||
| 			    struct pool *mem, const char *vg_name); | ||||
|  | ||||
| int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, | ||||
| 		   struct dev_filter *filter, | ||||
| 		   struct pool *mem, struct list *results); | ||||
|  | ||||
| int write_disks(const struct format_type *fmt, struct list *pvds); | ||||
|  | ||||
| /* | ||||
|  * Functions to translate to between disk and in | ||||
|  * core structures. | ||||
|  */ | ||||
| int import_pv(struct pool *mem, struct device *dev, | ||||
| 	      struct volume_group *vg, | ||||
| 	      struct physical_volume *pv, struct pv_disk *pvd); | ||||
| int export_pv(struct cmd_context *cmd, struct pool *mem, | ||||
| 	      struct volume_group *vg, | ||||
| 	      struct pv_disk *pvd, struct physical_volume *pv); | ||||
|  | ||||
| int import_vg(struct pool *mem, | ||||
| 	      struct volume_group *vg, struct disk_list *dl, int partial); | ||||
| int export_vg(struct vg_disk *vgd, struct volume_group *vg); | ||||
|  | ||||
| int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd); | ||||
|  | ||||
| int import_extents(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		   struct list *pvds); | ||||
| int export_extents(struct disk_list *dl, uint32_t lv_num, | ||||
| 		   struct logical_volume *lv, struct physical_volume *pv); | ||||
|  | ||||
| int import_pvs(const struct format_type *fmt, struct pool *mem, | ||||
| 	       struct volume_group *vg, | ||||
| 	       struct list *pvds, struct list *results, int *count); | ||||
|  | ||||
| int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds); | ||||
| int export_lvs(struct disk_list *dl, struct volume_group *vg, | ||||
| 	       struct physical_volume *pv, const char *dev_dir); | ||||
|  | ||||
| int import_snapshots(struct pool *mem, struct volume_group *vg, | ||||
| 		     struct list *pvds); | ||||
|  | ||||
| int export_uuids(struct disk_list *dl, struct volume_group *vg); | ||||
|  | ||||
| void export_numbers(struct list *pvds, struct volume_group *vg); | ||||
|  | ||||
| void export_pv_act(struct list *pvds); | ||||
| int munge_pvd(struct device *dev, struct pv_disk *pvd); | ||||
|  | ||||
| /* blech */ | ||||
| int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, | ||||
| 		       const char *candidate_vg, int *result); | ||||
| int export_vg_number(struct format_instance *fid, struct list *pvds, | ||||
| 		     const char *vg_name, struct dev_filter *filter); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										582
									
								
								lib/format1/format1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								lib/format1/format1.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,582 @@ | ||||
| /* | ||||
|  * 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 "disk-rep.h" | ||||
| #include "pool.h" | ||||
| #include "hash.h" | ||||
| #include "limits.h" | ||||
| #include "list.h" | ||||
| #include "display.h" | ||||
| #include "toolcontext.h" | ||||
| #include "lvmcache.h" | ||||
| #include "lvm1-label.h" | ||||
| #include "format1.h" | ||||
|  | ||||
| #define FMT_LVM1_NAME "lvm1" | ||||
|  | ||||
| /* VG consistency checks */ | ||||
| static int _check_vgs(struct list *pvs, int *partial) | ||||
| { | ||||
| 	struct list *pvh, *t; | ||||
| 	struct disk_list *dl = NULL; | ||||
| 	struct disk_list *first = NULL; | ||||
|  | ||||
| 	uint32_t pv_count = 0; | ||||
| 	uint32_t exported = 0; | ||||
| 	int first_time = 1; | ||||
|  | ||||
| 	*partial = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * If there are exported and unexported PVs, ignore exported ones. | ||||
| 	 * This means an active VG won't be affected if disks are inserted | ||||
| 	 * bearing an exported VG with the same name. | ||||
| 	 */ | ||||
| 	list_iterate(pvh, pvs) { | ||||
| 		dl = list_item(pvh, struct disk_list); | ||||
|  | ||||
| 		if (first_time) { | ||||
| 			exported = dl->pvd.pv_status & VG_EXPORTED; | ||||
| 			first_time = 0; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (exported != (dl->pvd.pv_status & VG_EXPORTED)) { | ||||
| 			/* Remove exported PVs */ | ||||
| 			list_iterate_safe(pvh, t, pvs) { | ||||
| 				dl = list_item(pvh, struct disk_list); | ||||
| 				if (dl->pvd.pv_status & VG_EXPORTED) | ||||
| 					list_del(pvh); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Remove any PVs with VG structs that differ from the first */ | ||||
| 	list_iterate_safe(pvh, t, pvs) { | ||||
| 		dl = list_item(pvh, struct disk_list); | ||||
|  | ||||
| 		if (!first) | ||||
| 			first = dl; | ||||
|  | ||||
| 		else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) { | ||||
| 			log_error("VG data differs between PVs %s and %s", | ||||
| 				  dev_name(first->dev), dev_name(dl->dev)); | ||||
| 			log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32 | ||||
| 				  "  %" PRIu32 " %" PRIu32 " %" PRIu32 " %" | ||||
| 				  PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 | ||||
| 				  " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" | ||||
| 				  PRIu32 " %" PRIu32 " %" PRIu32, | ||||
| 				  dev_name(first->dev), first->vgd.vg_uuid, | ||||
| 				  first->vgd.vg_name_dummy, | ||||
| 				  first->vgd.vg_number, first->vgd.vg_access, | ||||
| 				  first->vgd.vg_status, first->vgd.lv_max, | ||||
| 				  first->vgd.lv_cur, first->vgd.lv_open, | ||||
| 				  first->vgd.pv_max, first->vgd.pv_cur, | ||||
| 				  first->vgd.pv_act, first->vgd.dummy, | ||||
| 				  first->vgd.vgda, first->vgd.pe_size, | ||||
| 				  first->vgd.pe_total, first->vgd.pe_allocated, | ||||
| 				  first->vgd.pvg_total); | ||||
| 			log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32 | ||||
| 				  "  %" PRIu32 " %" PRIu32 " %" PRIu32 " %" | ||||
| 				  PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 | ||||
| 				  " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" | ||||
| 				  PRIu32 " %" PRIu32 " %" PRIu32, | ||||
| 				  dev_name(dl->dev), dl->vgd.vg_uuid, | ||||
| 				  dl->vgd.vg_name_dummy, dl->vgd.vg_number, | ||||
| 				  dl->vgd.vg_access, dl->vgd.vg_status, | ||||
| 				  dl->vgd.lv_max, dl->vgd.lv_cur, | ||||
| 				  dl->vgd.lv_open, dl->vgd.pv_max, | ||||
| 				  dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy, | ||||
| 				  dl->vgd.vgda, dl->vgd.pe_size, | ||||
| 				  dl->vgd.pe_total, dl->vgd.pe_allocated, | ||||
| 				  dl->vgd.pvg_total); | ||||
| 			list_del(pvh); | ||||
| 			if (partial_mode()) { | ||||
| 				*partial = 1; | ||||
| 				continue; | ||||
| 			} | ||||
| 			return 0; | ||||
| 		} | ||||
| 		pv_count++; | ||||
| 	} | ||||
|  | ||||
| 	/* On entry to fn, list known to be non-empty */ | ||||
| 	if (pv_count != first->vgd.pv_cur) { | ||||
| 		log_error("%d PV(s) found for VG %s: expected %d", | ||||
| 			  pv_count, first->pvd.vg_name, first->vgd.pv_cur); | ||||
| 		if (!partial_mode()) | ||||
| 			return 0; | ||||
| 		*partial = 1; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct volume_group *_build_vg(struct format_instance *fid, | ||||
| 				      struct list *pvs) | ||||
| { | ||||
| 	struct pool *mem = fid->fmt->cmd->mem; | ||||
| 	struct volume_group *vg = pool_alloc(mem, sizeof(*vg)); | ||||
| 	struct disk_list *dl; | ||||
| 	int partial; | ||||
|  | ||||
| 	if (!vg) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (list_empty(pvs)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	memset(vg, 0, sizeof(*vg)); | ||||
|  | ||||
| 	vg->cmd = fid->fmt->cmd; | ||||
| 	vg->fid = fid; | ||||
| 	vg->seqno = 0; | ||||
| 	list_init(&vg->pvs); | ||||
| 	list_init(&vg->lvs); | ||||
| 	list_init(&vg->snapshots); | ||||
| 	list_init(&vg->tags); | ||||
|  | ||||
| 	if (!_check_vgs(pvs, &partial)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	dl = list_item(pvs->n, struct disk_list); | ||||
|  | ||||
| 	if (!import_vg(mem, vg, dl, partial)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!import_lvs(mem, vg, pvs)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!import_extents(fid->fmt->cmd, vg, pvs)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!import_snapshots(mem, vg, pvs)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	return vg; | ||||
|  | ||||
|       bad: | ||||
| 	stack; | ||||
| 	pool_free(mem, vg); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static struct volume_group *_vg_read(struct format_instance *fid, | ||||
| 				     const char *vg_name, | ||||
| 				     struct metadata_area *mda) | ||||
| { | ||||
| 	struct pool *mem = pool_create(1024 * 10); | ||||
| 	struct list pvs; | ||||
| 	struct volume_group *vg = NULL; | ||||
| 	list_init(&pvs); | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* Strip dev_dir if present */ | ||||
| 	vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); | ||||
|  | ||||
| 	if (!read_pvs_in_vg | ||||
| 	    (fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!(vg = _build_vg(fid, &pvs))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
|       bad: | ||||
| 	pool_destroy(mem); | ||||
| 	return vg; | ||||
| } | ||||
|  | ||||
| static struct disk_list *_flatten_pv(struct format_instance *fid, | ||||
| 				     struct pool *mem, struct volume_group *vg, | ||||
| 				     struct physical_volume *pv, | ||||
| 				     const char *dev_dir) | ||||
| { | ||||
| 	struct disk_list *dl = pool_alloc(mem, sizeof(*dl)); | ||||
|  | ||||
| 	if (!dl) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	dl->mem = mem; | ||||
| 	dl->dev = pv->dev; | ||||
|  | ||||
| 	list_init(&dl->uuids); | ||||
| 	list_init(&dl->lvds); | ||||
|  | ||||
| 	if (!export_pv(fid->fmt->cmd, mem, vg, &dl->pvd, pv) || | ||||
| 	    !export_vg(&dl->vgd, vg) || | ||||
| 	    !export_uuids(dl, vg) || | ||||
| 	    !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) { | ||||
| 		stack; | ||||
| 		pool_free(mem, dl); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return dl; | ||||
| } | ||||
|  | ||||
| static int _flatten_vg(struct format_instance *fid, struct pool *mem, | ||||
| 		       struct volume_group *vg, | ||||
| 		       struct list *pvds, const char *dev_dir, | ||||
| 		       struct dev_filter *filter) | ||||
| { | ||||
| 	struct list *pvh; | ||||
| 	struct pv_list *pvl; | ||||
| 	struct disk_list *data; | ||||
|  | ||||
| 	list_iterate(pvh, &vg->pvs) { | ||||
| 		pvl = list_item(pvh, struct pv_list); | ||||
|  | ||||
| 		if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		list_add(pvds, &data->list); | ||||
| 	} | ||||
|  | ||||
| 	export_numbers(pvds, vg); | ||||
| 	export_pv_act(pvds); | ||||
|  | ||||
| 	if (!export_vg_number(fid, pvds, vg->name, filter)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _vg_write(struct format_instance *fid, struct volume_group *vg, | ||||
| 		     struct metadata_area *mda) | ||||
| { | ||||
| 	struct pool *mem = pool_create(1024 * 10); | ||||
| 	struct list pvds; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	list_init(&pvds); | ||||
|  | ||||
| 	r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir, | ||||
| 			 fid->fmt->cmd->filter) && | ||||
| 	     write_disks(fid->fmt, &pvds)); | ||||
|  | ||||
| 	lvmcache_update_vg(vg); | ||||
| 	pool_destroy(mem); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _pv_read(const struct format_type *fmt, const char *pv_name, | ||||
| 		    struct physical_volume *pv, struct list *mdas) | ||||
| { | ||||
| 	struct pool *mem = pool_create(1024); | ||||
| 	struct disk_list *dl; | ||||
| 	struct device *dev; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	log_very_verbose("Reading physical volume data %s from disk", pv_name); | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dl = read_disk(fmt, dev, mem, NULL))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	pv->fmt = fmt; | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	pool_destroy(mem); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _pv_setup(const struct format_type *fmt, | ||||
| 		     uint64_t pe_start, uint32_t extent_count, | ||||
| 		     uint32_t extent_size, | ||||
| 		     int pvmetadatacopies, | ||||
| 		     uint64_t pvmetadatasize, struct list *mdas, | ||||
| 		     struct physical_volume *pv, struct volume_group *vg) | ||||
| { | ||||
| 	if (pv->size > MAX_PV_SIZE) | ||||
| 		pv->size--; | ||||
| 	if (pv->size > MAX_PV_SIZE) { | ||||
| 		log_error("Physical volumes cannot be bigger than %s", | ||||
| 			  display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE, | ||||
| 				       SIZE_SHORT)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Nothing more to do if extent size isn't provided */ | ||||
| 	if (!extent_size) | ||||
| 		return 1; | ||||
|  | ||||
| 	/* | ||||
| 	 * This works out pe_start and pe_count. | ||||
| 	 */ | ||||
| 	if (!calculate_extent_count(pv, extent_size, extent_count, pe_start)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Retain existing extent locations exactly */ | ||||
| 	if (((pe_start || extent_count) && (pe_start != pv->pe_start)) || | ||||
| 	    (extent_count && (extent_count != pv->pe_count))) { | ||||
| 		log_error("Metadata would overwrite physical extents"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _lv_setup(struct format_instance *fid, struct logical_volume *lv) | ||||
| { | ||||
| 	uint64_t max_size = UINT_MAX; | ||||
|  | ||||
| 	if (!*lv->lvid.s) | ||||
| 		lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv)); | ||||
|  | ||||
| 	if (lv->le_count > MAX_LE_TOTAL) { | ||||
| 		log_error("logical volumes cannot contain more than " | ||||
| 			  "%d extents.", MAX_LE_TOTAL); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (lv->size > max_size) { | ||||
| 		log_error("logical volumes cannot be larger than %s", | ||||
| 			  display_size(fid->fmt->cmd, max_size, | ||||
| 				       SIZE_SHORT)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, | ||||
| 		     struct list *mdas, int64_t sector) | ||||
| { | ||||
| 	struct pool *mem; | ||||
| 	struct disk_list *dl; | ||||
| 	struct list pvs; | ||||
| 	struct label *label; | ||||
| 	struct lvmcache_info *info; | ||||
|  | ||||
| 	if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev, | ||||
| 				  pv->vg_name, NULL))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	label = info->label; | ||||
| 	info->device_size = pv->size << SECTOR_SHIFT; | ||||
| 	info->fmt = fmt; | ||||
|  | ||||
| 	list_init(&info->mdas); | ||||
|  | ||||
| 	list_init(&pvs); | ||||
|  | ||||
| 	/* Ensure any residual PE structure is gone */ | ||||
| 	pv->pe_size = pv->pe_count = 0; | ||||
| 	pv->pe_start = PE_ALIGN; | ||||
|  | ||||
| 	if (!(mem = pool_create(1024))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dl = pool_alloc(mem, sizeof(*dl)))) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
| 	dl->mem = mem; | ||||
| 	dl->dev = pv->dev; | ||||
|  | ||||
| 	if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	/* must be set to be able to zero gap after PV structure in | ||||
| 	   dev_write in order to make other disk tools happy */ | ||||
| 	dl->pvd.pv_on_disk.base = METADATA_BASE; | ||||
| 	dl->pvd.pv_on_disk.size = PV_SIZE; | ||||
| 	dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT; | ||||
|  | ||||
| 	list_add(&pvs, &dl->list); | ||||
| 	if (!write_disks(fmt, &pvs)) { | ||||
| 		stack; | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	pool_destroy(mem); | ||||
| 	return 1; | ||||
|  | ||||
|       bad: | ||||
| 	pool_destroy(mem); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _vg_setup(struct format_instance *fid, struct volume_group *vg) | ||||
| { | ||||
| 	/* just check max_pv and max_lv */ | ||||
| 	if (!vg->max_lv || vg->max_lv >= MAX_LV) | ||||
| 		vg->max_lv = MAX_LV - 1; | ||||
|  | ||||
| 	if (!vg->max_pv || vg->max_pv >= MAX_PV) | ||||
| 		vg->max_pv = MAX_PV - 1; | ||||
|  | ||||
| 	if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) { | ||||
| 		log_error("Extent size must be between %s and %s", | ||||
| 			  display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE, | ||||
| 				       SIZE_SHORT), | ||||
| 			  display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE, | ||||
| 				       SIZE_SHORT)); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (vg->extent_size % MIN_PE_SIZE) { | ||||
| 		log_error("Extent size must be multiple of %s", | ||||
| 			  display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE, | ||||
| 				       SIZE_SHORT)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Redundant? */ | ||||
| 	if (vg->extent_size & (vg->extent_size - 1)) { | ||||
| 		log_error("Extent size must be power of 2"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct metadata_area_ops _metadata_format1_ops = { | ||||
| 	vg_read:_vg_read, | ||||
| 	vg_write:_vg_write, | ||||
| }; | ||||
|  | ||||
| static struct format_instance *_create_instance(const struct format_type *fmt, | ||||
| 						const char *vgname, | ||||
| 						void *private) | ||||
| { | ||||
| 	struct format_instance *fid; | ||||
| 	struct metadata_area *mda; | ||||
|  | ||||
| 	if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	fid->fmt = fmt; | ||||
| 	list_init(&fid->metadata_areas); | ||||
|  | ||||
| 	/* Define a NULL metadata area */ | ||||
| 	if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) { | ||||
| 		stack; | ||||
| 		pool_free(fmt->cmd->mem, fid); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	mda->ops = &_metadata_format1_ops; | ||||
| 	mda->metadata_locn = NULL; | ||||
| 	list_add(&fid->metadata_areas, &mda->list); | ||||
|  | ||||
| 	return fid; | ||||
| } | ||||
|  | ||||
| static void _destroy_instance(struct format_instance *fid) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| static void _destroy(const struct format_type *fmt) | ||||
| { | ||||
| 	dbg_free((void *) fmt); | ||||
| } | ||||
|  | ||||
| static struct format_handler _format1_ops = { | ||||
| 	pv_read:_pv_read, | ||||
| 	pv_setup:_pv_setup, | ||||
| 	pv_write:_pv_write, | ||||
| 	lv_setup:_lv_setup, | ||||
| 	vg_setup:_vg_setup, | ||||
| 	create_instance:_create_instance, | ||||
| 	destroy_instance:_destroy_instance, | ||||
| 	destroy:_destroy, | ||||
| }; | ||||
|  | ||||
| #ifdef LVM1_INTERNAL | ||||
| struct format_type *init_lvm1_format(struct cmd_context *cmd) | ||||
| #else				/* Shared */ | ||||
| struct format_type *init_format(struct cmd_context *cmd); | ||||
| struct format_type *init_format(struct cmd_context *cmd) | ||||
| #endif | ||||
| { | ||||
| 	struct format_type *fmt = dbg_malloc(sizeof(*fmt)); | ||||
|  | ||||
| 	if (!fmt) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	fmt->cmd = cmd; | ||||
| 	fmt->ops = &_format1_ops; | ||||
| 	fmt->name = FMT_LVM1_NAME; | ||||
| 	fmt->alias = NULL; | ||||
| 	fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE; | ||||
| 	fmt->private = NULL; | ||||
|  | ||||
| 	if (!(fmt->labeller = lvm1_labeller_create(fmt))) { | ||||
| 		log_error("Couldn't create lvm1 label handler."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) { | ||||
| 		log_error("Couldn't register lvm1 label handler."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return fmt; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/format1/format1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/format1/format1.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * 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_FORMAT1_H | ||||
| #define _LVM_FORMAT1_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| #ifdef LVM1_INTERNAL | ||||
| struct format_type *init_lvm1_format(struct cmd_context *cmd); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										736
									
								
								lib/format1/import-export.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										736
									
								
								lib/format1/import-export.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,736 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Translates between disk and in-core formats. | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "disk-rep.h" | ||||
| #include "pool.h" | ||||
| #include "hash.h" | ||||
| #include "list.h" | ||||
| #include "lvm-string.h" | ||||
| #include "filter.h" | ||||
| #include "toolcontext.h" | ||||
| #include "segtypes.h" | ||||
|  | ||||
| #include <time.h> | ||||
|  | ||||
| static int _check_vg_name(const char *name) | ||||
| { | ||||
| 	return strlen(name) < NAME_LEN; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Extracts the last part of a path. | ||||
|  */ | ||||
| static char *_create_lv_name(struct pool *mem, const char *full_name) | ||||
| { | ||||
| 	const char *ptr = strrchr(full_name, '/'); | ||||
|  | ||||
| 	if (!ptr) | ||||
| 		ptr = full_name; | ||||
| 	else | ||||
| 		ptr++; | ||||
|  | ||||
| 	return pool_strdup(mem, ptr); | ||||
| } | ||||
|  | ||||
| int import_pv(struct pool *mem, struct device *dev, | ||||
| 	      struct volume_group *vg, | ||||
| 	      struct physical_volume *pv, struct pv_disk *pvd) | ||||
| { | ||||
| 	memset(pv, 0, sizeof(*pv)); | ||||
| 	memcpy(&pv->id, pvd->pv_uuid, ID_LEN); | ||||
|  | ||||
| 	pv->dev = dev; | ||||
| 	if (!(pv->vg_name = pool_strdup(mem, pvd->vg_name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Store system_id from first PV if PV belongs to a VG */ | ||||
| 	if (vg && !*vg->system_id) | ||||
| 		strncpy(vg->system_id, pvd->system_id, NAME_LEN); | ||||
|  | ||||
| 	if (vg && | ||||
| 	    strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))) | ||||
| 		    log_very_verbose("System ID %s on %s differs from %s for " | ||||
| 				     "volume group", pvd->system_id, | ||||
| 				     dev_name(pv->dev), vg->system_id); | ||||
|  | ||||
| 	/* | ||||
| 	 * If exported, we still need to flag in pv->status too because | ||||
| 	 * we don't always have a struct volume_group when we need this. | ||||
| 	 */ | ||||
| 	if (pvd->pv_status & VG_EXPORTED) | ||||
| 		pv->status |= EXPORTED_VG; | ||||
|  | ||||
| 	if (pvd->pv_allocatable) | ||||
| 		pv->status |= ALLOCATABLE_PV; | ||||
|  | ||||
| 	pv->size = pvd->pv_size; | ||||
| 	pv->pe_size = pvd->pe_size; | ||||
| 	pv->pe_start = pvd->pe_start; | ||||
| 	pv->pe_count = pvd->pe_total; | ||||
| 	pv->pe_alloc_count = pvd->pe_allocated; | ||||
|  | ||||
| 	list_init(&pv->tags); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _system_id(struct cmd_context *cmd, char *s, const char *prefix) | ||||
| { | ||||
|  | ||||
| 	if (lvm_snprintf(s, NAME_LEN, "%s%s%lu", | ||||
| 			 prefix, cmd->hostname, time(NULL)) < 0) { | ||||
| 		log_error("Generated system_id too long"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int export_pv(struct cmd_context *cmd, struct pool *mem, | ||||
| 	      struct volume_group *vg, | ||||
| 	      struct pv_disk *pvd, struct physical_volume *pv) | ||||
| { | ||||
| 	memset(pvd, 0, sizeof(*pvd)); | ||||
|  | ||||
| 	pvd->id[0] = 'H'; | ||||
| 	pvd->id[1] = 'M'; | ||||
| 	pvd->version = 1; | ||||
|  | ||||
| 	memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN); | ||||
|  | ||||
| 	if (!_check_vg_name(pv->vg_name)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	memset(pvd->vg_name, 0, sizeof(pvd->vg_name)); | ||||
|  | ||||
| 	if (pv->vg_name) | ||||
| 		strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name)); | ||||
|  | ||||
| 	/* Preserve existing system_id if it exists */ | ||||
| 	if (vg && *vg->system_id) | ||||
| 		strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id)); | ||||
|  | ||||
| 	/* Is VG already exported or being exported? */ | ||||
| 	if (vg && (vg->status & EXPORTED_VG)) { | ||||
| 		/* Does system_id need setting? */ | ||||
| 		if (!*vg->system_id || | ||||
| 		    strncmp(vg->system_id, EXPORTED_TAG, | ||||
| 			    sizeof(EXPORTED_TAG) - 1)) { | ||||
| 			if (!_system_id(cmd, pvd->system_id, EXPORTED_TAG)) { | ||||
| 				stack; | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		if (strlen(pvd->vg_name) + sizeof(EXPORTED_TAG) > | ||||
| 		    sizeof(pvd->vg_name)) { | ||||
| 			log_error("Volume group name %s too long to export", | ||||
| 				  pvd->vg_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		strcat(pvd->vg_name, EXPORTED_TAG); | ||||
| 	} | ||||
|  | ||||
| 	/* Is VG being imported? */ | ||||
| 	if (vg && !(vg->status & EXPORTED_VG) && *vg->system_id && | ||||
| 	    !strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) { | ||||
| 		if (!_system_id(cmd, pvd->system_id, IMPORTED_TAG)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Generate system_id if PV is in VG */ | ||||
| 	if (!pvd->system_id || !*pvd->system_id) | ||||
| 		if (!_system_id(cmd, pvd->system_id, "")) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 	/* Update internal system_id if we changed it */ | ||||
| 	if (vg && | ||||
| 	    (!*vg->system_id || | ||||
| 	     strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))) | ||||
| 		    strncpy(vg->system_id, pvd->system_id, NAME_LEN); | ||||
|  | ||||
| 	//pvd->pv_major = MAJOR(pv->dev); | ||||
|  | ||||
| 	if (pv->status & ALLOCATABLE_PV) | ||||
| 		pvd->pv_allocatable = PV_ALLOCATABLE; | ||||
|  | ||||
| 	pvd->pv_size = pv->size; | ||||
| 	pvd->lv_cur = 0;	/* this is set when exporting the lv list */ | ||||
| 	if (vg) | ||||
| 		pvd->pe_size = vg->extent_size; | ||||
| 	else | ||||
| 		pvd->pe_size = pv->pe_size; | ||||
| 	pvd->pe_total = pv->pe_count; | ||||
| 	pvd->pe_allocated = pv->pe_alloc_count; | ||||
| 	pvd->pe_start = pv->pe_start; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_vg(struct pool *mem, | ||||
| 	      struct volume_group *vg, struct disk_list *dl, int partial) | ||||
| { | ||||
| 	struct vg_disk *vgd = &dl->vgd; | ||||
| 	memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN); | ||||
|  | ||||
| 	if (!_check_vg_name(dl->pvd.vg_name)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(vg->name = pool_strdup(mem, dl->pvd.vg_name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(vg->system_id = pool_alloc(mem, NAME_LEN))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	*vg->system_id = '\0'; | ||||
|  | ||||
| 	if (vgd->vg_status & VG_EXPORTED) | ||||
| 		vg->status |= EXPORTED_VG; | ||||
|  | ||||
| 	if (vgd->vg_status & VG_EXTENDABLE) | ||||
| 		vg->status |= RESIZEABLE_VG; | ||||
|  | ||||
| 	if (partial || (vgd->vg_access & VG_READ)) | ||||
| 		vg->status |= LVM_READ; | ||||
|  | ||||
| 	if (!partial && (vgd->vg_access & VG_WRITE)) | ||||
| 		vg->status |= LVM_WRITE; | ||||
|  | ||||
| 	if (vgd->vg_access & VG_CLUSTERED) | ||||
| 		vg->status |= CLUSTERED; | ||||
|  | ||||
| 	if (vgd->vg_access & VG_SHARED) | ||||
| 		vg->status |= SHARED; | ||||
|  | ||||
| 	vg->extent_size = vgd->pe_size; | ||||
| 	vg->extent_count = vgd->pe_total; | ||||
| 	vg->free_count = vgd->pe_total - vgd->pe_allocated; | ||||
| 	vg->max_lv = vgd->lv_max; | ||||
| 	vg->max_pv = vgd->pv_max; | ||||
| 	vg->alloc = ALLOC_NORMAL; | ||||
|  | ||||
| 	if (partial) | ||||
| 		vg->status |= PARTIAL_VG; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int export_vg(struct vg_disk *vgd, struct volume_group *vg) | ||||
| { | ||||
| 	memset(vgd, 0, sizeof(*vgd)); | ||||
| 	memcpy(vgd->vg_uuid, vg->id.uuid, ID_LEN); | ||||
|  | ||||
| 	if (vg->status & LVM_READ) | ||||
| 		vgd->vg_access |= VG_READ; | ||||
|  | ||||
| 	if (vg->status & LVM_WRITE) | ||||
| 		vgd->vg_access |= VG_WRITE; | ||||
|  | ||||
| 	if (vg->status & CLUSTERED) | ||||
| 		vgd->vg_access |= VG_CLUSTERED; | ||||
|  | ||||
| 	if (vg->status & SHARED) | ||||
| 		vgd->vg_access |= VG_SHARED; | ||||
|  | ||||
| 	if (vg->status & EXPORTED_VG) | ||||
| 		vgd->vg_status |= VG_EXPORTED; | ||||
|  | ||||
| 	if (vg->status & RESIZEABLE_VG) | ||||
| 		vgd->vg_status |= VG_EXTENDABLE; | ||||
|  | ||||
| 	vgd->lv_max = vg->max_lv; | ||||
| 	vgd->lv_cur = vg->lv_count; | ||||
|  | ||||
| 	vgd->pv_max = vg->max_pv; | ||||
| 	vgd->pv_cur = vg->pv_count; | ||||
|  | ||||
| 	vgd->pe_size = vg->extent_size; | ||||
| 	vgd->pe_total = vg->extent_count; | ||||
| 	vgd->pe_allocated = vg->extent_count - vg->free_count; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd) | ||||
| { | ||||
| 	lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number); | ||||
|  | ||||
| 	if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	lv->status |= VISIBLE_LV; | ||||
|  | ||||
| 	if (lvd->lv_status & LV_SPINDOWN) | ||||
| 		lv->status |= SPINDOWN_LV; | ||||
|  | ||||
| 	if (lvd->lv_status & LV_PERSISTENT_MINOR) { | ||||
| 		lv->status |= FIXED_MINOR; | ||||
| 		lv->minor = MINOR(lvd->lv_dev); | ||||
| 		lv->major = MAJOR(lvd->lv_dev); | ||||
| 	} else { | ||||
| 		lv->major = -1; | ||||
| 		lv->minor = -1; | ||||
| 	} | ||||
|  | ||||
| 	if (lvd->lv_access & LV_READ) | ||||
| 		lv->status |= LVM_READ; | ||||
|  | ||||
| 	if (lvd->lv_access & LV_WRITE) | ||||
| 		lv->status |= LVM_WRITE; | ||||
|  | ||||
| 	if (lvd->lv_badblock) | ||||
| 		lv->status |= BADBLOCK_ON; | ||||
|  | ||||
| 	/* Drop the unused LV_STRICT here */ | ||||
| 	if (lvd->lv_allocation & LV_CONTIGUOUS) | ||||
| 		lv->alloc = ALLOC_CONTIGUOUS; | ||||
| 	else | ||||
| 		lv->alloc = ALLOC_NORMAL; | ||||
|  | ||||
| 	lv->read_ahead = lvd->lv_read_ahead; | ||||
| 	lv->size = lvd->lv_size; | ||||
| 	lv->le_count = lvd->lv_allocated_le; | ||||
|  | ||||
| 	list_init(&lv->segments); | ||||
| 	list_init(&lv->tags); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _export_lv(struct lv_disk *lvd, struct volume_group *vg, | ||||
| 		       struct logical_volume *lv, const char *dev_dir) | ||||
| { | ||||
| 	memset(lvd, 0, sizeof(*lvd)); | ||||
| 	snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s", | ||||
| 		 dev_dir, vg->name, lv->name); | ||||
|  | ||||
| 	strcpy(lvd->vg_name, vg->name); | ||||
|  | ||||
| 	if (lv->status & LVM_READ) | ||||
| 		lvd->lv_access |= LV_READ; | ||||
|  | ||||
| 	if (lv->status & LVM_WRITE) | ||||
| 		lvd->lv_access |= LV_WRITE; | ||||
|  | ||||
| 	if (lv->status & SPINDOWN_LV) | ||||
| 		lvd->lv_status |= LV_SPINDOWN; | ||||
|  | ||||
| 	if (lv->status & FIXED_MINOR) { | ||||
| 		lvd->lv_status |= LV_PERSISTENT_MINOR; | ||||
| 		lvd->lv_dev = MKDEV(lv->major, lv->minor); | ||||
| 	} else { | ||||
| 		lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid)); | ||||
| 	} | ||||
|  | ||||
| 	lvd->lv_read_ahead = lv->read_ahead; | ||||
| 	lvd->lv_stripes = | ||||
| 	    list_item(lv->segments.n, struct lv_segment)->area_count; | ||||
| 	lvd->lv_stripesize = | ||||
| 	    list_item(lv->segments.n, struct lv_segment)->stripe_size; | ||||
|  | ||||
| 	lvd->lv_size = lv->size; | ||||
| 	lvd->lv_allocated_le = lv->le_count; | ||||
|  | ||||
| 	if (lv->status & BADBLOCK_ON) | ||||
| 		lvd->lv_badblock = LV_BADBLOCK_ON; | ||||
|  | ||||
| 	if (lv->alloc == ALLOC_CONTIGUOUS) | ||||
| 		lvd->lv_allocation |= LV_CONTIGUOUS; | ||||
| } | ||||
|  | ||||
| int export_extents(struct disk_list *dl, uint32_t lv_num, | ||||
| 		   struct logical_volume *lv, struct physical_volume *pv) | ||||
| { | ||||
| 	struct list *segh; | ||||
| 	struct pe_disk *ped; | ||||
| 	struct lv_segment *seg; | ||||
| 	uint32_t pe, s; | ||||
|  | ||||
| 	list_iterate(segh, &lv->segments) { | ||||
| 		seg = list_item(segh, struct lv_segment); | ||||
|  | ||||
| 		for (s = 0; s < seg->area_count; s++) { | ||||
| 			if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { | ||||
| 				log_error("Segment type %s in LV %s: " | ||||
| 					  "unsupported by format1", | ||||
| 					  seg->segtype->name, lv->name); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if (seg->area[s].type != AREA_PV) { | ||||
| 				log_error("LV stripe found in LV %s: " | ||||
| 					  "unsupported by format1", lv->name); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if (seg->area[s].u.pv.pv != pv) | ||||
| 				continue;	/* not our pv */ | ||||
|  | ||||
| 			for (pe = 0; pe < (seg->len / seg->area_count); pe++) { | ||||
| 				ped = &dl->extents[pe + seg->area[s].u.pv.pe]; | ||||
| 				ped->lv_num = lv_num; | ||||
| 				ped->le_num = (seg->le / seg->area_count) + pe + | ||||
| 				    s * (lv->le_count / seg->area_count); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_pvs(const struct format_type *fmt, struct pool *mem, | ||||
| 	       struct volume_group *vg, | ||||
| 	       struct list *pvds, struct list *results, int *count) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	struct pv_list *pvl; | ||||
|  | ||||
| 	*count = 0; | ||||
| 	list_iterate(pvdh, pvds) { | ||||
|  | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
|  | ||||
| 		if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) || | ||||
| 		    !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		pvl->pv->fmt = fmt; | ||||
| 		list_add(results, &pvl->list); | ||||
| 		(*count)++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct logical_volume *_add_lv(struct pool *mem, | ||||
| 				      struct volume_group *vg, | ||||
| 				      struct lv_disk *lvd) | ||||
| { | ||||
| 	struct lv_list *ll; | ||||
| 	struct logical_volume *lv; | ||||
|  | ||||
| 	if (!(ll = pool_zalloc(mem, sizeof(*ll))) || | ||||
| 	    !(ll->lv = pool_zalloc(mem, sizeof(*ll->lv)))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	lv = ll->lv; | ||||
| 	lv->vg = vg; | ||||
|  | ||||
| 	if (!import_lv(mem, lv, lvd)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_add(&vg->lvs, &ll->list); | ||||
| 	vg->lv_count++; | ||||
|  | ||||
| 	return lv; | ||||
| } | ||||
|  | ||||
| int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds) | ||||
| { | ||||
| 	struct disk_list *dl; | ||||
| 	struct lvd_list *ll; | ||||
| 	struct lv_disk *lvd; | ||||
| 	struct list *pvdh, *lvdh; | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		list_iterate(lvdh, &dl->lvds) { | ||||
| 			ll = list_item(lvdh, struct lvd_list); | ||||
| 			lvd = &ll->lvd; | ||||
|  | ||||
| 			if (!find_lv(vg, lvd->lv_name) && | ||||
| 			    !_add_lv(mem, vg, lvd)) { | ||||
| 				stack; | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* FIXME: tidy */ | ||||
| int export_lvs(struct disk_list *dl, struct volume_group *vg, | ||||
| 	       struct physical_volume *pv, const char *dev_dir) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	struct list *lvh, *sh; | ||||
| 	struct lv_list *ll; | ||||
| 	struct lvd_list *lvdl; | ||||
| 	size_t len; | ||||
| 	uint32_t lv_num; | ||||
| 	struct hash_table *lvd_hash; | ||||
|  | ||||
| 	if (!_check_vg_name(vg->name)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(lvd_hash = hash_create(32))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * setup the pv's extents array | ||||
| 	 */ | ||||
| 	len = sizeof(struct pe_disk) * dl->pvd.pe_total; | ||||
| 	if (!(dl->extents = pool_alloc(dl->mem, len))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	memset(dl->extents, 0, len); | ||||
|  | ||||
| 	list_iterate(lvh, &vg->lvs) { | ||||
| 		ll = list_item(lvh, struct lv_list); | ||||
| 		if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) { | ||||
| 			stack; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); | ||||
|  | ||||
| 		lv_num = lvnum_from_lvid(&ll->lv->lvid); | ||||
|  | ||||
| 		lvdl->lvd.lv_number = lv_num; | ||||
|  | ||||
| 		if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) { | ||||
| 			stack; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		if (!export_extents(dl, lv_num + 1, ll->lv, pv)) { | ||||
| 			stack; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		list_add(&dl->lvds, &lvdl->list); | ||||
| 		dl->pvd.lv_cur++; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Now we need to run through the snapshots, exporting | ||||
| 	 * the SNAPSHOT_ORG flags etc. | ||||
| 	 */ | ||||
| 	list_iterate(sh, &vg->snapshots) { | ||||
| 		struct lv_disk *org, *cow; | ||||
| 		struct snapshot *s = list_item(sh, | ||||
| 					       struct snapshot_list)->snapshot; | ||||
|  | ||||
| 		if (!(org = hash_lookup(lvd_hash, s->origin->name))) { | ||||
| 			log_err("Couldn't find snapshot origin '%s'.", | ||||
| 				s->origin->name); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		if (!(cow = hash_lookup(lvd_hash, s->cow->name))) { | ||||
| 			log_err("Couldn't find snapshot cow store '%s'.", | ||||
| 				s->cow->name); | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		org->lv_access |= LV_SNAPSHOT_ORG; | ||||
| 		cow->lv_access |= LV_SNAPSHOT; | ||||
| 		cow->lv_snapshot_minor = org->lv_number; | ||||
| 		cow->lv_chunk_size = s->chunk_size; | ||||
| 	} | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	hash_destroy(lvd_hash); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * FIXME: More inefficient code. | ||||
|  */ | ||||
| int import_snapshots(struct pool *mem, struct volume_group *vg, | ||||
| 		     struct list *pvds) | ||||
| { | ||||
| 	struct logical_volume *lvs[MAX_LV]; | ||||
| 	struct list *pvdh, *lvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	struct lv_disk *lvd; | ||||
| 	int lvnum; | ||||
| 	struct logical_volume *org, *cow; | ||||
|  | ||||
| 	/* build an index of lv numbers */ | ||||
| 	memset(lvs, 0, sizeof(lvs)); | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
|  | ||||
| 		list_iterate(lvdh, &dl->lvds) { | ||||
| 			lvd = &(list_item(lvdh, struct lvd_list)->lvd); | ||||
|  | ||||
| 			lvnum = lvd->lv_number; | ||||
|  | ||||
| 			if (lvnum > MAX_LV) { | ||||
| 				log_err("Logical volume number " | ||||
| 					"out of bounds."); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			if (!lvs[lvnum] && | ||||
| 			    !(lvs[lvnum] = find_lv(vg, lvd->lv_name))) { | ||||
| 				log_err("Couldn't find logical volume '%s'.", | ||||
| 					lvd->lv_name); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Now iterate through yet again adding the snapshots. | ||||
| 	 */ | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
|  | ||||
| 		list_iterate(lvdh, &dl->lvds) { | ||||
| 			lvd = &(list_item(lvdh, struct lvd_list)->lvd); | ||||
|  | ||||
| 			if (!(lvd->lv_access & LV_SNAPSHOT)) | ||||
| 				continue; | ||||
|  | ||||
| 			lvnum = lvd->lv_number; | ||||
| 			cow = lvs[lvnum]; | ||||
| 			if (!(org = lvs[lvd->lv_snapshot_minor])) { | ||||
| 				log_err("Couldn't find origin logical volume " | ||||
| 					"for snapshot '%s'.", lvd->lv_name); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			/* we may have already added this snapshot */ | ||||
| 			if (lv_is_cow(cow)) | ||||
| 				continue; | ||||
|  | ||||
| 			/* insert the snapshot */ | ||||
| 			if (!vg_add_snapshot(org, cow, 1, NULL, | ||||
| 					     lvd->lv_chunk_size)) { | ||||
| 				log_err("Couldn't add snapshot."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int export_uuids(struct disk_list *dl, struct volume_group *vg) | ||||
| { | ||||
| 	struct uuid_list *ul; | ||||
| 	struct pv_list *pvl; | ||||
| 	struct list *pvh; | ||||
|  | ||||
| 	list_iterate(pvh, &vg->pvs) { | ||||
| 		pvl = list_item(pvh, struct pv_list); | ||||
| 		if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		memset(ul->uuid, 0, sizeof(ul->uuid)); | ||||
| 		memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN); | ||||
|  | ||||
| 		list_add(&dl->uuids, &ul->list); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This calculates the nasty pv_number field | ||||
|  * used by LVM1. | ||||
|  */ | ||||
| void export_numbers(struct list *pvds, struct volume_group *vg) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	int pv_num = 1; | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		dl->pvd.pv_number = pv_num++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Calculate vg_disk->pv_act. | ||||
|  */ | ||||
| void export_pv_act(struct list *pvds) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	int act = 0; | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		if (dl->pvd.pv_status & PV_ACTIVE) | ||||
| 			act++; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		dl->vgd.pv_act = act; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int export_vg_number(struct format_instance *fid, struct list *pvds, | ||||
| 		     const char *vg_name, struct dev_filter *filter) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	int vg_num; | ||||
|  | ||||
| 	if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		dl->vgd.vg_number = vg_num; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										381
									
								
								lib/format1/import-extents.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								lib/format1/import-extents.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,381 @@ | ||||
| /* | ||||
|  * 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 "hash.h" | ||||
| #include "pool.h" | ||||
| #include "disk-rep.h" | ||||
| #include "lv_alloc.h" | ||||
| #include "display.h" | ||||
| #include "segtypes.h" | ||||
|  | ||||
| /* | ||||
|  * After much thought I have decided it is easier, | ||||
|  * and probably no less efficient, to convert the | ||||
|  * pe->le map to a full le->pe map, and then | ||||
|  * process this to get the segments form that | ||||
|  * we're after.  Any code which goes directly from | ||||
|  * the pe->le map to segments would be gladly | ||||
|  * accepted, if it is less complicated than this | ||||
|  * file. | ||||
|  */ | ||||
| struct pe_specifier { | ||||
| 	struct physical_volume *pv; | ||||
| 	uint32_t pe; | ||||
| }; | ||||
|  | ||||
| struct lv_map { | ||||
| 	struct logical_volume *lv; | ||||
| 	uint32_t stripes; | ||||
| 	uint32_t stripe_size; | ||||
| 	struct pe_specifier *map; | ||||
| }; | ||||
|  | ||||
| static struct hash_table *_create_lv_maps(struct pool *mem, | ||||
| 					  struct volume_group *vg) | ||||
| { | ||||
| 	struct hash_table *maps = hash_create(32); | ||||
| 	struct list *llh; | ||||
| 	struct lv_list *ll; | ||||
| 	struct lv_map *lvm; | ||||
|  | ||||
| 	if (!maps) { | ||||
| 		log_err("Unable to create hash table for holding " | ||||
| 			"extent maps."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate(llh, &vg->lvs) { | ||||
| 		ll = list_item(llh, struct lv_list); | ||||
|  | ||||
| 		if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) { | ||||
| 			stack; | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		lvm->lv = ll->lv; | ||||
| 		if (!(lvm->map = pool_zalloc(mem, sizeof(*lvm->map) | ||||
| 					     * ll->lv->le_count))) { | ||||
| 			stack; | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		if (!hash_insert(maps, ll->lv->name, lvm)) { | ||||
| 			stack; | ||||
| 			goto bad; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return maps; | ||||
|  | ||||
|       bad: | ||||
| 	hash_destroy(maps); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static int _fill_lv_array(struct lv_map **lvs, | ||||
| 			  struct hash_table *maps, struct disk_list *dl) | ||||
| { | ||||
| 	struct list *lvh; | ||||
| 	struct lv_map *lvm; | ||||
|  | ||||
| 	memset(lvs, 0, sizeof(*lvs) * MAX_LV); | ||||
| 	list_iterate(lvh, &dl->lvds) { | ||||
| 		struct lvd_list *ll = list_item(lvh, struct lvd_list); | ||||
|  | ||||
| 		if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/') | ||||
| 					+ 1))) { | ||||
| 			log_err("Physical volume (%s) contains an " | ||||
| 				"unknown logical volume (%s).", | ||||
| 				dev_name(dl->dev), ll->lvd.lv_name); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		lvm->stripes = ll->lvd.lv_stripes; | ||||
| 		lvm->stripe_size = ll->lvd.lv_stripesize; | ||||
|  | ||||
| 		lvs[ll->lvd.lv_number] = lvm; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _fill_maps(struct hash_table *maps, struct volume_group *vg, | ||||
| 		      struct list *pvds) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct disk_list *dl; | ||||
| 	struct physical_volume *pv; | ||||
| 	struct lv_map *lvms[MAX_LV], *lvm; | ||||
| 	struct pe_disk *e; | ||||
| 	uint32_t i, lv_num, le; | ||||
|  | ||||
| 	list_iterate(pvdh, pvds) { | ||||
| 		dl = list_item(pvdh, struct disk_list); | ||||
| 		pv = find_pv(vg, dl->dev); | ||||
| 		e = dl->extents; | ||||
|  | ||||
| 		/* build an array of lv's for this pv */ | ||||
| 		if (!_fill_lv_array(lvms, maps, dl)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		for (i = 0; i < dl->pvd.pe_total; i++) { | ||||
| 			lv_num = e[i].lv_num; | ||||
|  | ||||
| 			if (lv_num == UNMAPPED_EXTENT) | ||||
| 				continue; | ||||
|  | ||||
| 			else { | ||||
| 				lv_num--; | ||||
| 				lvm = lvms[lv_num]; | ||||
|  | ||||
| 				if (!lvm) { | ||||
| 					log_err("invalid lv in extent map"); | ||||
| 					return 0; | ||||
| 				} | ||||
|  | ||||
| 				le = e[i].le_num; | ||||
|  | ||||
| 				if (le >= lvm->lv->le_count) { | ||||
| 					log_err("logical extent number " | ||||
| 						"out of bounds"); | ||||
| 					return 0; | ||||
| 				} | ||||
|  | ||||
| 				if (lvm->map[le].pv) { | ||||
| 					log_err("logical extent (%u) " | ||||
| 						"already mapped.", le); | ||||
| 					return 0; | ||||
| 				} | ||||
|  | ||||
| 				lvm->map[le].pv = pv; | ||||
| 				lvm->map[le].pe = i; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _check_single_map(struct lv_map *lvm) | ||||
| { | ||||
| 	uint32_t i; | ||||
|  | ||||
| 	for (i = 0; i < lvm->lv->le_count; i++) { | ||||
| 		if (!lvm->map[i].pv) { | ||||
| 			log_err("Logical volume (%s) contains an incomplete " | ||||
| 				"mapping table.", lvm->lv->name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _check_maps_are_complete(struct hash_table *maps) | ||||
| { | ||||
| 	struct hash_node *n; | ||||
| 	struct lv_map *lvm; | ||||
|  | ||||
| 	for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) { | ||||
| 		lvm = (struct lv_map *) hash_get_data(maps, n); | ||||
|  | ||||
| 		if (!_check_single_map(lvm)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) | ||||
| { | ||||
| 	uint32_t le = 0; | ||||
| 	struct lv_segment *seg; | ||||
|  | ||||
| 	while (le < lvm->lv->le_count) { | ||||
| 		seg = alloc_lv_segment(cmd->mem, 1); | ||||
|  | ||||
| 		seg->lv = lvm->lv; | ||||
| 		if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		seg->le = le; | ||||
| 		seg->len = 0; | ||||
| 		seg->area_len = 0; | ||||
| 		seg->stripe_size = 0; | ||||
|  | ||||
| 		seg->area[0].type = AREA_PV; | ||||
| 		seg->area[0].u.pv.pv = lvm->map[le].pv; | ||||
| 		seg->area[0].u.pv.pe = lvm->map[le].pe; | ||||
|  | ||||
| 		do { | ||||
| 			seg->len++; | ||||
| 			seg->area_len++; | ||||
| 		} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) && | ||||
| 			 (seg->area[0].u.pv.pv && | ||||
| 			  lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe + | ||||
| 			  seg->len)); | ||||
|  | ||||
| 		le += seg->len; | ||||
|  | ||||
| 		list_add(&lvm->lv->segments, &seg->list); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg, | ||||
| 			 uint32_t base_le, uint32_t len) | ||||
| { | ||||
| 	uint32_t le, st; | ||||
|  | ||||
| 	le = base_le + seg->len; | ||||
|  | ||||
| 	/* | ||||
| 	 * Is the next physical extent in every stripe adjacent to the last? | ||||
| 	 */ | ||||
| 	for (st = 0; st < seg->area_count; st++) | ||||
| 		if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) || | ||||
| 		    (seg->area[st].u.pv.pv && | ||||
| 		     lvm->map[le + st * len].pe != | ||||
| 		     seg->area[st].u.pv.pe + seg->len)) return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) | ||||
| { | ||||
| 	uint32_t st, le = 0, len; | ||||
| 	struct lv_segment *seg; | ||||
|  | ||||
| 	/* | ||||
| 	 * Work out overall striped length | ||||
| 	 */ | ||||
| 	if (lvm->lv->le_count % lvm->stripes) { | ||||
| 		log_error("Number of stripes (%u) incompatible " | ||||
| 			  "with logical extent count (%u) for %s", | ||||
| 			  lvm->stripes, lvm->lv->le_count, lvm->lv->name); | ||||
| 	} | ||||
| 	len = lvm->lv->le_count / lvm->stripes; | ||||
|  | ||||
| 	while (le < len) { | ||||
| 		if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		seg->lv = lvm->lv; | ||||
| 		if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		seg->stripe_size = lvm->stripe_size; | ||||
| 		seg->le = seg->area_count * le; | ||||
| 		seg->len = 1; | ||||
| 		seg->area_len = 1; | ||||
|  | ||||
| 		/* | ||||
| 		 * Set up start positions of each stripe in this segment | ||||
| 		 */ | ||||
| 		for (st = 0; st < seg->area_count; st++) { | ||||
| 			seg->area[st].u.pv.pv = lvm->map[le + st * len].pv; | ||||
| 			seg->area[st].u.pv.pe = lvm->map[le + st * len].pe; | ||||
| 		} | ||||
|  | ||||
| 		/*  | ||||
| 		 * Find how many blocks are contiguous in all stripes | ||||
| 		 * and so can form part of this segment | ||||
| 		 */ | ||||
| 		while (_check_stripe(lvm, seg, le, len)) { | ||||
| 			seg->len++; | ||||
| 			seg->area_len++; | ||||
| 		} | ||||
|  | ||||
| 		le += seg->len; | ||||
| 		seg->len *= seg->area_count; | ||||
|  | ||||
| 		list_add(&lvm->lv->segments, &seg->list); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm) | ||||
| { | ||||
| 	return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) : | ||||
| 		_read_linear(cmd, lvm)); | ||||
| } | ||||
|  | ||||
| static int _build_all_segments(struct cmd_context *cmd, struct hash_table *maps) | ||||
| { | ||||
| 	struct hash_node *n; | ||||
| 	struct lv_map *lvm; | ||||
|  | ||||
| 	for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) { | ||||
| 		lvm = (struct lv_map *) hash_get_data(maps, n); | ||||
| 		if (!_build_segments(cmd, lvm)) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_extents(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		   struct list *pvds) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	struct pool *scratch = pool_create(10 * 1024); | ||||
| 	struct hash_table *maps; | ||||
|  | ||||
| 	if (!scratch) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(maps = _create_lv_maps(scratch, vg))) { | ||||
| 		log_err("Couldn't allocate logical volume maps."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!_fill_maps(maps, vg, pvds)) { | ||||
| 		log_err("Couldn't fill logical volume maps."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!_build_all_segments(cmd, maps)) { | ||||
| 		log_err("Couldn't build extent segments."); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	if (maps) | ||||
| 		hash_destroy(maps); | ||||
| 	pool_destroy(scratch); | ||||
| 	return r; | ||||
| } | ||||
							
								
								
									
										172
									
								
								lib/format1/layout.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								lib/format1/layout.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| /* | ||||
|  * 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 "disk-rep.h" | ||||
|  | ||||
| /* | ||||
|  * Only works with powers of 2. | ||||
|  */ | ||||
| static inline uint32_t _round_up(uint32_t n, uint32_t size) | ||||
| { | ||||
| 	size--; | ||||
| 	return (n + size) & ~size; | ||||
| } | ||||
|  | ||||
| static inline uint32_t _div_up(uint32_t n, uint32_t size) | ||||
| { | ||||
| 	return _round_up(n, size) / size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Each chunk of metadata should be aligned to | ||||
|  * METADATA_ALIGN. | ||||
|  */ | ||||
| static uint32_t _next_base(struct data_area *area) | ||||
| { | ||||
| 	return _round_up(area->base + area->size, METADATA_ALIGN); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Quick calculation based on pe_start. | ||||
|  */ | ||||
| static int _adjust_pe_on_disk(struct pv_disk *pvd) | ||||
| { | ||||
| 	uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT; | ||||
|  | ||||
| 	if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size) | ||||
| 		return 0; | ||||
|  | ||||
| 	pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _calc_simple_layout(struct pv_disk *pvd) | ||||
| { | ||||
| 	pvd->pv_on_disk.base = METADATA_BASE; | ||||
| 	pvd->pv_on_disk.size = PV_SIZE; | ||||
|  | ||||
| 	pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk); | ||||
| 	pvd->vg_on_disk.size = VG_SIZE; | ||||
|  | ||||
| 	pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk); | ||||
| 	pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN; | ||||
|  | ||||
| 	pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk); | ||||
| 	pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk); | ||||
|  | ||||
| 	pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk); | ||||
| 	pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk); | ||||
| } | ||||
|  | ||||
| static int _check_vg_limits(struct disk_list *dl) | ||||
| { | ||||
| 	if (dl->vgd.lv_max > MAX_LV) { | ||||
| 		log_error("MaxLogicalVolumes of %d exceeds format limit of %d " | ||||
| 			  "for VG '%s'", dl->vgd.lv_max, MAX_LV - 1, | ||||
| 			  dl->pvd.vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dl->vgd.pv_max > MAX_PV) { | ||||
| 		log_error("MaxPhysicalVolumes of %d exceeds format limit of %d " | ||||
| 			  "for VG '%s'", dl->vgd.pv_max, MAX_PV - 1, | ||||
| 			  dl->pvd.vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This assumes pe_count and pe_start have already | ||||
|  * been calculated correctly. | ||||
|  */ | ||||
| int calculate_layout(struct disk_list *dl) | ||||
| { | ||||
| 	struct pv_disk *pvd = &dl->pvd; | ||||
|  | ||||
| 	_calc_simple_layout(pvd); | ||||
| 	if (!_adjust_pe_on_disk(pvd)) { | ||||
| 		log_error("Insufficient space for metadata and PE's."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_check_vg_limits(dl)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * The number of extents that can fit on a disk is metadata format dependant. | ||||
|  * pe_start is any existing value for pe_start | ||||
|  */ | ||||
| int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size, | ||||
| 			   uint32_t max_extent_count, uint64_t pe_start) | ||||
| { | ||||
| 	struct pv_disk *pvd = dbg_malloc(sizeof(*pvd)); | ||||
| 	uint32_t end; | ||||
|  | ||||
| 	if (!pvd) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Guess how many extents will fit, bearing in mind that | ||||
| 	 * one is going to be knocked off at the start of the | ||||
| 	 * next loop. | ||||
| 	 */ | ||||
| 	if (max_extent_count) | ||||
| 		pvd->pe_total = max_extent_count + 1; | ||||
| 	else | ||||
| 		pvd->pe_total = (pv->size / extent_size); | ||||
|  | ||||
| 	if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) { | ||||
| 		log_error("Too few extents on %s.  Try smaller extent size.", | ||||
| 			  dev_name(pv->dev)); | ||||
| 		dbg_free(pvd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		pvd->pe_total--; | ||||
| 		_calc_simple_layout(pvd); | ||||
| 		end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + | ||||
| 			SECTOR_SIZE - 1) >> SECTOR_SHIFT); | ||||
|  | ||||
| 		if (pe_start && end < pe_start) | ||||
| 			end = pe_start; | ||||
|  | ||||
| 		pvd->pe_start = _round_up(end, PE_ALIGN); | ||||
|  | ||||
| 	} while ((pvd->pe_start + (pvd->pe_total * extent_size)) | ||||
| 		 > pv->size); | ||||
|  | ||||
| 	if (pvd->pe_total > MAX_PE_TOTAL) { | ||||
| 		log_error("Metadata extent limit (%u) exceeded for %s - " | ||||
| 			  "%u required", MAX_PE_TOTAL, dev_name(pv->dev), | ||||
| 			  pvd->pe_total); | ||||
| 		dbg_free(pvd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pv->pe_count = pvd->pe_total; | ||||
| 	pv->pe_start = pvd->pe_start; | ||||
| 	/* We can't set pe_size here without breaking LVM1 compatibility */ | ||||
| 	dbg_free(pvd); | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										119
									
								
								lib/format1/lvm1-label.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								lib/format1/lvm1-label.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| /* | ||||
|  * 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 "lib.h" | ||||
| #include "lvm1-label.h" | ||||
| #include "disk-rep.h" | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "xlate.h" | ||||
| #include "lvmcache.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| static void _not_supported(const char *op) | ||||
| { | ||||
| 	log_err("The '%s' operation is not supported for the lvm1 labeller.", | ||||
| 		op); | ||||
| } | ||||
|  | ||||
| static int _can_handle(struct labeller *l, char *buf, uint64_t sector) | ||||
| { | ||||
| 	struct pv_disk *pvd = (struct pv_disk *) buf; | ||||
| 	uint32_t version; | ||||
|  | ||||
| 	/* LVM1 label must always be in first sector */ | ||||
| 	if (sector) | ||||
| 		return 0; | ||||
|  | ||||
| 	version = xlate16(pvd->version); | ||||
|  | ||||
| 	if (pvd->id[0] == 'H' && pvd->id[1] == 'M' && | ||||
| 	    (version == 1 || version == 2)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _write(struct label *label, char *buf) | ||||
| { | ||||
| 	_not_supported("write"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _read(struct labeller *l, struct device *dev, char *buf, | ||||
| 		 struct label **label) | ||||
| { | ||||
| 	struct pv_disk *pvd = (struct pv_disk *) buf; | ||||
| 	struct lvmcache_info *info; | ||||
|  | ||||
| 	munge_pvd(dev, pvd); | ||||
|  | ||||
| 	if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*label = info->label; | ||||
|  | ||||
| 	info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT; | ||||
| 	list_init(&info->mdas); | ||||
|  | ||||
| 	info->status &= ~CACHE_INVALID; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _initialise_label(struct labeller *l, struct label *label) | ||||
| { | ||||
| 	strcpy(label->type, "LVM1"); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _destroy_label(struct labeller *l, struct label *label) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| static void _destroy(struct labeller *l) | ||||
| { | ||||
| 	dbg_free(l); | ||||
| } | ||||
|  | ||||
| struct label_ops _lvm1_ops = { | ||||
| 	can_handle:_can_handle, | ||||
| 	write:_write, | ||||
| 	read:_read, | ||||
| 	verify:_can_handle, | ||||
| 	initialise_label:_initialise_label, | ||||
| 	destroy_label:_destroy_label, | ||||
| 	destroy:_destroy | ||||
| }; | ||||
|  | ||||
| struct labeller *lvm1_labeller_create(struct format_type *fmt) | ||||
| { | ||||
| 	struct labeller *l; | ||||
|  | ||||
| 	if (!(l = dbg_malloc(sizeof(*l)))) { | ||||
| 		log_err("Couldn't allocate labeller object."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	l->ops = &_lvm1_ops; | ||||
| 	l->private = (const void *) fmt; | ||||
|  | ||||
| 	return l; | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/format1/lvm1-label.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/format1/lvm1-label.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * 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_LVM1_LABEL_H | ||||
| #define _LVM_LVM1_LABEL_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| struct labeller *lvm1_labeller_create(struct format_type *fmt); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										69
									
								
								lib/format1/vg_number.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								lib/format1/vg_number.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| /* | ||||
|  * 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 "disk-rep.h" | ||||
|  | ||||
| /* | ||||
|  * FIXME: Quick hack.  We can use caching to | ||||
|  * prevent a total re-read, even so vg_number | ||||
|  * causes the tools to check *every* pv.  Yuck. | ||||
|  * Put in separate file so it wouldn't contaminate | ||||
|  * other code. | ||||
|  */ | ||||
| int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, | ||||
| 		       const char *candidate_vg, int *result) | ||||
| { | ||||
| 	struct list *pvh; | ||||
| 	struct list all_pvs; | ||||
| 	struct disk_list *dl; | ||||
| 	struct pool *mem = pool_create(10 * 1024); | ||||
| 	int numbers[MAX_VG], i, r = 0; | ||||
|  | ||||
| 	list_init(&all_pvs); | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	memset(numbers, 0, sizeof(numbers)); | ||||
|  | ||||
| 	list_iterate(pvh, &all_pvs) { | ||||
| 		dl = list_item(pvh, struct disk_list); | ||||
| 		if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg)) | ||||
| 			continue; | ||||
|  | ||||
| 		numbers[dl->vgd.vg_number] = 1; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < MAX_VG; i++) { | ||||
| 		if (!numbers[i]) { | ||||
| 			r = 1; | ||||
| 			*result = i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|       out: | ||||
| 	pool_destroy(mem); | ||||
| 	return r; | ||||
| } | ||||
							
								
								
									
										1
									
								
								lib/format_pool/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								lib/format_pool/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| init_format | ||||
							
								
								
									
										37
									
								
								lib/format_pool/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/format_pool/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # | ||||
| # Copyright (C) 2003-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@ | ||||
|  | ||||
| SOURCES =\ | ||||
| 	disk_rep.c \ | ||||
| 	format_pool.c \ | ||||
| 	import_export.c \ | ||||
| 	pool_label.c | ||||
|  | ||||
| LIB_SHARED = liblvm2formatpool.so | ||||
|  | ||||
| include ../../make.tmpl | ||||
|  | ||||
| .PHONY: install | ||||
|  | ||||
| install: liblvm2formatpool.so | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/liblvm2formatpool.so.$(LIB_VERSION) | ||||
| 	$(LN_S) -f liblvm2formatpool.so.$(LIB_VERSION) \ | ||||
| 		$(libdir)/liblvm2formatpool.so | ||||
|  | ||||
|  | ||||
							
								
								
									
										385
									
								
								lib/format_pool/disk_rep.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								lib/format_pool/disk_rep.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,385 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "pool.h" | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "lvmcache.h" | ||||
| #include "filter.h" | ||||
| #include "list.h" | ||||
| #include "xlate.h" | ||||
|  | ||||
| #include "disk_rep.h" | ||||
|  | ||||
| /* FIXME: memcpy might not be portable */ | ||||
| #define CPIN_8(x, y, z) {memcpy((x), (y), (z));} | ||||
| #define CPOUT_8(x, y, z) {memcpy((y), (x), (z));} | ||||
| #define CPIN_16(x, y) {(x) = xlate16_be((y));} | ||||
| #define CPOUT_16(x, y) {(y) = xlate16_be((x));} | ||||
| #define CPIN_32(x, y) {(x) = xlate32_be((y));} | ||||
| #define CPOUT_32(x, y) {(y) = xlate32_be((x));} | ||||
| #define CPIN_64(x, y) {(x) = xlate64_be((y));} | ||||
| #define CPOUT_64(x, y) {(y) = xlate64_be((x));} | ||||
|  | ||||
| static int __read_pool_disk(const struct format_type *fmt, struct device *dev, | ||||
| 			    struct pool *mem, struct pool_list *pl, | ||||
| 			    const char *vg_name) | ||||
| { | ||||
| 	char buf[512]; | ||||
|  | ||||
| 	/* FIXME: Need to check the cache here first */ | ||||
| 	if (!dev_read(dev, UINT64_C(0), 512, buf)) { | ||||
| 		log_very_verbose("Failed to read PV data from %s", | ||||
| 				 dev_name(dev)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _add_pl_to_list(struct list *head, struct pool_list *data) | ||||
| { | ||||
| 	struct list *pvdh; | ||||
| 	struct pool_list *pl; | ||||
|  | ||||
| 	list_iterate(pvdh, head) { | ||||
| 		pl = list_item(pvdh, struct pool_list); | ||||
|  | ||||
| 		if (id_equal(&data->pv_uuid, &pl->pv_uuid)) { | ||||
| 			char uuid[ID_LEN + 7]; | ||||
|  | ||||
| 			id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7); | ||||
|  | ||||
| 			if (MAJOR(data->dev->dev) != md_major()) { | ||||
| 				log_very_verbose("Ignoring duplicate PV %s on " | ||||
| 						 "%s", uuid, | ||||
| 						 dev_name(data->dev)); | ||||
| 				return; | ||||
| 			} | ||||
| 			log_very_verbose("Duplicate PV %s - using md %s", | ||||
| 					 uuid, dev_name(data->dev)); | ||||
| 			list_del(pvdh); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	list_add(head, &data->list); | ||||
| } | ||||
|  | ||||
| int read_pool_label(struct pool_list *pl, struct labeller *l, | ||||
| 		    struct device *dev, char *buf, struct label **label) | ||||
| { | ||||
| 	struct lvmcache_info *info; | ||||
| 	struct id pvid; | ||||
| 	struct id vgid; | ||||
| 	char uuid[ID_LEN + 7]; | ||||
| 	struct pool_disk *pd = &pl->pd; | ||||
|  | ||||
| 	pool_label_in(pd, buf); | ||||
|  | ||||
| 	get_pool_pv_uuid(&pvid, pd); | ||||
| 	id_write_format(&pvid, uuid, ID_LEN + 7); | ||||
| 	log_debug("Calculated uuid %s for %s", uuid, dev_name(dev)); | ||||
|  | ||||
| 	get_pool_vg_uuid(&vgid, pd); | ||||
| 	id_write_format(&vgid, uuid, ID_LEN + 7); | ||||
| 	log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name); | ||||
|  | ||||
| 	if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name, | ||||
| 				  (char *) &vgid))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (label) | ||||
| 		*label = info->label; | ||||
|  | ||||
| 	info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT; | ||||
| 	list_init(&info->mdas); | ||||
|  | ||||
| 	info->status &= ~CACHE_INVALID; | ||||
|  | ||||
| 	pl->dev = dev; | ||||
| 	pl->pv = NULL; | ||||
| 	memcpy(&pl->pv_uuid, &pvid, sizeof(pvid)); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * pool_label_out - copies a pool_label_t into a char buffer | ||||
|  * @pl: ptr to a pool_label_t struct | ||||
|  * @buf: ptr to raw space where label info will be copied | ||||
|  * | ||||
|  * This function is important because it takes care of all of | ||||
|  * the endian issues when copying to disk.  This way, when | ||||
|  * machines of different architectures are used, they will | ||||
|  * be able to interpret ondisk labels correctly.  Always use | ||||
|  * this function before writing to disk. | ||||
|  */ | ||||
| void pool_label_out(struct pool_disk *pl, char *buf) | ||||
| { | ||||
| 	struct pool_disk *bufpl = (struct pool_disk *) buf; | ||||
|  | ||||
| 	CPOUT_64(pl->pl_magic, bufpl->pl_magic); | ||||
| 	CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id); | ||||
| 	CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); | ||||
| 	CPOUT_32(pl->pl_version, bufpl->pl_version); | ||||
| 	CPOUT_32(pl->pl_subpools, bufpl->pl_subpools); | ||||
| 	CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id); | ||||
| 	CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs); | ||||
| 	CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid); | ||||
| 	CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type); | ||||
| 	CPOUT_64(pl->pl_blocks, bufpl->pl_blocks); | ||||
| 	CPOUT_32(pl->pl_striping, bufpl->pl_striping); | ||||
| 	CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); | ||||
| 	CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); | ||||
| 	CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight); | ||||
| 	CPOUT_32(pl->pl_minor, bufpl->pl_minor); | ||||
| 	CPOUT_32(pl->pl_padding, bufpl->pl_padding); | ||||
| 	CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * pool_label_in - copies a char buffer into a pool_label_t | ||||
|  * @pl: ptr to a pool_label_t struct | ||||
|  * @buf: ptr to raw space where label info is copied from | ||||
|  * | ||||
|  * This function is important because it takes care of all of | ||||
|  * the endian issues when information from disk is about to be | ||||
|  * used.  This way, when machines of different architectures | ||||
|  * are used, they will be able to interpret ondisk labels | ||||
|  * correctly.  Always use this function before using labels that | ||||
|  * were read from disk. | ||||
|  */ | ||||
| void pool_label_in(struct pool_disk *pl, char *buf) | ||||
| { | ||||
| 	struct pool_disk *bufpl = (struct pool_disk *) buf; | ||||
|  | ||||
| 	CPIN_64(pl->pl_magic, bufpl->pl_magic); | ||||
| 	CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id); | ||||
| 	CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); | ||||
| 	CPIN_32(pl->pl_version, bufpl->pl_version); | ||||
| 	CPIN_32(pl->pl_subpools, bufpl->pl_subpools); | ||||
| 	CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id); | ||||
| 	CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs); | ||||
| 	CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid); | ||||
| 	CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type); | ||||
| 	CPIN_64(pl->pl_blocks, bufpl->pl_blocks); | ||||
| 	CPIN_32(pl->pl_striping, bufpl->pl_striping); | ||||
| 	CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); | ||||
| 	CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); | ||||
| 	CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight); | ||||
| 	CPIN_32(pl->pl_minor, bufpl->pl_minor); | ||||
| 	CPIN_32(pl->pl_padding, bufpl->pl_padding); | ||||
| 	CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184); | ||||
| } | ||||
|  | ||||
| static char _calc_char(unsigned int id) | ||||
| { | ||||
| 	/* | ||||
| 	 * [0-9A-Za-z!#] - 64 printable chars (6-bits) | ||||
| 	 */ | ||||
|  | ||||
| 	if (id < 10) | ||||
| 		return id + 48; | ||||
| 	if (id < 36) | ||||
| 		return (id - 10) + 65; | ||||
| 	if (id < 62) | ||||
| 		return (id - 36) + 97; | ||||
| 	if (id == 62) | ||||
| 		return '!'; | ||||
| 	if (id == 63) | ||||
| 		return '#'; | ||||
|  | ||||
| 	return '%'; | ||||
| } | ||||
|  | ||||
| void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned shifter = 0x003F; | ||||
|  | ||||
| 	assert(ID_LEN == 32); | ||||
| 	memset(uuid, 0, ID_LEN); | ||||
| 	strcat(uuid, "POOL0000000000"); | ||||
|  | ||||
| 	/* We grab the entire 64 bits (+2 that get shifted in) */ | ||||
| 	for (i = 13; i < 24; i++) { | ||||
| 		uuid[i] = _calc_char(((unsigned) poolid) & shifter); | ||||
| 		poolid = poolid >> 6; | ||||
| 	} | ||||
|  | ||||
| 	/* We grab the entire 32 bits (+4 that get shifted in) */ | ||||
| 	for (i = 24; i < 30; i++) { | ||||
| 		uuid[i] = _calc_char((unsigned) (spid & shifter)); | ||||
| 		spid = spid >> 6; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Since we can only have 128 devices, we only worry about the | ||||
| 	 * last 12 bits | ||||
| 	 */ | ||||
| 	for (i = 30; i < 32; i++) { | ||||
| 		uuid[i] = _calc_char((unsigned) (devid & shifter)); | ||||
| 		devid = devid >> 6; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| static int _read_vg_pds(const struct format_type *fmt, struct pool *mem, | ||||
| 			struct lvmcache_vginfo *vginfo, struct list *head, | ||||
| 			uint32_t *devcount) | ||||
| { | ||||
|  | ||||
| 	struct list *vgih = NULL; | ||||
| 	struct device *dev; | ||||
| 	struct pool_list *pl = NULL; | ||||
| 	struct pool *tmpmem = NULL; | ||||
|  | ||||
| 	uint32_t sp_count = 0; | ||||
| 	uint32_t *sp_devs = NULL; | ||||
| 	int i; | ||||
|  | ||||
| 	/* FIXME: maybe should return a different error in memory | ||||
| 	 * allocation failure */ | ||||
| 	if (!(tmpmem = pool_create(512))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	list_iterate(vgih, &vginfo->infos) { | ||||
| 		dev = list_item(vgih, struct lvmcache_info)->dev; | ||||
| 		if (dev && | ||||
| 		    !(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname))) | ||||
| 			    break; | ||||
| 		/* | ||||
| 		 * We need to keep track of the total expected number | ||||
| 		 * of devices per subpool | ||||
| 		 */ | ||||
| 		if (!sp_count) { | ||||
| 			sp_count = pl->pd.pl_subpools; | ||||
| 			if (!(sp_devs = | ||||
| 			      pool_zalloc(tmpmem, | ||||
| 					  sizeof(uint32_t) * sp_count))) { | ||||
| 				log_error("Unable to allocate %d 32-bit uints", | ||||
| 					  sp_count); | ||||
| 				pool_destroy(tmpmem); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		/* | ||||
| 		 * watch out for a pool label with a different subpool | ||||
| 		 * count than the original - give up if it does | ||||
| 		 */ | ||||
| 		if (sp_count != pl->pd.pl_subpools) | ||||
| 			break; | ||||
|  | ||||
| 		_add_pl_to_list(head, pl); | ||||
|  | ||||
| 		if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0) | ||||
| 			sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs; | ||||
| 	} | ||||
|  | ||||
| 	*devcount = 0; | ||||
| 	for (i = 0; i < sp_count; i++) { | ||||
| 		*devcount += sp_devs[i]; | ||||
| 	} | ||||
|  | ||||
| 	pool_destroy(tmpmem); | ||||
|  | ||||
| 	if (pl && *pl->pd.pl_pool_name) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| } | ||||
|  | ||||
| int read_pool_pds(const struct format_type *fmt, const char *vg_name, | ||||
| 		  struct pool *mem, struct list *pdhead) | ||||
| { | ||||
| 	struct lvmcache_vginfo *vginfo; | ||||
| 	uint32_t totaldevs; | ||||
| 	int full_scan = -1; | ||||
|  | ||||
| 	do { | ||||
| 		/* | ||||
| 		 * If the cache scanning doesn't work, this will never work | ||||
| 		 */ | ||||
| 		if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) && | ||||
| 		    vginfo->infos.n) { | ||||
|  | ||||
| 			if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) { | ||||
| 				/* | ||||
| 				 * If we found all the devices we were | ||||
| 				 * expecting, return success | ||||
| 				 */ | ||||
| 				if (list_size(pdhead) == totaldevs) | ||||
| 					return 1; | ||||
|  | ||||
| 				/* | ||||
| 				 * accept partial pool if we've done a full | ||||
| 				 * rescan of the cache | ||||
| 				 */ | ||||
| 				if (full_scan > 0) | ||||
| 					return 1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Failed */ | ||||
| 		list_init(pdhead); | ||||
|  | ||||
| 		full_scan++; | ||||
| 		if (full_scan > 1) { | ||||
| 			log_debug("No devices for vg %s found in cache", | ||||
| 				  vg_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		lvmcache_label_scan(fmt->cmd, full_scan); | ||||
|  | ||||
| 	} while (1); | ||||
|  | ||||
| } | ||||
|  | ||||
| struct pool_list *read_pool_disk(const struct format_type *fmt, | ||||
| 				 struct device *dev, struct pool *mem, | ||||
| 				 const char *vg_name) | ||||
| { | ||||
| 	struct pool_list *pl; | ||||
|  | ||||
| 	if (!dev_open(dev)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(pl = pool_zalloc(mem, sizeof(*pl)))) { | ||||
| 		log_error("Unable to allocate pool list structure"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev_close(dev)) | ||||
| 		stack; | ||||
|  | ||||
| 	return pl; | ||||
|  | ||||
| } | ||||
							
								
								
									
										178
									
								
								lib/format_pool/disk_rep.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								lib/format_pool/disk_rep.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
| /* | ||||
|  * 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 DISK_REP_FORMAT_POOL_H | ||||
| #define DISK_REP_FORMAT_POOL_H | ||||
|  | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "pool.h" | ||||
|  | ||||
| /* From NSP.cf */ | ||||
| #define NSPMajorVersion	4 | ||||
| #define NSPMinorVersion	1 | ||||
| #define NSPUpdateLevel	3 | ||||
|  | ||||
| /* From pool_std.h */ | ||||
| #define POOL_NAME_SIZE          (256) | ||||
| #define POOL_MAGIC 		0x011670 | ||||
| #define POOL_MAJOR              (121) | ||||
| #define POOL_MAX_DEVICES 	128 | ||||
|  | ||||
| /* When checking for version matching, the first two numbers ** | ||||
| ** are important for metadata formats, a.k.a pool labels.   ** | ||||
| ** All the numbers are important when checking if the user  ** | ||||
| ** space tools match up with the kernel module............. */ | ||||
| #define POOL_VERSION		(NSPMajorVersion << 16 | \ | ||||
| 				 NSPMinorVersion <<  8 | \ | ||||
| 				 NSPUpdateLevel) | ||||
|  | ||||
| /* Pool label is at the head of every pool disk partition */ | ||||
| #define SIZEOF_POOL_LABEL       (8192) | ||||
|  | ||||
| /* in sectors */ | ||||
| #define POOL_PE_SIZE     (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) | ||||
| #define POOL_PE_START    (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) | ||||
|  | ||||
| /* Helper fxns */ | ||||
| #define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \ | ||||
|                                                     (pd)->pl_pool_id, 0, 0); \ | ||||
|                                     } while(0) | ||||
| #define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \ | ||||
|                                                     (pd)->pl_pool_id, \ | ||||
|                                                     (pd)->pl_sp_id, \ | ||||
|                                                     (pd)->pl_sp_devid); \ | ||||
|                                     } while(0) | ||||
| #define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \ | ||||
|                                                     (pd)->pl_pool_id, 0, 0); \ | ||||
|                                       get_pool_uuid((char*)&(id)[1], \ | ||||
|                                                     (pd)->pl_pool_id, 0, 0); \ | ||||
|                                     } while(0) | ||||
|  | ||||
| struct pool_disk; | ||||
| struct pool_list; | ||||
| struct user_subpool; | ||||
| struct user_device; | ||||
|  | ||||
| /* This must be kept up to date with sistina/pool/module/pool_sptypes.h */ | ||||
|  | ||||
| /*  Generic Labels  */ | ||||
| #define SPTYPE_DATA                (0x00000000) | ||||
|  | ||||
| /*  GFS specific labels  */ | ||||
| #define SPTYPE_GFS_DATA            (0x68011670) | ||||
| #define SPTYPE_GFS_JOURNAL         (0x69011670) | ||||
|  | ||||
| struct sptype_name { | ||||
| 	const char *name; | ||||
| 	uint32_t label; | ||||
| }; | ||||
|  | ||||
| static const struct sptype_name sptype_names[] = { | ||||
| 	{"data",	SPTYPE_DATA}, | ||||
|  | ||||
| 	{"gfs_data",	SPTYPE_GFS_DATA}, | ||||
| 	{"gfs_journal",	SPTYPE_GFS_JOURNAL}, | ||||
|  | ||||
| 	{"", 0x0}		/*  This must be the last flag.  */ | ||||
| }; | ||||
|  | ||||
| struct pool_disk { | ||||
| 	uint64_t pl_magic;	/* Pool magic number */ | ||||
| 	uint64_t pl_pool_id;	/* Unique pool identifier */ | ||||
| 	char pl_pool_name[POOL_NAME_SIZE];	/* Name of pool */ | ||||
| 	uint32_t pl_version;	/* Pool version */ | ||||
| 	uint32_t pl_subpools;	/* Number of subpools in this pool */ | ||||
| 	uint32_t pl_sp_id;	/* Subpool number within pool */ | ||||
| 	uint32_t pl_sp_devs;	/* Number of data partitions in this subpool */ | ||||
| 	uint32_t pl_sp_devid;	/* Partition number within subpool */ | ||||
| 	uint32_t pl_sp_type;	/* Partition type */ | ||||
| 	uint64_t pl_blocks;	/* Number of blocks in this partition */ | ||||
| 	uint32_t pl_striping;	/* Striping size within subpool */ | ||||
| 	/* | ||||
| 	 * If the number of DMEP devices is zero, then the next field ** | ||||
| 	 * ** (pl_sp_dmepid) becomes the subpool ID for redirection.  In ** | ||||
| 	 * ** other words, if this subpool does not have the capability  ** | ||||
| 	 * ** to do DMEP, then it must specify which subpool will do it  ** | ||||
| 	 * ** in it's place | ||||
| 	 */ | ||||
|  | ||||
| 	/* | ||||
| 	 * While the next 3 field are no longer used, they must stay to keep ** | ||||
| 	 * ** backward compatibility........................................... | ||||
| 	 */ | ||||
| 	uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */ | ||||
| 	uint32_t pl_sp_dmepid;	/* Dmep device number within subpool */ | ||||
| 	uint32_t pl_sp_weight;	/* if dmep dev, pref to using it */ | ||||
|  | ||||
| 	uint32_t pl_minor;	/* the pool minor number */ | ||||
| 	uint32_t pl_padding;	/* reminder - think about alignment */ | ||||
|  | ||||
| 	/* | ||||
| 	 * Even though we're zeroing out 8k at the front of the disk before | ||||
| 	 * writing the label, putting this in | ||||
| 	 */ | ||||
| 	char pl_reserve[184];	/* bump the structure size out to 512 bytes */ | ||||
| }; | ||||
|  | ||||
| struct pool_list { | ||||
| 	struct list list; | ||||
| 	struct pool_disk pd; | ||||
| 	struct physical_volume *pv; | ||||
| 	struct id pv_uuid; | ||||
| 	struct device *dev; | ||||
| }; | ||||
|  | ||||
| struct user_subpool { | ||||
| 	uint32_t initialized; | ||||
| 	uint32_t id; | ||||
| 	uint32_t striping; | ||||
| 	uint32_t num_devs; | ||||
| 	uint32_t type; | ||||
| 	uint32_t dummy; | ||||
| 	struct user_device *devs; | ||||
| }; | ||||
|  | ||||
| struct user_device { | ||||
| 	uint32_t initialized; | ||||
| 	uint32_t sp_id; | ||||
| 	uint32_t devid; | ||||
| 	uint32_t dummy; | ||||
| 	uint64_t blocks; | ||||
| 	struct physical_volume *pv; | ||||
| }; | ||||
|  | ||||
| int read_pool_label(struct pool_list *pl, struct labeller *l, | ||||
| 		    struct device *dev, char *buf, struct label **label); | ||||
| void pool_label_out(struct pool_disk *pl, char *buf); | ||||
| void pool_label_in(struct pool_disk *pl, char *buf); | ||||
| void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid); | ||||
| int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls); | ||||
| int import_pool_lvs(struct volume_group *vg, struct pool *mem, | ||||
| 		    struct list *pls); | ||||
| int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, | ||||
| 		    struct list *pvs, struct pool *mem, struct list *pls); | ||||
| int import_pool_pv(const struct format_type *fmt, struct pool *mem, | ||||
| 		   struct volume_group *vg, struct physical_volume *pv, | ||||
| 		   struct pool_list *pl); | ||||
| int import_pool_segments(struct list *lvs, struct pool *mem, | ||||
| 			 struct user_subpool *usp, int sp_count); | ||||
| int read_pool_pds(const struct format_type *fmt, const char *vgname, | ||||
| 		  struct pool *mem, struct list *head); | ||||
| struct pool_list *read_pool_disk(const struct format_type *fmt, | ||||
| 				 struct device *dev, struct pool *mem, | ||||
| 				 const char *vg_name); | ||||
|  | ||||
| #endif				/* DISK_REP_POOL_FORMAT_H */ | ||||
							
								
								
									
										361
									
								
								lib/format_pool/format_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								lib/format_pool/format_pool.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,361 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "pool.h" | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "hash.h" | ||||
| #include "limits.h" | ||||
| #include "list.h" | ||||
| #include "display.h" | ||||
| #include "toolcontext.h" | ||||
| #include "lvmcache.h" | ||||
| #include "disk_rep.h" | ||||
| #include "format_pool.h" | ||||
| #include "pool_label.h" | ||||
|  | ||||
| #define FMT_POOL_NAME "pool" | ||||
|  | ||||
| /* Must be called after pvs are imported */ | ||||
| static struct user_subpool *_build_usp(struct list *pls, struct pool *mem, | ||||
| 				       int *sps) | ||||
| { | ||||
|  | ||||
| 	struct list *plhs; | ||||
| 	struct pool_list *pl; | ||||
| 	struct user_subpool *usp = NULL, *cur_sp = NULL; | ||||
| 	struct user_device *cur_dev = NULL; | ||||
|  | ||||
| 	/* | ||||
| 	 * FIXME: Need to do some checks here - I'm tempted to add a | ||||
| 	 * user_pool structure and build the entire thing to check against. | ||||
| 	 */ | ||||
| 	list_iterate(plhs, pls) { | ||||
| 		pl = list_item(plhs, struct pool_list); | ||||
|  | ||||
| 		*sps = pl->pd.pl_subpools; | ||||
| 		if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) { | ||||
| 			log_error("Unable to allocate %d subpool structures", | ||||
| 				  *sps); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (cur_sp != &usp[pl->pd.pl_sp_id]) { | ||||
| 			cur_sp = &usp[pl->pd.pl_sp_id]; | ||||
|  | ||||
| 			cur_sp->id = pl->pd.pl_sp_id; | ||||
| 			cur_sp->striping = pl->pd.pl_striping; | ||||
| 			cur_sp->num_devs = pl->pd.pl_sp_devs; | ||||
| 			cur_sp->type = pl->pd.pl_sp_type; | ||||
| 			cur_sp->initialized = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (!cur_sp->devs && | ||||
| 		    (!(cur_sp->devs = | ||||
| 		       pool_zalloc(mem, | ||||
| 				   sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) { | ||||
|  | ||||
| 			log_error("Unable to allocate %d pool_device " | ||||
| 				  "structures", pl->pd.pl_sp_devs); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid]; | ||||
| 		cur_dev->sp_id = cur_sp->id; | ||||
| 		cur_dev->devid = pl->pd.pl_sp_id; | ||||
| 		cur_dev->blocks = pl->pd.pl_blocks; | ||||
| 		cur_dev->pv = pl->pv; | ||||
| 		cur_dev->initialized = 1; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return usp; | ||||
| } | ||||
|  | ||||
| static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count) | ||||
| { | ||||
| 	int i, j; | ||||
|  | ||||
| 	for (i = 0; i < sp_count; i++) { | ||||
| 		if (!usp[i].initialized) { | ||||
| 			log_error("Missing subpool %d in pool %s", i, vgname); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		for (j = 0; j < usp[i].num_devs; j++) { | ||||
| 			if (!usp[i].devs[j].initialized) { | ||||
| 				log_error("Missing device %d for subpool %d" | ||||
| 					  " in pool %s", j, i, vgname); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct volume_group *_build_vg_from_pds(struct format_instance | ||||
| 					       *fid, struct pool *mem, | ||||
| 					       struct list *pds) | ||||
| { | ||||
| 	struct pool *smem = fid->fmt->cmd->mem; | ||||
| 	struct volume_group *vg = NULL; | ||||
| 	struct user_subpool *usp = NULL; | ||||
| 	int sp_count; | ||||
|  | ||||
| 	if (!(vg = pool_zalloc(smem, sizeof(*vg)))) { | ||||
| 		log_error("Unable to allocate volume group structure"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	vg->cmd = fid->fmt->cmd; | ||||
| 	vg->fid = fid; | ||||
| 	vg->name = NULL; | ||||
| 	vg->status = 0; | ||||
| 	vg->extent_count = 0; | ||||
| 	vg->pv_count = 0; | ||||
| 	vg->lv_count = 0; | ||||
| 	vg->snapshot_count = 0; | ||||
| 	vg->seqno = 1; | ||||
| 	vg->system_id = NULL; | ||||
| 	list_init(&vg->pvs); | ||||
| 	list_init(&vg->lvs); | ||||
| 	list_init(&vg->snapshots); | ||||
| 	list_init(&vg->tags); | ||||
|  | ||||
| 	if (!import_pool_vg(vg, smem, pds)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!import_pool_pvs(fid->fmt, vg, &vg->pvs, smem, pds)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!import_pool_lvs(vg, smem, pds)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * I need an intermediate subpool structure that contains all the | ||||
| 	 * relevant info for this.  Then i can iterate through the subpool | ||||
| 	 * structures for checking, and create the segments | ||||
| 	 */ | ||||
| 	if (!(usp = _build_usp(pds, mem, &sp_count))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * check the subpool structures - we can't handle partial VGs in | ||||
| 	 * the pool format, so this will error out if we're missing PVs | ||||
| 	 */ | ||||
| 	if (!_check_usp(vg->name, usp, sp_count)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!import_pool_segments(&vg->lvs, smem, usp, sp_count)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return vg; | ||||
| } | ||||
|  | ||||
| static struct volume_group *_vg_read(struct format_instance *fid, | ||||
| 				     const char *vg_name, | ||||
| 				     struct metadata_area *mda) | ||||
| { | ||||
| 	struct pool *mem = pool_create(1024); | ||||
| 	struct list pds; | ||||
| 	struct volume_group *vg = NULL; | ||||
|  | ||||
| 	list_init(&pds); | ||||
|  | ||||
| 	/* We can safely ignore the mda passed in */ | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* Strip dev_dir if present */ | ||||
| 	vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); | ||||
|  | ||||
| 	/* Read all the pvs in the vg */ | ||||
| 	if (!read_pool_pds(fid->fmt, vg_name, mem, &pds)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* Do the rest of the vg stuff */ | ||||
| 	if (!(vg = _build_vg_from_pds(fid, mem, &pds))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
|       out: | ||||
| 	pool_destroy(mem); | ||||
| 	return vg; | ||||
| } | ||||
|  | ||||
| static int _pv_setup(const struct format_type *fmt, | ||||
| 		     uint64_t pe_start, uint32_t extent_count, | ||||
| 		     uint32_t extent_size, | ||||
| 		     int pvmetadatacopies, | ||||
| 		     uint64_t pvmetadatasize, struct list *mdas, | ||||
| 		     struct physical_volume *pv, struct volume_group *vg) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _pv_read(const struct format_type *fmt, const char *pv_name, | ||||
| 		    struct physical_volume *pv, struct list *mdas) | ||||
| { | ||||
| 	struct pool *mem = pool_create(1024); | ||||
| 	struct pool_list *pl; | ||||
| 	struct device *dev; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	log_very_verbose("Reading physical volume data %s from disk", pv_name); | ||||
|  | ||||
| 	if (!mem) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * I need to read the disk and populate a pv structure here | ||||
| 	 * I'll probably need to abstract some of this later for the | ||||
| 	 * vg_read code | ||||
| 	 */ | ||||
| 	if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) { | ||||
| 		stack; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	pv->fmt = fmt; | ||||
|  | ||||
| 	r = 1; | ||||
|  | ||||
|       out: | ||||
| 	pool_destroy(mem); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* *INDENT-OFF* */ | ||||
| static struct metadata_area_ops _metadata_format_pool_ops = { | ||||
| 	vg_read:_vg_read, | ||||
| }; | ||||
| /* *INDENT-ON* */ | ||||
|  | ||||
| static struct format_instance *_create_instance(const struct format_type *fmt, | ||||
| 						const char *vgname, | ||||
| 						void *private) | ||||
| { | ||||
| 	struct format_instance *fid; | ||||
| 	struct metadata_area *mda; | ||||
|  | ||||
| 	if (!(fid = pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) { | ||||
| 		log_error("Unable to allocate format instance structure for " | ||||
| 			  "pool format"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	fid->fmt = fmt; | ||||
| 	list_init(&fid->metadata_areas); | ||||
|  | ||||
| 	/* Define a NULL metadata area */ | ||||
| 	if (!(mda = pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) { | ||||
| 		log_error("Unable to allocate metadata area structure " | ||||
| 			  "for pool format"); | ||||
| 		pool_free(fmt->cmd->mem, fid); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	mda->ops = &_metadata_format_pool_ops; | ||||
| 	mda->metadata_locn = NULL; | ||||
| 	list_add(&fid->metadata_areas, &mda->list); | ||||
|  | ||||
| 	return fid; | ||||
| } | ||||
|  | ||||
| static void _destroy_instance(struct format_instance *fid) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| static void _destroy(const struct format_type *fmt) | ||||
| { | ||||
| 	dbg_free((void *) fmt); | ||||
| } | ||||
|  | ||||
| /* *INDENT-OFF* */ | ||||
| static struct format_handler _format_pool_ops = { | ||||
| 	pv_read:_pv_read, | ||||
| 	pv_setup:_pv_setup, | ||||
| 	create_instance:_create_instance, | ||||
| 	destroy_instance:_destroy_instance, | ||||
| 	destroy:_destroy, | ||||
| }; | ||||
| /* *INDENT-ON */ | ||||
|  | ||||
| #ifdef POOL_INTERNAL | ||||
| struct format_type *init_pool_format(struct cmd_context *cmd) | ||||
| #else				/* Shared */ | ||||
| struct format_type *init_format(struct cmd_context *cmd); | ||||
| struct format_type *init_format(struct cmd_context *cmd) | ||||
| #endif | ||||
| { | ||||
| 	struct format_type *fmt = dbg_malloc(sizeof(*fmt)); | ||||
|  | ||||
| 	if (!fmt) { | ||||
| 		log_error("Unable to allocate format type structure for pool " | ||||
| 			  "format"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	fmt->cmd = cmd; | ||||
| 	fmt->ops = &_format_pool_ops; | ||||
| 	fmt->name = FMT_POOL_NAME; | ||||
| 	fmt->alias = NULL; | ||||
| 	fmt->features = 0; | ||||
| 	fmt->private = NULL; | ||||
|  | ||||
| 	if (!(fmt->labeller = pool_labeller_create(fmt))) { | ||||
| 		log_error("Couldn't create pool label handler."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) { | ||||
| 		log_error("Couldn't register pool label handler."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return fmt; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/format_pool/format_pool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/format_pool/format_pool.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_FORMAT_POOL_H | ||||
| #define _LVM_FORMAT_POOL_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| #ifdef POOL_INTERNAL | ||||
| struct format_type *init_pool_format(struct cmd_context *cmd); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										309
									
								
								lib/format_pool/import_export.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								lib/format_pool/import_export.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,309 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "pool.h" | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "lvmcache.h" | ||||
| #include "disk_rep.h" | ||||
| #include "lv_alloc.h" | ||||
| #include "str_list.h" | ||||
| #include "display.h" | ||||
| #include "segtypes.h" | ||||
|  | ||||
| /* This file contains only imports at the moment... */ | ||||
|  | ||||
| int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls) | ||||
| { | ||||
| 	struct list *plhs; | ||||
| 	struct pool_list *pl; | ||||
|  | ||||
| 	list_iterate(plhs, pls) { | ||||
| 		pl = list_item(plhs, struct pool_list); | ||||
|  | ||||
| 		vg->extent_count += | ||||
| 		    ((pl->pd.pl_blocks) / POOL_PE_SIZE); | ||||
|  | ||||
| 		vg->pv_count++; | ||||
|  | ||||
| 		if (vg->name) | ||||
| 			continue; | ||||
|  | ||||
| 		vg->name = pool_strdup(mem, pl->pd.pl_pool_name); | ||||
| 		get_pool_vg_uuid(&vg->id, &pl->pd); | ||||
| 		vg->extent_size = POOL_PE_SIZE; | ||||
| 		vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; | ||||
| 		vg->free_count = 0; | ||||
| 		vg->max_lv = 1; | ||||
| 		vg->max_pv = POOL_MAX_DEVICES; | ||||
| 		vg->alloc = ALLOC_NORMAL; | ||||
| 		vg->lv_count = 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) | ||||
| { | ||||
| 	struct pool_list *pl; | ||||
| 	struct list *plhs; | ||||
| 	struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl)); | ||||
| 	struct logical_volume *lv; | ||||
|  | ||||
| 	if (!lvl) { | ||||
| 		log_error("Unable to allocate lv list structure"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) { | ||||
| 		log_error("Unable to allocate logical volume structure"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	lv = lvl->lv; | ||||
| 	lv->status = 0; | ||||
| 	lv->vg = vg; | ||||
| 	lv->alloc = ALLOC_NORMAL; | ||||
| 	lv->size = 0; | ||||
| 	lv->name = NULL; | ||||
| 	lv->le_count = 0; | ||||
| 	lv->read_ahead = 0; | ||||
| 	list_init(&lv->segments); | ||||
| 	list_init(&lv->tags); | ||||
|  | ||||
| 	list_iterate(plhs, pls) { | ||||
| 		pl = list_item(plhs, struct pool_list); | ||||
|  | ||||
| 		lv->size += pl->pd.pl_blocks; | ||||
|  | ||||
| 		if (lv->name) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!(lv->name = pool_strdup(mem, pl->pd.pl_pool_name))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		get_pool_lv_uuid(lv->lvid.id, &pl->pd); | ||||
| 		log_debug("Calculated lv uuid for lv %s: %s", lv->name, | ||||
| 			  lv->lvid.s); | ||||
|  | ||||
| 		lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE; | ||||
| 		lv->major = POOL_MAJOR; | ||||
|  | ||||
| 		/* for pool a minor of 0 is dynamic */ | ||||
| 		if (pl->pd.pl_minor) { | ||||
| 			lv->status |= FIXED_MINOR; | ||||
| 			lv->minor = pl->pd.pl_minor; | ||||
| 		} else { | ||||
| 			lv->minor = -1; | ||||
| 		} | ||||
| 		list_init(&lv->segments); | ||||
| 		list_init(&lv->tags); | ||||
| 	} | ||||
|  | ||||
| 	lv->le_count = lv->size / POOL_PE_SIZE; | ||||
| 	lvl->lv = lv; | ||||
| 	list_add(&vg->lvs, &lvl->list); | ||||
| 	vg->lv_count++; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, | ||||
| 		    struct list *pvs, struct pool *mem, struct list *pls) | ||||
| { | ||||
| 	struct pv_list *pvl; | ||||
| 	struct pool_list *pl; | ||||
| 	struct list *plhs; | ||||
|  | ||||
| 	list_iterate(plhs, pls) { | ||||
| 		pl = list_item(plhs, struct pool_list); | ||||
|  | ||||
| 		if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) { | ||||
| 			log_error("Unable to allocate pv list structure"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) { | ||||
| 			log_error("Unable to allocate pv structure"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) { | ||||
| 			return 0; | ||||
| 		} | ||||
| 		pl->pv = pvl->pv; | ||||
| 		pvl->mdas = NULL; | ||||
| 		pvl->alloc_areas = NULL; | ||||
| 		list_add(pvs, &pvl->list); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_pool_pv(const struct format_type *fmt, struct pool *mem, | ||||
| 		   struct volume_group *vg, struct physical_volume *pv, | ||||
| 		   struct pool_list *pl) | ||||
| { | ||||
| 	struct pool_disk *pd = &pl->pd; | ||||
|  | ||||
| 	memset(pv, 0, sizeof(*pv)); | ||||
|  | ||||
| 	get_pool_pv_uuid(&pv->id, pd); | ||||
| 	pv->fmt = fmt; | ||||
|  | ||||
| 	pv->dev = pl->dev; | ||||
| 	if (!(pv->vg_name = pool_strdup(mem, pd->pl_pool_name))) { | ||||
| 		log_error("Unable to duplicate vg_name string"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	pv->status = 0; | ||||
| 	pv->size = pd->pl_blocks; | ||||
| 	pv->pe_size = POOL_PE_SIZE; | ||||
| 	pv->pe_start = POOL_PE_START; | ||||
| 	pv->pe_count = pv->size / POOL_PE_SIZE; | ||||
| 	pv->pe_alloc_count = pv->pe_count; | ||||
|  | ||||
| 	list_init(&pv->tags); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static const char *_cvt_sptype(uint32_t sptype) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; sptype_names[i].name[0]; i++) { | ||||
| 		if (sptype == sptype_names[i].label) { | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	log_debug("Found sptype %X and converted it to %s", | ||||
| 		  sptype, sptype_names[i].name); | ||||
| 	return sptype_names[i].name; | ||||
| } | ||||
|  | ||||
| static int _add_stripe_seg(struct pool *mem, | ||||
| 			   struct user_subpool *usp, struct logical_volume *lv, | ||||
| 			   uint32_t *le_cur) | ||||
| { | ||||
| 	struct lv_segment *seg; | ||||
| 	int j; | ||||
|  | ||||
| 	if (!(seg = alloc_lv_segment(mem, usp->num_devs))) { | ||||
| 		log_error("Unable to allocate striped lv_segment structure"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if(usp->striping & (usp->striping - 1)) { | ||||
| 		log_error("Stripe size must be a power of 2"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	seg->stripe_size = usp->striping; | ||||
| 	seg->status |= 0; | ||||
| 	seg->le += *le_cur; | ||||
|  | ||||
| 	/* add the subpool type to the segment tag list */ | ||||
| 	str_list_add(mem, &seg->tags, _cvt_sptype(usp->type)); | ||||
|  | ||||
| 	for (j = 0; j < usp->num_devs; j++) { | ||||
| 		if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, | ||||
| 							     "striped"))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; | ||||
| 		seg->len += seg->area_len; | ||||
| 		*le_cur += seg->area_len; | ||||
| 		seg->lv = lv; | ||||
|  | ||||
| 		seg->area[j].type = AREA_PV; | ||||
| 		seg->area[j].u.pv.pv = usp->devs[j].pv; | ||||
| 		seg->area[j].u.pv.pe = 0; | ||||
| 	} | ||||
| 	list_add(&lv->segments, &seg->list); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _add_linear_seg(struct pool *mem, | ||||
| 			   struct user_subpool *usp, struct logical_volume *lv, | ||||
| 			   uint32_t *le_cur) | ||||
| { | ||||
| 	struct lv_segment *seg; | ||||
| 	int j; | ||||
|  | ||||
| 	for (j = 0; j < usp->num_devs; j++) { | ||||
| 		/* linear segments only have 1 data area */ | ||||
| 		if (!(seg = alloc_lv_segment(mem, 1))) { | ||||
| 			log_error("Unable to allocate linear lv_segment " | ||||
| 				  "structure"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		seg->stripe_size = usp->striping; | ||||
| 		seg->le += *le_cur; | ||||
| 		seg->chunk_size = POOL_PE_SIZE; | ||||
| 		seg->status |= 0; | ||||
| 		if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, | ||||
| 							     "striped"))) { | ||||
| 			stack; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		/* add the subpool type to the segment tag list */ | ||||
| 		str_list_add(mem, &seg->tags, _cvt_sptype(usp->type)); | ||||
|  | ||||
| 		seg->lv = lv; | ||||
|  | ||||
| 		seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; | ||||
| 		seg->len = seg->area_len; | ||||
| 		*le_cur += seg->len; | ||||
| 		seg->area[0].type = AREA_PV; | ||||
| 		seg->area[0].u.pv.pv = usp->devs[j].pv; | ||||
| 		seg->area[0].u.pv.pe = 0; | ||||
| 		list_add(&lv->segments, &seg->list); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int import_pool_segments(struct list *lvs, struct pool *mem, | ||||
| 			 struct user_subpool *usp, int subpools) | ||||
| { | ||||
|  | ||||
| 	struct list *lvhs; | ||||
| 	struct lv_list *lvl; | ||||
| 	struct logical_volume *lv; | ||||
| 	uint32_t le_cur = 0; | ||||
| 	int i; | ||||
|  | ||||
| 	list_iterate(lvhs, lvs) { | ||||
| 		lvl = list_item(lvhs, struct lv_list); | ||||
|  | ||||
| 		lv = lvl->lv; | ||||
| 		for (i = 0; i < subpools; i++) { | ||||
| 			if (usp[i].striping) { | ||||
| 				if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) { | ||||
| 					stack; | ||||
| 					return 0; | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) { | ||||
| 					stack; | ||||
| 					return 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
|  | ||||
| } | ||||
							
								
								
									
										108
									
								
								lib/format_pool/pool_label.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/format_pool/pool_label.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "pool.h" | ||||
| #include "label.h" | ||||
| #include "metadata.h" | ||||
| #include "xlate.h" | ||||
| #include "disk_rep.h" | ||||
| #include "pool_label.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| static void _not_supported(const char *op) | ||||
| { | ||||
| 	log_error("The '%s' operation is not supported for the pool labeller.", | ||||
| 		  op); | ||||
| } | ||||
|  | ||||
| static int _can_handle(struct labeller *l, char *buf, uint64_t sector) | ||||
| { | ||||
|  | ||||
| 	struct pool_disk pd; | ||||
|  | ||||
| 	/* | ||||
| 	 * POOL label must always be in first sector | ||||
| 	 */ | ||||
| 	if (sector) | ||||
| 		return 0; | ||||
|  | ||||
| 	pool_label_in(&pd, buf); | ||||
|  | ||||
| 	/* can ignore 8 rightmost bits for ondisk format check */ | ||||
| 	if ((pd.pl_magic == POOL_MAGIC) && | ||||
| 	    (pd.pl_version >> 8 == POOL_VERSION >> 8)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _write(struct label *label, char *buf) | ||||
| { | ||||
| 	_not_supported("write"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _read(struct labeller *l, struct device *dev, char *buf, | ||||
| 		 struct label **label) | ||||
| { | ||||
| 	struct pool_list pl; | ||||
|  | ||||
| 	return read_pool_label(&pl, l, dev, buf, label); | ||||
| } | ||||
|  | ||||
| static int _initialise_label(struct labeller *l, struct label *label) | ||||
| { | ||||
| 	strcpy(label->type, "POOL"); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _destroy_label(struct labeller *l, struct label *label) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| static void _destroy(struct labeller *l) | ||||
| { | ||||
| 	dbg_free(l); | ||||
| } | ||||
|  | ||||
| struct label_ops _pool_ops = { | ||||
|       can_handle:_can_handle, | ||||
|       write:_write, | ||||
|       read:_read, | ||||
|       verify:_can_handle, | ||||
|       initialise_label:_initialise_label, | ||||
|       destroy_label:_destroy_label, | ||||
|       destroy:_destroy | ||||
| }; | ||||
|  | ||||
| struct labeller *pool_labeller_create(struct format_type *fmt) | ||||
| { | ||||
| 	struct labeller *l; | ||||
|  | ||||
| 	if (!(l = dbg_malloc(sizeof(*l)))) { | ||||
| 		log_error("Couldn't allocate labeller object."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	l->ops = &_pool_ops; | ||||
| 	l->private = (const void *) fmt; | ||||
|  | ||||
| 	return l; | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/format_pool/pool_label.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/format_pool/pool_label.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * 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 _LVM_POOL_LABEL_H | ||||
| #define _LVM_POOL_LABEL_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| struct labeller *pool_labeller_create(struct format_type *fmt); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										382
									
								
								lib/format_text/archive.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								lib/format_text/archive.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,382 @@ | ||||
| /* | ||||
|  * 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 "format-text.h" | ||||
|  | ||||
| #include "pool.h" | ||||
| #include "config.h" | ||||
| #include "hash.h" | ||||
| #include "import-export.h" | ||||
| #include "lvm-string.h" | ||||
| #include "lvm-file.h" | ||||
| #include "toolcontext.h" | ||||
|  | ||||
| #include <dirent.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/file.h> | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #define SECS_PER_DAY 86400	/* 24*60*60 */ | ||||
|  | ||||
| /* | ||||
|  * The format instance is given a directory path upon creation. | ||||
|  * Each file in this directory whose name is of the form | ||||
|  * '(.*)_[0-9]*.vg' is a config file (see lib/config.[hc]), which | ||||
|  * contains a description of a single volume group. | ||||
|  * | ||||
|  * The prefix ($1 from the above regex) of the config file gives | ||||
|  * the volume group name. | ||||
|  * | ||||
|  * Backup files that have expired will be removed. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * A list of these is built up for our volume group.  Ordered | ||||
|  * with the least recent at the head. | ||||
|  */ | ||||
| struct archive_file { | ||||
| 	struct list list; | ||||
|  | ||||
| 	char *path; | ||||
| 	int index; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Extract vg name and version number from a filename. | ||||
|  */ | ||||
| static int _split_vg(const char *filename, char *vgname, size_t vg_size, | ||||
| 		     uint32_t *ix) | ||||
| { | ||||
| 	size_t len, vg_len; | ||||
| 	const char *dot, *underscore; | ||||
|  | ||||
| 	len = strlen(filename); | ||||
| 	if (len < 7) | ||||
| 		return 0; | ||||
|  | ||||
| 	dot = (filename + len - 3); | ||||
| 	if (strcmp(".vg", dot)) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!(underscore = rindex(filename, '_'))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (sscanf(underscore + 1, "%u", ix) != 1) | ||||
| 		return 0; | ||||
|  | ||||
| 	vg_len = underscore - filename; | ||||
| 	if (vg_len + 1 > vg_size) | ||||
| 		return 0; | ||||
|  | ||||
| 	strncpy(vgname, filename, vg_len); | ||||
| 	vgname[vg_len] = '\0'; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _insert_file(struct list *head, struct archive_file *b) | ||||
| { | ||||
| 	struct list *bh; | ||||
| 	struct archive_file *bf = NULL; | ||||
|  | ||||
| 	if (list_empty(head)) { | ||||
| 		list_add(head, &b->list); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* index increases through list */ | ||||
| 	list_iterate(bh, head) { | ||||
| 		bf = list_item(bh, struct archive_file); | ||||
|  | ||||
| 		if (bf->index > b->index) { | ||||
| 			list_add(&bf->list, &b->list); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	list_add_h(&bf->list, &b->list); | ||||
| } | ||||
|  | ||||
| static char *_join(struct pool *mem, const char *dir, const char *name) | ||||
| { | ||||
| 	if (!pool_begin_object(mem, 32) || | ||||
| 	    !pool_grow_object(mem, dir, strlen(dir)) || | ||||
| 	    !pool_grow_object(mem, "/", 1) || | ||||
| 	    !pool_grow_object(mem, name, strlen(name)) || | ||||
| 	    !pool_grow_object(mem, "\0", 1)) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return pool_end_object(mem); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns a list of archive_files. | ||||
|  */ | ||||
| static struct list *_scan_archive(struct pool *mem, | ||||
| 				  const char *vgname, const char *dir) | ||||
| { | ||||
| 	int i, count, ix; | ||||
| 	char vgname_found[64], *path; | ||||
| 	struct dirent **dirent; | ||||
| 	struct archive_file *af; | ||||
| 	struct list *results; | ||||
|  | ||||
| 	if (!(results = pool_alloc(mem, sizeof(*results)))) { | ||||
| 		stack; | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_init(results); | ||||
|  | ||||
| 	/* Sort fails beyond 5-digit indexes */ | ||||
| 	if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) { | ||||
| 		log_err("Couldn't scan archive directory."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		/* ignore dot files */ | ||||
| 		if (dirent[i]->d_name[0] == '.') | ||||
| 			continue; | ||||
|  | ||||
| 		/* check the name is the correct format */ | ||||
| 		if (!_split_vg(dirent[i]->d_name, vgname_found, | ||||
| 			       sizeof(vgname_found), &ix)) | ||||
| 			continue; | ||||
|  | ||||
| 		/* is it the vg we're interested in ? */ | ||||
| 		if (strcmp(vgname, vgname_found)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!(path = _join(mem, dir, dirent[i]->d_name))) { | ||||
| 			stack; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Create a new archive_file. | ||||
| 		 */ | ||||
| 		if (!(af = pool_alloc(mem, sizeof(*af)))) { | ||||
| 			log_err("Couldn't create new archive file."); | ||||
| 			results = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		af->index = ix; | ||||
| 		af->path = path; | ||||
|  | ||||
| 		/* | ||||
| 		 * Insert it to the correct part of the list. | ||||
| 		 */ | ||||
| 		_insert_file(results, af); | ||||
| 	} | ||||
|  | ||||
|       out: | ||||
| 	for (i = 0; i < count; i++) | ||||
| 		free(dirent[i]); | ||||
| 	free(dirent); | ||||
|  | ||||
| 	return results; | ||||
| } | ||||
|  | ||||
| static void _remove_expired(struct list *archives, uint32_t archives_size, | ||||
| 			    uint32_t retain_days, uint32_t min_archive) | ||||
| { | ||||
| 	struct list *bh; | ||||
| 	struct archive_file *bf; | ||||
| 	struct stat sb; | ||||
| 	time_t retain_time; | ||||
|  | ||||
| 	/* Make sure there are enough archives to even bother looking for | ||||
| 	 * expired ones... */ | ||||
| 	if (archives_size <= min_archive) | ||||
| 		return; | ||||
|  | ||||
| 	/* Convert retain_days into the time after which we must retain */ | ||||
| 	retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY; | ||||
|  | ||||
| 	/* Assume list is ordered oldest first (by index) */ | ||||
| 	list_iterate(bh, archives) { | ||||
| 		bf = list_item(bh, struct archive_file); | ||||
|  | ||||
| 		/* Get the mtime of the file and unlink if too old */ | ||||
| 		if (stat(bf->path, &sb)) { | ||||
| 			log_sys_error("stat", bf->path); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (sb.st_mtime > retain_time) | ||||
| 			return; | ||||
|  | ||||
| 		log_very_verbose("Expiring archive %s", bf->path); | ||||
| 		if (unlink(bf->path)) | ||||
| 			log_sys_error("unlink", bf->path); | ||||
|  | ||||
| 		/* Don't delete any more if we've reached the minimum */ | ||||
| 		if (--archives_size <= min_archive) | ||||
| 			return; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int archive_vg(struct volume_group *vg, | ||||
| 	       const char *dir, const char *desc, | ||||
| 	       uint32_t retain_days, uint32_t min_archive) | ||||
| { | ||||
| 	int i, fd, renamed = 0; | ||||
| 	unsigned int ix = 0; | ||||
| 	struct archive_file *last; | ||||
| 	FILE *fp = NULL; | ||||
| 	char temp_file[PATH_MAX], archive_name[PATH_MAX]; | ||||
| 	struct list *archives; | ||||
|  | ||||
| 	/* | ||||
| 	 * Write the vg out to a temporary file. | ||||
| 	 */ | ||||
| 	if (!create_temp_name(dir, temp_file, sizeof(temp_file), &fd)) { | ||||
| 		log_err("Couldn't create temporary archive name."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(fp = fdopen(fd, "w"))) { | ||||
| 		log_err("Couldn't create FILE object for archive."); | ||||
| 		close(fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!text_vg_export_file(vg, desc, fp)) { | ||||
| 		stack; | ||||
| 		fclose(fp); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	/* | ||||
| 	 * Now we want to rename this file to <vg>_index.vg. | ||||
| 	 */ | ||||
| 	if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) { | ||||
| 		log_err("Couldn't scan the archive directory (%s).", dir); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (list_empty(archives)) | ||||
| 		ix = 0; | ||||
| 	else { | ||||
| 		last = list_item(archives->p, struct archive_file); | ||||
| 		ix = last->index + 1; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < 10; i++) { | ||||
| 		if (lvm_snprintf(archive_name, sizeof(archive_name), | ||||
| 				 "%s/%s_%05d.vg", dir, vg->name, ix) < 0) { | ||||
| 			log_error("Archive file name too long."); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if ((renamed = lvm_rename(temp_file, archive_name))) | ||||
| 			break; | ||||
|  | ||||
| 		ix++; | ||||
| 	} | ||||
|  | ||||
| 	if (!renamed) | ||||
| 		log_error("Archive rename failed for %s", temp_file); | ||||
|  | ||||
| 	_remove_expired(archives, list_size(archives) + renamed, retain_days, | ||||
| 			min_archive); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _display_archive(struct cmd_context *cmd, struct archive_file *af) | ||||
| { | ||||
| 	struct volume_group *vg = NULL; | ||||
| 	struct format_instance *tf; | ||||
| 	time_t when; | ||||
| 	char *desc; | ||||
| 	void *context; | ||||
|  | ||||
| 	log_print(" "); | ||||
| 	log_print("File:\t\t%s", af->path); | ||||
|  | ||||
| 	if (!(context = create_text_context(cmd, af->path, NULL)) || | ||||
| 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL, | ||||
| 							 context))) { | ||||
| 		log_error("Couldn't create text instance object."); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Read the archive file to ensure that it is valid, and | ||||
| 	 * retrieve the archive time and description. | ||||
| 	 */ | ||||
| 	/* FIXME Use variation on _vg_read */ | ||||
| 	if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) { | ||||
| 		log_print("Unable to read archive file."); | ||||
| 		tf->fmt->ops->destroy_instance(tf); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	log_print("VG name:    \t%s", vg->name); | ||||
| 	log_print("Description:\t%s", desc ? desc : "<No description>"); | ||||
| 	log_print("Backup Time:\t%s", ctime(&when)); | ||||
|  | ||||
| 	pool_free(cmd->mem, vg); | ||||
| 	tf->fmt->ops->destroy_instance(tf); | ||||
| } | ||||
|  | ||||
| int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname) | ||||
| { | ||||
| 	struct list *archives, *ah; | ||||
| 	struct archive_file *af; | ||||
|  | ||||
| 	if (!(archives = _scan_archive(cmd->mem, vgname, dir))) { | ||||
| 		log_err("Couldn't scan the archive directory (%s).", dir); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (list_empty(archives)) | ||||
| 		log_print("No archives found in %s.", dir); | ||||
|  | ||||
| 	list_iterate(ah, archives) { | ||||
| 		af = list_item(ah, struct archive_file); | ||||
|  | ||||
| 		_display_archive(cmd, af); | ||||
| 	} | ||||
|  | ||||
| 	pool_free(cmd->mem, archives); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname) | ||||
| { | ||||
| 	struct archive_file af; | ||||
|  | ||||
| 	if (!(af.path = _join(cmd->mem, dir, vgname))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (path_exists(af.path)) | ||||
| 		_display_archive(cmd, &af); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user