mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			1010 Commits
		
	
	
		
			dev-dct-sc
			...
			old-v1_00_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 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 | 
							
								
								
									
										147
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,147 +0,0 @@ | ||||
| *.5 | ||||
| *.7 | ||||
| *.8 | ||||
| *.8_gen | ||||
| *.a | ||||
| *.d | ||||
| *.o | ||||
| *.orig | ||||
| *.pc | ||||
| *.pot | ||||
| *.pyc | ||||
| *.pyo | ||||
| *.rej | ||||
| *.so | ||||
| *.so.* | ||||
| *.sw* | ||||
| *~ | ||||
|  | ||||
| .export.sym | ||||
| .exported_symbols_generated | ||||
| .gdb_history | ||||
|  | ||||
| Makefile | ||||
| make.tmpl | ||||
|  | ||||
| /autom4te.cache/ | ||||
| /autoscan.log | ||||
| /build/ | ||||
| /config.cache | ||||
| /config.log | ||||
| /config.status | ||||
| /configure.scan | ||||
| /cscope.* | ||||
| /html/ | ||||
| /python/ | ||||
| /reports/ | ||||
| /tags | ||||
| /tmp/ | ||||
|  | ||||
| coverity/coverity_model.xml | ||||
|  | ||||
| # gcov files: | ||||
| *.gcda | ||||
| *.gcno | ||||
|  | ||||
| tools/man-generator | ||||
| tools/man-generator.c | ||||
|  | ||||
| test/.lib-dir-stamp | ||||
| test/.tests-stamp | ||||
| test/lib/dmsecuretest | ||||
| test/lib/lvchange | ||||
| test/lib/lvconvert | ||||
| test/lib/lvcreate | ||||
| test/lib/lvdisplay | ||||
| test/lib/lvextend | ||||
| test/lib/lvmconfig | ||||
| test/lib/lvmdiskscan | ||||
| test/lib/lvmsadc | ||||
| test/lib/lvmsar | ||||
| test/lib/lvreduce | ||||
| test/lib/lvremove | ||||
| test/lib/lvrename | ||||
| test/lib/lvresize | ||||
| test/lib/lvs | ||||
| test/lib/lvscan | ||||
| test/lib/pvchange | ||||
| test/lib/pvck | ||||
| test/lib/pvcreate | ||||
| test/lib/pvdisplay | ||||
| test/lib/pvmove | ||||
| test/lib/pvremove | ||||
| test/lib/pvresize | ||||
| test/lib/pvs | ||||
| test/lib/pvscan | ||||
| test/lib/securetest | ||||
| test/lib/vgcfgbackup | ||||
| test/lib/vgcfgrestore | ||||
| test/lib/vgchange | ||||
| test/lib/vgck | ||||
| test/lib/vgconvert | ||||
| test/lib/vgcreate | ||||
| test/lib/vgdisplay | ||||
| test/lib/vgexport | ||||
| test/lib/vgextend | ||||
| test/lib/vgimport | ||||
| test/lib/vgimportclone | ||||
| test/lib/vgmerge | ||||
| test/lib/vgmknodes | ||||
| test/lib/vgreduce | ||||
| test/lib/vgremove | ||||
| test/lib/vgrename | ||||
| test/lib/vgs | ||||
| test/lib/vgscan | ||||
| test/lib/vgsplit | ||||
| test/api/lvtest.t | ||||
| test/api/pe_start.t | ||||
| test/api/percent.t | ||||
| test/api/python_lvm_unit.py | ||||
| test/api/test | ||||
| test/api/thin_percent.t | ||||
| test/api/vglist.t | ||||
| test/api/vgtest.t | ||||
| test/lib/aux | ||||
| test/lib/check | ||||
| test/lib/clvmd | ||||
| test/lib/dm-version-expected | ||||
| test/lib/dmeventd | ||||
| test/lib/dmsetup | ||||
| test/lib/dmstats | ||||
| test/lib/fail | ||||
| test/lib/flavour-ndev-cluster | ||||
| test/lib/flavour-ndev-cluster-lvmpolld | ||||
| test/lib/flavour-ndev-lvmetad | ||||
| test/lib/flavour-ndev-lvmetad-lvmpolld | ||||
| test/lib/flavour-ndev-lvmpolld | ||||
| test/lib/flavour-ndev-vanilla | ||||
| test/lib/flavour-udev-cluster | ||||
| test/lib/flavour-udev-cluster-lvmpolld | ||||
| test/lib/flavour-udev-lvmetad | ||||
| test/lib/flavour-udev-lvmetad-lvmpolld | ||||
| test/lib/flavour-udev-lvmlockd-dlm | ||||
| test/lib/flavour-udev-lvmlockd-sanlock | ||||
| test/lib/flavour-udev-lvmlockd-test | ||||
| test/lib/flavour-udev-lvmpolld | ||||
| test/lib/flavour-udev-vanilla | ||||
| test/lib/fsadm | ||||
| test/lib/get | ||||
| test/lib/inittest | ||||
| test/lib/invalid | ||||
| test/lib/lvm | ||||
| test/lib/lvm-wrapper | ||||
| test/lib/lvmchange | ||||
| test/lib/lvmdbusd.profile | ||||
| test/lib/lvmetad | ||||
| test/lib/lvmpolld | ||||
| test/lib/not | ||||
| test/lib/paths | ||||
| test/lib/paths-common | ||||
| test/lib/runner | ||||
| test/lib/should | ||||
| test/lib/test | ||||
| test/lib/thin-performance.profile | ||||
| test/lib/utils | ||||
| test/lib/version-expected | ||||
| test/unit/dmraid_t.c | ||||
| test/unit/unit-test | ||||
							
								
								
									
										2
									
								
								BUGS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								BUGS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| Snapshots under 2.4.18 can deadlock due to a bug in the VM system. | ||||
| 2.4.19-pre8 is fine. | ||||
							
								
								
									
										4
									
								
								COPYING
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								COPYING
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|      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. | ||||
|  | ||||
| @@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|     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. | ||||
|   | ||||
							
								
								
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| BSD 2-Clause License | ||||
|  | ||||
| Copyright (c) 2014, Red Hat, Inc. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		       Version 2.1, February 1999 | ||||
|  | ||||
|  Copyright (C) 1991, 1999 Free Software Foundation, Inc. | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| 		  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 Lesser GPL.  It also counts | ||||
|  as the successor of the GNU Library Public License, version 2, hence | ||||
|  the version number 2.1.] | ||||
| [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 | ||||
|  | ||||
| @@ -17,109 +17,97 @@ freedom to share and change it.  By contrast, the GNU General Public | ||||
| Licenses are intended to guarantee your freedom to share and change | ||||
| free software--to make sure the software is free for all its users. | ||||
|  | ||||
|   This license, the Lesser General Public License, applies to some | ||||
| specially designated software packages--typically libraries--of the | ||||
| Free Software Foundation and other authors who decide to use it.  You | ||||
| can use it too, but we suggest you first think carefully about whether | ||||
| this license or the ordinary General Public License is the better | ||||
| strategy to use in any particular case, based on the explanations below. | ||||
|   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 of use, | ||||
| not price.  Our General Public Licenses are designed to make sure that | ||||
| you have the freedom to distribute copies of free software (and charge | ||||
| for this service if you wish); that you receive source code or can get | ||||
| it if you want it; that you can change the software and use pieces of | ||||
| it in new free programs; and that you are informed that you can do | ||||
| these things. | ||||
|   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 | ||||
| distributors to deny you these rights or to ask you to surrender these | ||||
| rights.  These restrictions translate to certain responsibilities for | ||||
| you if you distribute copies of the library or if you modify it. | ||||
| 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 other code with the library, you must provide | ||||
| complete object files to the recipients, so that they can relink them | ||||
| with the library after making changes to the library and recompiling | ||||
| 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. | ||||
|  | ||||
|   We protect your rights with a two-step method: (1) we copyright the | ||||
| library, and (2) we offer you this license, which gives you legal | ||||
|   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. | ||||
|  | ||||
|   To protect each distributor, we want to make it very clear that | ||||
| there is no warranty for the free library.  Also, if the library is | ||||
| modified by someone else and passed on, the recipients should know | ||||
| that what they have is not the original version, so that the original | ||||
| author's reputation will not be affected by problems that might be | ||||
| introduced by others. | ||||
|   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, software patents pose a constant threat to the existence of | ||||
| any free program.  We wish to make sure that a company cannot | ||||
| effectively restrict the users of a free program by obtaining a | ||||
| restrictive license from a patent holder.  Therefore, we insist that | ||||
| any patent license obtained for a version of the library must be | ||||
| consistent with the full freedom of use specified in this license. | ||||
|   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.  This license, the GNU Lesser | ||||
| General Public License, applies to certain designated libraries, and | ||||
| is quite different from the ordinary General Public License.  We use | ||||
| this license for certain libraries in order to permit linking those | ||||
| libraries into non-free programs. | ||||
|   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. | ||||
|  | ||||
|   When a program is linked with a library, whether statically or using | ||||
| a shared library, the combination of the two is legally speaking a | ||||
| combined work, a derivative of the original library.  The ordinary | ||||
| General Public License therefore permits such linking only if the | ||||
| entire combination fits its criteria of freedom.  The Lesser General | ||||
| Public License permits more lax criteria for linking other code with | ||||
| the library. | ||||
|   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. | ||||
|  | ||||
|   We call this license the "Lesser" General Public License because it | ||||
| does Less to protect the user's freedom than the ordinary General | ||||
| Public License.  It also provides other free software developers Less | ||||
| of an advantage over competing non-free programs.  These disadvantages | ||||
| are the reason we use the ordinary General Public License for many | ||||
| libraries.  However, the Lesser license provides advantages in certain | ||||
| special circumstances. | ||||
|   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. | ||||
|  | ||||
|   For example, on rare occasions, there may be a special need to | ||||
| encourage the widest possible use of a certain library, so that it becomes | ||||
| a de-facto standard.  To achieve this, non-free programs must be | ||||
| allowed to use the library.  A more frequent case is that a free | ||||
| library does the same job as widely used non-free libraries.  In this | ||||
| case, there is little to gain by limiting the free library to free | ||||
| software only, so we use the Lesser General Public License. | ||||
|  | ||||
|   In other cases, permission to use a particular library in non-free | ||||
| programs enables a greater number of people to use a large body of | ||||
| free software.  For example, permission to use the GNU C Library in | ||||
| non-free programs enables many more people to use the whole GNU | ||||
| operating system, as well as its variant, the GNU/Linux operating | ||||
| system. | ||||
|  | ||||
|   Although the Lesser General Public License is Less protective of the | ||||
| users' freedom, it does ensure that the user of a program that is | ||||
| linked with the Library has the freedom and the wherewithal to run | ||||
| that program using a modified version of the Library. | ||||
|   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, whereas the latter must | ||||
| be combined with the library in order to run. | ||||
| 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 LESSER GENERAL PUBLIC LICENSE | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License Agreement applies to any software library or other | ||||
| program which contains a notice placed by the copyright holder or | ||||
| other authorized party saying it may be distributed under the terms of | ||||
| this Lesser General Public License (also called "this License"). | ||||
| Each licensee is addressed as "you". | ||||
|   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 | ||||
| @@ -268,7 +256,7 @@ distribute the object code for the work under the terms of Section 6. | ||||
| Any executables containing that work also fall under Section 6, | ||||
| whether or not they are linked directly with the Library itself. | ||||
|  | ||||
|   6. As an exception to the Sections above, you may also combine or | ||||
|   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 | ||||
| @@ -295,31 +283,23 @@ of these things: | ||||
|     Library will not necessarily be able to recompile the application | ||||
|     to use the modified definitions.) | ||||
|  | ||||
|     b) Use a suitable shared library mechanism for linking with the | ||||
|     Library.  A suitable mechanism is one that (1) uses at run time a | ||||
|     copy of the library already present on the user's computer system, | ||||
|     rather than copying library functions into the executable, and (2) | ||||
|     will operate properly with a modified version of the library, if | ||||
|     the user installs one, as long as the modified version is | ||||
|     interface-compatible with the version that the work was made with. | ||||
|  | ||||
|     c) Accompany the work with a written offer, valid for at | ||||
|     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. | ||||
|  | ||||
|     d) If distribution of the work is made by offering access to copy | ||||
|     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. | ||||
|  | ||||
|     e) Verify that the user has already received a copy of these | ||||
|     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 materials to be distributed need not include anything that is | ||||
| normally distributed (in either source or binary form) with the major | ||||
| 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. | ||||
| @@ -368,7 +348,7 @@ Library), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute, link with or modify the Library | ||||
| subject to these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties with | ||||
| 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 | ||||
| @@ -411,7 +391,7 @@ excluded.  In such case, this License incorporates the limitation as if | ||||
| written in the body of this License. | ||||
|  | ||||
|   13. The Free Software Foundation may publish revised and/or new | ||||
| versions of the Lesser General Public License from time to time. | ||||
| 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. | ||||
|  | ||||
| @@ -457,7 +437,7 @@ DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
|            How to Apply These Terms to Your New Libraries | ||||
|      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 | ||||
| @@ -474,18 +454,19 @@ convey the exclusion of warranty; and each file should have at least the | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This library is free software; you can redistribute it and/or | ||||
|     modify it under the terms of the GNU Lesser General Public | ||||
|     modify it under the terms of the GNU Library General Public | ||||
|     License as published by the Free Software Foundation; either | ||||
|     version 2.1 of the License, or (at your option) any later version. | ||||
|     version 2 of the License, or (at your option) any later version. | ||||
|  | ||||
|     This library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|     Lesser General Public License for more details. | ||||
|     Library General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Lesser General Public | ||||
|     License along with this library; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|     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. | ||||
|  | ||||
| @@ -500,5 +481,3 @@ necessary.  Here is a sample; alter the names: | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| That's all there is to it! | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -1,30 +1,44 @@ | ||||
| Installation | ||||
| ============ | ||||
| LVM2 installation | ||||
| ================= | ||||
|  | ||||
| 1) Generate custom makefiles. | ||||
| 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 | ||||
|  | ||||
|    Use ./configure --help to see other options. | ||||
|  | ||||
| 2) Build and install. | ||||
| 3) Build and install LVM2. | ||||
|  | ||||
|    Run 'make' from the top directory to build everything you configured. | ||||
|    Run 'make install' to build and install everything you configured. | ||||
|    Run 'make install' from the top directory. | ||||
|  | ||||
|    If you only want the device-mapper libraries and tools use | ||||
|    'make device-mapper' or 'make install_device-mapper'. | ||||
|  | ||||
| 3) If using LVM2, create a configuration file. | ||||
| 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. | ||||
|   | ||||
							
								
								
									
										214
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								Makefile.in
									
									
									
									
									
								
							| @@ -1,211 +1,35 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2001 Sistina Software | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This LVM 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 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. | ||||
| # This LVM 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 General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # You should have received a copy of the GNU Library General Public | ||||
| # License along with this LVM library; 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@ | ||||
| top_builddir = @top_builddir@ | ||||
| abs_top_builddir = @abs_top_builddir@ | ||||
| abs_top_srcdir = @abs_top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS = libdm conf daemons include lib libdaemon man scripts tools | ||||
| SUBDIRS = include man lib tools | ||||
|  | ||||
| ifeq ("@UDEV_RULES@", "yes") | ||||
|   SUBDIRS += udev | ||||
| endif | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),clean) | ||||
|   SUBDIRS += test | ||||
| endif | ||||
| # FIXME Should use intermediate Makefiles here! | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = conf include man test scripts \ | ||||
|     libdaemon lib tools daemons libdm \ | ||||
|     udev po | ||||
| tools.distclean: test.distclean | ||||
|   SUBDIRS += lib/format1 \ | ||||
| 	     test/mm test/device test/format1 test/regex test/filters | ||||
| endif | ||||
| DISTCLEAN_DIRS += lcov_reports* | ||||
| DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| include $(top_srcdir)/base/Makefile | ||||
| include $(top_srcdir)/device_mapper/Makefile | ||||
| include $(top_srcdir)/test/unit/Makefile | ||||
| lib: include | ||||
| tools: include lib | ||||
|  | ||||
| lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET) | ||||
| daemons: lib libdaemon tools | ||||
| scripts: lib | ||||
| tools: lib libdaemon | ||||
| po: tools daemons | ||||
| man: tools | ||||
| all_man: tools | ||||
| test: tools daemons | ||||
| unit-test  run-unit-test: test | ||||
|  | ||||
| daemons.device-mapper: libdm.device-mapper | ||||
| tools.device-mapper: libdm.device-mapper | ||||
| device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper | ||||
| device_mapper: device-mapper | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| daemons.pofile: lib.pofile | ||||
| po.pofile: tools.pofile daemons.pofile | ||||
| pofile: po.pofile | ||||
| endif | ||||
|  | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| tools.cflow: libdm.cflow lib.cflow | ||||
| daemons.cflow: tools.cflow | ||||
| cflow: include.cflow | ||||
| endif | ||||
|  | ||||
| CSCOPE_DIRS = base daemons device_mapper include lib libdaemon scripts tools libdm test | ||||
| ifneq ("@CSCOPE_CMD@", "") | ||||
| cscope.out: | ||||
| 	@CSCOPE_CMD@ -b -R $(patsubst %,-s%,$(addprefix $(srcdir)/,$(CSCOPE_DIRS))) | ||||
| all: cscope.out | ||||
| endif | ||||
| DISTCLEAN_TARGETS += cscope.out | ||||
| CLEAN_DIRS += autom4te.cache | ||||
|  | ||||
| check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test | ||||
| 	$(MAKE) -C test $(@) | ||||
|  | ||||
| conf.generate man.generate: tools | ||||
|  | ||||
| # how to use parenthesis in makefiles | ||||
| leftparen:=( | ||||
| LVM_VER := $(firstword $(subst $(leftparen), ,$(LVM_VERSION))) | ||||
| VER := LVM2.$(LVM_VER) | ||||
| # release file name | ||||
| FILE_VER := $(VER).tgz | ||||
| CLEAN_TARGETS += $(FILE_VER) | ||||
| CLEAN_DIRS += $(rpmbuilddir) | ||||
|  | ||||
| dist: | ||||
| 	@echo "Generating $(FILE_VER)";\ | ||||
| 	(cd $(top_srcdir); git ls-tree -r HEAD --name-only | xargs tar --transform "s,^,$(VER)/," -c) | gzip >$(FILE_VER) | ||||
|  | ||||
| rpm: dist | ||||
| 	$(RM) -r $(rpmbuilddir)/SOURCES | ||||
| 	$(MKDIR_P) $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_builddir)/$(FILE_VER) $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES | ||||
| 	DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\ | ||||
| 	GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\ | ||||
| 	$(SED) -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \ | ||||
| 	    -e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \ | ||||
| 	    -e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \ | ||||
| 	    $(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc | ||||
| 	V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec | ||||
|  | ||||
| generate: conf.generate man.generate | ||||
| 	$(MAKE) -C conf generate | ||||
| 	$(MAKE) -C man generate | ||||
|  | ||||
| all_man: | ||||
| 	$(MAKE) -C man all_man | ||||
|  | ||||
| install_system_dirs: | ||||
| 	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR) | ||||
| 	$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache | ||||
|  | ||||
| install_initscripts: | ||||
| 	$(MAKE) -C scripts install_initscripts | ||||
|  | ||||
| install_systemd_generators: | ||||
| 	$(MAKE) -C scripts install_systemd_generators | ||||
| 	$(MAKE) -C man install_systemd_generators | ||||
|  | ||||
| install_systemd_units: | ||||
| 	$(MAKE) -C scripts install_systemd_units | ||||
|  | ||||
| install_all_man: | ||||
| 	$(MAKE) -C man install_all_man | ||||
|  | ||||
| install_tmpfiles_configuration: | ||||
| 	$(MAKE) -C scripts install_tmpfiles_configuration | ||||
|  | ||||
| help: | ||||
| 	@echo -e "\nAvailable targets:" | ||||
| 	@echo "  all			Default target." | ||||
| 	@echo "  all_man		Build all man pages with generators." | ||||
| 	@echo "  clean			Remove all compile files." | ||||
| 	@echo "  device-mapper		Device mapper part of lvm2." | ||||
| 	@echo "  dist			Generate distributable file." | ||||
| 	@echo "  distclean		Remove all build files." | ||||
| 	@echo "  generate		Generate man pages for sources." | ||||
| 	@echo "  help			Display callable targets." | ||||
| 	@echo "  install		Install all files." | ||||
| 	@echo "  install_all_man	Install all man pages." | ||||
| 	@echo "  install_cluster	Install cmirrord." | ||||
| 	@echo "  install_device-mapper	Install device mapper files." | ||||
| 	@echo "  install_initscripts	Install initialization scripts." | ||||
| 	@echo "  install_lvm2		Install lvm2 files." | ||||
| 	@echo "  install_systemd_units	Install systemd units." | ||||
| 	@echo "  lcov			Generate lcov output." | ||||
| 	@echo "  lcov-dated		Generate lcov with timedate suffix." | ||||
| 	@echo "  lcov-reset		Reset lcov counters" | ||||
| 	@echo "  man			Build man pages." | ||||
| 	@echo "  rpm			Build rpm." | ||||
| 	@echo "  run-unit-test		Run unit tests." | ||||
| 	@echo "  tags			Generate c/etags." | ||||
|  | ||||
| ifneq ("$(LCOV)", "") | ||||
| .PHONY: lcov-reset lcov lcov-dated | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),lcov-dated) | ||||
| LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S) | ||||
| lcov-dated: lcov | ||||
| else | ||||
| LCOV_REPORTS_DIR := lcov_reports | ||||
| endif | ||||
|  | ||||
| lcov-reset: | ||||
| 	$(LCOV) --zerocounters --directory $(top_builddir) | ||||
|  | ||||
| ifneq ("$(GENHTML)", "") | ||||
| lcov: | ||||
| 	$(RM) -rf $(LCOV_REPORTS_DIR) | ||||
| 	$(MKDIR_P) $(LCOV_REPORTS_DIR) | ||||
| 	$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \ | ||||
| 		--output-file $(LCOV_REPORTS_DIR)/out.info | ||||
| 	-test ! -s $(LCOV_REPORTS_DIR)/out.info || \ | ||||
| 		$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \ | ||||
| 		$(LCOV_REPORTS_DIR)/out.info | ||||
| endif | ||||
|  | ||||
| endif | ||||
|  | ||||
| ifneq ($(shell which ctags 2>/dev/null),) | ||||
| .PHONY: tags | ||||
| tags: | ||||
| 	test -z "$(shell find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags | ||||
| 	test -f tags || find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' + | ||||
|  | ||||
| CLEAN_TARGETS += tags | ||||
| endif | ||||
|   | ||||
							
								
								
									
										56
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								README
									
									
									
									
									
								
							| @@ -1,51 +1,25 @@ | ||||
| This tree contains the LVM2 and device-mapper tools and libraries. | ||||
| This directory contains a beta release of LVM2, the new version of  | ||||
| the userland LVM tools designed for the new device-mapper for  | ||||
| the Linux kernel. | ||||
|  | ||||
| This is development branch, for stable 2.02 release see stable-2.02 branch. | ||||
| The device-mapper needs to be installed before compiling these LVM2 tools. | ||||
|  | ||||
| For more information about LVM2 read the changelog in the WHATS_NEW file. | ||||
| For more information about LVM2 read the WHATS_NEW file. | ||||
| Installation instructions are in INSTALL. | ||||
|  | ||||
| This is beta-quality software, released for testing purposes only. | ||||
| There is no warranty - see COPYING and COPYING.LIB. | ||||
|  | ||||
| Tarballs are available from: | ||||
|   ftp://sourceware.org/pub/lvm2/ | ||||
|   https://github.com/lvmteam/lvm2/releases | ||||
|   ftp://ftp.sistina.com/pub/LVM2/tools/ | ||||
|   ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
| The source code is stored in git: | ||||
|   https://sourceware.org/git/?p=lvm2.git | ||||
|   git clone git://sourceware.org/git/lvm2.git | ||||
| mirrored to: | ||||
|   https://github.com/lvmteam/lvm2 | ||||
|   git clone https://github.com/lvmteam/lvm2.git | ||||
|   git clone git@github.com:lvmteam/lvm2.git | ||||
| To access the CVS tree use: | ||||
|   cvs -d :pserver:cvs@tech.sistina.com:/data/cvs login | ||||
|   CVS password: cvs1 | ||||
|   cvs -d :pserver:cvs@tech.sistina.com:/data/cvs checkout LVM2 | ||||
|  | ||||
| Mailing list for general discussion related to LVM2: | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
| Mailing list for discussion/bug reports etc. | ||||
|   lvm-devel@sistina.com | ||||
|   Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel | ||||
|  | ||||
| Mailing lists for LVM2 development, patches and commits: | ||||
|   lvm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel | ||||
|  | ||||
|   lvm2-commits@lists.fedorahosted.org (Read-only archive of commits) | ||||
|   Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits | ||||
|  | ||||
| Mailing list for device-mapper development, including kernel patches | ||||
| and multipath-tools: | ||||
|   dm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel | ||||
|  | ||||
| Website: | ||||
|   https://sourceware.org/lvm2/ | ||||
|  | ||||
| Report upstream bugs at: | ||||
|   https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper | ||||
| or open issues at: | ||||
|   https://github.com/lvmteam/lvm2/issues | ||||
|  | ||||
| The source code repository used until 7th June 2012 is accessible using CVS: | ||||
|  | ||||
|   cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs | ||||
|   cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2 | ||||
|  | ||||
| The password is cvs. | ||||
|   | ||||
							
								
								
									
										62
									
								
								TESTING
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								TESTING
									
									
									
									
									
								
							| @@ -1,62 +0,0 @@ | ||||
| LVM2 Test Suite | ||||
| =============== | ||||
|  | ||||
| The codebase contains many tests in the test subdirectory. | ||||
|  | ||||
| Before running tests | ||||
| -------------------- | ||||
|  | ||||
| Keep in mind the testsuite MUST run under root user. | ||||
|  | ||||
| It is recommended not to use LVM on the test machine, especially when running | ||||
| tests with udev (`make check_system`.) | ||||
|  | ||||
| You MUST disable (or mask) any LVM daemons: | ||||
|  | ||||
| - lvmetad | ||||
| - dmeventd | ||||
| - lvmpolld | ||||
| - lvmdbusd | ||||
| - lvmlockd | ||||
| - clvmd | ||||
| - cmirrord | ||||
|  | ||||
| For running cluster tests, we are using singlenode locking. Pass | ||||
| `--with-clvmd=singlenode` to configure. | ||||
|  | ||||
| NOTE: This is useful only for testing, and should not be used in produciton | ||||
| code. | ||||
|  | ||||
| To run D-Bus daemon tests, existing D-Bus session is required. | ||||
|  | ||||
| Running tests | ||||
| ------------- | ||||
|  | ||||
| As root run: | ||||
|  | ||||
|     make check | ||||
|  | ||||
| To run only tests matching a string: | ||||
|  | ||||
|     make check T=test | ||||
|  | ||||
| To skip tests matching a string: | ||||
|  | ||||
|     make check S=test | ||||
|  | ||||
| There are other targets and many environment variables can be used to tweak the | ||||
| testsuite - for full list and description run `make -C test help`. | ||||
|  | ||||
| Installing testsuite | ||||
| -------------------- | ||||
|  | ||||
| It is possible to install and run a testsuite against installed LVM. Run the | ||||
| following: | ||||
|  | ||||
|     make -C test install | ||||
|  | ||||
| Then lvm2-testsuite binary can be executed to test installed binaries. | ||||
|  | ||||
| See `lvm2-testsuite --help` for options. The same environment variables can be | ||||
| used as with `make check`. | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 1.02.179-git (2021-05-07) | ||||
							
								
								
									
										1490
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										1490
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										234
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								acinclude.m4
									
									
									
									
									
								
							| @@ -1,234 +0,0 @@ | ||||
| dnl AC_GCC_VERSION | ||||
| dnl check for compiler version | ||||
| dnl sets COMPILER_VERSION and GCC_VERSION | ||||
|  | ||||
| AC_DEFUN([AC_CC_VERSION], | ||||
| [ | ||||
|     AC_MSG_CHECKING([C compiler version]) | ||||
|     COMPILER_VERSION=`$CC -v 2>&1 | grep version` | ||||
|     case "$COMPILER_VERSION" in | ||||
|         *gcc*) | ||||
| 	   dnl Ok, how to turn $3 into the real $3 | ||||
| 	   GCC_VERSION=`echo $COMPILER_VERSION | \ | ||||
| 	   sed -e 's/[[^ ]]*\ [[^ ]]*\ \([[^ ]]*\)\ .*/\1/'` ;; | ||||
| 	*) GCC_VERSION=unknown ;; | ||||
|     esac | ||||
|     AC_MSG_RESULT($GCC_VERSION) | ||||
| ]) | ||||
|  | ||||
| dnl AC_TRY_CCFLAG([CCFLAG], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports a given flag | ||||
|  | ||||
| AC_DEFUN([AC_TRY_CCFLAG], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_CFLAGS=$CFLAGS | ||||
|     CFLAGS=$1 | ||||
|     AC_CACHE_CHECK([whether $CC accepts $1 flag], [ac_cv_flag_$2], | ||||
| 	[AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     CFLAGS=$ac_save_CFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| dnl AC_IF_YES([TEST-FOR-YES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) | ||||
| dnl AS_IF() abstraction, checks shell variable for 'yes' | ||||
| AC_DEFUN([AC_IF_YES], [AS_IF([test $$1 = yes], [$2], [$3])]) | ||||
|  | ||||
| dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports given ld flags | ||||
|  | ||||
| AC_DEFUN([AC_TRY_LDFLAGS], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_LDFLAGS=$LDFLAGS | ||||
|     LDFLAGS=$1 | ||||
| 	AC_CACHE_CHECK([whether $CC accepts $1 ld flags], [ac_cv_flag_$2], | ||||
| 	[AC_LINK_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     LDFLAGS=$ac_save_LDFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| # =========================================================================== | ||||
| #      http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html | ||||
| # =========================================================================== | ||||
| # | ||||
| # SYNOPSIS | ||||
| # | ||||
| #   AX_GCC_BUILTIN(BUILTIN) | ||||
| # | ||||
| # DESCRIPTION | ||||
| # | ||||
| #   This macro checks if the compiler supports one of GCC's built-in | ||||
| #   functions; many other compilers also provide those same built-ins. | ||||
| # | ||||
| #   The BUILTIN parameter is the name of the built-in function. | ||||
| # | ||||
| #   If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since | ||||
| #   builtins usually start with two underscores they will be copied over | ||||
| #   into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for | ||||
| #   __builtin_expect()). | ||||
| # | ||||
| #   The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g. | ||||
| #   ax_cv_have___builtin_expect). | ||||
| # | ||||
| #   The macro currently supports the following built-in functions: | ||||
| # | ||||
| #    __builtin_assume_aligned | ||||
| #    __builtin_bswap16 | ||||
| #    __builtin_bswap32 | ||||
| #    __builtin_bswap64 | ||||
| #    __builtin_choose_expr | ||||
| #    __builtin___clear_cache | ||||
| #    __builtin_clrsb | ||||
| #    __builtin_clrsbl | ||||
| #    __builtin_clrsbll | ||||
| #    __builtin_clz | ||||
| #    __builtin_clzl | ||||
| #    __builtin_clzll | ||||
| #    __builtin_complex | ||||
| #    __builtin_constant_p | ||||
| #    __builtin_ctz | ||||
| #    __builtin_ctzl | ||||
| #    __builtin_ctzll | ||||
| #    __builtin_expect | ||||
| #    __builtin_ffs | ||||
| #    __builtin_ffsl | ||||
| #    __builtin_ffsll | ||||
| #    __builtin_fpclassify | ||||
| #    __builtin_huge_val | ||||
| #    __builtin_huge_valf | ||||
| #    __builtin_huge_vall | ||||
| #    __builtin_inf | ||||
| #    __builtin_infd128 | ||||
| #    __builtin_infd32 | ||||
| #    __builtin_infd64 | ||||
| #    __builtin_inff | ||||
| #    __builtin_infl | ||||
| #    __builtin_isinf_sign | ||||
| #    __builtin_nan | ||||
| #    __builtin_nand128 | ||||
| #    __builtin_nand32 | ||||
| #    __builtin_nand64 | ||||
| #    __builtin_nanf | ||||
| #    __builtin_nanl | ||||
| #    __builtin_nans | ||||
| #    __builtin_nansf | ||||
| #    __builtin_nansl | ||||
| #    __builtin_object_size | ||||
| #    __builtin_parity | ||||
| #    __builtin_parityl | ||||
| #    __builtin_parityll | ||||
| #    __builtin_popcount | ||||
| #    __builtin_popcountl | ||||
| #    __builtin_popcountll | ||||
| #    __builtin_powi | ||||
| #    __builtin_powif | ||||
| #    __builtin_powil | ||||
| #    __builtin_prefetch | ||||
| #    __builtin_trap | ||||
| #    __builtin_types_compatible_p | ||||
| #    __builtin_unreachable | ||||
| # | ||||
| #   Unsuppored built-ins will be tested with an empty parameter set and the | ||||
| #   result of the check might be wrong or meaningless so use with care. | ||||
| # | ||||
| # LICENSE | ||||
| # | ||||
| #   Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com> | ||||
| # | ||||
| #   Copying and distribution of this file, with or without modification, are | ||||
| #   permitted in any medium without royalty provided the copyright notice | ||||
| #   and this notice are preserved.  This file is offered as-is, without any | ||||
| #   warranty. | ||||
|  | ||||
| serial 3 | ||||
|  | ||||
| AC_DEFUN([AX_GCC_BUILTIN], [ | ||||
|     AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) | ||||
|  | ||||
|     AC_CACHE_CHECK([for $1], [ac_var], [ | ||||
|         AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ | ||||
|             m4_case([$1], | ||||
|                 [__builtin_assume_aligned], [$1("", 0)], | ||||
|                 [__builtin_bswap16], [$1(0)], | ||||
|                 [__builtin_bswap32], [$1(0)], | ||||
|                 [__builtin_bswap64], [$1(0)], | ||||
|                 [__builtin_choose_expr], [$1(0, 0, 0)], | ||||
|                 [__builtin___clear_cache], [$1("", "")], | ||||
|                 [__builtin_clrsb], [$1(0)], | ||||
|                 [__builtin_clrsbl], [$1(0)], | ||||
|                 [__builtin_clrsbll], [$1(0)], | ||||
|                 [__builtin_clz], [$1(0)], | ||||
|                 [__builtin_clzl], [$1(0)], | ||||
|                 [__builtin_clzll], [$1(0)], | ||||
|                 [__builtin_complex], [$1(0.0, 0.0)], | ||||
|                 [__builtin_constant_p], [$1(0)], | ||||
|                 [__builtin_ctz], [$1(0)], | ||||
|                 [__builtin_ctzl], [$1(0)], | ||||
|                 [__builtin_ctzll], [$1(0)], | ||||
|                 [__builtin_expect], [$1(0, 0)], | ||||
|                 [__builtin_ffs], [$1(0)], | ||||
|                 [__builtin_ffsl], [$1(0)], | ||||
|                 [__builtin_ffsll], [$1(0)], | ||||
|                 [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], | ||||
|                 [__builtin_huge_val], [$1()], | ||||
|                 [__builtin_huge_valf], [$1()], | ||||
|                 [__builtin_huge_vall], [$1()], | ||||
|                 [__builtin_inf], [$1()], | ||||
|                 [__builtin_infd128], [$1()], | ||||
|                 [__builtin_infd32], [$1()], | ||||
|                 [__builtin_infd64], [$1()], | ||||
|                 [__builtin_inff], [$1()], | ||||
|                 [__builtin_infl], [$1()], | ||||
|                 [__builtin_isinf_sign], [$1(0.0)], | ||||
|                 [__builtin_nan], [$1("")], | ||||
|                 [__builtin_nand128], [$1("")], | ||||
|                 [__builtin_nand32], [$1("")], | ||||
|                 [__builtin_nand64], [$1("")], | ||||
|                 [__builtin_nanf], [$1("")], | ||||
|                 [__builtin_nanl], [$1("")], | ||||
|                 [__builtin_nans], [$1("")], | ||||
|                 [__builtin_nansf], [$1("")], | ||||
|                 [__builtin_nansl], [$1("")], | ||||
|                 [__builtin_object_size], [$1("", 0)], | ||||
|                 [__builtin_parity], [$1(0)], | ||||
|                 [__builtin_parityl], [$1(0)], | ||||
|                 [__builtin_parityll], [$1(0)], | ||||
|                 [__builtin_popcount], [$1(0)], | ||||
|                 [__builtin_popcountl], [$1(0)], | ||||
|                 [__builtin_popcountll], [$1(0)], | ||||
|                 [__builtin_powi], [$1(0, 0)], | ||||
|                 [__builtin_powif], [$1(0, 0)], | ||||
|                 [__builtin_powil], [$1(0, 0)], | ||||
|                 [__builtin_prefetch], [$1("")], | ||||
|                 [__builtin_trap], [$1()], | ||||
|                 [__builtin_types_compatible_p], [$1(int, int)], | ||||
|                 [__builtin_unreachable], [$1()], | ||||
|                 [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) | ||||
|                  $1()] | ||||
|             ) | ||||
|             ])], | ||||
|             [AS_VAR_SET([ac_var], [yes])], | ||||
|             [AS_VAR_SET([ac_var], [no])]) | ||||
|     ]) | ||||
|  | ||||
|     AS_IF([test yes = AS_VAR_GET([ac_var])], | ||||
|         [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, | ||||
|             [Define to 1 if the system has the `$1' built-in function])], []) | ||||
|  | ||||
|     AS_VAR_POPDEF([ac_var]) | ||||
| ]) | ||||
							
								
								
									
										673
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										673
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							| @@ -1,673 +0,0 @@ | ||||
| # generated automatically by aclocal 1.16.2 -*- Autoconf -*- | ||||
|  | ||||
| # Copyright (C) 1996-2020 Free Software Foundation, Inc. | ||||
|  | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||||
| # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||||
| # PARTICULAR PURPOSE. | ||||
|  | ||||
| m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) | ||||
| # =========================================================================== | ||||
| #     https://www.gnu.org/software/autoconf-archive/ax_python_module.html | ||||
| # =========================================================================== | ||||
| # | ||||
| # SYNOPSIS | ||||
| # | ||||
| #   AX_PYTHON_MODULE(modname[, fatal, python]) | ||||
| # | ||||
| # DESCRIPTION | ||||
| # | ||||
| #   Checks for Python module. | ||||
| # | ||||
| #   If fatal is non-empty then absence of a module will trigger an error. | ||||
| #   The third parameter can either be "python" for Python 2 or "python3" for | ||||
| #   Python 3; defaults to Python 3. | ||||
| # | ||||
| # LICENSE | ||||
| # | ||||
| #   Copyright (c) 2008 Andrew Collier | ||||
| # | ||||
| #   Copying and distribution of this file, with or without modification, are | ||||
| #   permitted in any medium without royalty provided the copyright notice | ||||
| #   and this notice are preserved. This file is offered as-is, without any | ||||
| #   warranty. | ||||
|  | ||||
| #serial 9 | ||||
|  | ||||
| AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE]) | ||||
| AC_DEFUN([AX_PYTHON_MODULE],[ | ||||
|     if test -z $PYTHON; | ||||
|     then | ||||
|         if test -z "$3"; | ||||
|         then | ||||
|             PYTHON="python3" | ||||
|         else | ||||
|             PYTHON="$3" | ||||
|         fi | ||||
|     fi | ||||
|     PYTHON_NAME=`basename $PYTHON` | ||||
|     AC_MSG_CHECKING($PYTHON_NAME module: $1) | ||||
|     $PYTHON -c "import $1" 2>/dev/null | ||||
|     if test $? -eq 0; | ||||
|     then | ||||
|         AC_MSG_RESULT(yes) | ||||
|         eval AS_TR_CPP(HAVE_PYMOD_$1)=yes | ||||
|     else | ||||
|         AC_MSG_RESULT(no) | ||||
|         eval AS_TR_CPP(HAVE_PYMOD_$1)=no | ||||
|         # | ||||
|         if test -n "$2" | ||||
|         then | ||||
|             AC_MSG_ERROR(failed to find required module $1) | ||||
|             exit 1 | ||||
|         fi | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| # pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*- | ||||
| # serial 11 (pkg-config-0.29.1) | ||||
|  | ||||
| dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. | ||||
| dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> | ||||
| dnl | ||||
| dnl This program is free software; you can redistribute it and/or modify | ||||
| dnl it under the terms of the GNU General Public License as published by | ||||
| dnl the Free Software Foundation; either version 2 of the License, or | ||||
| dnl (at your option) any later version. | ||||
| dnl | ||||
| dnl This program is distributed in the hope that it will be useful, but | ||||
| dnl WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| dnl General Public License for more details. | ||||
| dnl | ||||
| dnl You should have received a copy of the GNU General Public License | ||||
| dnl along with this program; if not, write to the Free Software | ||||
| dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
| dnl 02111-1307, USA. | ||||
| dnl | ||||
| dnl As a special exception to the GNU General Public License, if you | ||||
| dnl distribute this file as part of a program that contains a | ||||
| dnl configuration script generated by Autoconf, you may include it under | ||||
| dnl the same distribution terms that you use for the rest of that | ||||
| dnl program. | ||||
|  | ||||
| dnl PKG_PREREQ(MIN-VERSION) | ||||
| dnl ----------------------- | ||||
| dnl Since: 0.29 | ||||
| dnl | ||||
| dnl Verify that the version of the pkg-config macros are at least | ||||
| dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's | ||||
| dnl installed version of pkg-config, this checks the developer's version | ||||
| dnl of pkg.m4 when generating configure. | ||||
| dnl | ||||
| dnl To ensure that this macro is defined, also add: | ||||
| dnl m4_ifndef([PKG_PREREQ], | ||||
| dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) | ||||
| dnl | ||||
| dnl See the "Since" comment for each macro you use to see what version | ||||
| dnl of the macros you require. | ||||
| m4_defun([PKG_PREREQ], | ||||
| [m4_define([PKG_MACROS_VERSION], [0.29.1]) | ||||
| m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, | ||||
|     [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) | ||||
| ])dnl PKG_PREREQ | ||||
|  | ||||
| dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) | ||||
| dnl ---------------------------------- | ||||
| dnl Since: 0.16 | ||||
| dnl | ||||
| dnl Search for the pkg-config tool and set the PKG_CONFIG variable to | ||||
| dnl first found in the path. Checks that the version of pkg-config found | ||||
| dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is | ||||
| dnl used since that's the first version where most current features of | ||||
| dnl pkg-config existed. | ||||
| AC_DEFUN([PKG_PROG_PKG_CONFIG], | ||||
| [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) | ||||
| m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) | ||||
| m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) | ||||
| AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) | ||||
| AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) | ||||
| AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) | ||||
|  | ||||
| if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then | ||||
| 	AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) | ||||
| fi | ||||
| if test -n "$PKG_CONFIG"; then | ||||
| 	_pkg_min_version=m4_default([$1], [0.9.0]) | ||||
| 	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) | ||||
| 	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then | ||||
| 		AC_MSG_RESULT([yes]) | ||||
| 	else | ||||
| 		AC_MSG_RESULT([no]) | ||||
| 		PKG_CONFIG="" | ||||
| 	fi | ||||
| fi[]dnl | ||||
| ])dnl PKG_PROG_PKG_CONFIG | ||||
|  | ||||
| dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| dnl ------------------------------------------------------------------- | ||||
| dnl Since: 0.18 | ||||
| dnl | ||||
| dnl Check to see whether a particular set of modules exists. Similar to | ||||
| dnl PKG_CHECK_MODULES(), but does not set variables or print errors. | ||||
| dnl | ||||
| dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| dnl only at the first occurence in configure.ac, so if the first place | ||||
| dnl it's called might be skipped (such as if it is within an "if", you | ||||
| dnl have to call PKG_CHECK_EXISTS manually | ||||
| AC_DEFUN([PKG_CHECK_EXISTS], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| if test -n "$PKG_CONFIG" && \ | ||||
|     AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then | ||||
|   m4_default([$2], [:]) | ||||
| m4_ifvaln([$3], [else | ||||
|   $3])dnl | ||||
| fi]) | ||||
|  | ||||
| dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) | ||||
| dnl --------------------------------------------- | ||||
| dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting | ||||
| dnl pkg_failed based on the result. | ||||
| m4_define([_PKG_CONFIG], | ||||
| [if test -n "$$1"; then | ||||
|     pkg_cv_[]$1="$$1" | ||||
|  elif test -n "$PKG_CONFIG"; then | ||||
|     PKG_CHECK_EXISTS([$3], | ||||
|                      [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` | ||||
| 		      test "x$?" != "x0" && pkg_failed=yes ], | ||||
| 		     [pkg_failed=yes]) | ||||
|  else | ||||
|     pkg_failed=untried | ||||
| fi[]dnl | ||||
| ])dnl _PKG_CONFIG | ||||
|  | ||||
| dnl _PKG_SHORT_ERRORS_SUPPORTED | ||||
| dnl --------------------------- | ||||
| dnl Internal check to see if pkg-config supports short errors. | ||||
| AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then | ||||
|         _pkg_short_errors_supported=yes | ||||
| else | ||||
|         _pkg_short_errors_supported=no | ||||
| fi[]dnl | ||||
| ])dnl _PKG_SHORT_ERRORS_SUPPORTED | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||||
| dnl   [ACTION-IF-NOT-FOUND]) | ||||
| dnl -------------------------------------------------------------- | ||||
| dnl Since: 0.4.0 | ||||
| dnl | ||||
| dnl Note that if there is a possibility the first call to | ||||
| dnl PKG_CHECK_MODULES might not happen, you should be sure to include an | ||||
| dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac | ||||
| AC_DEFUN([PKG_CHECK_MODULES], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl | ||||
| AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl | ||||
|  | ||||
| pkg_failed=no | ||||
| AC_MSG_CHECKING([for $1]) | ||||
|  | ||||
| _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) | ||||
| _PKG_CONFIG([$1][_LIBS], [libs], [$2]) | ||||
|  | ||||
| m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS | ||||
| and $1[]_LIBS to avoid the need to call pkg-config. | ||||
| See the pkg-config man page for more details.]) | ||||
|  | ||||
| if test $pkg_failed = yes; then | ||||
|    	AC_MSG_RESULT([no]) | ||||
|         _PKG_SHORT_ERRORS_SUPPORTED | ||||
|         if test $_pkg_short_errors_supported = yes; then | ||||
| 	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` | ||||
|         else  | ||||
| 	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` | ||||
|         fi | ||||
| 	# Put the nasty error message in config.log where it belongs | ||||
| 	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD | ||||
|  | ||||
| 	m4_default([$4], [AC_MSG_ERROR( | ||||
| [Package requirements ($2) were not met: | ||||
|  | ||||
| $$1_PKG_ERRORS | ||||
|  | ||||
| Consider adjusting the PKG_CONFIG_PATH environment variable if you | ||||
| installed software in a non-standard prefix. | ||||
|  | ||||
| _PKG_TEXT])[]dnl | ||||
|         ]) | ||||
| elif test $pkg_failed = untried; then | ||||
|      	AC_MSG_RESULT([no]) | ||||
| 	m4_default([$4], [AC_MSG_FAILURE( | ||||
| [The pkg-config script could not be found or is too old.  Make sure it | ||||
| is in your PATH or set the PKG_CONFIG environment variable to the full | ||||
| path to pkg-config. | ||||
|  | ||||
| _PKG_TEXT | ||||
|  | ||||
| To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl | ||||
|         ]) | ||||
| else | ||||
| 	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS | ||||
| 	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS | ||||
|         AC_MSG_RESULT([yes]) | ||||
| 	$3 | ||||
| fi[]dnl | ||||
| ])dnl PKG_CHECK_MODULES | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||||
| dnl   [ACTION-IF-NOT-FOUND]) | ||||
| dnl --------------------------------------------------------------------- | ||||
| dnl Since: 0.29 | ||||
| dnl | ||||
| dnl Checks for existence of MODULES and gathers its build flags with | ||||
| dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags | ||||
| dnl and VARIABLE-PREFIX_LIBS from --libs. | ||||
| dnl | ||||
| dnl Note that if there is a possibility the first call to | ||||
| dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to | ||||
| dnl include an explicit call to PKG_PROG_PKG_CONFIG in your | ||||
| dnl configure.ac. | ||||
| AC_DEFUN([PKG_CHECK_MODULES_STATIC], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| _save_PKG_CONFIG=$PKG_CONFIG | ||||
| PKG_CONFIG="$PKG_CONFIG --static" | ||||
| PKG_CHECK_MODULES($@) | ||||
| PKG_CONFIG=$_save_PKG_CONFIG[]dnl | ||||
| ])dnl PKG_CHECK_MODULES_STATIC | ||||
|  | ||||
|  | ||||
| dnl PKG_INSTALLDIR([DIRECTORY]) | ||||
| dnl ------------------------- | ||||
| dnl Since: 0.27 | ||||
| dnl | ||||
| dnl Substitutes the variable pkgconfigdir as the location where a module | ||||
| dnl should install pkg-config .pc files. By default the directory is | ||||
| dnl $libdir/pkgconfig, but the default can be changed by passing | ||||
| dnl DIRECTORY. The user can override through the --with-pkgconfigdir | ||||
| dnl parameter. | ||||
| AC_DEFUN([PKG_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, | ||||
|     [with_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ])dnl PKG_INSTALLDIR | ||||
|  | ||||
|  | ||||
| dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) | ||||
| dnl -------------------------------- | ||||
| dnl Since: 0.27 | ||||
| dnl | ||||
| dnl Substitutes the variable noarch_pkgconfigdir as the location where a | ||||
| dnl module should install arch-independent pkg-config .pc files. By | ||||
| dnl default the directory is $datadir/pkgconfig, but the default can be | ||||
| dnl changed by passing DIRECTORY. The user can override through the | ||||
| dnl --with-noarch-pkgconfigdir parameter. | ||||
| AC_DEFUN([PKG_NOARCH_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([noarch-pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, | ||||
|     [with_noarch_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ])dnl PKG_NOARCH_INSTALLDIR | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, | ||||
| dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| dnl ------------------------------------------- | ||||
| dnl Since: 0.28 | ||||
| dnl | ||||
| dnl Retrieves the value of the pkg-config variable for the given module. | ||||
| AC_DEFUN([PKG_CHECK_VAR], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl | ||||
|  | ||||
| _PKG_CONFIG([$1], [variable="][$3]["], [$2]) | ||||
| AS_VAR_COPY([$1], [pkg_cv_][$1]) | ||||
|  | ||||
| AS_VAR_IF([$1], [""], [$5], [$4])dnl | ||||
| ])dnl PKG_CHECK_VAR | ||||
|  | ||||
| dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ------------------------------------------ | ||||
| dnl | ||||
| dnl Prepare a "--with-" configure option using the lowercase | ||||
| dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and | ||||
| dnl PKG_CHECK_MODULES in a single macro. | ||||
| AC_DEFUN([PKG_WITH_MODULES], | ||||
| [ | ||||
| m4_pushdef([with_arg], m4_tolower([$1])) | ||||
|  | ||||
| m4_pushdef([description], | ||||
|            [m4_default([$5], [build with ]with_arg[ support])]) | ||||
|  | ||||
| m4_pushdef([def_arg], [m4_default([$6], [auto])]) | ||||
| m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) | ||||
| m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) | ||||
|  | ||||
| m4_case(def_arg, | ||||
|             [yes],[m4_pushdef([with_without], [--without-]with_arg)], | ||||
|             [m4_pushdef([with_without],[--with-]with_arg)]) | ||||
|  | ||||
| AC_ARG_WITH(with_arg, | ||||
|      AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, | ||||
|     [AS_TR_SH([with_]with_arg)=def_arg]) | ||||
|  | ||||
| AS_CASE([$AS_TR_SH([with_]with_arg)], | ||||
|             [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], | ||||
|             [auto],[PKG_CHECK_MODULES([$1],[$2], | ||||
|                                         [m4_n([def_action_if_found]) $3], | ||||
|                                         [m4_n([def_action_if_not_found]) $4])]) | ||||
|  | ||||
| m4_popdef([with_arg]) | ||||
| m4_popdef([description]) | ||||
| m4_popdef([def_arg]) | ||||
|  | ||||
| ])dnl PKG_WITH_MODULES | ||||
|  | ||||
| dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ----------------------------------------------- | ||||
| dnl | ||||
| dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES | ||||
| dnl check._[VARIABLE-PREFIX] is exported as make variable. | ||||
| AC_DEFUN([PKG_HAVE_WITH_MODULES], | ||||
| [ | ||||
| PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) | ||||
|  | ||||
| AM_CONDITIONAL([HAVE_][$1], | ||||
|                [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) | ||||
| ])dnl PKG_HAVE_WITH_MODULES | ||||
|  | ||||
| dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ------------------------------------------------------ | ||||
| dnl | ||||
| dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after | ||||
| dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make | ||||
| dnl and preprocessor variable. | ||||
| AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], | ||||
| [ | ||||
| PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) | ||||
|  | ||||
| AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], | ||||
|         [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) | ||||
| ])dnl PKG_HAVE_DEFINE_WITH_MODULES | ||||
|  | ||||
| # Copyright (C) 1999-2020 Free Software Foundation, Inc. | ||||
| # | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
|  | ||||
| # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| # --------------------------------------------------------------------------- | ||||
| # Adds support for distributing Python modules and packages.  To | ||||
| # install modules, copy them to $(pythondir), using the python_PYTHON | ||||
| # automake variable.  To install a package with the same name as the | ||||
| # automake package, install to $(pkgpythondir), or use the | ||||
| # pkgpython_PYTHON automake variable. | ||||
| # | ||||
| # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as | ||||
| # locations to install python extension modules (shared libraries). | ||||
| # Another macro is required to find the appropriate flags to compile | ||||
| # extension modules. | ||||
| # | ||||
| # If your package is configured with a different prefix to python, | ||||
| # users will have to add the install directory to the PYTHONPATH | ||||
| # environment variable, or create a .pth file (see the python | ||||
| # documentation for details). | ||||
| # | ||||
| # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will | ||||
| # cause an error if the version of python installed on the system | ||||
| # doesn't meet the requirement.  MINIMUM-VERSION should consist of | ||||
| # numbers and dots only. | ||||
| AC_DEFUN([AM_PATH_PYTHON], | ||||
|  [ | ||||
|   dnl Find a Python interpreter.  Python versions prior to 2.0 are not | ||||
|   dnl supported. (2.0 was released on October 16, 2000). | ||||
|   m4_define_default([_AM_PYTHON_INTERPRETER_LIST], | ||||
| [python python2 python3 dnl | ||||
|  python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl | ||||
|  python3.2 python3.1 python3.0 dnl | ||||
|  python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl | ||||
|  python2.0]) | ||||
|  | ||||
|   AC_ARG_VAR([PYTHON], [the Python interpreter]) | ||||
|  | ||||
|   m4_if([$1],[],[ | ||||
|     dnl No version check is needed. | ||||
|     # Find any Python interpreter. | ||||
|     if test -z "$PYTHON"; then | ||||
|       AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) | ||||
|     fi | ||||
|     am_display_PYTHON=python | ||||
|   ], [ | ||||
|     dnl A version check is needed. | ||||
|     if test -n "$PYTHON"; then | ||||
|       # If the user set $PYTHON, use it and don't search something else. | ||||
|       AC_MSG_CHECKING([whether $PYTHON version is >= $1]) | ||||
|       AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], | ||||
| 			      [AC_MSG_RESULT([yes])], | ||||
| 			      [AC_MSG_RESULT([no]) | ||||
| 			       AC_MSG_ERROR([Python interpreter is too old])]) | ||||
|       am_display_PYTHON=$PYTHON | ||||
|     else | ||||
|       # Otherwise, try each interpreter until we find one that satisfies | ||||
|       # VERSION. | ||||
|       AC_CACHE_CHECK([for a Python interpreter with version >= $1], | ||||
| 	[am_cv_pathless_PYTHON],[ | ||||
| 	for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do | ||||
| 	  test "$am_cv_pathless_PYTHON" = none && break | ||||
| 	  AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) | ||||
| 	done]) | ||||
|       # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. | ||||
|       if test "$am_cv_pathless_PYTHON" = none; then | ||||
| 	PYTHON=: | ||||
|       else | ||||
|         AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) | ||||
|       fi | ||||
|       am_display_PYTHON=$am_cv_pathless_PYTHON | ||||
|     fi | ||||
|   ]) | ||||
|  | ||||
|   if test "$PYTHON" = :; then | ||||
|   dnl Run any user-specified action, or abort. | ||||
|     m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) | ||||
|   else | ||||
|  | ||||
|   dnl Query Python for its version number.  Although site.py simply uses | ||||
|   dnl sys.version[:3], printing that failed with Python 3.10, since the | ||||
|   dnl trailing zero was eliminated. So now we output just the major | ||||
|   dnl and minor version numbers, as numbers. Apparently the tertiary | ||||
|   dnl version is not of interest. | ||||
|  | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], | ||||
|     [am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`]) | ||||
|   AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) | ||||
|  | ||||
|   dnl Use the values of $prefix and $exec_prefix for the corresponding | ||||
|   dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX.  These are made | ||||
|   dnl distinct variables so they can be overridden if need be.  However, | ||||
|   dnl general consensus is that you shouldn't need this ability. | ||||
|  | ||||
|   AC_SUBST([PYTHON_PREFIX], ['${prefix}']) | ||||
|   AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) | ||||
|  | ||||
|   dnl At times (like when building shared libraries) you may want | ||||
|   dnl to know which OS platform Python thinks this is. | ||||
|  | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], | ||||
|     [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) | ||||
|   AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) | ||||
|  | ||||
|   # Just factor out some code duplication. | ||||
|   am_python_setup_sysconfig="\ | ||||
| import sys | ||||
| # Prefer sysconfig over distutils.sysconfig, for better compatibility | ||||
| # with python 3.x.  See automake bug#10227. | ||||
| try: | ||||
|     import sysconfig | ||||
| except ImportError: | ||||
|     can_use_sysconfig = 0 | ||||
| else: | ||||
|     can_use_sysconfig = 1 | ||||
| # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: | ||||
| # <https://github.com/pypa/virtualenv/issues/118> | ||||
| try: | ||||
|     from platform import python_implementation | ||||
|     if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': | ||||
|         can_use_sysconfig = 0 | ||||
| except ImportError: | ||||
|     pass" | ||||
|  | ||||
|   dnl Set up 4 directories: | ||||
|  | ||||
|   dnl pythondir -- where to install python scripts.  This is the | ||||
|   dnl   site-packages directory, not the python standard library | ||||
|   dnl   directory like in previous automake betas.  This behavior | ||||
|   dnl   is more consistent with lispdir.m4 for example. | ||||
|   dnl Query distutils for this directory. | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON script directory], | ||||
|     [am_cv_python_pythondir], | ||||
|     [if test "x$prefix" = xNONE | ||||
|      then | ||||
|        am_py_prefix=$ac_default_prefix | ||||
|      else | ||||
|        am_py_prefix=$prefix | ||||
|      fi | ||||
|      am_cv_python_pythondir=`$PYTHON -c " | ||||
| $am_python_setup_sysconfig | ||||
| if can_use_sysconfig: | ||||
|     sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) | ||||
| else: | ||||
|     from distutils import sysconfig | ||||
|     sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') | ||||
| sys.stdout.write(sitedir)"` | ||||
|      case $am_cv_python_pythondir in | ||||
|      $am_py_prefix*) | ||||
|        am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` | ||||
|        am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` | ||||
|        ;; | ||||
|      *) | ||||
|        case $am_py_prefix in | ||||
|          /usr|/System*) ;; | ||||
|          *) | ||||
| 	  am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages | ||||
| 	  ;; | ||||
|        esac | ||||
|        ;; | ||||
|      esac | ||||
|     ]) | ||||
|   AC_SUBST([pythondir], [$am_cv_python_pythondir]) | ||||
|  | ||||
|   dnl pkgpythondir -- $PACKAGE directory under pythondir.  Was | ||||
|   dnl   PYTHON_SITE_PACKAGE in previous betas, but this naming is | ||||
|   dnl   more consistent with the rest of automake. | ||||
|  | ||||
|   AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) | ||||
|  | ||||
|   dnl pyexecdir -- directory for installing python extension modules | ||||
|   dnl   (shared libraries) | ||||
|   dnl Query distutils for this directory. | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], | ||||
|     [am_cv_python_pyexecdir], | ||||
|     [if test "x$exec_prefix" = xNONE | ||||
|      then | ||||
|        am_py_exec_prefix=$am_py_prefix | ||||
|      else | ||||
|        am_py_exec_prefix=$exec_prefix | ||||
|      fi | ||||
|      am_cv_python_pyexecdir=`$PYTHON -c " | ||||
| $am_python_setup_sysconfig | ||||
| if can_use_sysconfig: | ||||
|     sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) | ||||
| else: | ||||
|     from distutils import sysconfig | ||||
|     sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') | ||||
| sys.stdout.write(sitedir)"` | ||||
|      case $am_cv_python_pyexecdir in | ||||
|      $am_py_exec_prefix*) | ||||
|        am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` | ||||
|        am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` | ||||
|        ;; | ||||
|      *) | ||||
|        case $am_py_exec_prefix in | ||||
|          /usr|/System*) ;; | ||||
|          *) | ||||
| 	   am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages | ||||
| 	   ;; | ||||
|        esac | ||||
|        ;; | ||||
|      esac | ||||
|     ]) | ||||
|   AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) | ||||
|  | ||||
|   dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) | ||||
|  | ||||
|   AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) | ||||
|  | ||||
|   dnl Run any user-specified action. | ||||
|   $2 | ||||
|   fi | ||||
|  | ||||
| ]) | ||||
|  | ||||
|  | ||||
| # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) | ||||
| # --------------------------------------------------------------------------- | ||||
| # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. | ||||
| # Run ACTION-IF-FALSE otherwise. | ||||
| # This test uses sys.hexversion instead of the string equivalent (first | ||||
| # word of sys.version), in order to cope with versions such as 2.2c1. | ||||
| # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). | ||||
| AC_DEFUN([AM_PYTHON_CHECK_VERSION], | ||||
|  [prog="import sys | ||||
| # split strings by '.' and convert to numeric.  Append some zeros | ||||
| # because we need at least 4 digits for the hex conversion. | ||||
| # map returns an iterator in Python 3.0 and a list in 2.x | ||||
| minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] | ||||
| minverhex = 0 | ||||
| # xrange is not present in Python 3.0 and range returns an iterator | ||||
| for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] | ||||
| sys.exit(sys.hexversion < minverhex)" | ||||
|   AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) | ||||
|  | ||||
| # Copyright (C) 2001-2020 Free Software Foundation, Inc. | ||||
| # | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
| # AM_RUN_LOG(COMMAND) | ||||
| # ------------------- | ||||
| # Run COMMAND, save the exit status in ac_status, and log it. | ||||
| # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) | ||||
| AC_DEFUN([AM_RUN_LOG], | ||||
| [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD | ||||
|    ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD | ||||
|    ac_status=$? | ||||
|    echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD | ||||
|    (exit $ac_status); }]) | ||||
|  | ||||
| m4_include([acinclude.m4]) | ||||
							
								
								
									
										1325
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1325
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										718
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										718
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,62 +1,36 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # install - install a program, script, or datafile | ||||
|  | ||||
| scriptversion=2006-10-14.15 | ||||
|  | ||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||
| # later released in X11R6 (xc/config/util/install.sh) with the | ||||
| # following copyright and license. | ||||
| # This comes from X11R5 (mit/util/scripts/install.sh). | ||||
| # | ||||
| # Copyright (C) 1994 X Consortium | ||||
| # Copyright 1991 by the Massachusetts Institute of Technology | ||||
| # | ||||
| # 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. | ||||
| # 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. | ||||
| # | ||||
| # Calling this script install-sh is preferred over install.sh, to prevent | ||||
| # `make' implicit rules from creating a file called install from it | ||||
| # when there is no Makefile. | ||||
| # | ||||
| # This script is compatible with the BSD install script, but was written | ||||
| # from scratch. | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
|  | ||||
| nl=' | ||||
| ' | ||||
| IFS=" ""	$nl" | ||||
|  | ||||
| # set DOITPROG to echo to test this script | ||||
|  | ||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||
| doit="${DOITPROG-}" | ||||
| if test -z "$doit"; then | ||||
|   doit_exec=exec | ||||
| else | ||||
|   doit_exec=$doit | ||||
| fi | ||||
|  | ||||
| # Put in absolute file names if you don't have them in your path; | ||||
| # or use environment vars. | ||||
|  | ||||
| # put in absolute paths if you don't have them in your path; or use env. vars. | ||||
|  | ||||
| mvprog="${MVPROG-mv}" | ||||
| cpprog="${CPPROG-cp}" | ||||
| @@ -67,441 +41,211 @@ stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| posix_glob= | ||||
| posix_mkdir= | ||||
|  | ||||
| # Desired mode of installed file. | ||||
| mode=0755 | ||||
|  | ||||
| chmodcmd=$chmodprog | ||||
| chowncmd= | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
| transformbasename="" | ||||
| transform_arg="" | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd="" | ||||
| chgrpcmd="" | ||||
| stripcmd="" | ||||
| rmcmd="$rmprog -f" | ||||
| mvcmd="$mvprog" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
| dstarg= | ||||
| no_target_directory= | ||||
| src="" | ||||
| dst="" | ||||
| dir_arg="" | ||||
|  | ||||
| usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||
|    or: $0 [OPTION]... -d DIRECTORIES... | ||||
| while [ x"$1" != x ]; do | ||||
|     case $1 in | ||||
| 	-c) instcmd="$cpprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
| In the 1st form, copy SRCFILE to DSTFILE. | ||||
| In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | ||||
| In the 4th, create DIRECTORIES. | ||||
| 	-d) dir_arg=true | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
| Options: | ||||
| -c         (ignored) | ||||
| -d         create directories instead of installing files. | ||||
| -g GROUP   $chgrpprog installed files to GROUP. | ||||
| -m MODE    $chmodprog installed files to MODE. | ||||
| -o USER    $chownprog installed files to USER. | ||||
| -s         $stripprog installed files. | ||||
| -t DIRECTORY  install into DIRECTORY. | ||||
| -T         report an error if DSTFILE is a directory. | ||||
| --help     display this help and exit. | ||||
| --version  display version info and exit. | ||||
| 	-m) chmodcmd="$chmodprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
| Environment variables override the default commands: | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG | ||||
| " | ||||
| 	-o) chowncmd="$chownprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
| while test $# -ne 0; do | ||||
|   case $1 in | ||||
|     -c) shift | ||||
|         continue;; | ||||
| 	-g) chgrpcmd="$chgrpprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
|     -d) dir_arg=true | ||||
|         shift | ||||
|         continue;; | ||||
| 	-s) stripcmd="$stripprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
|     -g) chgrpcmd="$chgrpprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
| 	-t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
|     --help) echo "$usage"; exit $?;; | ||||
| 	-b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|  | ||||
|     -m) mode=$2 | ||||
|         shift | ||||
|         shift | ||||
| 	case $mode in | ||||
| 	  *' '* | *'	'* | *' | ||||
| '*	  | *'*'* | *'?'* | *'['*) | ||||
| 	    echo "$0: invalid mode: $mode" >&2 | ||||
| 	    exit 1;; | ||||
| 	esac | ||||
|         continue;; | ||||
|  | ||||
|     -o) chowncmd="$chownprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -s) stripcmd=$stripprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -t) dstarg=$2 | ||||
| 	shift | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
|     -T) no_target_directory=true | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
|     --version) echo "$0 $scriptversion"; exit $?;; | ||||
|  | ||||
|     --)	shift | ||||
| 	break;; | ||||
|  | ||||
|     -*)	echo "$0: invalid option: $1" >&2 | ||||
| 	exit 1;; | ||||
|  | ||||
|     *)  break;; | ||||
|   esac | ||||
| done | ||||
|  | ||||
| if test $# -ne 0 && test -z "$dir_arg$dstarg"; then | ||||
|   # When -d is used, all remaining arguments are directories to create. | ||||
|   # When -t is used, the destination is already specified. | ||||
|   # Otherwise, the last argument is the destination.  Remove it from $@. | ||||
|   for arg | ||||
|   do | ||||
|     if test -n "$dstarg"; then | ||||
|       # $@ is not empty: it contains at least $arg. | ||||
|       set fnord "$@" "$dstarg" | ||||
|       shift # fnord | ||||
|     fi | ||||
|     shift # arg | ||||
|     dstarg=$arg | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if test $# -eq 0; then | ||||
|   if test -z "$dir_arg"; then | ||||
|     echo "$0: no input file specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|   # It's OK to call `install-sh -d' without argument. | ||||
|   # This can happen when creating conditional directories. | ||||
|   exit 0 | ||||
| fi | ||||
|  | ||||
| if test -z "$dir_arg"; then | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
|   # Set umask so as not to create temps with too-generous modes. | ||||
|   # However, 'strip' requires both read and write access to temps. | ||||
|   case $mode in | ||||
|     # Optimize common cases. | ||||
|     *644) cp_umask=133;; | ||||
|     *755) cp_umask=22;; | ||||
|  | ||||
|     *[0-7]) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw='% 200' | ||||
|       fi | ||||
|       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; | ||||
|     *) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw=,u+rw | ||||
|       fi | ||||
|       cp_umask=$mode$u_plus_rw;; | ||||
|   esac | ||||
| fi | ||||
|  | ||||
| for src | ||||
| do | ||||
|   # Protect names starting with `-'. | ||||
|   case $src in | ||||
|     -*) src=./$src ;; | ||||
|   esac | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     dst=$src | ||||
|     dstdir=$dst | ||||
|     test -d "$dstdir" | ||||
|     dstdir_status=$? | ||||
|   else | ||||
|  | ||||
|     # Waiting for this to be detected by the "$cpprog $src $dsttmp" command | ||||
|     # might cause directories to be created, which would be especially bad | ||||
|     # if $src (and thus $dsttmp) contains '*'. | ||||
|     if test ! -f "$src" && test ! -d "$src"; then | ||||
|       echo "$0: $src does not exist." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     if test -z "$dstarg"; then | ||||
|       echo "$0: no destination specified." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     dst=$dstarg | ||||
|     # Protect names starting with `-'. | ||||
|     case $dst in | ||||
|       -*) dst=./$dst ;; | ||||
|     esac | ||||
|  | ||||
|     # If destination is a directory, append the input filename; won't work | ||||
|     # if double slashes aren't ignored. | ||||
|     if test -d "$dst"; then | ||||
|       if test -n "$no_target_directory"; then | ||||
| 	echo "$0: $dstarg: Is a directory" >&2 | ||||
| 	exit 1 | ||||
|       fi | ||||
|       dstdir=$dst | ||||
|       dst=$dstdir/`basename "$src"` | ||||
|       dstdir_status=0 | ||||
|     else | ||||
|       # Prefer dirname, but fall back on a substitute if dirname fails. | ||||
|       dstdir=` | ||||
| 	(dirname "$dst") 2>/dev/null || | ||||
| 	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | ||||
| 	     X"$dst" : 'X\(//\)[^/]' \| \ | ||||
| 	     X"$dst" : 'X\(//\)$' \| \ | ||||
| 	     X"$dst" : 'X\(/\)' \| . 2>/dev/null || | ||||
| 	echo X"$dst" | | ||||
| 	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)[^/].*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\).*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 s/.*/./; q' | ||||
|       ` | ||||
|  | ||||
|       test -d "$dstdir" | ||||
|       dstdir_status=$? | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   obsolete_mkdir_used=false | ||||
|  | ||||
|   if test $dstdir_status != 0; then | ||||
|     case $posix_mkdir in | ||||
|       '') | ||||
| 	# Create intermediate dirs using mode 755 as modified by the umask. | ||||
| 	# This is like FreeBSD 'install' as of 1997-10-28. | ||||
| 	umask=`umask` | ||||
| 	case $stripcmd.$umask in | ||||
| 	  # Optimize common cases. | ||||
| 	  *[2367][2367]) mkdir_umask=$umask;; | ||||
| 	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; | ||||
|  | ||||
| 	  *[0-7]) | ||||
| 	    mkdir_umask=`expr $umask + 22 \ | ||||
| 	      - $umask % 100 % 40 + $umask % 20 \ | ||||
| 	      - $umask % 10 % 4 + $umask % 2 | ||||
| 	    `;; | ||||
| 	  *) mkdir_umask=$umask,go-w;; | ||||
| 	esac | ||||
|  | ||||
| 	# With -d, create the new directory with the user-specified mode. | ||||
| 	# Otherwise, rely on $mkdir_umask. | ||||
| 	if test -n "$dir_arg"; then | ||||
| 	  mkdir_mode=-m$mode | ||||
| 	else | ||||
| 	  mkdir_mode= | ||||
| 	fi | ||||
|  | ||||
| 	posix_mkdir=false | ||||
| 	case $umask in | ||||
| 	  *[123567][0-7][0-7]) | ||||
| 	    # POSIX mkdir -p sets u+wx bits regardless of umask, which | ||||
| 	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0. | ||||
| 	    ;; | ||||
| 	  *) | ||||
| 	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ | ||||
| 	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 | ||||
|  | ||||
| 	    if (umask $mkdir_umask && | ||||
| 		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 | ||||
| 	*)  if [ x"$src" = x ] | ||||
| 	    then | ||||
| 	      if test -z "$dir_arg" || { | ||||
| 		   # Check for POSIX incompatibilities with -m. | ||||
| 		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | ||||
| 		   # other-writeable bit of parent directory when it shouldn't. | ||||
| 		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | ||||
| 		   ls_ld_tmpdir=`ls -ld "$tmpdir"` | ||||
| 		   case $ls_ld_tmpdir in | ||||
| 		     d????-?r-*) different_mode=700;; | ||||
| 		     d????-?--*) different_mode=755;; | ||||
| 		     *) false;; | ||||
| 		   esac && | ||||
| 		   $mkdirprog -m$different_mode -p -- "$tmpdir" && { | ||||
| 		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"` | ||||
| 		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" | ||||
| 		   } | ||||
| 		 } | ||||
| 	      then posix_mkdir=: | ||||
| 	      fi | ||||
| 	      rmdir "$tmpdir/d" "$tmpdir" | ||||
| 		src=$1 | ||||
| 	    else | ||||
| 	      # Remove any dirs left behind by ancient mkdir implementations. | ||||
| 	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null | ||||
| 		# this colon is to work around a 386BSD /bin/sh bug | ||||
| 		: | ||||
| 		dst=$1 | ||||
| 	    fi | ||||
| 	    trap '' 0;; | ||||
| 	esac;; | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     esac | ||||
|  | ||||
|     if | ||||
|       $posix_mkdir && ( | ||||
| 	umask $mkdir_umask && | ||||
| 	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" | ||||
|       ) | ||||
|     then : | ||||
|     else | ||||
|  | ||||
|       # The umask is ridiculous, or mkdir does not conform to POSIX, | ||||
|       # or it failed possibly due to a race condition.  Create the | ||||
|       # directory the slow way, step by step, checking for races as we go. | ||||
|  | ||||
|       case $dstdir in | ||||
| 	/*) prefix=/ ;; | ||||
| 	-*) prefix=./ ;; | ||||
| 	*)  prefix= ;; | ||||
|       esac | ||||
|  | ||||
|       case $posix_glob in | ||||
|         '') | ||||
| 	  if (set -f) 2>/dev/null; then | ||||
| 	    posix_glob=true | ||||
| 	  else | ||||
| 	    posix_glob=false | ||||
| 	  fi ;; | ||||
|       esac | ||||
|  | ||||
|       oIFS=$IFS | ||||
|       IFS=/ | ||||
|       $posix_glob && set -f | ||||
|       set fnord $dstdir | ||||
|       shift | ||||
|       $posix_glob && set +f | ||||
|       IFS=$oIFS | ||||
|  | ||||
|       prefixes= | ||||
|  | ||||
|       for d | ||||
|       do | ||||
| 	test -z "$d" && continue | ||||
|  | ||||
| 	prefix=$prefix$d | ||||
| 	if test -d "$prefix"; then | ||||
| 	  prefixes= | ||||
| 	else | ||||
| 	  if $posix_mkdir; then | ||||
| 	    (umask=$mkdir_umask && | ||||
| 	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break | ||||
| 	    # Don't fail if two instances are running concurrently. | ||||
| 	    test -d "$prefix" || exit 1 | ||||
| 	  else | ||||
| 	    case $prefix in | ||||
| 	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; | ||||
| 	      *) qprefix=$prefix;; | ||||
| 	    esac | ||||
| 	    prefixes="$prefixes '$qprefix'" | ||||
| 	  fi | ||||
| 	fi | ||||
| 	prefix=$prefix/ | ||||
|       done | ||||
|  | ||||
|       if test -n "$prefixes"; then | ||||
| 	# Don't fail if two instances are running concurrently. | ||||
| 	(umask $mkdir_umask && | ||||
| 	 eval "\$doit_exec \$mkdirprog $prefixes") || | ||||
| 	  test -d "$dstdir" || exit 1 | ||||
| 	obsolete_mkdir_used=true | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && | ||||
|     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && | ||||
|     { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || | ||||
|       test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 | ||||
|   else | ||||
|  | ||||
|     # Make a couple of temp file names in the proper directory. | ||||
|     dsttmp=$dstdir/_inst.$$_ | ||||
|     rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
|     # Trap to clean up those temp files at exit. | ||||
|     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | ||||
|  | ||||
|     # Copy the file name to the temp name. | ||||
|     (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && | ||||
|  | ||||
|     # and set any options; do chmod last to preserve setuid bits. | ||||
|     # | ||||
|     # If any of these fail, we abort the whole thing.  If we want to | ||||
|     # ignore errors from any of these, just make sure not to ignore | ||||
|     # errors from the above "$doit $cpprog $src $dsttmp" command. | ||||
|     # | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ | ||||
|       && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ | ||||
|       && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ | ||||
|       && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | ||||
|  | ||||
|     # Now rename the file to the real destination. | ||||
|     { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ | ||||
|       || { | ||||
| 	   # The rename failed, perhaps because mv can't rename something else | ||||
| 	   # to itself, or perhaps because mv is so ancient that it does not | ||||
| 	   # support -f. | ||||
|  | ||||
| 	   # Now remove or move aside any old file at destination location. | ||||
| 	   # We try this two ways since rm can't unlink itself on some | ||||
| 	   # systems and the destination file might be busy for other | ||||
| 	   # reasons.  In this case, the final cleanup might fail but the new | ||||
| 	   # file should still install successfully. | ||||
| 	   { | ||||
| 	     if test -f "$dst"; then | ||||
| 	       $doit $rmcmd -f "$dst" 2>/dev/null \ | ||||
| 	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ | ||||
| 		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ | ||||
| 	       || { | ||||
| 		 echo "$0: cannot unlink or rename $dst" >&2 | ||||
| 		 (exit 1); exit 1 | ||||
| 	       } | ||||
| 	     else | ||||
| 	       : | ||||
| 	     fi | ||||
| 	   } && | ||||
|  | ||||
| 	   # Now rename the file to the real destination. | ||||
| 	   $doit $mvcmd "$dsttmp" "$dst" | ||||
| 	 } | ||||
|     } || exit 1 | ||||
|  | ||||
|     trap '' 0 | ||||
|   fi | ||||
| done | ||||
|  | ||||
| # 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: | ||||
| if [ x"$src" = x ] | ||||
| then | ||||
| 	echo "install:	no input file specified" | ||||
| 	exit 1 | ||||
| else | ||||
| 	true | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ]; then | ||||
| 	dst=$src | ||||
| 	src="" | ||||
| 	 | ||||
| 	if [ -d $dst ]; then | ||||
| 		instcmd=: | ||||
| 		chmodcmd="" | ||||
| 	else | ||||
| 		instcmd=mkdir | ||||
| 	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 [ -f $src -o -d $src ] | ||||
| 	then | ||||
| 		true | ||||
| 	else | ||||
| 		echo "install:  $src does not exist" | ||||
| 		exit 1 | ||||
| 	fi | ||||
| 	 | ||||
| 	if [ x"$dst" = x ] | ||||
| 	then | ||||
| 		echo "install:	no destination specified" | ||||
| 		exit 1 | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| # If destination is a directory, append the input filename; if your system | ||||
| # does not like double slashes in filenames, you may need to add some logic | ||||
|  | ||||
| 	if [ -d $dst ] | ||||
| 	then | ||||
| 		dst="$dst"/`basename $src` | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ## this sed command emulates the dirname command | ||||
| dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | ||||
|  | ||||
| # Make sure that the destination directory exists. | ||||
| #  this part is taken from Noah Friedman's mkinstalldirs script | ||||
|  | ||||
| # Skip lots of stat calls in the usual case. | ||||
| if [ ! -d "$dstdir" ]; then | ||||
| defaultIFS='	 | ||||
| ' | ||||
| IFS="${IFS-${defaultIFS}}" | ||||
|  | ||||
| oIFS="${IFS}" | ||||
| # Some sh's can't handle IFS=/ for some reason. | ||||
| IFS='%' | ||||
| set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` | ||||
| IFS="${oIFS}" | ||||
|  | ||||
| pathcomp='' | ||||
|  | ||||
| while [ $# -ne 0 ] ; do | ||||
| 	pathcomp="${pathcomp}${1}" | ||||
| 	shift | ||||
|  | ||||
| 	if [ ! -d "${pathcomp}" ] ; | ||||
|         then | ||||
| 		$mkdirprog "${pathcomp}" | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| 	pathcomp="${pathcomp}/" | ||||
| done | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ] | ||||
| then | ||||
| 	$doit $instcmd $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 [ x"$transformarg" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	else | ||||
| 		dstfile=`basename $dst $transformbasename |  | ||||
| 			sed $transformarg`$transformbasename | ||||
| 	fi | ||||
|  | ||||
| # don't allow the sed command to completely eliminate the filename | ||||
|  | ||||
| 	if [ x"$dstfile" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| # Make a temp file name in the proper directory. | ||||
|  | ||||
| 	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  | ||||
|  | ||||
| fi && | ||||
|  | ||||
|  | ||||
| exit 0 | ||||
|   | ||||
| @@ -1,170 +0,0 @@ | ||||
| #!/bin/sh | ||||
| # py-compile - Compile a Python program | ||||
|  | ||||
| scriptversion=2011-06-08.12; # UTC | ||||
|  | ||||
| # Copyright (C) 2000-2014 Free Software Foundation, Inc. | ||||
|  | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| # As a special exception to the GNU General Public License, if you | ||||
| # distribute this file as part of a program that contains a | ||||
| # configuration script generated by Autoconf, you may include it under | ||||
| # the same distribution terms that you use for the rest of that program. | ||||
|  | ||||
| # This file is maintained in Automake, please report | ||||
| # bugs to <bug-automake@gnu.org> or send patches to | ||||
| # <automake-patches@gnu.org>. | ||||
|  | ||||
| if [ -z "$PYTHON" ]; then | ||||
|   PYTHON=python | ||||
| fi | ||||
|  | ||||
| me=py-compile | ||||
|  | ||||
| usage_error () | ||||
| { | ||||
|   echo "$me: $*" >&2 | ||||
|   echo "Try '$me --help' for more information." >&2 | ||||
|   exit 1 | ||||
| } | ||||
|  | ||||
| basedir= | ||||
| destdir= | ||||
| while test $# -ne 0; do | ||||
|   case "$1" in | ||||
|     --basedir) | ||||
|       if test $# -lt 2; then | ||||
|         usage_error "option '--basedir' requires an argument" | ||||
|       else | ||||
|         basedir=$2 | ||||
|       fi | ||||
|       shift | ||||
|       ;; | ||||
|     --destdir) | ||||
|       if test $# -lt 2; then | ||||
|         usage_error "option '--destdir' requires an argument" | ||||
|       else | ||||
|         destdir=$2 | ||||
|       fi | ||||
|       shift | ||||
|       ;; | ||||
|     -h|--help) | ||||
|       cat <<\EOF | ||||
| Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..." | ||||
|  | ||||
| Byte compile some python scripts FILES.  Use --destdir to specify any | ||||
| leading directory path to the FILES that you don't want to include in the | ||||
| byte compiled file.  Specify --basedir for any additional path information you | ||||
| do want to be shown in the byte compiled file. | ||||
|  | ||||
| Example: | ||||
|   py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py | ||||
|  | ||||
| Report bugs to <bug-automake@gnu.org>. | ||||
| EOF | ||||
|       exit $? | ||||
|       ;; | ||||
|     -v|--version) | ||||
|       echo "$me $scriptversion" | ||||
|       exit $? | ||||
|       ;; | ||||
|     --) | ||||
|       shift | ||||
|       break | ||||
|       ;; | ||||
|     -*) | ||||
|       usage_error "unrecognized option '$1'" | ||||
|       ;; | ||||
|     *) | ||||
|       break | ||||
|       ;; | ||||
|   esac | ||||
|   shift | ||||
| done | ||||
|  | ||||
| files=$* | ||||
| if test -z "$files"; then | ||||
|     usage_error "no files given" | ||||
| fi | ||||
|  | ||||
| # if basedir was given, then it should be prepended to filenames before | ||||
| # byte compilation. | ||||
| if [ -z "$basedir" ]; then | ||||
|     pathtrans="path = file" | ||||
| else | ||||
|     pathtrans="path = os.path.join('$basedir', file)" | ||||
| fi | ||||
|  | ||||
| # if destdir was given, then it needs to be prepended to the filename to | ||||
| # byte compile but not go into the compiled file. | ||||
| if [ -z "$destdir" ]; then | ||||
|     filetrans="filepath = path" | ||||
| else | ||||
|     filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)" | ||||
| fi | ||||
|  | ||||
| $PYTHON -c " | ||||
| import sys, os, py_compile, imp | ||||
|  | ||||
| files = '''$files''' | ||||
|  | ||||
| sys.stdout.write('Byte-compiling python modules...\n') | ||||
| for file in files.split(): | ||||
|     $pathtrans | ||||
|     $filetrans | ||||
|     if not os.path.exists(filepath) or not (len(filepath) >= 3 | ||||
|                                             and filepath[-3:] == '.py'): | ||||
| 	    continue | ||||
|     sys.stdout.write(file) | ||||
|     sys.stdout.flush() | ||||
|     if hasattr(imp, 'get_tag'): | ||||
|         py_compile.compile(filepath, imp.cache_from_source(filepath), path) | ||||
|     else: | ||||
|         py_compile.compile(filepath, filepath + 'c', path) | ||||
| sys.stdout.write('\n')" || exit $? | ||||
|  | ||||
| # this will fail for python < 1.5, but that doesn't matter ... | ||||
| $PYTHON -O -c " | ||||
| import sys, os, py_compile, imp | ||||
|  | ||||
| # pypy does not use .pyo optimization | ||||
| if hasattr(sys, 'pypy_translation_info'): | ||||
|     sys.exit(0) | ||||
|  | ||||
| files = '''$files''' | ||||
| sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n') | ||||
| for file in files.split(): | ||||
|     $pathtrans | ||||
|     $filetrans | ||||
|     if not os.path.exists(filepath) or not (len(filepath) >= 3 | ||||
|                                             and filepath[-3:] == '.py'): | ||||
| 	    continue | ||||
|     sys.stdout.write(file) | ||||
|     sys.stdout.flush() | ||||
|     if hasattr(imp, 'get_tag'): | ||||
|         py_compile.compile(filepath, imp.cache_from_source(filepath, False), path) | ||||
|     else: | ||||
|         py_compile.compile(filepath, filepath + 'o', path) | ||||
| sys.stdout.write('\n')" 2>/dev/null || : | ||||
|  | ||||
| # Local Variables: | ||||
| # mode: shell-script | ||||
| # sh-indentation: 2 | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
| # time-stamp-start: "scriptversion=" | ||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||
| # time-stamp-time-zone: "UTC" | ||||
| # time-stamp-end: "; # UTC" | ||||
| # End: | ||||
| @@ -1,40 +0,0 @@ | ||||
| # Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| # Uncomment this to build the simple radix tree.  You'll need to make clean too. | ||||
| # Comment to build the advanced radix tree. | ||||
| #base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE | ||||
|  | ||||
| # NOTE: this Makefile only works as 'include' for toplevel Makefile | ||||
| #       which defined all top_* variables | ||||
|  | ||||
| BASE_SOURCE=\ | ||||
| 	base/data-struct/hash.c \ | ||||
| 	base/data-struct/list.c \ | ||||
| 	base/data-struct/radix-tree.c | ||||
|  | ||||
| BASE_TARGET = base/libbase.a | ||||
| BASE_DEPENDS = $(BASE_SOURCE:%.c=%.d) | ||||
| BASE_OBJECTS = $(BASE_SOURCE:%.c=%.o) | ||||
| CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \ | ||||
| 	$(BASE_SOURCE:%.c=%.gcda) \ | ||||
| 	$(BASE_SOURCE:%.c=%.gcno) \ | ||||
| 	$(BASE_TARGET) | ||||
|  | ||||
| $(BASE_TARGET): $(BASE_OBJECTS) | ||||
| 	@echo "    [AR] $@" | ||||
| 	$(Q) $(RM) $@ | ||||
| 	$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null | ||||
|  | ||||
| ifeq ("$(DEPENDS)","yes") | ||||
| -include $(BASE_DEPENDS) | ||||
| endif | ||||
| @@ -1,477 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "device_mapper/misc/dmlib.h" | ||||
| #include "base/memory/zalloc.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| struct dm_hash_node { | ||||
| 	struct dm_hash_node *next; | ||||
| 	void *data; | ||||
| 	unsigned data_len; | ||||
| 	unsigned keylen; | ||||
| 	unsigned hash; | ||||
| 	char key[]; | ||||
| }; | ||||
|  | ||||
| struct dm_hash_table { | ||||
| 	unsigned num_nodes; | ||||
| 	unsigned num_hint; | ||||
| 	unsigned mask_slots;    /* (slots - 1) -> used as hash mask */ | ||||
| 	unsigned collisions;    /* Collissions of hash keys */ | ||||
| 	unsigned search;        /* How many keys were searched */ | ||||
| 	unsigned found;         /* How many nodes were found */ | ||||
| 	unsigned same_hash;     /* Was there a colision with same masked hash and len ? */ | ||||
| 	struct dm_hash_node **slots; | ||||
| }; | ||||
|  | ||||
| #if 0 /* TO BE REMOVED */ | ||||
| static unsigned _hash(const void *key, unsigned len) | ||||
| { | ||||
| 	/* 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 | ||||
| 	}; | ||||
|  | ||||
| 	const uint8_t *str = key; | ||||
| 	unsigned h = 0, g; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		h <<= 4; | ||||
| 		h += _nums[*str++]; | ||||
| 		g = h & ((unsigned) 0xf << 16u); | ||||
| 		if (g) { | ||||
| 			h ^= g >> 16u; | ||||
| 			h ^= g >> 5u; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| /* In-kernel DM hashing, still lots of collisions */ | ||||
| static unsigned _hash_in_kernel(const char *key, unsigned len) | ||||
| { | ||||
| 	const unsigned char *str = (unsigned char *)key; | ||||
| 	const unsigned hash_mult = 2654435387U; | ||||
| 	unsigned hash = 0, i; | ||||
|  | ||||
| 	for (i = 0; i < len; ++i) | ||||
| 		hash = (hash + str[i]) * hash_mult; | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #undef get16bits | ||||
| #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) | ||||
| #define get16bits(d) (*((const uint16_t *) (d))) | ||||
| #endif | ||||
|  | ||||
| #if !defined (get16bits) | ||||
| #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ | ||||
|                        +(uint32_t)(((const uint8_t *)(d))[0]) ) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Adapted Bob Jenkins hash to read by 2 bytes if possible. | ||||
|  * https://secure.wikimedia.org/wikipedia/en/wiki/Jenkins_hash_function | ||||
|  * | ||||
|  * Reduces amount of hash collisions | ||||
|  */ | ||||
| static unsigned _hash(const void *key, unsigned len) | ||||
| { | ||||
| 	const uint8_t *str = (uint8_t*) key; | ||||
| 	unsigned hash = 0, i; | ||||
| 	unsigned sz = len / 2; | ||||
|  | ||||
| 	for(i = 0; i < sz; ++i) { | ||||
| 		hash += get16bits(str + 2 * i); | ||||
| 		hash += (hash << 10); | ||||
| 		hash ^= (hash >> 6); | ||||
| 	} | ||||
|  | ||||
| 	if (len & 1) { | ||||
| 		hash += str[len - 1]; | ||||
| 		hash += (hash << 10); | ||||
| 		hash ^= (hash >> 6); | ||||
| 	} | ||||
|  | ||||
| 	hash += (hash << 3); | ||||
| 	hash ^= (hash >> 11); | ||||
| 	hash += (hash << 15); | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node *_create_node(const void *key, unsigned len) | ||||
| { | ||||
| 	struct dm_hash_node *n = malloc(sizeof(*n) + len); | ||||
|  | ||||
| 	if (n) { | ||||
| 		memcpy(n->key, key, len); | ||||
| 		n->keylen = len; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| struct dm_hash_table *dm_hash_create(unsigned size_hint) | ||||
| { | ||||
| 	size_t len; | ||||
| 	unsigned new_size = 16u; | ||||
| 	struct dm_hash_table *hc = zalloc(sizeof(*hc)); | ||||
|  | ||||
| 	if (!hc) { | ||||
| 		log_error("Failed to allocate memory for hash."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	hc->num_hint = size_hint; | ||||
|  | ||||
| 	/* round size hint up to a power of two */ | ||||
| 	while (new_size < size_hint) | ||||
| 		new_size = new_size << 1; | ||||
|  | ||||
| 	hc->mask_slots = new_size - 1; | ||||
| 	len = sizeof(*(hc->slots)) * new_size; | ||||
| 	if (!(hc->slots = zalloc(len))) { | ||||
| 		free(hc); | ||||
| 		log_error("Failed to allocate slots for hash."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return hc; | ||||
| } | ||||
|  | ||||
| static void _free_nodes(struct dm_hash_table *t) | ||||
| { | ||||
| 	struct dm_hash_node *c, *n; | ||||
| 	unsigned i; | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	log_debug("Free hash hint:%d slots:%d nodes:%d (s:%d f:%d c:%d h:%d)", | ||||
| 		  t->num_hint, t->mask_slots + 1, t->num_nodes, | ||||
| 		  t->search, t->found, t->collisions, t->same_hash); | ||||
| #endif | ||||
|  | ||||
| 	if (!t->num_nodes) | ||||
| 		return; | ||||
|  | ||||
| 	for (i = 0; i <= t->mask_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = n) { | ||||
| 			n = c->next; | ||||
| 			free(c); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void dm_hash_destroy(struct dm_hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	free(t->slots); | ||||
| 	free(t); | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_findh(struct dm_hash_table *t, const void *key, | ||||
| 				    uint32_t len, unsigned hash) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	++t->search; | ||||
| 	for (c = &t->slots[hash & t->mask_slots]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen == len && (*c)->hash == hash) { | ||||
| 			if (!memcmp(key, (*c)->key, len)) { | ||||
| 				++t->found; | ||||
| 				break; | ||||
| 			} | ||||
| 			++t->same_hash; | ||||
| 		} | ||||
| 		++t->collisions; | ||||
| 	} | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key, | ||||
| 				   uint32_t len) | ||||
| { | ||||
| 	return _findh(t, key, len, _hash(key, len)); | ||||
| } | ||||
|  | ||||
| void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, | ||||
| 			    uint32_t len) | ||||
| { | ||||
| 	struct dm_hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	return *c ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, | ||||
| 			  uint32_t len, void *data) | ||||
| { | ||||
| 	unsigned hash = _hash(key, len); | ||||
| 	struct dm_hash_node **c = _findh(t, key, len, hash); | ||||
|  | ||||
| 	if (*c) | ||||
| 		(*c)->data = data; | ||||
| 	else { | ||||
| 		struct dm_hash_node *n = _create_node(key, len); | ||||
|  | ||||
| 		if (!n) | ||||
| 			return 0; | ||||
|  | ||||
| 		n->data = data; | ||||
| 		n->hash = hash; | ||||
| 		n->next = 0; | ||||
| 		*c = n; | ||||
| 		t->num_nodes++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, | ||||
| 			uint32_t len) | ||||
| { | ||||
| 	struct dm_hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	if (*c) { | ||||
| 		struct dm_hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void *dm_hash_lookup(struct dm_hash_table *t, const char *key) | ||||
| { | ||||
| 	return dm_hash_lookup_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data) | ||||
| { | ||||
| 	return dm_hash_insert_binary(t, key, strlen(key) + 1, data); | ||||
| } | ||||
|  | ||||
| void dm_hash_remove(struct dm_hash_table *t, const char *key) | ||||
| { | ||||
| 	dm_hash_remove_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t, | ||||
| 					        const void *key, const void *val, | ||||
| 					        uint32_t len, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
| 	unsigned h; | ||||
|         | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen != len) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!memcmp(key, (*c)->key, len) && (*c)->data) { | ||||
| 			if (((*c)->data_len == val_len) && | ||||
| 			    !memcmp(val, (*c)->data, val_len)) | ||||
| 				return c; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key, | ||||
| 				  const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node *n; | ||||
| 	struct dm_hash_node *first; | ||||
| 	int len = strlen(key) + 1; | ||||
| 	unsigned h; | ||||
|  | ||||
| 	n = _create_node(key, len); | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	n->data = (void *)val; | ||||
| 	n->data_len = val_len; | ||||
|  | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	first = t->slots[h]; | ||||
|  | ||||
| 	if (first) | ||||
| 		n->next = first; | ||||
| 	else | ||||
| 		n->next = 0; | ||||
| 	t->slots[h] = n; | ||||
|  | ||||
| 	t->num_nodes++; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look through multiple entries with the same key for one that has a | ||||
|  * matching val and return that.  If none have maching val, return NULL. | ||||
|  */ | ||||
| void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key, | ||||
| 			      const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len); | ||||
|  | ||||
| 	return (c && *c) ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look through multiple entries with the same key for one that has a | ||||
|  * matching val and remove that. | ||||
|  */ | ||||
| void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key, | ||||
| 			     const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len); | ||||
|  | ||||
| 	if (c && *c) { | ||||
| 		struct dm_hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look up the value for a key and count how many | ||||
|  * entries have the same key. | ||||
|  * | ||||
|  * If no entries have key, return NULL and set count to 0. | ||||
|  * | ||||
|  * If one entry has the key, the function returns the val, | ||||
|  * and sets count to 1. | ||||
|  * | ||||
|  * If N entries have the key, the function returns the val | ||||
|  * from the first entry, and sets count to N. | ||||
|  */ | ||||
| void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
| 	struct dm_hash_node **c1 = NULL; | ||||
| 	uint32_t len = strlen(key) + 1; | ||||
| 	unsigned h; | ||||
|  | ||||
| 	*count = 0; | ||||
|  | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen != len) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!memcmp(key, (*c)->key, len)) { | ||||
| 			(*count)++; | ||||
| 			if (!c1) | ||||
| 				c1 = c; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!c1) | ||||
| 		return NULL; | ||||
| 	else | ||||
| 		return *c1 ? (*c1)->data : 0; | ||||
| } | ||||
|  | ||||
| unsigned dm_hash_get_num_entries(struct dm_hash_table *t) | ||||
| { | ||||
| 	return t->num_nodes; | ||||
| } | ||||
|  | ||||
| void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f) | ||||
| { | ||||
| 	struct dm_hash_node *c, *n; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i <= t->mask_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = n) { | ||||
| 			n = c->next; | ||||
| 			f(c->data); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void dm_hash_wipe(struct dm_hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	memset(t->slots, 0, sizeof(struct dm_hash_node *) * (t->mask_slots + 1)); | ||||
| 	t->num_nodes = t->collisions = t->search = t->same_hash = 0u; | ||||
| } | ||||
|  | ||||
| char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)), | ||||
| 		      struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->key; | ||||
| } | ||||
|  | ||||
| void *dm_hash_get_data(struct dm_hash_table *t __attribute__((unused)), | ||||
| 		       struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->data; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s) | ||||
| { | ||||
| 	struct dm_hash_node *c = NULL; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = s; i <= t->mask_slots && !c; i++) | ||||
| 		c = t->slots[i]; | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t) | ||||
| { | ||||
| 	return _next_slot(t, 0); | ||||
| } | ||||
|  | ||||
| struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->next ? n->next : _next_slot(t, (n->hash & t->mask_slots) + 1); | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| #ifndef BASE_DATA_STRUCT_HASH_H | ||||
| #define BASE_DATA_STRUCT_HASH_H | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| struct dm_hash_table; | ||||
| struct dm_hash_node; | ||||
|  | ||||
| typedef void (*dm_hash_iterate_fn) (void *data); | ||||
|  | ||||
| struct dm_hash_table *dm_hash_create(unsigned size_hint) | ||||
| 	__attribute__((__warn_unused_result__)); | ||||
| void dm_hash_destroy(struct dm_hash_table *t); | ||||
| void dm_hash_wipe(struct dm_hash_table *t); | ||||
|  | ||||
| void *dm_hash_lookup(struct dm_hash_table *t, const char *key); | ||||
| int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data); | ||||
| void dm_hash_remove(struct dm_hash_table *t, const char *key); | ||||
|  | ||||
| void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len); | ||||
| int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len, | ||||
| 			  void *data); | ||||
| void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len); | ||||
|  | ||||
| unsigned dm_hash_get_num_entries(struct dm_hash_table *t); | ||||
| void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f); | ||||
|  | ||||
| char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
| void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
| struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t); | ||||
| struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
|  | ||||
| /* | ||||
|  * dm_hash_insert() replaces the value of an existing | ||||
|  * entry with a matching key if one exists.  Otherwise | ||||
|  * it adds a new entry. | ||||
|  * | ||||
|  * dm_hash_insert_with_val() inserts a new entry if | ||||
|  * another entry with the same key already exists. | ||||
|  * val_len is the size of the data being inserted. | ||||
|  * | ||||
|  * If two entries with the same key exist, | ||||
|  * (added using dm_hash_insert_allow_multiple), then: | ||||
|  * . dm_hash_lookup() returns the first one it finds, and | ||||
|  *   dm_hash_lookup_with_val() returns the one with a matching | ||||
|  *   val_len/val. | ||||
|  * . dm_hash_remove() removes the first one it finds, and | ||||
|  *   dm_hash_remove_with_val() removes the one with a matching | ||||
|  *   val_len/val. | ||||
|  * | ||||
|  * If a single entry with a given key exists, and it has | ||||
|  * zero val_len, then: | ||||
|  * . dm_hash_lookup() returns it | ||||
|  * . dm_hash_lookup_with_val(val_len=0) returns it | ||||
|  * . dm_hash_remove() removes it | ||||
|  * . dm_hash_remove_with_val(val_len=0) removes it | ||||
|  * | ||||
|  * dm_hash_lookup_with_count() is a single call that will | ||||
|  * both lookup a key's value and check if there is more | ||||
|  * than one entry with the given key. | ||||
|  * | ||||
|  * (It is not meant to retrieve all the entries with the | ||||
|  * given key.  In the common case where a single entry exists | ||||
|  * for the key, it is useful to have a single call that will | ||||
|  * both look up the value and indicate if multiple values | ||||
|  * exist for the key.) | ||||
|  * | ||||
|  * dm_hash_lookup_with_count: | ||||
|  * . If no entries exist, the function returns NULL, and | ||||
|  *   the count is set to 0. | ||||
|  * . If only one entry exists, the value of that entry is | ||||
|  *   returned and count is set to 1. | ||||
|  * . If N entries exists, the value of the first entry is | ||||
|  *   returned and count is set to N. | ||||
|  */ | ||||
|  | ||||
| void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key, | ||||
|                               const void *val, uint32_t val_len); | ||||
| void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key, | ||||
|                              const void *val, uint32_t val_len); | ||||
| int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key, | ||||
|                                   const void *val, uint32_t val_len); | ||||
| void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count); | ||||
|  | ||||
|  | ||||
| #define dm_hash_iterate(v, h) \ | ||||
| 	for (v = dm_hash_get_first((h)); v; \ | ||||
| 	     v = dm_hash_get_next((h), v)) | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,170 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "list.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| void dm_list_init(struct dm_list *head) | ||||
| { | ||||
| 	head->n = head->p = head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head; | ||||
| 	elem->p = head->p; | ||||
|  | ||||
| 	head->p->n = elem; | ||||
| 	head->p = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head->n; | ||||
| 	elem->p = head; | ||||
|  | ||||
| 	head->n->p = elem; | ||||
| 	head->n = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem) | ||||
| { | ||||
| 	elem->n->p = elem->p; | ||||
| 	elem->p->n = elem->n; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
|         dm_list_del(elem); | ||||
|         dm_list_add(head, elem); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head) | ||||
| { | ||||
| 	return head->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->p == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_start(head, elem) ? NULL : elem->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_end(head, elem) ? NULL : elem->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head) | ||||
| { | ||||
| 	unsigned int s = 0; | ||||
| 	const struct dm_list *v; | ||||
|  | ||||
| 	dm_list_iterate(v, head) | ||||
| 	    s++; | ||||
|  | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Join two lists together. | ||||
|  * This moves all the elements of the list 'head1' to the end of the list | ||||
|  * 'head', leaving 'head1' empty. | ||||
|  */ | ||||
| void dm_list_splice(struct dm_list *head, struct dm_list *head1) | ||||
| { | ||||
| 	assert(head->n); | ||||
| 	assert(head1->n); | ||||
|  | ||||
| 	if (dm_list_empty(head1)) | ||||
| 	    return; | ||||
|  | ||||
| 	head1->p->n = head; | ||||
| 	head1->n->p = head->p; | ||||
|  | ||||
| 	head->p->n = head1->n; | ||||
| 	head->p = head1->p; | ||||
|  | ||||
| 	dm_list_init(head1); | ||||
| } | ||||
| @@ -1,211 +0,0 @@ | ||||
| #ifndef BASE_DATA_STRUCT_LIST_H | ||||
| #define BASE_DATA_STRUCT_LIST_H | ||||
|  | ||||
| #include "base/memory/container_of.h" | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| /* | ||||
|  * A list consists of a list head plus elements. | ||||
|  * Each element has 'next' and 'previous' pointers. | ||||
|  * The list head's pointers point to the first and the last element. | ||||
|  */ | ||||
|  | ||||
| struct dm_list { | ||||
| 	struct dm_list *n, *p; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * String list. | ||||
|  */ | ||||
| struct dm_str_list { | ||||
| 	struct dm_list list; | ||||
| 	const char *str; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| #define DM_LIST_HEAD_INIT(name)	 { &(name), &(name) } | ||||
| #define DM_LIST_INIT(name)	struct dm_list name = DM_LIST_HEAD_INIT(name) | ||||
| void dm_list_init(struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Join 'head1' to the end of 'head'. | ||||
|  */ | ||||
| void dm_list_splice(struct dm_list *head, struct dm_list *head1); | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list' called 'head' | ||||
|  * contained in a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_struct_base(v, t, head) \ | ||||
|     container_of(v, t, head) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list list' contained in | ||||
|  * a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_item(v, t) dm_list_struct_base((v), t, list) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of one known element e in a known structure of type t, | ||||
|  * return another element f. | ||||
|  */ | ||||
| #define dm_struct_field(v, t, e, f) \ | ||||
|     (((t *)((uintptr_t)(v) - offsetof(t, e)))->f) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of a known element e in a known structure of type t, | ||||
|  * return the list head 'list' | ||||
|  */ | ||||
| #define dm_list_head(v, t, e) dm_struct_field(v, t, e, list) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element of a list in turn. | ||||
|  */ | ||||
| #define dm_list_iterate(v, head) \ | ||||
| 	for (v = (head)->n; v != head; v = v->n) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element in a list in turn, starting from the element | ||||
|  * in front of 'start'. | ||||
|  * You can use this to 'unwind' a list_iterate and back out actions on | ||||
|  * already-processed elements. | ||||
|  * If 'start' is 'head' it walks the list backwards. | ||||
|  */ | ||||
| #define dm_list_uniterate(v, head, start) \ | ||||
| 	for (v = (start)->p; v != head; v = v->p) | ||||
|  | ||||
| /* | ||||
|  * A safe way to walk a list and delete and free some elements along | ||||
|  * the way. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_safe(v, t, head) \ | ||||
| 	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.n, __typeof__(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_items(v, head) dm_list_iterate_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen_safe(v, t, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field), \ | ||||
| 	     t = dm_list_struct_base(v->field.n, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = t, t = dm_list_struct_base(v->field.n, __typeof__(*v), field)) | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_safe(v, t, head) \ | ||||
| 	dm_list_iterate_items_gen_safe(v, t, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->p, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.p, __typeof__(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items(v, head) dm_list_iterate_back_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head); | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,256 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #include "radix-tree.h" | ||||
|  | ||||
| #include "base/memory/container_of.h" | ||||
| #include "base/memory/zalloc.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| // This implementation is based around nested binary trees.  Very | ||||
| // simple (and hopefully correct). | ||||
|  | ||||
| struct node { | ||||
| 	struct node *left; | ||||
| 	struct node *right; | ||||
|  | ||||
| 	uint8_t key; | ||||
| 	struct node *center; | ||||
|  | ||||
| 	bool has_value; | ||||
| 	union radix_value value; | ||||
| }; | ||||
|  | ||||
| struct radix_tree { | ||||
| 	radix_value_dtr dtr; | ||||
| 	void *dtr_context; | ||||
|  | ||||
| 	struct node *root; | ||||
| }; | ||||
|  | ||||
| struct radix_tree * | ||||
| radix_tree_create(radix_value_dtr dtr, void *dtr_context) | ||||
| { | ||||
| 	struct radix_tree *rt = zalloc(sizeof(*rt)); | ||||
|  | ||||
| 	if (rt) { | ||||
| 		rt->dtr = dtr; | ||||
| 		rt->dtr_context = dtr_context; | ||||
| 	} | ||||
|  | ||||
| 	return rt; | ||||
| } | ||||
|  | ||||
| // Returns the number of entries in the tree | ||||
| static unsigned _destroy_tree(struct node *n, radix_value_dtr dtr, void *context) | ||||
| { | ||||
| 	unsigned r; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = _destroy_tree(n->left, dtr, context); | ||||
| 	r += _destroy_tree(n->right, dtr, context); | ||||
| 	r += _destroy_tree(n->center, dtr, context); | ||||
|  | ||||
| 	if (n->has_value) { | ||||
| 		if (dtr) | ||||
| 			dtr(context, n->value); | ||||
| 		r++; | ||||
| 	} | ||||
|  | ||||
| 	free(n); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void radix_tree_destroy(struct radix_tree *rt) | ||||
| { | ||||
| 	_destroy_tree(rt->root, rt->dtr, rt->dtr_context); | ||||
| 	free(rt); | ||||
| } | ||||
|  | ||||
| static unsigned _count(struct node *n) | ||||
| { | ||||
| 	unsigned r; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = _count(n->left); | ||||
| 	r += _count(n->right); | ||||
| 	r += _count(n->center); | ||||
|  | ||||
| 	if (n->has_value) | ||||
| 		r++; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| unsigned radix_tree_size(struct radix_tree *rt) | ||||
| { | ||||
| 	return _count(rt->root); | ||||
| } | ||||
|  | ||||
| static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke) | ||||
| { | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n || (kb == ke)) | ||||
| 		return pn; | ||||
|  | ||||
| 	if (*kb < n->key) | ||||
| 		return _lookup(&n->left, kb, ke); | ||||
|  | ||||
| 	else if (*kb > n->key) | ||||
| 		return _lookup(&n->right, kb, ke); | ||||
|  | ||||
| 	else | ||||
| 		return _lookup(&n->center, kb + 1, ke); | ||||
| } | ||||
|  | ||||
| static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v) | ||||
| { | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n) { | ||||
| 		n = zalloc(sizeof(*n)); | ||||
| 		if (!n) | ||||
| 			return false; | ||||
|  | ||||
| 		n->key = *kb; | ||||
| 		*pn = n; | ||||
| 	} | ||||
|  | ||||
| 	if (kb == ke) { | ||||
| 		n->has_value = true; | ||||
| 		n->value = v; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	if (*kb < n->key) | ||||
| 		return _insert(&n->left, kb, ke, v); | ||||
|  | ||||
| 	else if (*kb > n->key) | ||||
| 		return _insert(&n->right, kb, ke, v); | ||||
|  | ||||
| 	else | ||||
| 		return _insert(&n->center, kb + 1, ke, v); | ||||
| } | ||||
|  | ||||
| bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v) | ||||
| { | ||||
| 	return _insert(&rt->root, kb, ke, v); | ||||
| } | ||||
|  | ||||
| bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke) | ||||
| { | ||||
| 	struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n || !n->has_value) | ||||
| 		return false; | ||||
|  | ||||
| 	else { | ||||
| 		if (rt->dtr) | ||||
| 			rt->dtr(rt->dtr_context, n->value); | ||||
|  | ||||
| 		if (n->left || n->center || n->right) { | ||||
| 			n->has_value = false; | ||||
| 			return true; | ||||
|  | ||||
| 		} else { | ||||
| 			// FIXME: delete parent if this was the last entry | ||||
| 			free(n); | ||||
| 			*pn = NULL; | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke) | ||||
| { | ||||
| 	struct node **pn; | ||||
| 	unsigned count; | ||||
|  | ||||
| 	pn = _lookup(&rt->root, kb, ke); | ||||
|  | ||||
| 	if (*pn) { | ||||
| 		count = _destroy_tree(*pn, rt->dtr, rt->dtr_context); | ||||
| 		*pn = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| bool | ||||
| radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result) | ||||
| { | ||||
| 	struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (n && n->has_value) { | ||||
| 		*result = n->value; | ||||
| 		return true; | ||||
| 	} else | ||||
| 		return false; | ||||
| } | ||||
|  | ||||
| static void _iterate(struct node *n, struct radix_tree_iterator *it) | ||||
| { | ||||
| 	if (!n) | ||||
| 		return; | ||||
|  | ||||
| 	_iterate(n->left, it); | ||||
|  | ||||
| 	if (n->has_value) | ||||
| 		// FIXME: fill out the key | ||||
| 		it->visit(it, NULL, NULL, n->value); | ||||
|  | ||||
| 	_iterate(n->center, it); | ||||
| 	_iterate(n->right, it); | ||||
| } | ||||
|  | ||||
| void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, | ||||
|                         struct radix_tree_iterator *it) | ||||
| { | ||||
| 	if (kb == ke) | ||||
| 		_iterate(rt->root, it); | ||||
|  | ||||
| 	else { | ||||
| 		struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 		struct node *n = *pn; | ||||
|  | ||||
| 		if (n) { | ||||
| 			if (n->has_value) | ||||
| 				it->visit(it, NULL, NULL, n->value); | ||||
| 			_iterate(n->center, it); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool radix_tree_is_well_formed(struct radix_tree *rt) | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void radix_tree_dump(struct radix_tree *rt, FILE *out) | ||||
| { | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| @@ -1,21 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #ifdef SIMPLE_RADIX_TREE | ||||
| #include "base/data-struct/radix-tree-simple.c" | ||||
| #else | ||||
| #include "base/data-struct/radix-tree-adaptive.c" | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| @@ -1,64 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|   | ||||
| #ifndef BASE_DATA_STRUCT_RADIX_TREE_H | ||||
| #define BASE_DATA_STRUCT_RADIX_TREE_H | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| struct radix_tree; | ||||
|  | ||||
| union radix_value { | ||||
| 	void *ptr; | ||||
| 	uint64_t n; | ||||
| }; | ||||
|  | ||||
| typedef void (*radix_value_dtr)(void *context, union radix_value v); | ||||
|  | ||||
| // dtr will be called on any deleted entries.  dtr may be NULL. | ||||
| struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context); | ||||
| void radix_tree_destroy(struct radix_tree *rt); | ||||
|  | ||||
| unsigned radix_tree_size(struct radix_tree *rt); | ||||
| bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v); | ||||
| bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke); | ||||
|  | ||||
| // Returns the number of values removed | ||||
| unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e); | ||||
|  | ||||
| bool radix_tree_lookup(struct radix_tree *rt, | ||||
| 		       uint8_t *kb, uint8_t *ke, union radix_value *result); | ||||
|  | ||||
| // The radix tree stores entries in lexicographical order.  Which means | ||||
| // we can iterate entries, in order.  Or iterate entries with a particular | ||||
| // prefix. | ||||
| struct radix_tree_iterator { | ||||
|         // Returns false if the iteration should end. | ||||
| 	bool (*visit)(struct radix_tree_iterator *it, | ||||
|                       uint8_t *kb, uint8_t *ke, union radix_value v); | ||||
| }; | ||||
|  | ||||
| void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, | ||||
|                         struct radix_tree_iterator *it); | ||||
|  | ||||
| // Checks that some constraints on the shape of the tree are | ||||
| // being held.  For debug only. | ||||
| bool radix_tree_is_well_formed(struct radix_tree *rt); | ||||
| void radix_tree_dump(struct radix_tree *rt, FILE *out); | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,25 +0,0 @@ | ||||
| // Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #ifndef BASE_MEMORY_CONTAINER_OF_H | ||||
| #define BASE_MEMORY_CONTAINER_OF_H | ||||
|  | ||||
| #include <stddef.h>  // offsetof | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #define container_of(v, t, head) \ | ||||
|     ((t *)((char *)(v) - offsetof(t, head))) | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,27 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #ifndef BASE_MEMORY_ZALLOC_H | ||||
| #define BASE_MEMORY_ZALLOC_H | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| static inline void *zalloc(size_t len) | ||||
| { | ||||
| 	return calloc(1, len); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										6
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +0,0 @@ | ||||
| command_profile_template.profile | ||||
| example.conf | ||||
| lvmlocal.conf | ||||
| metadata_profile_template.profile | ||||
| configure.h | ||||
| lvm-version.h | ||||
| @@ -1,60 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CONFSRC=example.conf | ||||
| CONFDEST=lvm.conf | ||||
| CONFLOCAL=lvmlocal.conf | ||||
|  | ||||
| PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile | ||||
| PROFILES=$(PROFILE_TEMPLATES) \ | ||||
| 	$(srcdir)/cache-mq.profile \ | ||||
| 	$(srcdir)/cache-smq.profile \ | ||||
| 	$(srcdir)/thin-generic.profile \ | ||||
| 	$(srcdir)/thin-performance.profile \ | ||||
| 	$(srcdir)/vdo-small.profile \ | ||||
| 	$(srcdir)/lvmdbusd.profile | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| .PHONY: install_conf install_localconf install_profiles | ||||
|  | ||||
| generate: | ||||
| 	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in | ||||
| 	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in | ||||
|  | ||||
| install_conf: $(CONFSRC) | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \ | ||||
| 	fi | ||||
|  | ||||
| install_localconf: $(CONFLOCAL) | ||||
| 	@if [ ! -e $(confdir)/$(CONFLOCAL) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL); \ | ||||
| 	fi | ||||
|  | ||||
| install_profiles: $(PROFILES) | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DIR) $(profiledir) | ||||
| 	$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/ | ||||
|  | ||||
| install_lvm2: install_conf install_localconf install_profiles | ||||
|  | ||||
| install: install_lvm2 | ||||
|  | ||||
| DISTCLEAN_TARGETS += $(CONFSRC) $(CONFLOCAL) $(PROFILE_TEMPLATES) | ||||
| @@ -1,20 +0,0 @@ | ||||
| # Demo configuration 'mq' cache policy | ||||
| # | ||||
| # Note: This policy has been deprecated in favor of the smq policy | ||||
| # keyword "default" means, setting is left with kernel defaults. | ||||
| # | ||||
|  | ||||
| allocation { | ||||
| 	cache_pool_chunk_size = 64 | ||||
| 	cache_mode = "writethrough" | ||||
| 	cache_policy = "mq" | ||||
| 	cache_settings { | ||||
| 		mq { | ||||
| 			sequential_threshold = "default"	#  #nr_sequential_ios | ||||
| 			random_threshold = "default"		#  #nr_random_ios | ||||
| 			read_promote_adjustment = "default" | ||||
| 			write_promote_adjustment = "default" | ||||
| 			discard_promote_adjustment = "default" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| # Demo configuration 'smq' cache policy | ||||
| # | ||||
| # The stochastic multi-queue (smq) policy addresses some of the problems | ||||
| # with the multiqueue (mq) policy and uses less memory. | ||||
| # | ||||
|  | ||||
| allocation { | ||||
| 	cache_pool_chunk_size = 64 | ||||
| 	cache_mode = "writethrough" | ||||
| 	cache_policy = "smq" | ||||
| 	cache_settings { | ||||
| 	        # currently no settings for "smq" policy | ||||
| 	} | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| # This is a command profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by command | ||||
| # profiles. To create a new command profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Command profiles can be referenced by using the --commandprofile option then. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| allocation { | ||||
| 	cache_mode="writethrough" | ||||
| 	cache_settings { | ||||
| 	} | ||||
| } | ||||
| log { | ||||
| 	report_command_log=0 | ||||
| 	command_log_sort="log_seq_num" | ||||
| 	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code" | ||||
| 	command_log_selection="!(log_type=status && message=success)" | ||||
| } | ||||
| global { | ||||
| 	units="h" | ||||
| 	si_unit_consistency=1 | ||||
| 	suffix=1 | ||||
| 	lvdisplay_shows_full_device_path=0 | ||||
| } | ||||
| report { | ||||
| 	output_format="basic" | ||||
| 	compact_output=0 | ||||
| 	compact_output_cols="" | ||||
| 	aligned=1 | ||||
| 	buffered=1 | ||||
| 	headings=1 | ||||
| 	separator=" " | ||||
| 	list_item_separator="," | ||||
| 	prefixes=0 | ||||
| 	quoted=1 | ||||
| 	columns_as_rows=0 | ||||
| 	binary_values_as_numeric=0 | ||||
| 	time_format="%Y-%m-%d %T %z" | ||||
| 	devtypes_sort="devtype_name" | ||||
| 	devtypes_cols="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	lvs_sort="vg_name,lv_name" | ||||
| 	lvs_cols="lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv" | ||||
| 	lvs_cols_verbose="lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid,lv_profile" | ||||
| 	vgs_sort="vg_name" | ||||
| 	vgs_cols="vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" | ||||
| 	vgs_cols_verbose="vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile" | ||||
| 	pvs_sort="pv_name" | ||||
| 	pvs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" | ||||
| 	pvs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" | ||||
| 	segs_sort="vg_name,lv_name,seg_start" | ||||
| 	segs_cols="lv_name,vg_name,lv_attr,stripes,segtype,seg_size" | ||||
| 	segs_cols_verbose="lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" | ||||
| 	pvsegs_sort="pv_name,pvseg_start" | ||||
| 	pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" | ||||
| 	pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges" | ||||
| 	vgs_cols_full="vg_all" | ||||
| 	pvs_cols_full="pv_all" | ||||
| 	lvs_cols_full="lv_all" | ||||
| 	pvsegs_cols_full="pvseg_all,pv_uuid,lv_uuid" | ||||
| 	segs_cols_full="seg_all,lv_uuid" | ||||
| 	vgs_sort_full="vg_name" | ||||
| 	pvs_sort_full="pv_name" | ||||
| 	lvs_sort_full="vg_name,lv_name" | ||||
| 	pvsegs_sort_full="pv_uuid,pvseg_start" | ||||
| 	segs_sort_full="lv_uuid,seg_start" | ||||
| 	mark_hidden_devices=1 | ||||
| } | ||||
							
								
								
									
										2365
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
							
						
						
									
										2365
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,50 +0,0 @@ | ||||
| # | ||||
| # DO NOT EDIT THIS FILE! | ||||
| # | ||||
| # LVM configuration profile used by lvmdbusd daemon. | ||||
| # | ||||
| # This sets up LVM to produce output in the most suitable format for processing | ||||
| # by lvmdbusd daemon which utilizes LVM shell to execute LVM commands. | ||||
| # | ||||
| # Do not edit this file in any way. This profile is distributed together with | ||||
| # lvmdbusd and it contains configuration that is important for lvmdbusd to | ||||
| # cooperate and interface with LVM correctly. | ||||
| # | ||||
|  | ||||
| global { | ||||
| 	# use bytes for expected and deterministic output | ||||
| 	units=b | ||||
| 	# no need for suffix if we have units set | ||||
| 	suffix=0 | ||||
| } | ||||
|  | ||||
| report { | ||||
| 	compact_output=0 | ||||
| 	compact_output_cols="" | ||||
| 	binary_values_as_numeric=0 | ||||
| 	# time in number of seconds since the Epoch | ||||
| 	time_format="%s" | ||||
| 	mark_hidden_devices=1 | ||||
| 	# lvmdbusd expects JSON output | ||||
| 	output_format=json | ||||
| 	# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state | ||||
| 	vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags" | ||||
| 	pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid" | ||||
| 	lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout" | ||||
| 	pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name" | ||||
| 	segs_cols_full="seg_pe_ranges,segtype,lv_uuid" | ||||
| 	vgs_sort_full="vg_name" | ||||
| 	pvs_sort_full="pv_name" | ||||
| 	lvs_sort_full="vg_name,lv_name" | ||||
| 	pvsegs_sort_full="pv_uuid,pvseg_start" | ||||
| 	segs_sort_full="lv_uuid,seg_start" | ||||
| } | ||||
|  | ||||
| log { | ||||
| 	# lvmdbusd relies on command log report to inspect LVM command's execution status | ||||
| 	report_command_log=1 | ||||
| 	# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed) | ||||
| 	command_log_selection="log_context=shell" | ||||
| 	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code" | ||||
| 	command_log_sort="log_seq_num" | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| # This is a local configuration file template for the LVM2 system | ||||
| # which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf . | ||||
| # | ||||
| # Refer to 'man lvm.conf' for information about the file layout. | ||||
| # | ||||
| # To put this file in a different directory and override | ||||
| # @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before | ||||
| # running the tools. | ||||
| # | ||||
| # The lvmlocal.conf file is normally expected to contain only the | ||||
| # "local" section which contains settings that should not be shared or | ||||
| # repeated among different hosts.  (But if other sections are present, | ||||
| # they *will* get processed.  Settings in this file override equivalent | ||||
| # ones in lvm.conf and are in turn overridden by ones in any enabled | ||||
| # lvm_<tag>.conf files.) | ||||
| # | ||||
| # Please take care that each setting only appears once if uncommenting | ||||
| # example settings in this file and never copy this file between hosts. | ||||
|  | ||||
|  | ||||
| # Configuration section local. | ||||
| # LVM settings that are specific to the local host. | ||||
| local { | ||||
|  | ||||
| 	# Configuration option local/system_id. | ||||
| 	# Defines the local system ID for lvmlocal mode. | ||||
| 	# This is used when global/system_id_source is set to 'lvmlocal' in the | ||||
| 	# main configuration file, e.g. lvm.conf. When used, it must be set to | ||||
| 	# a unique value among all hosts sharing access to the storage, | ||||
| 	# e.g. a host name. | ||||
| 	# | ||||
| 	# Example | ||||
| 	# Set no system ID: | ||||
| 	# system_id = "" | ||||
| 	# Set the system_id to a specific name: | ||||
| 	# system_id = "host1" | ||||
| 	# | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# system_id = "" | ||||
|  | ||||
| 	# Configuration option local/extra_system_ids. | ||||
| 	# A list of extra VG system IDs the local host can access. | ||||
| 	# VGs with the system IDs listed here (in addition to the host's own | ||||
| 	# system ID) can be fully accessed by the local host. (These are | ||||
| 	# system IDs that the host sees in VGs, not system IDs that identify | ||||
| 	# the local host, which is determined by system_id_source.) | ||||
| 	# Use this only after consulting 'man lvmsystemid' to be certain of | ||||
| 	# correct usage and possible dangers. | ||||
| 	# This configuration option does not have a default value defined. | ||||
|  | ||||
| 	# Configuration option local/host_id. | ||||
| 	# The lvmlockd sanlock host_id. | ||||
| 	# This must be unique among all hosts, and must be between 1 and 2000. | ||||
| 	# Applicable only if LVM is compiled with lockd support | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# host_id = 0 | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| # This is a metadata profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by metadata | ||||
| # profiles. To create a new metadata profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Metadata profiles can be referenced by using the --metadataprofile LVM2 | ||||
| # command line option. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| allocation { | ||||
| 	thin_pool_zero=1 | ||||
| 	thin_pool_discards="passdown" | ||||
| 	thin_pool_chunk_size_policy="generic" | ||||
| #	thin_pool_chunk_size=128 | ||||
| } | ||||
| activation { | ||||
| 	thin_pool_autoextend_threshold=100 | ||||
| 	thin_pool_autoextend_percent=20 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "generic" | ||||
| 	thin_pool_zero = 1 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "performance" | ||||
| 	thin_pool_zero = 0 | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| # Demo configuration for 'VDO' using less memory. | ||||
| # ~lvmconfig --type full | grep vdo | ||||
|  | ||||
| allocation { | ||||
| 	vdo_use_compression=1 | ||||
| 	vdo_use_deduplication=1 | ||||
| 	vdo_use_metadata_hints=1 | ||||
| 	vdo_minimum_io_size=4096 | ||||
| 	vdo_block_map_cache_size_mb=128 | ||||
| 	vdo_block_map_period=16380 | ||||
| 	vdo_check_point_frequency=0 | ||||
| 	vdo_use_sparse_index=0 | ||||
| 	vdo_index_memory_size_mb=256 | ||||
| 	vdo_slab_size_mb=2048 | ||||
| 	vdo_ack_threads=1 | ||||
| 	vdo_bio_threads=1 | ||||
| 	vdo_bio_rotation=64 | ||||
| 	vdo_cpu_threads=2 | ||||
| 	vdo_hash_zone_threads=1 | ||||
| 	vdo_logical_threads=1 | ||||
| 	vdo_physical_threads=1 | ||||
| 	vdo_write_policy="auto" | ||||
| 	vdo_max_discard=1 | ||||
| } | ||||
							
								
								
									
										2013
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										2013
									
								
								configure.ac
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										205
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| ################################################################################ | ||||
| ## | ||||
| ##    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= ;; | ||||
| esac | ||||
|  | ||||
| dnl -- prefix is /usr by default, the exec_prefix default is setup later | ||||
| AC_PREFIX_DEFAULT(/usr) | ||||
|  | ||||
| dnl -- setup the ownership of the files | ||||
| AC_ARG_WITH(user, | ||||
|   [  --with-user=USER        Set the owner of installed files ], | ||||
|   [ OWNER="$withval" ], | ||||
|   [ OWNER="root" ]) | ||||
|  | ||||
| dnl -- setup the group ownership of the files | ||||
| AC_ARG_WITH(group, | ||||
|   [  --with-group=GROUP      Set the group owner of installed files ], | ||||
|   [ GROUP="$withval" ], | ||||
|   [ GROUP="root" ]) | ||||
|  | ||||
| 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 | ||||
|  | ||||
| AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) | ||||
|  | ||||
| dnl Enables staticly linked tools | ||||
| AC_ARG_ENABLE(static_link, [  --enable-static_link    Use this to link the tools to the liblvm library | ||||
|                           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 | ||||
|  | ||||
| dnl Enable Debugging | ||||
| AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debugging],  \ | ||||
| DEBUG=yes, DEBUG=no) | ||||
|  | ||||
| dnl Disable devmapper | ||||
| AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable device-mapper interaction],  \ | ||||
| DEVMAPPER=no, DEVMAPPER=yes) | ||||
|  | ||||
| if test x$DEVMAPPER = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT" | ||||
| 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 test x$HAVE_LIBDL = xyes; then | ||||
| 	CFLAGS="$CFLAGS -DHAVE_LIBDL" | ||||
| 	LIBS="-ldl $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 | ||||
|  | ||||
| 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(OWNER) | ||||
| AC_SUBST(GROUP) | ||||
| AC_SUBST(CFLAGS) | ||||
| AC_SUBST(LIBS) | ||||
| AC_SUBST(LVM_VERSION) | ||||
| AC_SUBST(DEBUG) | ||||
| AC_SUBST(DEVMAPPER) | ||||
| AC_SUBST(HAVE_LIBDL) | ||||
| 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                                                               \ | ||||
| include/Makefile						 	\ | ||||
| lib/Makefile							 	\ | ||||
| lib/format1/Makefile						 	\ | ||||
| man/Makefile							 	\ | ||||
| tools/Makefile							 	\ | ||||
| tools/version.h								\ | ||||
| test/mm/Makefile							\ | ||||
| test/device/Makefile							\ | ||||
| test/format1/Makefile							\ | ||||
| test/regex/Makefile                                                     \ | ||||
| test/filters/Makefile                                                   \ | ||||
| ) | ||||
| @@ -1,148 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Coverity usage: | ||||
|  * | ||||
|  * translate model into xml | ||||
|  * cov-make-library -of coverity_model.xml coverity_model.c | ||||
|  * | ||||
|  * compile (using outdir 'cov'): | ||||
|  * cov-build --dir=cov make CC=gcc | ||||
|  * | ||||
|  * analyze (agressively, using 'cov') | ||||
|  * cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml | ||||
|  * | ||||
|  * generate html output (to 'html' from 'cov'): | ||||
|  * cov-format-errors --dir cov  --html-output html | ||||
|  */ | ||||
|  | ||||
| struct lv_segment; | ||||
| struct logical_volume; | ||||
|  | ||||
| struct lv_segment *first_seg(const struct logical_volume *lv) | ||||
| { | ||||
| 	return ((struct lv_segment **)lv)[0]; | ||||
| } | ||||
|  | ||||
| struct lv_segment *last_seg(const struct logical_volume *lv) | ||||
| { | ||||
| 	return ((struct lv_segment **)lv)[0]; | ||||
| } | ||||
|  | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	return "STRING"; | ||||
| } | ||||
|  | ||||
| /* | ||||
| struct logical_volume *origin_from_cow(const struct logical_volume *lv) | ||||
| { | ||||
| 	if (lv) | ||||
| 		return lv; | ||||
|  | ||||
| 	__coverity_panic__(); | ||||
| } | ||||
| */ | ||||
|  | ||||
| /* simple_memccpy() from glibc */ | ||||
| void *memccpy(void *dest, const void *src, int c, size_t n) | ||||
| { | ||||
| 	const char *s = src; | ||||
| 	char *d = dest; | ||||
|  | ||||
| 	while (n-- > 0) | ||||
| 		if ((*d++ = *s++) == (char) c) | ||||
| 			return d; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h | ||||
|  * Not sure about any other way. | ||||
|  * Without them, coverity shows warning since x86 system header files | ||||
|  * are using inline assembly to reset fdset | ||||
|  */ | ||||
| //#nodef FD_ZERO model_FD_ZERO | ||||
| //void model_FD_ZERO(void *fdset); | ||||
|  | ||||
| void model_FD_ZERO(void *fdset) | ||||
| { | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i < 1024 / 8 / sizeof(long); ++i) | ||||
| 		((long*)fdset)[i] = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Resent Coverity reports quite weird errors... */ | ||||
| int *__errno_location(void) | ||||
| { | ||||
| } | ||||
| const unsigned short **__ctype_b_loc (void) | ||||
| { | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Added extra pointer check to not need these models, | ||||
|  * for now just keep then in file | ||||
|  */ | ||||
|  | ||||
| /* | ||||
| struct cmd_context; | ||||
| struct profile; | ||||
|  | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
|         return "text"; | ||||
| } | ||||
|  | ||||
| const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
|         return "text"; | ||||
| } | ||||
| */ | ||||
|  | ||||
| /* | ||||
|  * Until fixed coverity case# 00531860: | ||||
|  *   A FORWARD_NULL false positive on a recursive function call | ||||
|  * | ||||
|  * model also these functions: | ||||
|  */ | ||||
| /* | ||||
| const struct dm_config_node; | ||||
| const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	const struct dm_config_node *cn; | ||||
|  | ||||
| 	return cn; | ||||
| } | ||||
|  | ||||
| const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	const struct dm_config_node *cn; | ||||
|  | ||||
| 	return cn; | ||||
| } | ||||
|  | ||||
| int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	int b; | ||||
|  | ||||
| 	return b; | ||||
| } | ||||
| */ | ||||
| @@ -1,51 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| .PHONY: dmeventd cmirrord lvmpolld lvmlockd | ||||
|  | ||||
| ifeq ("@BUILD_CMIRRORD@", "yes") | ||||
|   SUBDIRS += cmirrord | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
|   SUBDIRS += dmeventd | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| daemons.cflow: dmeventd.cflow | ||||
| endif | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMPOLLD@", "yes") | ||||
|   SUBDIRS += lvmpolld | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMLOCKD@", "yes") | ||||
|   SUBDIRS += lvmlockd | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMDBUSD@", "yes") | ||||
|   SUBDIRS += lvmdbusd | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
| device-mapper: dmeventd.device-mapper | ||||
| endif | ||||
							
								
								
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| cmirrord | ||||
| @@ -1,43 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2009-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CPG_LIBS = @CPG_LIBS@ | ||||
| CPG_CFLAGS = @CPG_CFLAGS@ | ||||
|  | ||||
| SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c | ||||
|  | ||||
| TARGETS = cmirrord | ||||
|  | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) | ||||
| CFLOW_TARGET := $(TARGETS) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LMLIBS += $(CPG_LIBS) | ||||
| CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS) | ||||
| LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) | ||||
|  | ||||
| cmirrord: $(OBJECTS) | ||||
| 	@echo "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ | ||||
| 		$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS) | ||||
|  | ||||
| install_cluster: $(TARGETS) | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F) | ||||
|  | ||||
| install: install_cluster | ||||
| @@ -1,292 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <getopt.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| static volatile sig_atomic_t exit_now = 0; | ||||
| /* FIXME Review signal handling.  Should be volatile sig_atomic_t */ | ||||
| static sigset_t signal_mask; | ||||
| static volatile sig_atomic_t signal_received; | ||||
|  | ||||
| static void process_signals(void); | ||||
| static void daemonize(void); | ||||
| static void init_all(void); | ||||
| static void cleanup_all(void); | ||||
|  | ||||
| static void usage (FILE *dest) | ||||
| { | ||||
| 	fprintf (dest, "Usage: cmirrord [options]\n" | ||||
| 		 "   -f, --foreground    stay in the foreground, log to the terminal\n" | ||||
| 		 "   -h, --help          print this help\n"); | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	int foreground_mode = 0; | ||||
| 	struct option longopts[] = { | ||||
| 		{ "foreground", no_argument, NULL, 'f' }, | ||||
| 		{ "help"      , no_argument, NULL, 'h' }, | ||||
| 		{ 0, 0, 0, 0 } | ||||
| 	}; | ||||
| 	int opt; | ||||
|  | ||||
| 	while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) { | ||||
| 		switch (opt) { | ||||
| 		case 'f': | ||||
| 			foreground_mode = 1; | ||||
| 			break; | ||||
| 		case 'h': | ||||
| 			usage (stdout); | ||||
| 			exit (0); | ||||
| 		default: | ||||
| 			usage (stderr); | ||||
| 			exit (2); | ||||
| 		} | ||||
| 	} | ||||
| 	if (optind < argc) { | ||||
| 		usage (stderr); | ||||
| 		exit (2); | ||||
| 	} | ||||
|  | ||||
| 	if (!foreground_mode) | ||||
| 		daemonize(); | ||||
|  | ||||
| 	init_all(); | ||||
|  | ||||
| 	/* Parent can now exit, we're ready to handle requests */ | ||||
| 	if (!foreground_mode) | ||||
| 		kill(getppid(), SIGTERM); | ||||
|  | ||||
| 	LOG_PRINT("Starting cmirrord:"); | ||||
| 	LOG_PRINT(" Built: "__DATE__" "__TIME__"\n"); | ||||
| 	LOG_DBG(" Compiled with debugging."); | ||||
|  | ||||
| 	while (!exit_now) { | ||||
| 		links_monitor(); | ||||
|  | ||||
| 		links_issue_callbacks(); | ||||
|  | ||||
| 		process_signals(); | ||||
| 	} | ||||
| 	exit(EXIT_SUCCESS); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * parent_exit_handler: exit the parent | ||||
|  * @sig: the signal | ||||
|  * | ||||
|  */ | ||||
| static void parent_exit_handler(int sig __attribute__((unused))) | ||||
| { | ||||
| 	exit_now = 1; | ||||
| } | ||||
|  | ||||
| static void sig_handler(int sig) | ||||
| { | ||||
| 	/* FIXME Races - don't touch signal_mask here. */ | ||||
| 	sigaddset(&signal_mask, sig); | ||||
| 	signal_received = 1; | ||||
| } | ||||
|  | ||||
| static void process_signal(int sig){ | ||||
| 	int r = 0; | ||||
|  | ||||
| 	switch(sig) { | ||||
| 	case SIGINT: | ||||
| 	case SIGQUIT: | ||||
| 	case SIGTERM: | ||||
| 	case SIGHUP: | ||||
| 		r += log_status(); | ||||
| 		break; | ||||
| 	case SIGUSR1: | ||||
| 	case SIGUSR2: | ||||
| 		log_debug(); | ||||
| 		/*local_debug();*/ | ||||
| 		cluster_debug(); | ||||
| 		return; | ||||
| 	default: | ||||
| 		LOG_PRINT("Unknown signal received... ignoring"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!r) { | ||||
| 		LOG_DBG("No current cluster logs... safe to exit."); | ||||
| 		cleanup_all(); | ||||
| 		exit(EXIT_SUCCESS); | ||||
| 	} | ||||
|  | ||||
| 	LOG_ERROR("Cluster logs exist.  Refusing to exit."); | ||||
| } | ||||
|  | ||||
| static void process_signals(void) | ||||
| { | ||||
| 	int x; | ||||
|  | ||||
| 	if (!signal_received) | ||||
| 		return; | ||||
|  | ||||
| 	signal_received = 0; | ||||
|  | ||||
| 	for (x = 1; x < _NSIG; x++) { | ||||
| 		if (sigismember(&signal_mask, x)) { | ||||
| 			sigdelset(&signal_mask, x); | ||||
| 			process_signal(x); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void remove_lockfile(void) | ||||
| { | ||||
| 	if (unlink(CMIRRORD_PIDFILE)) | ||||
| 		LOG_ERROR("Unable to remove \"" CMIRRORD_PIDFILE "\" %s", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemonize | ||||
|  * | ||||
|  * Performs the steps necessary to become a daemon. | ||||
|  */ | ||||
| static void daemonize(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	int status; | ||||
| 	int devnull; | ||||
|  | ||||
| 	if ((devnull = open("/dev/null", O_RDWR)) == -1) { | ||||
| 		LOG_ERROR("Can't open /dev/null: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	signal(SIGTERM, &parent_exit_handler); | ||||
|  | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) { | ||||
| 		LOG_ERROR("Unable to fork()"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if (pid) { | ||||
| 		/* Parent waits here for child to get going */ | ||||
| 		while (!waitpid(pid, &status, WNOHANG) && !exit_now); | ||||
| 		if (exit_now) | ||||
| 			exit(EXIT_SUCCESS); | ||||
|  | ||||
| 		switch (WEXITSTATUS(status)) { | ||||
| 		case EXIT_LOCKFILE: | ||||
| 			LOG_ERROR("Failed to create lockfile"); | ||||
| 			LOG_ERROR("Process already running?"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SOCKET: | ||||
| 			LOG_ERROR("Unable to create netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_BIND: | ||||
| 			LOG_ERROR("Unable to bind to netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SETSOCKOPT: | ||||
| 			LOG_ERROR("Unable to setsockopt on netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_CLUSTER_CKPT_INIT: | ||||
| 			LOG_ERROR("Unable to initialize checkpoint service"); | ||||
| 			LOG_ERROR("Has the cluster infrastructure been started?"); | ||||
| 			break; | ||||
| 		case EXIT_FAILURE: | ||||
| 			LOG_ERROR("Failed to start: Generic error"); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Failed to start: Unknown error"); | ||||
| 			break; | ||||
| 		} | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	setsid(); | ||||
| 	if (chdir("/")) { | ||||
| 		LOG_ERROR("Failed to chdir /: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	umask(0); | ||||
|  | ||||
| 	if (close(0) || close(1) || close(2)) { | ||||
| 		LOG_ERROR("Failed to close terminal FDs"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if ((dup2(devnull, 0) < 0) || /* reopen stdin */ | ||||
| 	    (dup2(devnull, 1) < 0) || /* reopen stdout */ | ||||
| 	    (dup2(devnull, 2) < 0))   /* reopen stderr */ | ||||
| 		exit(EXIT_FAILURE); | ||||
|  | ||||
| 	if ((devnull > STDERR_FILENO) && close(devnull)) { | ||||
| 		LOG_ERROR("Failed to close descriptor %d: %s", | ||||
| 			  devnull, strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_all | ||||
|  * | ||||
|  * Initialize modules.  Exit on failure. | ||||
|  */ | ||||
| static void init_all(void) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG); | ||||
| 	if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0) | ||||
| 		exit(EXIT_LOCKFILE); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	atexit(remove_lockfile); | ||||
|  | ||||
| 	/* FIXME Replace with sigaction. (deprecated) */ | ||||
| 	signal(SIGINT, &sig_handler); | ||||
| 	signal(SIGQUIT, &sig_handler); | ||||
| 	signal(SIGTERM, &sig_handler); | ||||
| 	signal(SIGHUP, &sig_handler); | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	signal(SIGUSR1, &sig_handler); | ||||
| 	signal(SIGUSR2, &sig_handler); | ||||
| 	sigemptyset(&signal_mask); | ||||
| 	signal_received = 0; | ||||
|  | ||||
| 	if ((r = init_local()) || | ||||
| 	    (r = init_cluster())) { | ||||
| 		exit(r); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_all | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| static void cleanup_all(void) | ||||
| { | ||||
| 	cleanup_local(); | ||||
| 	cleanup_cluster(); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_CLUSTER_H | ||||
| #define _LVM_CLOG_CLUSTER_H | ||||
|  | ||||
| #include "libdm/libdevmapper.h" | ||||
| #include "libdm/misc/dm-log-userspace.h" | ||||
|  | ||||
| #define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */ | ||||
| #define DM_ULOG_CHECKPOINT_READY 21 | ||||
| #define DM_ULOG_MEMBER_JOIN      22 | ||||
|  | ||||
| /* | ||||
|  * There is other information in addition to what can | ||||
|  * be found in the dm_ulog_request structure that we | ||||
|  * need for processing.  'clog_request' is the wrapping | ||||
|  * structure we use to make the additional fields | ||||
|  * available. | ||||
|  */ | ||||
| struct clog_request { | ||||
| 	/* | ||||
| 	 * If we don't use a union, the structure size will | ||||
| 	 * vary between 32-bit and 64-bit machines.  So, we | ||||
| 	 * pack two 64-bit version numbers in there to force | ||||
| 	 * the size of the structure to be the same. | ||||
| 	 * | ||||
| 	 * The two version numbers also help us with endian | ||||
| 	 * issues.  The first is always little endian, while | ||||
| 	 * the second is in native format of the sending | ||||
| 	 * machine.  If the two are equal, there is no need | ||||
| 	 * to do endian conversions. | ||||
| 	 */ | ||||
| 	union version_u { | ||||
| 		uint64_t version[2]; /* LE version and native version */ | ||||
| 		struct dm_list list; | ||||
| 	} u; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'originator' is the machine from which the requests | ||||
| 	 * was made. | ||||
| 	 */ | ||||
| 	uint32_t originator; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'pit_server' is the "point-in-time" server for the | ||||
| 	 * request.  (I.e.  The machine that was the server at | ||||
| 	 * the time the request was issued - only important during | ||||
| 	 * startup. | ||||
| 	 */ | ||||
| 	uint32_t pit_server; | ||||
|  | ||||
| 	/* | ||||
| 	 * The request from the kernel that is being processed | ||||
| 	 */ | ||||
| 	struct dm_ulog_request u_rq; | ||||
| }; | ||||
|  | ||||
| int init_cluster(void); | ||||
| void cleanup_cluster(void); | ||||
| void cluster_debug(void); | ||||
|  | ||||
| int create_cluster_cpg(char *uuid, uint64_t luid); | ||||
| int destroy_cluster_cpg(char *uuid); | ||||
|  | ||||
| int cluster_send(struct clog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_CLUSTER_H */ | ||||
| @@ -1,33 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMMON_H | ||||
| #define _LVM_CLOG_COMMON_H | ||||
|  | ||||
| /* | ||||
|  * If there are problems when forking off to become a daemon, | ||||
|  * the child will exist with one of these codes.  This allows | ||||
|  * the parent to know the reason for the failure and print it | ||||
|  * to the launching terminal. | ||||
|  * | ||||
|  * #define EXIT_SUCCESS 0 (from stdlib.h) | ||||
|  * #define EXIT_FAILURE 1 (from stdlib.h) | ||||
|  */ | ||||
| #define EXIT_LOCKFILE              2 | ||||
| #define EXIT_KERNEL_SOCKET         3 /* Failed netlink socket create */ | ||||
| #define EXIT_KERNEL_BIND           4 | ||||
| #define EXIT_KERNEL_SETSOCKOPT     5 | ||||
| #define EXIT_CLUSTER_CKPT_INIT     6 /* Failed to init checkpoint */ | ||||
| #define EXIT_QUEUE_NOMEM           7 | ||||
|  | ||||
| #define DM_ULOG_REQUEST_SIZE 1024 | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMMON_H */ | ||||
| @@ -1,210 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "cluster.h" | ||||
| #include "compat.h" | ||||
| #include "lib/mm/xlate.h" | ||||
|  | ||||
| #include <errno.h> | ||||
|  | ||||
| /* | ||||
|  * Older versions of the log daemon communicate with different | ||||
|  * versions of the inter-machine communication structure, which | ||||
|  * varies in size and fields.  The older versions append the | ||||
|  * standard upstream version of the structure to every request. | ||||
|  * COMPAT_OFFSET is where the upstream structure starts. | ||||
|  */ | ||||
| #define COMPAT_OFFSET 256 | ||||
|  | ||||
| static void v5_data_endian_switch(struct clog_request *rq, int to_network __attribute__((unused))) | ||||
| { | ||||
| 	int i, end; | ||||
| 	int64_t *pi64; | ||||
| 	uint64_t *pu64; | ||||
| 	uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE; | ||||
|  | ||||
| 	if (rq->u_rq.request_type & DM_ULOG_RESPONSE) { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid response type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 			/* No outbound data */ | ||||
| 			break; | ||||
|  | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			pu64 = ((uint64_t *)rq->u_rq.data) + 1; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			return; | ||||
| 		} | ||||
| 	} else { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid request type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 			/* No incoming data */ | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 			end = rq->u_rq.data_size/sizeof(uint64_t); | ||||
|  | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			for (i = 0; i < end; i++) | ||||
| 				pu64[i] = xlate64(pu64[i]); | ||||
| 			break; | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			pi64 = ((int64_t *)rq->u_rq.data) + 1; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			exit(EXIT_FAILURE); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int v5_endian_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 1); | ||||
|  | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	/* FIXME: Remove this safety check */ | ||||
| 	if (rq->u.version[0] != xlate64(rq->u.version[1])) { | ||||
| 		LOG_ERROR("Programmer error:  version[0] must be LE"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Are we already running in the endian mode we send | ||||
| 	 * over the wire? | ||||
| 	 */ | ||||
| 	if (rq->u.version[0] == rq->u.version[1]) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = v5_endian_to_network(rq); | ||||
| 	if (r < 0) | ||||
| 		return r; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int v5_endian_from_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 0); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_from_network(void *data, size_t data_len) | ||||
| { | ||||
| 	uint64_t *vp = data; | ||||
| 	uint64_t version = xlate64(vp[0]); | ||||
| 	struct clog_request *rq = data; | ||||
|  | ||||
| 	switch (version) { | ||||
| 	case 5: /* Upstream */ | ||||
| 		if (version == vp[0]) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case 4: /* RHEL 5.[45] */ | ||||
| 	case 3: /* RHEL 5.3 */ | ||||
| 	case 2: /* RHEL 5.2 */ | ||||
| 		/* FIXME: still need to account for payload */ | ||||
| 		if (data_len < (COMPAT_OFFSET + sizeof(*rq))) | ||||
| 			return -ENOSPC; | ||||
|  | ||||
| 		rq = (struct clog_request *)((char *)data + COMPAT_OFFSET); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unable to process cluster message: " | ||||
| 			  "Incompatible version"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	v5_endian_from_network(rq); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMPAT_H | ||||
| #define _LVM_CLOG_COMPAT_H | ||||
|  | ||||
| /* | ||||
|  * The intermachine communication structure version are: | ||||
|  *	0: Unused | ||||
|  *	1: Never in the wild | ||||
|  *	2: RHEL 5.2 | ||||
|  *	3: RHEL 5.3 | ||||
|  *	4: RHEL 5.4, RHEL 5.5 | ||||
|  *	5: RHEL 6, Current Upstream Format | ||||
|  */ | ||||
| #define CLOG_TFR_VERSION 5 | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq); | ||||
| int clog_request_from_network(void *data, size_t data_len); | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMPAT_H */ | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,35 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_FUNCTIONS_H | ||||
| #define _LVM_CLOG_FUNCTIONS_H | ||||
|  | ||||
| #include "libdm/libdevmapper.h" | ||||
| #include "libdm/misc/dm-log-userspace.h" | ||||
| #include "cluster.h" | ||||
|  | ||||
| #define LOG_RESUMED   1 | ||||
| #define LOG_SUSPENDED 2 | ||||
|  | ||||
| int local_resume(struct dm_ulog_request *rq); | ||||
| int cluster_postsuspend(char *, uint64_t); | ||||
|  | ||||
| int do_request(struct clog_request *rq, int server); | ||||
| int push_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char **buf, uint32_t debug_who); | ||||
| int pull_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char *buf, int size); | ||||
|  | ||||
| int log_get_state(struct dm_ulog_request *rq); | ||||
| int log_status(void); | ||||
| void log_debug(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_FUNCTIONS_H */ | ||||
| @@ -1,151 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "link_mon.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <poll.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| struct link_callback { | ||||
| 	int fd; | ||||
| 	const char *name; | ||||
| 	void *data; | ||||
| 	int (*callback)(void *data); | ||||
|  | ||||
| 	struct link_callback *next; | ||||
| }; | ||||
|  | ||||
| static unsigned used_pfds = 0; | ||||
| static unsigned free_pfds = 0; | ||||
| static struct pollfd *pfds = NULL; | ||||
| static struct link_callback *callbacks = NULL; | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			LOG_ERROR("links_register: Duplicate file descriptor"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lc = malloc(sizeof(*lc)); | ||||
| 	if (!lc) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	lc->fd = fd; | ||||
| 	lc->name = name; | ||||
| 	lc->data = data; | ||||
| 	lc->callback = callback; | ||||
|  | ||||
| 	if (!free_pfds) { | ||||
| 		struct pollfd *tmp; | ||||
| 		tmp = realloc(pfds, sizeof(struct pollfd) * ((used_pfds*2) + 1)); | ||||
| 		if (!tmp) { | ||||
| 			free(lc); | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
|  | ||||
| 		pfds = tmp; | ||||
| 		free_pfds = used_pfds + 1; | ||||
| 	} | ||||
|  | ||||
| 	free_pfds--; | ||||
| 	pfds[used_pfds].fd = fd; | ||||
| 	pfds[used_pfds].events = POLLIN; | ||||
| 	pfds[used_pfds].revents = 0; | ||||
| 	used_pfds++; | ||||
|  | ||||
| 	lc->next = callbacks; | ||||
| 	callbacks = lc; | ||||
| 	LOG_DBG("Adding %s/%d", lc->name, lc->fd); | ||||
| 	LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 		used_pfds, free_pfds); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_unregister(int fd) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *p, *c; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			/* entire struct is copied (overwritten) */ | ||||
| 			pfds[i] = pfds[used_pfds - 1]; | ||||
| 			used_pfds--; | ||||
| 			free_pfds++; | ||||
| 		} | ||||
|  | ||||
| 	for (p = NULL, c = callbacks; c; p = c, c = c->next) | ||||
| 		if (fd == c->fd) { | ||||
| 			LOG_DBG("Freeing up %s/%d", c->name, c->fd); | ||||
| 			LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 				used_pfds, free_pfds); | ||||
| 			if (p) | ||||
| 				p->next = c->next; | ||||
| 			else | ||||
| 				callbacks = c->next; | ||||
| 			free(c); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_monitor(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	int r; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		pfds[i].revents = 0; | ||||
| 	} | ||||
|  | ||||
| 	r = poll(pfds, used_pfds, -1); | ||||
| 	if (r <= 0) | ||||
| 		return r; | ||||
|  | ||||
| 	r = 0; | ||||
| 	/* FIXME: handle POLLHUP */ | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) { | ||||
| 			LOG_DBG("Data ready on %d", pfds[i].fd); | ||||
|  | ||||
| 			/* FIXME: Add this back return 1;*/ | ||||
| 			r++; | ||||
| 		} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int links_issue_callbacks(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) | ||||
| 			for (lc = callbacks; lc; lc = lc->next) | ||||
| 				if (pfds[i].fd == lc->fd) { | ||||
| 					LOG_DBG("Issuing callback on %s/%d", | ||||
| 						lc->name, lc->fd); | ||||
| 					lc->callback(lc->data); | ||||
| 					break; | ||||
| 				} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LINK_MON_H | ||||
| #define _LVM_CLOG_LINK_MON_H | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data); | ||||
| int links_unregister(int fd); | ||||
| int links_monitor(void); | ||||
| int links_issue_callbacks(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LINK_MON_H */ | ||||
| @@ -1,424 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <sys/socket.h> | ||||
| #include <linux/connector.h> | ||||
| #include <linux/netlink.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #ifndef CN_IDX_DM | ||||
| /* Kernel 2.6.31 is required to run this code */ | ||||
| #define CN_IDX_DM                       0x7     /* Device Mapper */ | ||||
| #define CN_VAL_DM_USERSPACE_LOG         0x1 | ||||
| #endif | ||||
|  | ||||
| static int cn_fd = -1;  /* Connector (netlink) socket fd */ | ||||
| static char recv_buf[2048]; | ||||
| static char send_buf[2048]; | ||||
|  | ||||
|  | ||||
| /* FIXME: merge this function with kernel_send_helper */ | ||||
| static int kernel_ack(uint32_t seq, int error) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh = (struct nlmsghdr *)send_buf; | ||||
| 	struct cn_msg *msg = NLMSG_DATA(nlh); | ||||
|  | ||||
| 	if (error < 0) { | ||||
| 		LOG_ERROR("Programmer error: error codes must be positive"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh->nlmsg_seq = 0; | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg->len = 0; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = seq; | ||||
| 	msg->ack = error; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * kernel_recv | ||||
|  * @rq: the newly allocated request from kernel | ||||
|  * | ||||
|  * Read requests from the kernel and allocate space for the new request. | ||||
|  * If there is no request from the kernel, *rq is NULL. | ||||
|  * | ||||
|  * This function is not thread safe due to returned stack pointer.  In fact, | ||||
|  * the returned pointer must not be in-use when this function is called again. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on error | ||||
|  */ | ||||
| static int kernel_recv(struct clog_request **rq) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	ssize_t len; | ||||
| 	char *foo; | ||||
| 	struct cn_msg *msg; | ||||
| 	struct dm_ulog_request *u_rq; | ||||
| 	struct nlmsghdr *nlmsg_h; | ||||
|  | ||||
| 	*rq = NULL; | ||||
| 	memset(recv_buf, 0, sizeof(recv_buf)); | ||||
|  | ||||
| 	len = recv(cn_fd, recv_buf, sizeof(recv_buf), 0); | ||||
| 	if (len < 0) { | ||||
| 		LOG_ERROR("Failed to recv message from kernel"); | ||||
| 		r = -errno; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	nlmsg_h = (struct nlmsghdr *)recv_buf; | ||||
| 	switch (nlmsg_h->nlmsg_type) { | ||||
| 	case NLMSG_ERROR: | ||||
| 		LOG_ERROR("Unable to recv message from kernel: NLMSG_ERROR"); | ||||
| 		r = -EBADE; | ||||
| 		goto fail; | ||||
| 	case NLMSG_DONE: | ||||
| 		msg = (struct cn_msg *)NLMSG_DATA((struct nlmsghdr *)recv_buf); | ||||
| 		len -= (ssize_t)sizeof(struct nlmsghdr); | ||||
|  | ||||
| 		if (len < (ssize_t)sizeof(struct cn_msg)) { | ||||
| 			LOG_ERROR("Incomplete request from kernel received"); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (msg->len > DM_ULOG_REQUEST_SIZE) { | ||||
| 			LOG_ERROR("Not enough space to receive kernel request (%d/%d)", | ||||
| 				  msg->len, DM_ULOG_REQUEST_SIZE); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (!msg->len) | ||||
| 			LOG_ERROR("Zero length message received"); | ||||
|  | ||||
| 		len -= (ssize_t)sizeof(struct cn_msg); | ||||
|  | ||||
| 		if (len < msg->len) | ||||
| 			LOG_ERROR("len = %zd, msg->len = %" PRIu16, len, msg->len); | ||||
|  | ||||
| 		msg->data[msg->len] = '\0'; /* Cleaner way to ensure this? */ | ||||
| 		u_rq = (struct dm_ulog_request *)msg->data; | ||||
|  | ||||
| 		if (!u_rq->request_type) { | ||||
| 			LOG_DBG("Bad transmission, requesting resend [%u]", | ||||
| 				msg->seq); | ||||
| 			r = -EAGAIN; | ||||
|  | ||||
| 			if (kernel_ack(msg->seq, EAGAIN)) { | ||||
| 				LOG_ERROR("Failed to NACK kernel transmission [%u]", | ||||
| 					  msg->seq); | ||||
| 				r = -EBADE; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Now we've got sizeof(struct cn_msg) + sizeof(struct nlmsghdr) | ||||
| 		 * worth of space that precede the request structure from the | ||||
| 		 * kernel.  Since that space isn't going to be used again, we | ||||
| 		 * can take it for our purposes; rather than allocating a whole | ||||
| 		 * new structure and doing a memcpy. | ||||
| 		 * | ||||
| 		 * We should really make sure 'clog_request' doesn't grow | ||||
| 		 * beyond what is available to us, but we need only check it | ||||
| 		 * once... perhaps at compile time? | ||||
| 		 */ | ||||
| 		foo = (char *)u_rq; | ||||
| 		foo -= (sizeof(struct clog_request) - sizeof(struct dm_ulog_request)); | ||||
| 		*rq = (struct clog_request *) foo; | ||||
|  | ||||
| 		/* Clear the wrapper container fields */ | ||||
| 		memset(*rq, 0, (size_t)((char *)u_rq - (char *)(*rq))); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unknown nlmsg_type"); | ||||
| 		r = -EBADE; | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	if (r) | ||||
| 		*rq = NULL; | ||||
|  | ||||
| 	return (r == -EAGAIN) ? 0 : r; | ||||
| } | ||||
|  | ||||
| static int kernel_send_helper(void *data, uint16_t out_size) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh; | ||||
| 	struct cn_msg *msg; | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh = (struct nlmsghdr *)send_buf; | ||||
| 	nlh->nlmsg_seq = 0;  /* FIXME: Is this used? */ | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(out_size + sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg = NLMSG_DATA(nlh); | ||||
| 	memcpy(msg->data, data, out_size); | ||||
| 	msg->len = out_size; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = 0; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(out_size + sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * do_local_work | ||||
|  * | ||||
|  * Any processing errors are placed in the 'rq' | ||||
|  * structure to be reported back to the kernel. | ||||
|  * It may be pointless for this function to | ||||
|  * return an int. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| static int do_local_work(void *data __attribute__((unused))) | ||||
| { | ||||
| 	int r; | ||||
| 	struct clog_request *rq; | ||||
| 	struct dm_ulog_request *u_rq = NULL; | ||||
|  | ||||
| 	r = kernel_recv(&rq); | ||||
| 	if (r) | ||||
| 		return r; | ||||
|  | ||||
| 	if (!rq) | ||||
| 		return 0; | ||||
|  | ||||
| 	u_rq = &rq->u_rq; | ||||
| 	LOG_DBG("[%s]  Request from kernel received: [%s/%u]", | ||||
| 		SHORT_UUID(u_rq->uuid), RQ_TYPE(u_rq->request_type), | ||||
| 		u_rq->seq); | ||||
| 	switch (u_rq->request_type) { | ||||
| 	case DM_ULOG_CTR: | ||||
| 	case DM_ULOG_DTR: | ||||
| 	case DM_ULOG_GET_REGION_SIZE: | ||||
| 	case DM_ULOG_IN_SYNC: | ||||
| 	case DM_ULOG_GET_SYNC_COUNT: | ||||
| 	case DM_ULOG_STATUS_TABLE: | ||||
| 	case DM_ULOG_PRESUSPEND: | ||||
| 		/* We do not specify ourselves as server here */ | ||||
| 		r = do_request(rq, 0); | ||||
| 		if (r) | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 		r = kernel_send(u_rq); | ||||
| 		if (r) | ||||
| 			LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 				  RQ_TYPE(u_rq->request_type)); | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_RESUME: | ||||
| 		/* | ||||
| 		 * Resume is a special case that requires a local | ||||
| 		 * component to join the CPG, and a cluster component | ||||
| 		 * to handle the request. | ||||
| 		 */ | ||||
| 		r = local_resume(u_rq); | ||||
| 		if (r) { | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 			r = kernel_send(u_rq); | ||||
| 			if (r) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* ELSE, fall through */ | ||||
| 	case DM_ULOG_IS_CLEAN: | ||||
| 	case DM_ULOG_FLUSH: | ||||
| 	case DM_ULOG_MARK_REGION: | ||||
| 	case DM_ULOG_GET_RESYNC_WORK: | ||||
| 	case DM_ULOG_SET_REGION_SYNC: | ||||
| 	case DM_ULOG_STATUS_INFO: | ||||
| 	case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 	case DM_ULOG_POSTSUSPEND: | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			u_rq->data_size = 0; | ||||
| 			u_rq->error = r; | ||||
| 			if (kernel_send(u_rq)) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_CLEAR_REGION: | ||||
| 		r = kernel_ack(u_rq->seq, 0); | ||||
|  | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			/* | ||||
| 			 * FIXME: store error for delivery on flush | ||||
| 			 *        This would allow us to optimize MARK_REGION | ||||
| 			 *        too. | ||||
| 			 */ | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Invalid log request received (%u), ignoring.", | ||||
| 			  u_rq->request_type); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (r && !u_rq->error) | ||||
| 		u_rq->error = r; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * kernel_send | ||||
|  * @u_rq: result to pass back to kernel | ||||
|  * | ||||
|  * This function returns the u_rq structure | ||||
|  * (containing the results) to the kernel. | ||||
|  * It then frees the structure. | ||||
|  * | ||||
|  * WARNING: should the structure be freed if | ||||
|  * there is an error?  I vote 'yes'.  If the | ||||
|  * kernel doesn't get the response, it should | ||||
|  * resend the request. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| int kernel_send(struct dm_ulog_request *u_rq) | ||||
| { | ||||
| 	int r; | ||||
| 	uint16_t size; | ||||
|  | ||||
| 	if (!u_rq) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	size = (uint16_t)(sizeof(struct dm_ulog_request) + u_rq->data_size); | ||||
|  | ||||
| 	if (!u_rq->data_size && !u_rq->error) { | ||||
| 		/* An ACK is all that is needed */ | ||||
|  | ||||
| 		/* FIXME: add ACK code */ | ||||
| 	} else if (size > DM_ULOG_REQUEST_SIZE) { | ||||
| 		/* | ||||
| 		 * If we gotten here, we've already overrun | ||||
| 		 * our allotted space somewhere. | ||||
| 		 * | ||||
| 		 * We must do something, because the kernel | ||||
| 		 * is waiting for a response. | ||||
| 		 */ | ||||
| 		LOG_ERROR("Not enough space to respond to server"); | ||||
| 		u_rq->error = -ENOSPC; | ||||
| 		size = sizeof(struct dm_ulog_request); | ||||
| 	} | ||||
|  | ||||
| 	r = kernel_send_helper(u_rq, size); | ||||
| 	if (r) | ||||
| 		LOG_ERROR("Failed to send msg to kernel."); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_local | ||||
|  * | ||||
|  * Initialize kernel communication socket (netlink) | ||||
|  * | ||||
|  * Returns: 0 on success, values from common.h on failure | ||||
|  */ | ||||
| int init_local(void) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	unsigned opt; | ||||
| 	struct sockaddr_nl addr; | ||||
|  | ||||
| 	cn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||||
| 	if (cn_fd < 0) | ||||
| 		return EXIT_KERNEL_SOCKET; | ||||
|  | ||||
| 	/* memset to fix valgrind complaint */ | ||||
| 	memset(&addr, 0, sizeof(struct sockaddr_nl)); | ||||
|  | ||||
| 	addr.nl_family = AF_NETLINK; | ||||
| 	addr.nl_groups = CN_IDX_DM; | ||||
| 	addr.nl_pid = 0; | ||||
|  | ||||
| 	r = bind(cn_fd, (struct sockaddr *) &addr, sizeof(addr)); | ||||
| 	if (r < 0) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_BIND; | ||||
| 	} | ||||
|  | ||||
| 	opt = addr.nl_groups; | ||||
| 	r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt)); | ||||
| 	if (r) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_SETSOCKOPT; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	r = fcntl(cn_fd, F_SETFL, FNDELAY); | ||||
| 	*/ | ||||
|  | ||||
| 	links_register(cn_fd, "local", do_local_work, NULL); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_local | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| void cleanup_local(void) | ||||
| { | ||||
| 	links_unregister(cn_fd); | ||||
| 	if (cn_fd >= 0 && close(cn_fd)) | ||||
| 		LOG_ERROR("Failed to close socket: %s", | ||||
| 			  strerror(errno)); | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LOCAL_H | ||||
| #define _LVM_CLOG_LOCAL_H | ||||
|  | ||||
| int init_local(void); | ||||
| void cleanup_local(void); | ||||
|  | ||||
| int kernel_send(struct dm_ulog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOCAL_H */ | ||||
| @@ -1,57 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
|  | ||||
| const char *__rq_types_off_by_one[] = { | ||||
| 	"DM_ULOG_CTR", | ||||
| 	"DM_ULOG_DTR", | ||||
| 	"DM_ULOG_PRESUSPEND", | ||||
| 	"DM_ULOG_POSTSUSPEND", | ||||
| 	"DM_ULOG_RESUME", | ||||
| 	"DM_ULOG_GET_REGION_SIZE", | ||||
| 	"DM_ULOG_IS_CLEAN", | ||||
| 	"DM_ULOG_IN_SYNC", | ||||
| 	"DM_ULOG_FLUSH", | ||||
| 	"DM_ULOG_MARK_REGION", | ||||
| 	"DM_ULOG_CLEAR_REGION", | ||||
| 	"DM_ULOG_GET_RESYNC_WORK", | ||||
| 	"DM_ULOG_SET_REGION_SYNC", | ||||
| 	"DM_ULOG_GET_SYNC_COUNT", | ||||
| 	"DM_ULOG_STATUS_INFO", | ||||
| 	"DM_ULOG_STATUS_TABLE", | ||||
| 	"DM_ULOG_IS_REMOTE_RECOVERING", | ||||
| 	NULL | ||||
| }; | ||||
|  | ||||
| int log_tabbing = 0; | ||||
| int log_is_open = 0; | ||||
|  | ||||
| /* | ||||
|  * Variables for various conditional logging | ||||
|  */ | ||||
| #ifdef MEMB | ||||
| int log_membership_change = 1; | ||||
| #else | ||||
| int log_membership_change = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef CKPT | ||||
| int log_checkpoint = 1; | ||||
| #else | ||||
| int log_checkpoint = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef RESEND | ||||
| int log_resend_requests = 1; | ||||
| #else | ||||
| int log_resend_requests = 0; | ||||
| #endif | ||||
| @@ -1,73 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CLOG_LOGGING_H | ||||
| #define _LVM_CLOG_LOGGING_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| /* SHORT_UUID - print last 8 chars of a string */ | ||||
| #define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x) | ||||
|  | ||||
| extern const char *__rq_types_off_by_one[]; | ||||
| #define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1] | ||||
|  | ||||
| extern int log_tabbing; | ||||
| extern int log_is_open; | ||||
| extern int log_membership_change; | ||||
| extern int log_checkpoint; | ||||
| extern int log_resend_requests; | ||||
|  | ||||
| #define LOG_OPEN(ident, option, facility) do { \ | ||||
| 		openlog(ident, option, facility); \ | ||||
| 		log_is_open = 1;		  \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_CLOSE(void) do { \ | ||||
| 		log_is_open = 0; \ | ||||
| 		closelog();	 \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_OUTPUT(level, f, arg...) do {				\ | ||||
| 		int __i;						\ | ||||
| 		char __buffer[16];					\ | ||||
| 		FILE *fp = (level > LOG_NOTICE) ? stderr : stdout;	\ | ||||
| 		if (log_is_open) {					\ | ||||
| 			for (__i = 0; (__i < log_tabbing) && (__i < 15); __i++) \ | ||||
| 				__buffer[__i] = '\t';			\ | ||||
| 			__buffer[__i] = '\0';				\ | ||||
| 			syslog(level, "%s" f "\n", __buffer, ## arg);	\ | ||||
| 		} else {						\ | ||||
| 			for (__i = 0; __i < log_tabbing; __i++)		\ | ||||
| 				fprintf(fp, "\t");			\ | ||||
| 			fprintf(fp, f "\n", ## arg);			\ | ||||
| 		}							\ | ||||
| 	} while (0) | ||||
|  | ||||
|  | ||||
| #ifdef DEBUG | ||||
| #define LOG_DBG(f, arg...) LOG_OUTPUT(LOG_DEBUG, f, ## arg) | ||||
| #else /* DEBUG */ | ||||
| #define LOG_DBG(f, arg...) do {} while (0) | ||||
| #endif /* DEBUG */ | ||||
|  | ||||
| #define LOG_COND(__X, f, arg...) do {\ | ||||
| 		if (__X) { 	     \ | ||||
| 			LOG_OUTPUT(LOG_NOTICE, f, ## arg); \ | ||||
| 		} \ | ||||
| 	} while (0) | ||||
| #define LOG_PRINT(f, arg...) LOG_OUTPUT(LOG_NOTICE, f, ## arg) | ||||
| #define LOG_ERROR(f, arg...) LOG_OUTPUT(LOG_ERR, f, ## arg) | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOGGING_H */ | ||||
| @@ -1,4 +0,0 @@ | ||||
| init_fifos | ||||
| fini_fifos | ||||
| daemon_talk | ||||
| dm_event_get_version | ||||
							
								
								
									
										1
									
								
								daemons/dmeventd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/dmeventd/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| dmeventd | ||||
| @@ -1,116 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| abs_srcdir = @abs_srcdir@ | ||||
|  | ||||
| SOURCES = libdevmapper-event.c | ||||
| SOURCES2 = dmeventd.c | ||||
|  | ||||
| TARGETS = dmeventd | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES) $(SOURCES2) \ | ||||
| 	plugins/lvm2/dmeventd_lvm.c \ | ||||
| 	plugins/mirror/dmeventd_mirror.c \ | ||||
| 	plugins/raid/dmeventd_raid.c \ | ||||
| 	plugins/snapshot/dmeventd_snapshot.c \ | ||||
| 	plugins/thin/dmeventd_thin.c \ | ||||
| 	plugins/vdo/dmeventd_vdo.c \ | ||||
| 	) | ||||
| CFLOW_TARGET := $(TARGETS) | ||||
|  | ||||
| .PHONY: install_lib_dynamic install_lib_static install_include \ | ||||
| 	install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \ | ||||
| 	install_lib install_dmeventd | ||||
|  | ||||
| INSTALL_DMEVENTD_TARGETS = install_dmeventd_dynamic | ||||
| INSTALL_LIB_TARGETS = install_lib_dynamic | ||||
|  | ||||
| LIB_NAME = libdevmapper-event | ||||
| ifeq ("@STATIC_LINK@", "yes") | ||||
|   LIB_STATIC = $(LIB_NAME).a | ||||
|   TARGETS += $(LIB_STATIC) dmeventd.static | ||||
|   INSTALL_DMEVENTD_TARGETS += install_dmeventd_static | ||||
|   INSTALL_LIB_TARGETS += install_lib_static | ||||
| endif | ||||
|  | ||||
| LIB_VERSION = $(LIB_VERSION_DM) | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIBS = $(PTHREAD_LIBS) -L$(interfacebuilddir) -ldevmapper | ||||
|  | ||||
| CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a | ||||
|  | ||||
| ifneq ($(MAKECMDGOALS),device-mapper) | ||||
|   SUBDIRS+=plugins | ||||
| endif | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h | ||||
| EXPORTED_FN_PREFIX = dm_event | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| all: device-mapper | ||||
| device-mapper: $(TARGETS) | ||||
| plugins.device-mapper: $(LIB_SHARED) | ||||
|  | ||||
| CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS) | ||||
|  | ||||
| dmeventd: $(LIB_SHARED) dmeventd.o | ||||
| 	@echo "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \ | ||||
| 		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) | ||||
|  | ||||
| dmeventd.static: $(LIB_STATIC) dmeventd.o | ||||
| 	@echo "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \ | ||||
| 		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS) | ||||
|  | ||||
| ifeq ("@PKGCONFIG@", "yes") | ||||
|   INSTALL_LIB_TARGETS += install_pkgconfig | ||||
| endif | ||||
|  | ||||
| install_include: $(srcdir)/libdevmapper-event.h | ||||
| 	@echo "    [INSTALL] $(<F)" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F) | ||||
|  | ||||
| install_pkgconfig: libdevmapper-event.pc | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc | ||||
|  | ||||
| install_lib_dynamic: install_lib_shared | ||||
|  | ||||
| install_lib_static: $(LIB_STATIC) | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F) | ||||
|  | ||||
| install_lib: $(INSTALL_LIB_TARGETS) | ||||
|  | ||||
| install_dmeventd_dynamic: dmeventd | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) | ||||
|  | ||||
| install_dmeventd_static: dmeventd.static | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F) | ||||
|  | ||||
| install_dmeventd: $(INSTALL_DMEVENTD_TARGETS) | ||||
|  | ||||
| install: install_include install_lib install_dmeventd | ||||
|  | ||||
| install_device-mapper: install_include install_lib install_dmeventd | ||||
|  | ||||
| DISTCLEAN_TARGETS += libdevmapper-event.pc | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #ifndef __DMEVENTD_DOT_H__ | ||||
| #define __DMEVENTD_DOT_H__ | ||||
|  | ||||
| /* FIXME This stuff must be configurable. */ | ||||
|  | ||||
| #define	DM_EVENT_FIFO_CLIENT	DEFAULT_DM_RUN_DIR "/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	DEFAULT_DM_RUN_DIR "/dmeventd-server" | ||||
|  | ||||
| #define DM_EVENT_DEFAULT_TIMEOUT 10 | ||||
|  | ||||
| /* Commands for the daemon passed in the message below. */ | ||||
| enum dm_event_command { | ||||
| 	DM_EVENT_CMD_ACTIVE = 1, | ||||
| 	DM_EVENT_CMD_REGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_UNREGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_GET_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_SET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_GET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_HELLO, | ||||
| 	DM_EVENT_CMD_DIE, | ||||
| 	DM_EVENT_CMD_GET_STATUS, | ||||
| 	DM_EVENT_CMD_GET_PARAMETERS, | ||||
| }; | ||||
|  | ||||
| /* Message passed between client and daemon. */ | ||||
| struct dm_event_daemon_message { | ||||
| 	uint32_t cmd; | ||||
| 	uint32_t size; | ||||
| 	char *data; | ||||
| }; | ||||
|  | ||||
| /* FIXME Is this meant to be exported?  I can't see where the | ||||
|    interface uses it. */ | ||||
| /* Fifos for client/daemon communication. */ | ||||
| struct dm_event_fifos { | ||||
| 	int client; | ||||
| 	int server; | ||||
| 	const char *client_path; | ||||
| 	const char *server_path; | ||||
| }; | ||||
|  | ||||
| /*      EXIT_SUCCESS             0 -- stdlib.h */ | ||||
| /*      EXIT_FAILURE             1 -- stdlib.h */ | ||||
| /*      EXIT_LOCKFILE_INUSE      2 -- obsoleted */ | ||||
| #define EXIT_DESC_CLOSE_FAILURE  3 | ||||
| #define EXIT_DESC_OPEN_FAILURE   4 | ||||
| /*      EXIT_OPEN_PID_FAILURE    5 -- obsoleted */ | ||||
| #define EXIT_FIFO_FAILURE        6 | ||||
| #define EXIT_CHDIR_FAILURE       7 | ||||
|  | ||||
| /* Implemented in libdevmapper-event.c, but not part of public API. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| int daemon_talk(struct dm_event_fifos *fifos, | ||||
| 		struct dm_event_daemon_message *msg, int cmd, | ||||
| 		const char *dso_name, const char *dev_name, | ||||
| 		enum dm_event_mask evmask, uint32_t timeout); | ||||
| int init_fifos(struct dm_event_fifos *fifos); | ||||
| void fini_fifos(struct dm_event_fifos *fifos); | ||||
| int dm_event_get_version(struct dm_event_fifos *fifos, int *version); | ||||
|  | ||||
| #endif /* __DMEVENTD_DOT_H__ */ | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,136 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Note that this file is released only as part of a technology preview | ||||
|  * and its contents may change in future updates in ways that do not | ||||
|  * preserve compatibility. | ||||
|  */ | ||||
|  | ||||
| #ifndef LIB_DMEVENT_H | ||||
| #define LIB_DMEVENT_H | ||||
|  | ||||
| #include <stdarg.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* | ||||
|  * Event library interface. | ||||
|  */ | ||||
|  | ||||
| enum dm_event_mask { | ||||
| 	DM_EVENT_SETTINGS_MASK  = 0x0000FF, | ||||
| 	DM_EVENT_SINGLE		= 0x000001, /* Report multiple errors just once. */ | ||||
| 	DM_EVENT_MULTI		= 0x000002, /* Report all of them. */ | ||||
|  | ||||
| 	DM_EVENT_ERROR_MASK     = 0x00FF00, | ||||
| 	DM_EVENT_SECTOR_ERROR	= 0x000100, /* Failure on a particular sector. */ | ||||
| 	DM_EVENT_DEVICE_ERROR	= 0x000200, /* Device failure. */ | ||||
| 	DM_EVENT_PATH_ERROR	= 0x000400, /* Failure on an io path. */ | ||||
| 	DM_EVENT_ADAPTOR_ERROR	= 0x000800, /* Failure of a host adaptor. */ | ||||
|  | ||||
| 	DM_EVENT_STATUS_MASK    = 0xFF0000, | ||||
| 	DM_EVENT_SYNC_STATUS	= 0x010000, /* Mirror synchronization completed/failed. */ | ||||
| 	DM_EVENT_TIMEOUT	= 0x020000, /* Timeout has occured */ | ||||
|  | ||||
| 	DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */ | ||||
| }; | ||||
|  | ||||
| #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK | ||||
| #define DM_EVENT_PROTOCOL_VERSION 2 | ||||
|  | ||||
| struct dm_task; | ||||
| struct dm_event_handler; | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void); | ||||
| void dm_event_handler_destroy(struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* | ||||
|  * Path of shared library to handle events. | ||||
|  * | ||||
|  * All of dmeventd, dso, device_name and uuid strings are duplicated so | ||||
|  * you do not need to keep the pointers valid after the call succeeds. | ||||
|  * They may return -ENOMEM though. | ||||
|  */ | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path); | ||||
|  | ||||
| /* | ||||
|  * Path of dmeventd binary. | ||||
|  */ | ||||
| int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path); | ||||
|  | ||||
| /* | ||||
|  * Identify the device to monitor by exactly one of device_name, uuid or | ||||
|  * device number. String arguments are duplicated, see above. | ||||
|  */ | ||||
| int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name); | ||||
|  | ||||
| int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid); | ||||
|  | ||||
| void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major); | ||||
| void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor); | ||||
| void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout); | ||||
|  | ||||
| /* | ||||
|  * Specify mask for events to monitor. | ||||
|  */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask); | ||||
|  | ||||
| const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh); | ||||
| // FIXME  misuse of bitmask as enum | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* FIXME Review interface (what about this next thing?) */ | ||||
| int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next); | ||||
|  | ||||
| /* | ||||
|  * Initiate monitoring using dmeventd. | ||||
|  */ | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh); | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* Set debug level for logging, and whether to log on stdout/stderr or syslog */ | ||||
| void dm_event_log_set(int debug_log_level, int use_syslog); | ||||
|  | ||||
| /* Log messages acroding to current debug level  */ | ||||
| __attribute__((format(printf, 6, 0))) | ||||
| void dm_event_log(const char *subsys, int level, const char *file, | ||||
| 		  int line, int dm_errno_or_class, | ||||
| 		  const char *format, va_list ap); | ||||
| /* Macro to route print_log do dm_event_log() */ | ||||
| #define DM_EVENT_LOG_FN(subsys) \ | ||||
| void print_log(int level, const char *file, int line, int dm_errno_or_class,\ | ||||
| 	       const char *format, ...)\ | ||||
| {\ | ||||
| 	va_list ap;\ | ||||
| 	va_start(ap, format);\ | ||||
| 	dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\ | ||||
| 	va_end(ap);\ | ||||
| } | ||||
|  | ||||
| /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for | ||||
|    detailed descriptions. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user); | ||||
| int register_device(const char *device_name, const char *uuid, int major, int minor, void **user); | ||||
| int unregister_device(const char *device_name, const char *uuid, int major, | ||||
| 		      int minor, void **user); | ||||
|  | ||||
| #endif | ||||
| @@ -1,10 +0,0 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=@exec_prefix@ | ||||
| libdir=@libdir@ | ||||
| includedir=@includedir@ | ||||
|  | ||||
| Name: devmapper-event | ||||
| Description: device-mapper event library | ||||
| Version: @DM_LIB_PATCHLEVEL@ | ||||
| Cflags: -I${includedir} | ||||
| Libs: -L${libdir} -ldevmapper-event | ||||
| @@ -1,27 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| SUBDIRS += lvm2 snapshot raid thin mirror vdo | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| snapshot: lvm2 | ||||
| mirror: lvm2 | ||||
| raid: lvm2 | ||||
| thin: lvm2 | ||||
| vdo: lvm2 | ||||
| @@ -1,7 +0,0 @@ | ||||
| dmeventd_lvm2_init | ||||
| dmeventd_lvm2_exit | ||||
| dmeventd_lvm2_lock | ||||
| dmeventd_lvm2_unlock | ||||
| dmeventd_lvm2_pool | ||||
| dmeventd_lvm2_run | ||||
| dmeventd_lvm2_command | ||||
| @@ -1,30 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2010-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/tools | ||||
| LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@ | ||||
|  | ||||
| SOURCES = dmeventd_lvm.c | ||||
|  | ||||
| LIB_SHARED = libdevmapper-event-lvm2.$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_lib_shared | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,192 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "tools/lvm2cmd.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| /* | ||||
|  * register_device() is called first and performs initialisation. | ||||
|  * Only one device may be registered or unregistered at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
| static DM_LIST_INIT(_env_registry); | ||||
|  | ||||
| struct env_data { | ||||
| 	struct dm_list list; | ||||
| 	const char *cmd; | ||||
| 	const char *data; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("#lvm") | ||||
|  | ||||
| static void _lvm2_print_log(int level, const char *file, int line, | ||||
| 			    int dm_errno_or_class, const char *msg) | ||||
| { | ||||
| 	print_log(level, file, line, dm_errno_or_class, "%s", msg); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| void dmeventd_lvm2_lock(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_unlock(void) | ||||
| { | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_init(void) | ||||
| { | ||||
| 	int r = 0; | ||||
|  | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_lvm2_print_log); | ||||
|  | ||||
| 		if (!(_lvm_handle = lvm2_init_threaded())) | ||||
| 			goto out; | ||||
|  | ||||
| 		/* | ||||
| 		 * Need some space for allocations.  1024 should be more | ||||
| 		 * than enough for what we need (device mapper name splitting) | ||||
| 		 */ | ||||
| 		if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) { | ||||
| 			lvm2_exit(_lvm_handle); | ||||
| 			_lvm_handle = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		lvm2_disable_dmeventd_monitoring(_lvm_handle); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 		log_debug("lvm plugin initilized."); | ||||
| 	} | ||||
|  | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_exit(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		log_debug("lvm plugin shuting down."); | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		dm_list_init(&_env_registry); | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 		log_debug("lvm plugin exited."); | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| } | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void) | ||||
| { | ||||
| 	return _mem_pool; | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_run(const char *cmdline) | ||||
| { | ||||
| 	return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device) | ||||
| { | ||||
| 	static char _internal_prefix[] =  "_dmeventd_"; | ||||
| 	char *vg = NULL, *lv = NULL, *layer; | ||||
| 	int r; | ||||
| 	struct env_data *env_data; | ||||
| 	const char *env = NULL; | ||||
|  | ||||
| 	if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) { | ||||
| 		log_error("Unable to determine VG name from %s.", | ||||
| 			  device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* strip off the mirror component designations */ | ||||
| 	if ((layer = strstr(lv, "_mimagetmp")) || | ||||
| 	    (layer = strstr(lv, "_mlog"))) | ||||
| 		*layer = '\0'; | ||||
|  | ||||
| 	if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) { | ||||
| 		/* check if ENVVAR wasn't already resolved */ | ||||
| 		dm_list_iterate_items(env_data, &_env_registry) | ||||
| 			if (!strcmp(cmd, env_data->cmd)) { | ||||
| 				env = env_data->data; | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 		if (!env) { | ||||
| 			/* run lvm2 command to find out setting value */ | ||||
| 			dmeventd_lvm2_lock(); | ||||
| 			if (!dmeventd_lvm2_run(cmd) || | ||||
| 			    !(env = getenv(cmd))) { | ||||
| 				dmeventd_lvm2_unlock(); | ||||
| 				log_error("Unable to find configured command."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			/* output of internal command passed via env var */ | ||||
| 			env = dm_pool_strdup(_mem_pool, env); /* copy with lock */ | ||||
| 			dmeventd_lvm2_unlock(); | ||||
| 			if (!env || | ||||
| 			    !(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) || | ||||
| 			    !(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) { | ||||
| 				log_error("Unable to allocate env memory."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			env_data->data = env; | ||||
| 			/* add to ENVVAR registry */ | ||||
| 			dm_list_add(&_env_registry, &env_data->list); | ||||
| 		} | ||||
| 		cmd = env; | ||||
| 	} | ||||
|  | ||||
| 	r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv); | ||||
|  | ||||
| 	dm_pool_free(mem, vg); | ||||
|  | ||||
| 	if (r < 0) { | ||||
| 		log_error("Unable to form LVM command. (too long)."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Wrappers around liblvm2cmd functions for dmeventd plug-ins. | ||||
|  * | ||||
|  * liblvm2cmd is not thread-safe so the locking in this library helps dmeventd | ||||
|  * threads to co-operate in sharing a single instance. | ||||
|  * | ||||
|  * FIXME Either support this properly as a generic liblvm2cmd wrapper or make | ||||
|  * liblvm2cmd thread-safe so this can go away. | ||||
|  */ | ||||
|  | ||||
| #ifndef _DMEVENTD_LVMWRAP_H | ||||
| #define _DMEVENTD_LVMWRAP_H | ||||
|  | ||||
| struct dm_pool; | ||||
|  | ||||
| int dmeventd_lvm2_init(void); | ||||
| void dmeventd_lvm2_exit(void); | ||||
| int dmeventd_lvm2_run(const char *cmdline); | ||||
|  | ||||
| void dmeventd_lvm2_lock(void); | ||||
| void dmeventd_lvm2_unlock(void); | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void); | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device); | ||||
|  | ||||
| #define dmeventd_lvm2_run_with_lock(cmdline) \ | ||||
| 	({\ | ||||
| 		int rc;\ | ||||
| 		dmeventd_lvm2_lock();\ | ||||
| 		rc = dmeventd_lvm2_run(cmdline);\ | ||||
| 		dmeventd_lvm2_unlock();\ | ||||
| 		rc;\ | ||||
| 	}) | ||||
|  | ||||
| #define dmeventd_lvm2_init_with_pool(name, st) \ | ||||
| 	({\ | ||||
| 		struct dm_pool *mem;\ | ||||
| 		st = NULL;\ | ||||
| 		if (dmeventd_lvm2_init()) {\ | ||||
| 			if ((mem = dm_pool_create(name, 2048)) &&\ | ||||
| 			    (st = dm_pool_zalloc(mem, sizeof(*st))))\ | ||||
| 				st->mem = mem;\ | ||||
| 			else {\ | ||||
| 				if (mem)\ | ||||
| 					dm_pool_destroy(mem);\ | ||||
| 				dmeventd_lvm2_exit();\ | ||||
| 			}\ | ||||
| 		}\ | ||||
| 		st;\ | ||||
| 	}) | ||||
|  | ||||
| #define dmeventd_lvm2_exit_with_pool(pool) \ | ||||
| 	do {\ | ||||
| 		dm_pool_destroy(pool->mem);\ | ||||
| 		dmeventd_lvm2_exit();\ | ||||
| 	} while(0) | ||||
|  | ||||
| #endif /* _DMEVENTD_LVMWRAP_H */ | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,32 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2008-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_mirror.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2mirror | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,211 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "lib/activate/activate.h" | ||||
|  | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
|  | ||||
| #define ME_IGNORE    0 | ||||
| #define ME_INSYNC    1 | ||||
| #define ME_FAILURE   2 | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	char cmd_lvconvert[512]; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("mirr") | ||||
|  | ||||
| static void _process_status_code(dm_status_mirror_health_t health, | ||||
| 				 uint32_t major, uint32_t minor, | ||||
| 				 const char *dev_type, int *r) | ||||
| { | ||||
| 	/* | ||||
| 	 *    A => Alive - No failures | ||||
| 	 *    D => Dead - A write failure occurred leaving mirror out-of-sync | ||||
| 	 *    F => Flush failed. | ||||
| 	 *    S => Sync - A sychronization failure occurred, mirror out-of-sync | ||||
| 	 *    R => Read - A read failure occurred, mirror data unaffected | ||||
| 	 *    U => Unclassified failure (bug) | ||||
| 	 */  | ||||
| 	switch (health) { | ||||
| 	case DM_STATUS_MIRROR_ALIVE: | ||||
| 		return; | ||||
| 	case DM_STATUS_MIRROR_FLUSH_FAILED: | ||||
| 		log_error("%s device %u:%u flush failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		*r = ME_FAILURE; | ||||
| 		break; | ||||
| 	case DM_STATUS_MIRROR_SYNC_FAILED: | ||||
| 		log_error("%s device %u:%u sync failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		break; | ||||
| 	case DM_STATUS_MIRROR_READ_FAILED: | ||||
| 		log_error("%s device %u:%u read failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		break; | ||||
| 	default: | ||||
| 		log_error("%s device %u:%u has failed (%c).", | ||||
| 			  dev_type, major, minor, (char)health); | ||||
| 		*r = ME_FAILURE; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _get_mirror_event(struct dso_state *state, char *params) | ||||
| { | ||||
| 	int r = ME_INSYNC; | ||||
| 	unsigned i; | ||||
| 	struct dm_status_mirror *ms; | ||||
|  | ||||
| 	if (!dm_get_status_mirror(state->mem, params, &ms)) { | ||||
| 		log_error("Unable to parse mirror status string."); | ||||
| 		return ME_IGNORE; | ||||
| 	} | ||||
|  | ||||
| 	/* Check for bad mirror devices */ | ||||
| 	for (i = 0; i < ms->dev_count; ++i) | ||||
| 		_process_status_code(ms->devs[i].health, | ||||
| 				     ms->devs[i].major, ms->devs[i].minor, | ||||
| 				     i ? "Secondary mirror" : "Primary mirror", &r); | ||||
|  | ||||
| 	/* Check for bad disk log device */ | ||||
| 	for (i = 0; i < ms->log_count; ++i) | ||||
| 		_process_status_code(ms->logs[i].health, | ||||
| 				     ms->logs[i].major, ms->logs[i].minor, | ||||
| 				     "Log", &r); | ||||
|  | ||||
| 	/* Ignore if not in-sync */ | ||||
| 	if ((r == ME_INSYNC) && (ms->insync_regions != ms->total_regions)) | ||||
| 		r = ME_IGNORE; | ||||
|  | ||||
| 	dm_pool_free(state->mem, ms); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _remove_failed_devices(const char *cmd_lvconvert, const char *device) | ||||
| { | ||||
| 	/* if repair goes OK, report success even if lvscan has failed */ | ||||
| 	if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) { | ||||
| 		log_error("Repair of mirrored device %s failed.", device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_info("Repair of mirrored device %s finished successfully.", device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			log_info("%s mapping lost.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, TARGET_NAME_MIRROR)) { | ||||
| 			log_info("%s has unmirrored portion.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		switch(_get_mirror_event(state, params)) { | ||||
| 		case ME_INSYNC: | ||||
| 			/* FIXME: all we really know is that this | ||||
| 			   _part_ of the device is in sync | ||||
| 			   Also, this is not an error | ||||
| 			*/ | ||||
| 			log_notice("%s is now in-sync.", device); | ||||
| 			break; | ||||
| 		case ME_FAILURE: | ||||
| 			log_error("Device failure in %s.", device); | ||||
| 			if (!_remove_failed_devices(state->cmd_lvconvert, device)) | ||||
| 				/* FIXME Why are all the error return codes unused? Get rid of them? */ | ||||
| 				log_error("Failed to remove faulty devices in %s.", | ||||
| 					  device); | ||||
| 			/* Should check before warning user that device is now linear | ||||
| 			else | ||||
| 				log_notice("%s is now a linear device.", | ||||
| 					   device); | ||||
| 			*/ | ||||
| 			break; | ||||
| 		case ME_IGNORE: | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* FIXME Provide value then! */ | ||||
| 			log_warn("WARNING: %s received unknown event.", device); | ||||
| 		} | ||||
| 	} while (next); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("mirror_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
|         /* CANNOT use --config as this disables cached content */ | ||||
| 	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert), | ||||
| 				   "lvconvert --repair --use-policies", device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring mirror device %s for events.", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	log_error("Failed to monitor mirror %s.", device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring mirror device %s for events.", | ||||
| 		 device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_raid.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2raid | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,189 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "lib/config/defaults.h" | ||||
|  | ||||
| /* Hold enough elements for the mximum number of RAID images */ | ||||
| #define	RAID_DEVS_ELEMS	((DEFAULT_RAID_MAX_IMAGES + 63) / 64) | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	char cmd_lvconvert[512]; | ||||
| 	uint64_t raid_devs[RAID_DEVS_ELEMS]; | ||||
| 	int failed; | ||||
| 	int warned; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("raid") | ||||
|  | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
|  | ||||
| static int _process_raid_event(struct dso_state *state, char *params, const char *device) | ||||
| { | ||||
| 	struct dm_status_raid *status; | ||||
| 	const char *d; | ||||
| 	int dead = 0, r = 1; | ||||
| 	uint32_t dev; | ||||
|  | ||||
| 	if (!dm_get_status_raid(state->mem, params, &status)) { | ||||
| 		log_error("Failed to process status line for %s.", device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	d = status->dev_health; | ||||
| 	while ((d = strchr(d, 'D'))) { | ||||
| 		dev = (uint32_t)(d - status->dev_health); | ||||
|  | ||||
| 		if (!(state->raid_devs[dev / 64] & (UINT64_C(1) << (dev % 64)))) { | ||||
| 			state->raid_devs[dev / 64] |= (UINT64_C(1) << (dev % 64)); | ||||
| 			log_warn("WARNING: Device #%u of %s array, %s, has failed.", | ||||
| 				 dev, status->raid_type, device); | ||||
| 		} | ||||
|  | ||||
| 		d++; | ||||
| 		dead = 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * if we are converting from non-RAID to RAID (e.g. linear -> raid1) | ||||
| 	 * and too many original devices die, such that we cannot continue | ||||
| 	 * the "recover" operation, the sync action will go to "idle", the | ||||
| 	 * unsynced devs will remain at 'a', and the original devices will | ||||
| 	 * NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived. | ||||
| 	 * | ||||
| 	 * This is simply the way the kernel works... | ||||
| 	 */ | ||||
| 	if (!strcmp(status->sync_action, "idle") && | ||||
| 	    (status->dev_health[0] == 'a') && | ||||
| 	    (status->insync_regions < status->total_regions)) { | ||||
| 		log_error("Primary sources for new RAID, %s, have failed.", | ||||
| 			  device); | ||||
| 		dead = 1; /* run it through LVM repair */ | ||||
| 	} | ||||
|  | ||||
| 	if (dead) { | ||||
| 		/* | ||||
| 		 * Use the first event to run a repair ignoring any additional ones. | ||||
| 		 * | ||||
| 		 * We presume lvconvert to do pre-repair | ||||
| 		 * checks to avoid bloat in this plugin. | ||||
| 		 */ | ||||
| 		if (!state->warned && status->insync_regions < status->total_regions) { | ||||
| 			state->warned = 1; | ||||
| 			log_warn("WARNING: waiting for resynchronization to finish " | ||||
| 				 "before initiating repair on RAID device %s.", device); | ||||
| 			/* Fall through to allow lvconvert to run. */ | ||||
| 		} | ||||
|  | ||||
| 		if (state->failed) | ||||
| 			goto out; /* already reported */ | ||||
|  | ||||
| 		state->failed = 1; | ||||
|  | ||||
| 		/* if repair goes OK, report success even if lvscan has failed */ | ||||
| 		if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) { | ||||
| 			log_error("Repair of RAID device %s failed.", device); | ||||
| 			r = 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		state->failed = 0; | ||||
| 		if (status->insync_regions == status->total_regions) | ||||
| 			memset(&state->raid_devs, 0, sizeof(state->raid_devs)); | ||||
| 		log_info("%s array, %s, is %s in-sync.", | ||||
| 			 status->raid_type, device, | ||||
| 			 (status->insync_regions == status->total_regions) ? "now" : "not"); | ||||
| 	} | ||||
| out: | ||||
| 	dm_pool_free(state->mem, status); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			log_info("%s mapping lost.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, "raid")) { | ||||
| 			log_info("%s has non-raid portion.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!_process_raid_event(state, params, device)) | ||||
| 			log_error("Failed to process event for %s.", | ||||
| 				  device); | ||||
| 	} while (next); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("raid_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert), | ||||
| 				   "lvconvert --repair --use-policies", device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring RAID device %s for events.", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	log_error("Failed to monitor RAID %s.", device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring RAID device %s for events.", | ||||
| 		 device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_snapshot.c | ||||
|  | ||||
| LIB_SHARED = libdevmapper-event-lvm2snapshot.$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,290 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
|  | ||||
| #include <sys/sysmacros.h> | ||||
| #include <sys/wait.h> | ||||
| #include <stdarg.h> | ||||
| #include <pthread.h> | ||||
|  | ||||
| /* First warning when snapshot is 80% full. */ | ||||
| #define WARNING_THRESH	(DM_PERCENT_1 * 80) | ||||
| /* Run a check every 5%. */ | ||||
| #define CHECK_STEP	(DM_PERCENT_1 *  5) | ||||
| /* Do not bother checking snapshots less than 50% full. */ | ||||
| #define CHECK_MINIMUM	(DM_PERCENT_1 * 50) | ||||
|  | ||||
| #define UMOUNT_COMMAND "/bin/umount" | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	dm_percent_t percent_check; | ||||
| 	uint64_t known_size; | ||||
| 	char cmd_lvextend[512]; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("snap") | ||||
|  | ||||
| static int _run(const char *cmd, ...) | ||||
| { | ||||
|         va_list ap; | ||||
|         int argc = 1; /* for argv[0], i.e. cmd */ | ||||
|         int i = 0; | ||||
|         const char **argv; | ||||
|         pid_t pid = fork(); | ||||
|         int status; | ||||
|  | ||||
|         if (pid == 0) { /* child */ | ||||
|                 va_start(ap, cmd); | ||||
|                 while (va_arg(ap, const char *)) | ||||
|                         ++ argc; | ||||
|                 va_end(ap); | ||||
|  | ||||
|                 /* + 1 for the terminating NULL */ | ||||
|                 argv = alloca(sizeof(const char *) * (argc + 1)); | ||||
|  | ||||
|                 argv[0] = cmd; | ||||
|                 va_start(ap, cmd); | ||||
|                 while ((argv[++i] = va_arg(ap, const char *))); | ||||
|                 va_end(ap); | ||||
|  | ||||
|                 execvp(cmd, (char **)argv); | ||||
|                 log_sys_error("exec", cmd); | ||||
|                 exit(127); | ||||
|         } | ||||
|  | ||||
|         if (pid > 0) { /* parent */ | ||||
|                 if (waitpid(pid, &status, 0) != pid) | ||||
|                         return 0; /* waitpid failed */ | ||||
|                 if (!WIFEXITED(status) || WEXITSTATUS(status)) | ||||
|                         return 0; /* the child failed */ | ||||
|         } | ||||
|  | ||||
|         if (pid < 0) | ||||
|                 return 0; /* fork failed */ | ||||
|  | ||||
|         return 1; /* all good */ | ||||
| } | ||||
|  | ||||
| static int _extend(const char *cmd) | ||||
| { | ||||
| 	log_debug("Extending snapshot via %s.", cmd); | ||||
| 	return dmeventd_lvm2_run_with_lock(cmd); | ||||
| } | ||||
|  | ||||
| #ifdef SNAPSHOT_REMOVE | ||||
| /* Remove invalid snapshot from dm-table */ | ||||
| /* Experimental for now and not used by default */ | ||||
| static int _remove(const char *uuid) | ||||
| { | ||||
| 	int r = 1; | ||||
| 	uint32_t cookie = 0; | ||||
| 	struct dm_task *dmt; | ||||
|  | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dm_task_set_uuid(dmt, uuid)) { | ||||
| 		r = 0; | ||||
| 		goto_out; | ||||
| 	} | ||||
|  | ||||
| 	dm_task_retry_remove(dmt); | ||||
|  | ||||
| 	if (!dm_task_set_cookie(dmt, &cookie, 0)) { | ||||
| 		r = 0; | ||||
| 		goto_out; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_run(dmt)) { | ||||
| 		r = 0; | ||||
| 		goto_out; | ||||
| 	} | ||||
| out: | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
| #endif /* SNAPSHOT_REMOVE */ | ||||
|  | ||||
| static void _umount(const char *device, int major, int minor) | ||||
| { | ||||
| 	FILE *mounts; | ||||
| 	char buffer[4096]; | ||||
| 	char *words[3]; | ||||
| 	struct stat st; | ||||
| 	const char procmounts[] = "/proc/mounts"; | ||||
|  | ||||
| 	if (!(mounts = fopen(procmounts, "r"))) { | ||||
| 		log_sys_error("fopen", procmounts); | ||||
| 		log_error("Not umounting %s.", device); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while (!feof(mounts)) { | ||||
| 		/* read a line of /proc/mounts */ | ||||
| 		if (!fgets(buffer, sizeof(buffer), mounts)) | ||||
| 			break; /* eof, likely */ | ||||
|  | ||||
| 		/* words[0] is the mount point and words[1] is the device path */ | ||||
| 		if (dm_split_words(buffer, 3, 0, words) < 2) | ||||
| 			continue; | ||||
|  | ||||
| 		/* find the major/minor of the device */ | ||||
| 		if (stat(words[0], &st)) | ||||
| 			continue; /* can't stat, skip this one */ | ||||
|  | ||||
| 		if (S_ISBLK(st.st_mode) && | ||||
| 		    (int) major(st.st_rdev) == major && | ||||
| 		    (int) minor(st.st_rdev) == minor) { | ||||
| 			log_error("Unmounting invalid snapshot %s from %s.", device, words[1]); | ||||
| 			if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL)) | ||||
| 				log_error("Failed to umount snapshot %s from %s: %s.", | ||||
| 					  device, words[1], strerror(errno)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (fclose(mounts)) | ||||
| 		log_sys_error("close", procmounts); | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	struct dm_status_snapshot *status = NULL; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	int percent; | ||||
| 	struct dm_info info; | ||||
| 	int ret; | ||||
|  | ||||
| 	/* No longer monitoring, waiting for remove */ | ||||
| 	if (!state->percent_check) | ||||
| 		return; | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
| 	if (!target_type || strcmp(target_type, "snapshot")) { | ||||
| 		log_error("Target %s is not snapshot.", target_type); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_get_status_snapshot(state->mem, params, &status)) { | ||||
| 		log_error("Cannot parse snapshot %s state: %s.", device, params); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If the snapshot has been invalidated or we failed to parse | ||||
| 	 * the status string. Report the full status string to syslog. | ||||
| 	 */ | ||||
| 	if (status->invalid || status->overflow || !status->total_sectors) { | ||||
| 		log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.", | ||||
| 			 device, params); | ||||
| 		state->percent_check = 0; | ||||
| 		if (dm_task_get_info(dmt, &info)) | ||||
| 			_umount(device, info.major, info.minor); | ||||
| #ifdef SNAPSHOT_REMOVE | ||||
| 		/* Maybe configurable ? */ | ||||
| 		_remove(dm_task_get_uuid(dmt)); | ||||
| #endif | ||||
| 		if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH)) | ||||
| 			log_sys_error("pthread_kill", "self"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (length <= (status->used_sectors - status->metadata_sectors)) { | ||||
| 		/* TODO eventually recognize earlier when room is enough */ | ||||
| 		log_info("Dropping monitoring of fully provisioned snapshot %s.", | ||||
| 			 device); | ||||
| 		if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH)) | ||||
| 			log_sys_error("pthread_kill", "self"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* Snapshot size had changed. Clear the threshold. */ | ||||
| 	if (state->known_size != status->total_sectors) { | ||||
| 		state->percent_check = CHECK_MINIMUM; | ||||
| 		state->known_size = status->total_sectors; | ||||
| 	} | ||||
|  | ||||
| 	percent = dm_make_percent(status->used_sectors, status->total_sectors); | ||||
| 	if (percent >= state->percent_check) { | ||||
| 		/* Usage has raised more than CHECK_STEP since the last | ||||
| 		   time. Run actions. */ | ||||
| 		state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; | ||||
|  | ||||
| 		if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ | ||||
| 			log_warn("WARNING: Snapshot %s is now %.2f%% full.", | ||||
| 				 device, dm_percent_to_round_float(percent, 2)); | ||||
|  | ||||
| 		/* Try to extend the snapshot, in accord with user-set policies */ | ||||
| 		if (!_extend(state->cmd_lvextend)) | ||||
| 			log_error("Failed to extend snapshot %s.", device); | ||||
| 	} | ||||
| out: | ||||
| 	dm_pool_free(state->mem, status); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("snapshot_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend, | ||||
| 				   sizeof(state->cmd_lvextend), | ||||
| 				   "lvextend --use-policies", device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	state->percent_check = CHECK_MINIMUM; | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring snapshot %s.", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	log_error("Failed to monitor snapshot %s.", device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring snapshot %s.", device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_thin.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2thin | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,436 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
|  | ||||
| #include <sys/wait.h> | ||||
| #include <stdarg.h> | ||||
|  | ||||
| /* TODO - move this mountinfo code into library to be reusable */ | ||||
| #ifdef __linux__ | ||||
| #  include "libdm/misc/kdev_t.h" | ||||
| #else | ||||
| #  define MAJOR(x) major((x)) | ||||
| #  define MINOR(x) minor((x)) | ||||
| #endif | ||||
|  | ||||
| /* First warning when thin data or metadata is 80% full. */ | ||||
| #define WARNING_THRESH	(DM_PERCENT_1 * 80) | ||||
| /* Umount thin LVs when thin data or metadata LV is >= | ||||
|  * and lvextend --use-policies has failed. */ | ||||
| #define UMOUNT_THRESH	(DM_PERCENT_1 * 95) | ||||
| /* Run a check every 5%. */ | ||||
| #define CHECK_STEP	(DM_PERCENT_1 *  5) | ||||
| /* Do not bother checking thin data or metadata is less than 50% full. */ | ||||
| #define CHECK_MINIMUM	(DM_PERCENT_1 * 50) | ||||
|  | ||||
| #define UMOUNT_COMMAND "/bin/umount" | ||||
|  | ||||
| #define MAX_FAILS	(256)  /* ~42 mins between cmd call retry with 10s delay */ | ||||
|  | ||||
| #define THIN_DEBUG 0 | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	int metadata_percent_check; | ||||
| 	int metadata_percent; | ||||
| 	int data_percent_check; | ||||
| 	int data_percent; | ||||
| 	uint64_t known_metadata_size; | ||||
| 	uint64_t known_data_size; | ||||
| 	unsigned fails; | ||||
| 	unsigned max_fails; | ||||
| 	int restore_sigset; | ||||
| 	sigset_t old_sigset; | ||||
| 	pid_t pid; | ||||
| 	char *argv[3]; | ||||
| 	char *cmd_str; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("thin") | ||||
|  | ||||
| static int _run_command(struct dso_state *state) | ||||
| { | ||||
| 	char val[16]; | ||||
| 	int i; | ||||
|  | ||||
| 	/* Mark for possible lvm2 command we are running from dmeventd | ||||
| 	 * lvm2 will not try to talk back to dmeventd while processing it */ | ||||
| 	(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1); | ||||
|  | ||||
| 	if (state->data_percent) { | ||||
| 		/* Prepare some known data to env vars for easy use */ | ||||
| 		if (dm_snprintf(val, sizeof(val), "%d", | ||||
| 				state->data_percent / DM_PERCENT_1) != -1) | ||||
| 			(void) setenv("DMEVENTD_THIN_POOL_DATA", val, 1); | ||||
| 		if (dm_snprintf(val, sizeof(val), "%d", | ||||
| 				state->metadata_percent / DM_PERCENT_1) != -1) | ||||
| 			(void) setenv("DMEVENTD_THIN_POOL_METADATA", val, 1); | ||||
| 	} else { | ||||
| 		/* For an error event it's for a user to check status and decide */ | ||||
| 		log_debug("Error event processing."); | ||||
| 	} | ||||
|  | ||||
| 	log_verbose("Executing command: %s", state->cmd_str); | ||||
|  | ||||
| 	/* TODO: | ||||
| 	 *   Support parallel run of 'task' and it's waitpid maintainence | ||||
| 	 *   ATM we can't handle signaling of  SIGALRM | ||||
| 	 *   as signalling is not allowed while 'process_event()' is running | ||||
| 	 */ | ||||
| 	if (!(state->pid = fork())) { | ||||
| 		/* child */ | ||||
| 		(void) close(0); | ||||
| 		for (i = 3; i < 255; ++i) (void) close(i); | ||||
| 		execvp(state->argv[0], state->argv); | ||||
| 		_exit(errno); | ||||
| 	} else if (state->pid == -1) { | ||||
| 		log_error("Can't fork command %s.", state->cmd_str); | ||||
| 		state->fails = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _use_policy(struct dm_task *dmt, struct dso_state *state) | ||||
| { | ||||
| #if THIN_DEBUG | ||||
| 	log_debug("dmeventd executes: %s.", state->cmd_str); | ||||
| #endif | ||||
| 	if (state->argv[0]) | ||||
| 		return _run_command(state); | ||||
|  | ||||
| 	if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) { | ||||
| 		log_error("Failed command for %s.", dm_task_get_name(dmt)); | ||||
| 		state->fails = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	state->fails = 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Check if executed command has finished | ||||
|  * Only 1 command may run */ | ||||
| static int _wait_for_pid(struct dso_state *state) | ||||
| { | ||||
| 	int status = 0; | ||||
|  | ||||
| 	if (state->pid == -1) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!waitpid(state->pid, &status, WNOHANG)) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* Wait for finish */ | ||||
| 	if (WIFEXITED(status)) { | ||||
| 		log_verbose("Child %d exited with status %d.", | ||||
| 			    state->pid, WEXITSTATUS(status)); | ||||
| 		state->fails = WEXITSTATUS(status) ? 1 : 0; | ||||
| 	} else { | ||||
| 		if (WIFSIGNALED(status)) | ||||
| 			log_verbose("Child %d was terminated with status %d.", | ||||
| 				    state->pid, WTERMSIG(status)); | ||||
| 		state->fails = 1; | ||||
| 	} | ||||
|  | ||||
| 	state->pid = -1; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	struct dso_state *state = *user; | ||||
| 	struct dm_status_thin_pool *tps = NULL; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	int needs_policy = 0; | ||||
| 	struct dm_task *new_dmt = NULL; | ||||
|  | ||||
| #if THIN_DEBUG | ||||
| 	log_debug("Watch for tp-data:%.2f%%  tp-metadata:%.2f%%.", | ||||
| 		  dm_percent_to_round_float(state->data_percent_check, 2), | ||||
| 		  dm_percent_to_round_float(state->metadata_percent_check, 2)); | ||||
| #endif | ||||
| 	if (!_wait_for_pid(state)) { | ||||
| 		log_warn("WARNING: Skipping event, child %d is still running (%s).", | ||||
| 			 state->pid, state->cmd_str); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (event & DM_EVENT_DEVICE_ERROR) { | ||||
| 		/* Error -> no need to check and do instant resize */ | ||||
| 		state->data_percent = state->metadata_percent = 0; | ||||
| 		if (_use_policy(dmt, state)) | ||||
| 			goto out; | ||||
|  | ||||
| 		stack; | ||||
|  | ||||
| 		/* | ||||
| 		 * Rather update oldish status | ||||
| 		 * since after 'command' processing | ||||
| 		 * percentage info could have changed a lot. | ||||
| 		 * If we would get above UMOUNT_THRESH | ||||
| 		 * we would wait for next sigalarm. | ||||
| 		 */ | ||||
| 		if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS))) | ||||
| 			goto_out; | ||||
|  | ||||
| 		if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt))) | ||||
| 			goto_out; | ||||
|  | ||||
| 		/* Non-blocking status read */ | ||||
| 		if (!dm_task_no_flush(new_dmt)) | ||||
| 			log_warn("WARNING: Can't set no_flush for dm status."); | ||||
|  | ||||
| 		if (!dm_task_run(new_dmt)) | ||||
| 			goto_out; | ||||
|  | ||||
| 		dmt = new_dmt; | ||||
| 	} | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
|  | ||||
| 	if (!target_type || (strcmp(target_type, "thin-pool") != 0)) { | ||||
| 		log_error("Invalid target type."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_get_status_thin_pool(state->mem, params, &tps)) { | ||||
| 		log_error("Failed to parse status."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| #if THIN_DEBUG | ||||
| 	log_debug("Thin pool status " FMTu64 "/" FMTu64 "  " | ||||
| 		  FMTu64 "/" FMTu64 ".", | ||||
| 		  tps->used_metadata_blocks, tps->total_metadata_blocks, | ||||
| 		  tps->used_data_blocks, tps->total_data_blocks); | ||||
| #endif | ||||
|  | ||||
| 	/* Thin pool size had changed. Clear the threshold. */ | ||||
| 	if (state->known_metadata_size != tps->total_metadata_blocks) { | ||||
| 		state->metadata_percent_check = CHECK_MINIMUM; | ||||
| 		state->known_metadata_size = tps->total_metadata_blocks; | ||||
| 		state->fails = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (state->known_data_size != tps->total_data_blocks) { | ||||
| 		state->data_percent_check = CHECK_MINIMUM; | ||||
| 		state->known_data_size = tps->total_data_blocks; | ||||
| 		state->fails = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Trigger action when threshold boundary is exceeded. | ||||
| 	 * Report 80% threshold warning when it's used above 80%. | ||||
| 	 * Only 100% is exception as it cannot be surpased so policy | ||||
| 	 * action is called for:  >50%, >55% ... >95%, 100% | ||||
| 	 */ | ||||
| 	state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks); | ||||
| 	if ((state->metadata_percent > WARNING_THRESH) && | ||||
| 	    (state->metadata_percent > state->metadata_percent_check)) | ||||
| 		log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.", | ||||
| 			 device, dm_percent_to_round_float(state->metadata_percent, 2)); | ||||
| 	if (state->metadata_percent > CHECK_MINIMUM) { | ||||
| 		/* Run action when usage raised more than CHECK_STEP since the last time */ | ||||
| 		if (state->metadata_percent > state->metadata_percent_check) | ||||
| 			needs_policy = 1; | ||||
| 		state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP; | ||||
| 		if (state->metadata_percent_check == DM_PERCENT_100) | ||||
| 			state->metadata_percent_check--; /* Can't get bigger then 100% */ | ||||
| 	} else | ||||
| 		state->metadata_percent_check = CHECK_MINIMUM; | ||||
|  | ||||
| 	state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks); | ||||
| 	if ((state->data_percent > WARNING_THRESH) && | ||||
| 	    (state->data_percent > state->data_percent_check)) | ||||
| 		log_warn("WARNING: Thin pool %s data is now %.2f%% full.", | ||||
| 			 device, dm_percent_to_round_float(state->data_percent, 2)); | ||||
| 	if (state->data_percent > CHECK_MINIMUM) { | ||||
| 		/* Run action when usage raised more than CHECK_STEP since the last time */ | ||||
| 		if (state->data_percent > state->data_percent_check) | ||||
| 			needs_policy = 1; | ||||
| 		state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP; | ||||
| 		if (state->data_percent_check == DM_PERCENT_100) | ||||
| 			state->data_percent_check--; /* Can't get bigger then 100% */ | ||||
| 	} else | ||||
| 		state->data_percent_check = CHECK_MINIMUM; | ||||
|  | ||||
| 	/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached. | ||||
| 	 * Avoids too high number of error retries, yet shows some status messages in log regularly. | ||||
| 	 * i.e. PV could have been pvmoved and VG/LV was locked for a while... | ||||
| 	 */ | ||||
| 	if (state->fails) { | ||||
| 		if (state->fails++ <= state->max_fails) { | ||||
| 			log_debug("Postponing frequently failing policy (%u <= %u).", | ||||
| 				  state->fails - 1, state->max_fails); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		if (state->max_fails < MAX_FAILS) | ||||
| 			state->max_fails <<= 1; | ||||
| 		state->fails = needs_policy = 1; /* Retry failing command */ | ||||
| 	} else | ||||
| 		state->max_fails = 1; /* Reset on success */ | ||||
|  | ||||
| 	if (needs_policy) | ||||
| 		_use_policy(dmt, state); | ||||
| out: | ||||
| 	if (tps) | ||||
| 		dm_pool_free(state->mem, tps); | ||||
|  | ||||
| 	if (new_dmt) | ||||
| 		dm_task_destroy(new_dmt); | ||||
| } | ||||
|  | ||||
| /* Handle SIGCHLD for a thread */ | ||||
| static void _sig_child(int signum __attribute__((unused))) | ||||
| { | ||||
| 	/* empty SIG_IGN */; | ||||
| } | ||||
|  | ||||
| /* Setup handler for SIGCHLD when executing external command | ||||
|  * to get quick 'waitpid()' reaction | ||||
|  * It will interrupt syscall just like SIGALRM and | ||||
|  * invoke process_event(). | ||||
|  */ | ||||
| static void _init_thread_signals(struct dso_state *state) | ||||
| { | ||||
| 	struct sigaction act = { .sa_handler = _sig_child }; | ||||
| 	sigset_t my_sigset; | ||||
|  | ||||
| 	sigemptyset(&my_sigset); | ||||
|  | ||||
| 	if (sigaction(SIGCHLD, &act, NULL)) | ||||
| 		log_warn("WARNING: Failed to set SIGCHLD action."); | ||||
| 	else if (sigaddset(&my_sigset, SIGCHLD)) | ||||
| 		log_warn("WARNING: Failed to add SIGCHLD to set."); | ||||
| 	else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset)) | ||||
| 		log_warn("WARNING: Failed to unblock SIGCHLD."); | ||||
| 	else | ||||
| 		state->restore_sigset = 1; | ||||
| } | ||||
|  | ||||
| static void _restore_thread_signals(struct dso_state *state) | ||||
| { | ||||
| 	if (state->restore_sigset && | ||||
| 	    pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL)) | ||||
| 		log_warn("WARNING: Failed to block SIGCHLD."); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
| 	char *str; | ||||
| 	char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */ | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), | ||||
| 				   "_dmeventd_thin_command", device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (strncmp(cmd_str, "lvm ", 4) == 0) { | ||||
| 		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) { | ||||
| 			log_error("Failed to copy lvm command."); | ||||
| 			goto bad; | ||||
| 		} | ||||
| 	} else if (cmd_str[0] == '/') { | ||||
| 		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) { | ||||
| 			log_error("Failed to copy thin command."); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		/* Find last space before 'vg/lv' */ | ||||
| 		if (!(str = strrchr(state->cmd_str, ' '))) | ||||
| 			goto inval; | ||||
|  | ||||
| 		if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str, | ||||
| 						       str - state->cmd_str))) { | ||||
| 			log_error("Failed to copy command."); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		state->argv[1] = str + 1;  /* 1 argument - vg/lv */ | ||||
| 		_init_thread_signals(state); | ||||
| 	} else /* Unuspported command format */ | ||||
| 		goto inval; | ||||
|  | ||||
| 	state->pid = -1; | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring thin pool %s.", device); | ||||
|  | ||||
| 	return 1; | ||||
| inval: | ||||
| 	log_error("Invalid command for monitoring: %s.", cmd_str); | ||||
| bad: | ||||
| 	log_error("Failed to monitor thin pool %s.", device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) { | ||||
| 		if (i == 0) | ||||
| 			/* Give it 2 seconds, then try to terminate & kill it */ | ||||
| 			log_verbose("Child %d still not finished (%s) waiting.", | ||||
| 				    state->pid, state->cmd_str); | ||||
| 		else if (i == 3) { | ||||
| 			log_warn("WARNING: Terminating child %d.", state->pid); | ||||
| 			kill(state->pid, SIGINT); | ||||
| 			kill(state->pid, SIGTERM); | ||||
| 		} else if (i == 5) { | ||||
| 			log_warn("WARNING: Killing child %d.", state->pid); | ||||
| 			kill(state->pid, SIGKILL); | ||||
| 		} | ||||
| 		sleep(1); | ||||
| 	} | ||||
|  | ||||
| 	if (state->pid != -1) | ||||
| 		log_warn("WARNING: Cannot kill child %d!", state->pid); | ||||
|  | ||||
| 	_restore_thread_signals(state); | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring thin pool %s.", device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_vdo.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2vdo | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,412 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
|  | ||||
| /* | ||||
|  * Use parser from new device_mapper library. | ||||
|  * Although during compilation we can see dm_vdo_status_parse() | ||||
|  * in runtime we are linked agains systems libdm 'older' library | ||||
|  * which does not provide this symbol and plugin fails to load | ||||
|  */ | ||||
| #include "device_mapper/vdo/status.c" | ||||
|  | ||||
| #include <sys/wait.h> | ||||
| #include <stdarg.h> | ||||
|  | ||||
| /* First warning when VDO pool is 80% full. */ | ||||
| #define WARNING_THRESH	(DM_PERCENT_1 * 80) | ||||
| /* Run a check every 5%. */ | ||||
| #define CHECK_STEP	(DM_PERCENT_1 *  5) | ||||
| /* Do not bother checking VDO pool is less than 50% full. */ | ||||
| #define CHECK_MINIMUM	(DM_PERCENT_1 * 50) | ||||
|  | ||||
| #define MAX_FAILS	(256)  /* ~42 mins between cmd call retry with 10s delay */ | ||||
|  | ||||
| #define VDO_DEBUG 0 | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	int percent_check; | ||||
| 	int percent; | ||||
| 	uint64_t known_data_size; | ||||
| 	unsigned fails; | ||||
| 	unsigned max_fails; | ||||
| 	int restore_sigset; | ||||
| 	sigset_t old_sigset; | ||||
| 	pid_t pid; | ||||
| 	char *argv[3]; | ||||
| 	const char *cmd_str; | ||||
| 	const char *name; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("vdo") | ||||
|  | ||||
| static int _run_command(struct dso_state *state) | ||||
| { | ||||
| 	char val[16]; | ||||
| 	int i; | ||||
|  | ||||
| 	/* Mark for possible lvm2 command we are running from dmeventd | ||||
| 	 * lvm2 will not try to talk back to dmeventd while processing it */ | ||||
| 	(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1); | ||||
|  | ||||
| 	if (state->percent) { | ||||
| 		/* Prepare some known data to env vars for easy use */ | ||||
| 		if (dm_snprintf(val, sizeof(val), "%d", | ||||
| 				state->percent / DM_PERCENT_1) != -1) | ||||
| 			(void) setenv("DMEVENTD_VDO_POOL", val, 1); | ||||
| 	} else { | ||||
| 		/* For an error event it's for a user to check status and decide */ | ||||
| 		log_debug("Error event processing."); | ||||
| 	} | ||||
|  | ||||
| 	log_verbose("Executing command: %s", state->cmd_str); | ||||
|  | ||||
| 	/* TODO: | ||||
| 	 *   Support parallel run of 'task' and it's waitpid maintainence | ||||
| 	 *   ATM we can't handle signaling of  SIGALRM | ||||
| 	 *   as signalling is not allowed while 'process_event()' is running | ||||
| 	 */ | ||||
| 	if (!(state->pid = fork())) { | ||||
| 		/* child */ | ||||
| 		(void) close(0); | ||||
| 		for (i = 3; i < 255; ++i) (void) close(i); | ||||
| 		execvp(state->argv[0], state->argv); | ||||
| 		_exit(errno); | ||||
| 	} else if (state->pid == -1) { | ||||
| 		log_error("Can't fork command %s.", state->cmd_str); | ||||
| 		state->fails = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _use_policy(struct dm_task *dmt, struct dso_state *state) | ||||
| { | ||||
| #if VDO_DEBUG | ||||
| 	log_debug("dmeventd executes: %s.", state->cmd_str); | ||||
| #endif | ||||
| 	if (state->argv[0]) | ||||
| 		return _run_command(state); | ||||
|  | ||||
| 	if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) { | ||||
| 		log_error("Failed command for %s.", dm_task_get_name(dmt)); | ||||
| 		state->fails = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	state->fails = 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Check if executed command has finished | ||||
|  * Only 1 command may run */ | ||||
| static int _wait_for_pid(struct dso_state *state) | ||||
| { | ||||
| 	int status = 0; | ||||
|  | ||||
| 	if (state->pid == -1) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!waitpid(state->pid, &status, WNOHANG)) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* Wait for finish */ | ||||
| 	if (WIFEXITED(status)) { | ||||
| 		log_verbose("Child %d exited with status %d.", | ||||
| 			    state->pid, WEXITSTATUS(status)); | ||||
| 		state->fails = WEXITSTATUS(status) ? 1 : 0; | ||||
| 	} else { | ||||
| 		if (WIFSIGNALED(status)) | ||||
| 			log_verbose("Child %d was terminated with status %d.", | ||||
| 				    state->pid, WTERMSIG(status)); | ||||
| 		state->fails = 1; | ||||
| 	} | ||||
|  | ||||
| 	state->pid = -1; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	int needs_policy = 0; | ||||
| 	struct dm_task *new_dmt = NULL; | ||||
| 	struct dm_vdo_status_parse_result vdop = { .status = NULL }; | ||||
|  | ||||
| #if VDO_DEBUG | ||||
| 	log_debug("Watch for VDO %s:%.2f%%.", state->name, | ||||
| 		  dm_percent_to_round_float(state->percent_check, 2)); | ||||
| #endif | ||||
| 	if (!_wait_for_pid(state)) { | ||||
| 		log_warn("WARNING: Skipping event, child %d is still running (%s).", | ||||
| 			 state->pid, state->cmd_str); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (event & DM_EVENT_DEVICE_ERROR) { | ||||
| #if VDO_DEBUG | ||||
| 		log_debug("VDO event error."); | ||||
| #endif | ||||
| 		/* Error -> no need to check and do instant resize */ | ||||
| 		state->percent = 0; | ||||
| 		if (_use_policy(dmt, state)) | ||||
| 			goto out; | ||||
|  | ||||
| 		stack; | ||||
|  | ||||
| 		if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS))) | ||||
| 			goto_out; | ||||
|  | ||||
| 		if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt))) | ||||
| 			goto_out; | ||||
|  | ||||
| 		/* Non-blocking status read */ | ||||
| 		if (!dm_task_no_flush(new_dmt)) | ||||
| 			log_warn("WARNING: Can't set no_flush for dm status."); | ||||
|  | ||||
| 		if (!dm_task_run(new_dmt)) | ||||
| 			goto_out; | ||||
|  | ||||
| 		dmt = new_dmt; | ||||
| 	} | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
|  | ||||
| 	if (!target_type || (strcmp(target_type, "vdo") != 0)) { | ||||
| 		log_error("Invalid target type."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_vdo_status_parse(state->mem, params, &vdop)) { | ||||
| 		log_error("Failed to parse status."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	state->percent = dm_make_percent(vdop.status->used_blocks, | ||||
| 					 vdop.status->total_blocks); | ||||
|  | ||||
| #if VDO_DEBUG | ||||
| 	log_debug("VDO %s status  %.2f%% " FMTu64 "/" FMTu64 ".", | ||||
| 		  state->name, dm_percent_to_round_float(state->percent, 2), | ||||
| 		  vdop.status->used_blocks, vdop.status->total_blocks); | ||||
| #endif | ||||
|  | ||||
| 	/* VDO pool size had changed. Clear the threshold. */ | ||||
| 	if (state->known_data_size != vdop.status->total_blocks) { | ||||
| 		state->percent_check = CHECK_MINIMUM; | ||||
| 		state->known_data_size = vdop.status->total_blocks; | ||||
| 		state->fails = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Trigger action when threshold boundary is exceeded. | ||||
| 	 * Report 80% threshold warning when it's used above 80%. | ||||
| 	 * Only 100% is exception as it cannot be surpased so policy | ||||
| 	 * action is called for:  >50%, >55% ... >95%, 100% | ||||
| 	 */ | ||||
| 	if ((state->percent > WARNING_THRESH) && | ||||
| 	    (state->percent > state->percent_check)) | ||||
| 		log_warn("WARNING: VDO %s %s is now %.2f%% full.", | ||||
| 			 state->name, device, | ||||
| 			 dm_percent_to_round_float(state->percent, 2)); | ||||
| 	if (state->percent > CHECK_MINIMUM) { | ||||
| 		/* Run action when usage raised more than CHECK_STEP since the last time */ | ||||
| 		if (state->percent > state->percent_check) | ||||
| 			needs_policy = 1; | ||||
| 		state->percent_check = (state->percent / CHECK_STEP + 1) * CHECK_STEP; | ||||
| 		if (state->percent_check == DM_PERCENT_100) | ||||
| 			state->percent_check--; /* Can't get bigger then 100% */ | ||||
| 	} else | ||||
| 		state->percent_check = CHECK_MINIMUM; | ||||
|  | ||||
| 	/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached. | ||||
| 	 * Avoids too high number of error retries, yet shows some status messages in log regularly. | ||||
| 	 * i.e. PV could have been pvmoved and VG/LV was locked for a while... | ||||
| 	 */ | ||||
| 	if (state->fails) { | ||||
| 		if (state->fails++ <= state->max_fails) { | ||||
| 			log_debug("Postponing frequently failing policy (%u <= %u).", | ||||
| 				  state->fails - 1, state->max_fails); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		if (state->max_fails < MAX_FAILS) | ||||
| 			state->max_fails <<= 1; | ||||
| 		state->fails = needs_policy = 1; /* Retry failing command */ | ||||
| 	} else | ||||
| 		state->max_fails = 1; /* Reset on success */ | ||||
|  | ||||
| 	if (needs_policy) | ||||
| 		_use_policy(dmt, state); | ||||
| out: | ||||
| 	if (vdop.status) | ||||
| 		dm_pool_free(state->mem, vdop.status); | ||||
|  | ||||
| 	if (new_dmt) | ||||
| 		dm_task_destroy(new_dmt); | ||||
| } | ||||
|  | ||||
| /* Handle SIGCHLD for a thread */ | ||||
| static void _sig_child(int signum __attribute__((unused))) | ||||
| { | ||||
| 	/* empty SIG_IGN */; | ||||
| } | ||||
|  | ||||
| /* Setup handler for SIGCHLD when executing external command | ||||
|  * to get quick 'waitpid()' reaction | ||||
|  * It will interrupt syscall just like SIGALRM and | ||||
|  * invoke process_event(). | ||||
|  */ | ||||
| static void _init_thread_signals(struct dso_state *state) | ||||
| { | ||||
| 	struct sigaction act = { .sa_handler = _sig_child }; | ||||
| 	sigset_t my_sigset; | ||||
|  | ||||
| 	sigemptyset(&my_sigset); | ||||
|  | ||||
| 	if (sigaction(SIGCHLD, &act, NULL)) | ||||
| 		log_warn("WARNING: Failed to set SIGCHLD action."); | ||||
| 	else if (sigaddset(&my_sigset, SIGCHLD)) | ||||
| 		log_warn("WARNING: Failed to add SIGCHLD to set."); | ||||
| 	else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset)) | ||||
| 		log_warn("WARNING: Failed to unblock SIGCHLD."); | ||||
| 	else | ||||
| 		state->restore_sigset = 1; | ||||
| } | ||||
|  | ||||
| static void _restore_thread_signals(struct dso_state *state) | ||||
| { | ||||
| 	if (state->restore_sigset && | ||||
| 	    pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL)) | ||||
| 		log_warn("WARNING: Failed to block SIGCHLD."); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid, | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
| 	const char *cmd; | ||||
| 	char *str; | ||||
| 	char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */ | ||||
|         const char *name = "pool"; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("vdo_pool_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	state->cmd_str = ""; | ||||
|  | ||||
| 	/* Search for command for LVM- prefixed devices only */ | ||||
| 	cmd = (strncmp(uuid, "LVM-", 4) == 0) ? "_dmeventd_vdo_command" : ""; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), cmd, device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (strncmp(cmd_str, "lvm ", 4) == 0) { | ||||
| 		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) { | ||||
| 			log_error("Failed to copy lvm VDO command."); | ||||
| 				goto bad; | ||||
| 		} | ||||
| 	} else if (cmd_str[0] == '/') { | ||||
| 		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) { | ||||
| 			log_error("Failed to copy VDO command."); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		/* Find last space before 'vg/lv' */ | ||||
| 		if (!(str = strrchr(state->cmd_str, ' '))) | ||||
| 			goto inval; | ||||
|  | ||||
| 		if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str, | ||||
| 						       str - state->cmd_str))) { | ||||
| 			log_error("Failed to copy command."); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		state->argv[1] = str + 1;  /* 1 argument - vg/lv */ | ||||
| 		_init_thread_signals(state); | ||||
| 	} else if (cmd[0] == 0) { | ||||
| 		state->name = "volume"; /* What to use with 'others?' */ | ||||
| 	} else/* Unuspported command format */ | ||||
| 		goto inval; | ||||
|  | ||||
| 	state->pid = -1; | ||||
| 	state->name = name; | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring VDO %s %s.", name, device); | ||||
|  | ||||
| 	return 1; | ||||
| inval: | ||||
| 	log_error("Invalid command for monitoring: %s.", cmd_str); | ||||
| bad: | ||||
| 	log_error("Failed to monitor VDO %s %s.", name, device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	const char *name = state->name; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) { | ||||
| 		if (i == 0) | ||||
| 			/* Give it 2 seconds, then try to terminate & kill it */ | ||||
| 			log_verbose("Child %d still not finished (%s) waiting.", | ||||
| 				    state->pid, state->cmd_str); | ||||
| 		else if (i == 3) { | ||||
| 			log_warn("WARNING: Terminating child %d.", state->pid); | ||||
| 			kill(state->pid, SIGINT); | ||||
| 			kill(state->pid, SIGTERM); | ||||
| 		} else if (i == 5) { | ||||
| 			log_warn("WARNING: Killing child %d.", state->pid); | ||||
| 			kill(state->pid, SIGKILL); | ||||
| 		} | ||||
| 		sleep(1); | ||||
| 	} | ||||
|  | ||||
| 	if (state->pid != -1) | ||||
| 		log_warn("WARNING: Cannot kill child %d!", state->pid); | ||||
|  | ||||
| 	_restore_thread_signals(state); | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring VDO %s %s.", name, device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										4
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +0,0 @@ | ||||
| path.py | ||||
| lvmdbusd | ||||
| lvmdb.py | ||||
| lvm_shell_proxy.py | ||||
| @@ -1,74 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| lvmdbuspydir = $(python3dir)/lvmdbusd | ||||
| lvmdbusdir = $(DESTDIR)$(lvmdbuspydir) | ||||
|  | ||||
| LVMDBUS_SRCDIR_FILES = \ | ||||
| 	automatedproperties.py \ | ||||
| 	background.py \ | ||||
| 	cfg.py \ | ||||
| 	cmdhandler.py \ | ||||
| 	fetch.py \ | ||||
| 	job.py \ | ||||
| 	loader.py \ | ||||
| 	lv.py \ | ||||
| 	main.py \ | ||||
| 	manager.py \ | ||||
| 	objectmanager.py \ | ||||
| 	pv.py \ | ||||
| 	request.py \ | ||||
| 	state.py \ | ||||
| 	udevwatch.py \ | ||||
| 	utils.py \ | ||||
| 	vg.py \ | ||||
| 	__init__.py | ||||
|  | ||||
| LVMDBUS_BUILDDIR_FILES = \ | ||||
| 	lvmdb.py \ | ||||
| 	lvm_shell_proxy.py \ | ||||
| 	path.py | ||||
|  | ||||
| LVMDBUSD = lvmdbusd | ||||
|  | ||||
| CLEAN_DIRS += __pycache__ | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| .PHONY: install_lvmdbusd | ||||
|  | ||||
| all: | ||||
| 	$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD) | ||||
|  | ||||
| install_lvmdbusd: $(LVMDBUSD) | ||||
| 	@echo "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DIR) $(sbindir) | ||||
| 	$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir) | ||||
| 	$(Q) $(INSTALL_DIR) $(lvmdbusdir) | ||||
| 	$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir)) | ||||
| 	$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir) | ||||
| 	$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES) | ||||
| 	$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__ | ||||
| 	$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co] | ||||
|  | ||||
| install_lvm2: install_lvmdbusd | ||||
|  | ||||
| install: install_lvm2 | ||||
|  | ||||
| DISTCLEAN_TARGETS+= \ | ||||
| 	$(LVMDBUS_BUILDDIR_FILES) \ | ||||
| 	$(LVMDBUSD) | ||||
| @@ -1,10 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| from .main import main | ||||
| @@ -1,194 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| import dbus | ||||
| import dbus.service | ||||
| from . import cfg | ||||
| from .utils import get_properties, add_properties, get_object_property_diff, \ | ||||
| 	log_debug | ||||
| from .state import State | ||||
|  | ||||
|  | ||||
| # noinspection PyPep8Naming,PyUnresolvedReferences | ||||
| class AutomatedProperties(dbus.service.Object): | ||||
| 	""" | ||||
| 	This class implements the needed interfaces for: | ||||
| 	org.freedesktop.DBus.Properties | ||||
|  | ||||
| 	Other classes inherit from it to get the same behavior | ||||
| 	""" | ||||
|  | ||||
| 	def __init__(self, object_path, search_method=None): | ||||
| 		dbus.service.Object.__init__(self, cfg.bus, object_path) | ||||
| 		self._ap_interface = [] | ||||
| 		self._ap_o_path = object_path | ||||
| 		self._ap_search_method = search_method | ||||
| 		self.state = None | ||||
|  | ||||
| 	def dbus_object_path(self): | ||||
| 		return self._ap_o_path | ||||
|  | ||||
| 	def emit_data(self): | ||||
| 		props = {} | ||||
|  | ||||
| 		for i in self.interface(): | ||||
| 			props[i] = AutomatedProperties._get_all_prop(self, i) | ||||
|  | ||||
| 		return self._ap_o_path, props | ||||
|  | ||||
| 	def set_interface(self, interface): | ||||
| 		""" | ||||
| 		With inheritance we can't easily tell what interfaces a class provides | ||||
| 		so we will have each class that implements an interface tell the | ||||
| 		base AutomatedProperties what it is they do provide.  This is kind of | ||||
| 		clunky and perhaps we can figure out a better way to do this later. | ||||
| 		:param interface:       An interface the object supports | ||||
| 		:return: | ||||
| 		""" | ||||
| 		if interface not in self._ap_interface: | ||||
| 			self._ap_interface.append(interface) | ||||
|  | ||||
| 	# noinspection PyUnusedLocal | ||||
| 	def interface(self, all_interfaces=False): | ||||
| 		if all_interfaces: | ||||
| 			cpy = list(self._ap_interface) | ||||
| 			cpy.extend( | ||||
| 				["org.freedesktop.DBus.Introspectable", | ||||
| 					"org.freedesktop.DBus.Properties"]) | ||||
| 			return cpy | ||||
|  | ||||
| 		return self._ap_interface | ||||
|  | ||||
| 	@staticmethod | ||||
| 	def _get_prop(obj, interface_name, property_name): | ||||
| 		value = getattr(obj, property_name) | ||||
| 		# Note: If we get an exception in this handler we won't know about it, | ||||
| 		# only the side effect of no returned value! | ||||
| 		log_debug('Get (%s), type (%s), value(%s)' % | ||||
| 					(property_name, str(type(value)), str(value))) | ||||
| 		return value | ||||
|  | ||||
| 	# Properties | ||||
| 	# noinspection PyUnusedLocal | ||||
| 	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, | ||||
| 							in_signature='ss', out_signature='v', | ||||
| 							async_callbacks=('cb', 'cbe')) | ||||
| 	def Get(self, interface_name, property_name, cb, cbe): | ||||
| 		# Note: If we get an exception in this handler we won't know about it, | ||||
| 		# only the side effect of no returned value! | ||||
| 		r = cfg.create_request_entry( | ||||
| 			-1, AutomatedProperties._get_prop, | ||||
| 			(self, interface_name, property_name), | ||||
| 			cb, cbe, False) | ||||
| 		cfg.worker_q.put(r) | ||||
|  | ||||
|  | ||||
| 	@staticmethod | ||||
| 	def _get_all_prop(obj, interface_name): | ||||
| 		if interface_name in obj.interface(True): | ||||
| 			# Using introspection, lets build this dynamically | ||||
| 			properties = get_properties(obj) | ||||
| 			if interface_name in properties: | ||||
| 				return properties[interface_name][1] | ||||
| 			return {} | ||||
| 		raise dbus.exceptions.DBusException( | ||||
| 			obj._ap_interface, | ||||
| 			'The object %s does not implement the %s interface' | ||||
| 			% (obj.__class__, interface_name)) | ||||
|  | ||||
| 	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, | ||||
| 							in_signature='s', out_signature='a{sv}', | ||||
| 							async_callbacks=('cb', 'cbe')) | ||||
| 	def GetAll(self, interface_name, cb, cbe): | ||||
| 		r = cfg.create_request_entry( | ||||
| 			-1, AutomatedProperties._get_all_prop, | ||||
| 			(self, interface_name), | ||||
| 			cb, cbe, False) | ||||
| 		cfg.worker_q.put(r) | ||||
|  | ||||
| 	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, | ||||
| 							in_signature='ssv') | ||||
| 	def Set(self, interface_name, property_name, new_value): | ||||
| 		setattr(self, property_name, new_value) | ||||
| 		self.PropertiesChanged(interface_name, | ||||
| 								{property_name: new_value}, []) | ||||
|  | ||||
| 	# As dbus-python does not support introspection for properties we will | ||||
| 	# get the autogenerated xml and then add our wanted properties to it. | ||||
| 	@dbus.service.method(dbus_interface=dbus.INTROSPECTABLE_IFACE, | ||||
| 							out_signature='s') | ||||
| 	def Introspect(self): | ||||
| 		r = dbus.service.Object.Introspect(self, self._ap_o_path, cfg.bus) | ||||
| 		# Look at the properties in the class | ||||
| 		props = get_properties(self) | ||||
|  | ||||
| 		for int_f, v in props.items(): | ||||
| 			r = add_properties(r, int_f, v[0]) | ||||
|  | ||||
| 		return r | ||||
|  | ||||
| 	@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE, | ||||
| 							signature='sa{sv}as') | ||||
| 	def PropertiesChanged(self, interface_name, changed_properties, | ||||
| 							invalidated_properties): | ||||
| 		log_debug(('SIGNAL: PropertiesChanged(%s, %s, %s, %s)' % | ||||
| 					(str(self._ap_o_path), str(interface_name), | ||||
| 					str(changed_properties), str(invalidated_properties)))) | ||||
|  | ||||
| 	def refresh(self, search_key=None, object_state=None): | ||||
| 		""" | ||||
| 		Take the values (properties) of an object and update them with what | ||||
| 		lvm currently has.  You can either fetch the new ones or supply the | ||||
| 		new state to be updated with | ||||
| 		:param search_key: The value to use to search for | ||||
| 		:param object_state: Use this as the new object state | ||||
| 		""" | ||||
| 		num_changed = 0 | ||||
|  | ||||
| 		# If we can't do a lookup, bail now, this happens if we blindly walk | ||||
| 		# through all dbus objects as some don't have a search method, like | ||||
| 		# 'Manager' object. | ||||
| 		if not self._ap_search_method: | ||||
| 			return 0 | ||||
|  | ||||
| 		search = self.lvm_id | ||||
| 		if search_key: | ||||
| 			search = search_key | ||||
|  | ||||
| 		# Either we have the new object state or we need to go fetch it | ||||
| 		if object_state: | ||||
| 			new_state = object_state | ||||
| 		else: | ||||
| 			new_state = self._ap_search_method([search])[0] | ||||
| 			assert isinstance(new_state, State) | ||||
|  | ||||
| 		assert new_state | ||||
|  | ||||
| 		# When we refresh an object the object identifiers might have changed | ||||
| 		# because LVM allows the user to change them (name & uuid), thus if | ||||
| 		# they have changed we need to update the object manager so that | ||||
| 		# look-ups will happen correctly | ||||
| 		old_id = self.state.identifiers() | ||||
| 		new_id = new_state.identifiers() | ||||
| 		if old_id[0] != new_id[0] or old_id[1] != new_id[1]: | ||||
| 			cfg.om.lookup_update(self, new_id[0], new_id[1]) | ||||
|  | ||||
| 		# Grab the properties values, then replace the state of the object | ||||
| 		# and retrieve the new values. | ||||
| 		o_prop = get_properties(self) | ||||
| 		self.state = new_state | ||||
| 		n_prop = get_properties(self) | ||||
|  | ||||
| 		changed = get_object_property_diff(o_prop, n_prop) | ||||
|  | ||||
| 		if changed: | ||||
| 			for int_f, v in changed.items(): | ||||
| 				self.PropertiesChanged(int_f, v, []) | ||||
| 			num_changed += 1 | ||||
| 		return num_changed | ||||
| @@ -1,163 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| import subprocess | ||||
| from . import cfg | ||||
| from .cmdhandler import options_to_cli_args, LvmExecutionMeta | ||||
| import dbus | ||||
| from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\ | ||||
| 	add_no_notify | ||||
| import os | ||||
| import threading | ||||
| import time | ||||
|  | ||||
|  | ||||
| def pv_move_lv_cmd(move_options, lv_full_name, | ||||
| 					pv_source, pv_source_range, pv_dest_range_list): | ||||
| 	cmd = ['pvmove', '-i', '1'] | ||||
| 	cmd.extend(options_to_cli_args(move_options)) | ||||
|  | ||||
| 	if lv_full_name: | ||||
| 		cmd.extend(['-n', lv_full_name]) | ||||
|  | ||||
| 	pv_range_append(cmd, pv_source, *pv_source_range) | ||||
| 	pv_dest_ranges(cmd, pv_dest_range_list) | ||||
|  | ||||
| 	return cmd | ||||
|  | ||||
|  | ||||
| def lv_merge_cmd(merge_options, lv_full_name): | ||||
| 	cmd = ['lvconvert', '--merge', '-i', '1'] | ||||
| 	cmd.extend(options_to_cli_args(merge_options)) | ||||
| 	cmd.append(lv_full_name) | ||||
| 	return cmd | ||||
|  | ||||
|  | ||||
| def _move_merge(interface_name, command, job_state): | ||||
| 	# We need to execute these command stand alone by forking & exec'ing | ||||
| 	# the command always as we will be getting periodic output from them on | ||||
| 	# the status of the long running operation. | ||||
| 	command.insert(0, cfg.LVM_CMD) | ||||
|  | ||||
| 	# Instruct lvm to not register an event with us | ||||
| 	command = add_no_notify(command) | ||||
|  | ||||
| 	#(self, start, ended, cmd, ec, stdout_txt, stderr_txt) | ||||
| 	meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None) | ||||
|  | ||||
| 	cfg.blackbox.add(meta) | ||||
|  | ||||
| 	process = subprocess.Popen(command, stdout=subprocess.PIPE, | ||||
| 								env=os.environ, | ||||
| 								stderr=subprocess.PIPE, close_fds=True) | ||||
|  | ||||
| 	log_debug("Background process for %s is %d" % | ||||
| 				(str(command), process.pid)) | ||||
|  | ||||
| 	lines_iterator = iter(process.stdout.readline, b"") | ||||
| 	for line in lines_iterator: | ||||
| 		line_str = line.decode("utf-8") | ||||
|  | ||||
| 		# Check to see if the line has the correct number of separators | ||||
| 		try: | ||||
| 			if line_str.count(':') == 2: | ||||
| 				(device, ignore, percentage) = line_str.split(':') | ||||
| 				job_state.Percent = round( | ||||
| 					float(percentage.strip()[:-1]), 1) | ||||
|  | ||||
| 				# While the move is in progress we need to periodically update | ||||
| 				# the state to reflect where everything is at. | ||||
| 				cfg.load() | ||||
| 		except ValueError: | ||||
| 			log_error("Trying to parse percentage which failed for %s" % | ||||
| 				line_str) | ||||
|  | ||||
| 	out = process.communicate() | ||||
|  | ||||
| 	with meta.lock: | ||||
| 		meta.ended = time.time() | ||||
| 		meta.ec = process.returncode | ||||
| 		meta.stderr_txt = out[1] | ||||
|  | ||||
| 	if process.returncode == 0: | ||||
| 		job_state.Percent = 100 | ||||
| 	else: | ||||
| 		raise dbus.exceptions.DBusException( | ||||
| 			interface_name, | ||||
| 			'Exit code %s, stderr = %s' % (str(process.returncode), out[1])) | ||||
|  | ||||
| 	cfg.load() | ||||
| 	return '/' | ||||
|  | ||||
|  | ||||
| def move(interface_name, lv_name, pv_src_obj, pv_source_range, | ||||
| 			pv_dests_and_ranges, move_options, job_state): | ||||
| 	""" | ||||
| 	Common code for the pvmove handling. | ||||
| 	:param interface_name:  What dbus interface we are providing for | ||||
| 	:param lv_name:     Optional (None or name of LV to move) | ||||
| 	:param pv_src_obj:  dbus object patch for source PV | ||||
| 	:param pv_source_range: (0,0 to ignore, else start, end segments) | ||||
| 	:param pv_dests_and_ranges: Array of PV object paths and start/end segs | ||||
| 	:param move_options: Hash with optional arguments | ||||
| 	:param job_state: Used to convey information about jobs between processes | ||||
| 	:return: '/' When complete, the empty object path | ||||
| 	""" | ||||
| 	pv_dests = [] | ||||
| 	pv_src = cfg.om.get_object_by_path(pv_src_obj) | ||||
| 	if pv_src: | ||||
|  | ||||
| 		# Check to see if we are handling a move to a specific | ||||
| 		# destination(s) | ||||
| 		if len(pv_dests_and_ranges): | ||||
| 			for pr in pv_dests_and_ranges: | ||||
| 				pv_dbus_obj = cfg.om.get_object_by_path(pr[0]) | ||||
| 				if not pv_dbus_obj: | ||||
| 					raise dbus.exceptions.DBusException( | ||||
| 						interface_name, | ||||
| 						'PV Destination (%s) not found' % pr[0]) | ||||
|  | ||||
| 				pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2])) | ||||
|  | ||||
| 		cmd = pv_move_lv_cmd(move_options, | ||||
| 								lv_name, | ||||
| 								pv_src.lvm_id, | ||||
| 								pv_source_range, | ||||
| 								pv_dests) | ||||
|  | ||||
| 		return _move_merge(interface_name, cmd, job_state) | ||||
| 	else: | ||||
| 		raise dbus.exceptions.DBusException( | ||||
| 			interface_name, 'pv_src_obj (%s) not found' % pv_src_obj) | ||||
|  | ||||
|  | ||||
| def merge(interface_name, lv_uuid, lv_name, merge_options, job_state): | ||||
| 	# Make sure we have a dbus object representing it | ||||
| 	dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name) | ||||
| 	if dbo: | ||||
| 		cmd = lv_merge_cmd(merge_options, dbo.lvm_id) | ||||
| 		return _move_merge(interface_name, cmd, job_state) | ||||
| 	else: | ||||
| 		raise dbus.exceptions.DBusException( | ||||
| 			interface_name, | ||||
| 			'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name)) | ||||
|  | ||||
|  | ||||
| def _run_cmd(req): | ||||
| 	log_debug( | ||||
| 		"_run_cmd: Running method: %s with args %s" % | ||||
| 		(str(req.method), str(req.arguments))) | ||||
| 	req.run_cmd() | ||||
| 	log_debug("_run_cmd: complete!") | ||||
|  | ||||
|  | ||||
| def cmd_runner(request): | ||||
| 	t = threading.Thread(target=_run_cmd, args=(request,), | ||||
| 							name="cmd_runner %s" % str(request.method)) | ||||
| 	t.start() | ||||
| @@ -1,106 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| import os | ||||
| import multiprocessing | ||||
| import queue | ||||
| import itertools | ||||
|  | ||||
| from lvmdbusd import path | ||||
|  | ||||
| LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY) | ||||
|  | ||||
| # This is the global object manager | ||||
| om = None | ||||
|  | ||||
| # This is the global bus connection | ||||
| bus = None | ||||
|  | ||||
| # Command line args | ||||
| args = None | ||||
|  | ||||
| # Set to true if we are depending on external events for updates | ||||
| got_external_event = False | ||||
|  | ||||
| # Shared state variable across all processes | ||||
| run = multiprocessing.Value('i', 1) | ||||
|  | ||||
| # If this is set to true, the current setup support lvm shell and we are | ||||
| # running in that mode of operation | ||||
| SHELL_IN_USE = None | ||||
|  | ||||
| # Lock used by pprint | ||||
| stdout_lock = multiprocessing.Lock() | ||||
|  | ||||
| worker_q = queue.Queue() | ||||
|  | ||||
| # Main event loop | ||||
| loop = None | ||||
|  | ||||
| BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1') | ||||
| BASE_INTERFACE = 'com.redhat.lvmdbus1' | ||||
| PV_INTERFACE = BASE_INTERFACE + '.Pv' | ||||
| VG_INTERFACE = BASE_INTERFACE + '.Vg' | ||||
| VG_VDO_INTERFACE = BASE_INTERFACE + '.VgVdo' | ||||
| LV_INTERFACE = BASE_INTERFACE + '.Lv' | ||||
| LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon' | ||||
| THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool' | ||||
| VDO_POOL_INTERFACE = BASE_INTERFACE + '.VdoPool' | ||||
| CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool' | ||||
| LV_CACHED = BASE_INTERFACE + '.CachedLv' | ||||
| SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot' | ||||
| MANAGER_INTERFACE = BASE_INTERFACE + '.Manager' | ||||
| JOB_INTERFACE = BASE_INTERFACE + '.Job' | ||||
|  | ||||
| BASE_OBJ_PATH = '/' + BASE_INTERFACE.replace('.', '/') | ||||
| PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv' | ||||
| VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg' | ||||
| LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv' | ||||
| THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool" | ||||
| VDO_POOL_PATH = BASE_OBJ_PATH + "/VdoPool" | ||||
| CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool" | ||||
| HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv" | ||||
| MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager' | ||||
| JOB_OBJ_PATH = BASE_OBJ_PATH + '/Job' | ||||
|  | ||||
| # Counters for object path generation | ||||
| pv_id = itertools.count() | ||||
| vg_id = itertools.count() | ||||
| lv_id = itertools.count() | ||||
| thin_id = itertools.count() | ||||
| vdo_id = itertools.count() | ||||
| cache_pool_id = itertools.count() | ||||
| job_id = itertools.count() | ||||
| hidden_lv = itertools.count() | ||||
|  | ||||
| # Used to prevent circular imports... | ||||
| load = None | ||||
| event = None | ||||
|  | ||||
| # Boolean to denote if lvm supports VDO integration | ||||
| vdo_support = False | ||||
|  | ||||
| # Global cached state | ||||
| db = None | ||||
|  | ||||
| # lvm flight recorder | ||||
| blackbox = None | ||||
|  | ||||
| # RequestEntry ctor | ||||
| create_request_entry = None | ||||
|  | ||||
|  | ||||
| def exit_daemon(): | ||||
|     """ | ||||
|     Exit the daemon cleanly | ||||
|     :return: | ||||
|     """ | ||||
|     if run and loop: | ||||
|         run.value = 0 | ||||
|         loop.quit() | ||||
| @@ -1,834 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| from subprocess import Popen, PIPE | ||||
| import time | ||||
| import threading | ||||
| from itertools import chain | ||||
| import collections | ||||
| import traceback | ||||
| import os | ||||
|  | ||||
| from lvmdbusd import cfg | ||||
| from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify | ||||
| from lvmdbusd.lvm_shell_proxy import LVMShellProxy | ||||
|  | ||||
| try: | ||||
| 	import simplejson as json | ||||
| except ImportError: | ||||
| 	import json | ||||
|  | ||||
| SEP = '{|}' | ||||
|  | ||||
| total_time = 0.0 | ||||
| total_count = 0 | ||||
|  | ||||
| # We need to prevent different threads from using the same lvm shell | ||||
| # at the same time. | ||||
| cmd_lock = threading.RLock() | ||||
|  | ||||
|  | ||||
| class LvmExecutionMeta(object): | ||||
|  | ||||
| 	def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt): | ||||
| 		self.lock = threading.RLock() | ||||
| 		self.start = start | ||||
| 		self.ended = ended | ||||
| 		self.cmd = cmd | ||||
| 		self.ec = ec | ||||
| 		self.stdout_txt = stdout_txt | ||||
| 		self.stderr_txt = stderr_txt | ||||
|  | ||||
| 	def __str__(self): | ||||
| 		with self.lock: | ||||
| 			return "EC= %d for %s\n" \ | ||||
| 				"STARTED: %f, ENDED: %f\n" \ | ||||
| 				"STDOUT=%s\n" \ | ||||
| 				"STDERR=%s\n" % \ | ||||
| 				(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt, | ||||
| 				self.stderr_txt) | ||||
|  | ||||
|  | ||||
| class LvmFlightRecorder(object): | ||||
|  | ||||
| 	def __init__(self, size=16): | ||||
| 		self.queue = collections.deque(maxlen=size) | ||||
|  | ||||
| 	def add(self, lvm_exec_meta): | ||||
| 		self.queue.append(lvm_exec_meta) | ||||
|  | ||||
| 	def dump(self): | ||||
| 		with cmd_lock: | ||||
| 			if len(self.queue): | ||||
| 				log_error("LVM dbus flight recorder START") | ||||
| 				for c in reversed(self.queue): | ||||
| 					log_error(str(c)) | ||||
| 				log_error("LVM dbus flight recorder END") | ||||
|  | ||||
|  | ||||
| cfg.blackbox = LvmFlightRecorder() | ||||
|  | ||||
|  | ||||
| def _debug_c(cmd, exit_code, out): | ||||
| 	log_error('CMD= %s' % ' '.join(cmd)) | ||||
| 	log_error(("EC= %d" % exit_code)) | ||||
| 	log_error(("STDOUT=\n %s\n" % out[0])) | ||||
| 	log_error(("STDERR=\n %s\n" % out[1])) | ||||
|  | ||||
|  | ||||
| def call_lvm(command, debug=False): | ||||
| 	""" | ||||
| 	Call an executable and return a tuple of exitcode, stdout, stderr | ||||
| 	:param command:     Command to execute | ||||
| 	:param debug:       Dump debug to stdout | ||||
| 	""" | ||||
| 	# print 'STACK:' | ||||
| 	# for line in traceback.format_stack(): | ||||
| 	#    print line.strip() | ||||
|  | ||||
| 	# Prepend the full lvm executable so that we can run different versions | ||||
| 	# in different locations on the same box | ||||
| 	command.insert(0, cfg.LVM_CMD) | ||||
| 	command = add_no_notify(command) | ||||
|  | ||||
| 	process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True, | ||||
| 					env=os.environ) | ||||
| 	out = process.communicate() | ||||
|  | ||||
| 	stdout_text = bytes(out[0]).decode("utf-8") | ||||
| 	stderr_text = bytes(out[1]).decode("utf-8") | ||||
|  | ||||
| 	if debug or process.returncode != 0: | ||||
| 		_debug_c(command, process.returncode, (stdout_text, stderr_text)) | ||||
|  | ||||
| 	return process.returncode, stdout_text, stderr_text | ||||
|  | ||||
| # The actual method which gets called to invoke the lvm command, can vary | ||||
| # from forking a new process to using lvm shell | ||||
| _t_call = call_lvm | ||||
|  | ||||
|  | ||||
| def _shell_cfg(): | ||||
| 	global _t_call | ||||
| 	# noinspection PyBroadException | ||||
| 	try: | ||||
| 		lvm_shell = LVMShellProxy() | ||||
| 		_t_call = lvm_shell.call_lvm | ||||
| 		cfg.SHELL_IN_USE = lvm_shell | ||||
| 		return True | ||||
| 	except Exception: | ||||
| 		_t_call = call_lvm | ||||
| 		cfg.SHELL_IN_USE = None | ||||
| 		log_error(traceback.format_exc()) | ||||
| 		log_error("Unable to utilize lvm shell, dropping back to fork & exec") | ||||
| 		return False | ||||
|  | ||||
|  | ||||
| def set_execution(shell): | ||||
| 	global _t_call | ||||
| 	with cmd_lock: | ||||
| 		# If the user requested lvm shell and we are currently setup that | ||||
| 		# way, just return | ||||
| 		if cfg.SHELL_IN_USE and shell: | ||||
| 			return True | ||||
| 		else: | ||||
| 			if not shell and cfg.SHELL_IN_USE: | ||||
| 				cfg.SHELL_IN_USE.exit_shell() | ||||
| 				cfg.SHELL_IN_USE = None | ||||
|  | ||||
| 		_t_call = call_lvm | ||||
| 		if shell: | ||||
| 			if cfg.args.use_json: | ||||
| 				return _shell_cfg() | ||||
| 			else: | ||||
| 				return False | ||||
| 		return True | ||||
|  | ||||
|  | ||||
| def time_wrapper(command, debug=False): | ||||
| 	global total_time | ||||
| 	global total_count | ||||
|  | ||||
| 	with cmd_lock: | ||||
| 		start = time.time() | ||||
| 		results = _t_call(command, debug) | ||||
| 		ended = time.time() | ||||
| 		total_time += (ended - start) | ||||
| 		total_count += 1 | ||||
| 		cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results)) | ||||
| 	return results | ||||
|  | ||||
|  | ||||
| call = time_wrapper | ||||
|  | ||||
|  | ||||
| # Default cmd | ||||
| # Place default arguments for every command here. | ||||
| def _dc(cmd, args): | ||||
| 	c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix', | ||||
| 		'--unbuffered', '--units', 'b'] | ||||
| 	c.extend(args) | ||||
| 	return c | ||||
|  | ||||
|  | ||||
| def parse(out): | ||||
| 	rc = [] | ||||
|  | ||||
| 	for line in out.split('\n'): | ||||
| 		# This line includes separators, so process them | ||||
| 		if SEP in line: | ||||
| 			elem = line.split(SEP) | ||||
| 			cleaned_elem = [] | ||||
| 			for e in elem: | ||||
| 				e = e.strip() | ||||
| 				cleaned_elem.append(e) | ||||
|  | ||||
| 			if len(cleaned_elem) > 1: | ||||
| 				rc.append(cleaned_elem) | ||||
| 		else: | ||||
| 			t = line.strip() | ||||
| 			if len(t) > 0: | ||||
| 				rc.append(t) | ||||
| 	return rc | ||||
|  | ||||
|  | ||||
| def parse_column_names(out, column_names): | ||||
| 	lines = parse(out) | ||||
| 	rc = [] | ||||
|  | ||||
| 	for i in range(0, len(lines)): | ||||
| 		d = dict(list(zip(column_names, lines[i]))) | ||||
| 		rc.append(d) | ||||
|  | ||||
| 	return rc | ||||
|  | ||||
|  | ||||
| def options_to_cli_args(options): | ||||
| 	rc = [] | ||||
| 	for k, v in list(dict(options).items()): | ||||
| 		if k.startswith("-"): | ||||
| 			rc.append(k) | ||||
| 		else: | ||||
| 			rc.append("--%s" % k) | ||||
| 		if v != "": | ||||
| 			if isinstance(v, int): | ||||
| 				rc.append(str(int(v))) | ||||
| 			else: | ||||
| 				rc.append(str(v)) | ||||
| 	return rc | ||||
|  | ||||
|  | ||||
| def pv_remove(device, remove_options): | ||||
| 	cmd = ['pvremove'] | ||||
| 	cmd.extend(options_to_cli_args(remove_options)) | ||||
| 	cmd.append(device) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def _qt(tag_name): | ||||
| 	return '@%s' % tag_name | ||||
|  | ||||
|  | ||||
| def _tag(operation, what, add, rm, tag_options): | ||||
| 	cmd = [operation] | ||||
| 	cmd.extend(options_to_cli_args(tag_options)) | ||||
|  | ||||
| 	if isinstance(what, list): | ||||
| 		cmd.extend(what) | ||||
| 	else: | ||||
| 		cmd.append(what) | ||||
|  | ||||
| 	if add: | ||||
| 		cmd.extend(list(chain.from_iterable( | ||||
| 			('--addtag', _qt(x)) for x in add))) | ||||
| 	if rm: | ||||
| 		cmd.extend(list(chain.from_iterable( | ||||
| 			('--deltag', _qt(x)) for x in rm))) | ||||
|  | ||||
| 	return call(cmd, False) | ||||
|  | ||||
|  | ||||
| def pv_tag(pv_devices, add, rm, tag_options): | ||||
| 	return _tag('pvchange', pv_devices, add, rm, tag_options) | ||||
|  | ||||
|  | ||||
| def vg_tag(vg_name, add, rm, tag_options): | ||||
| 	return _tag('vgchange', vg_name, add, rm, tag_options) | ||||
|  | ||||
|  | ||||
| def lv_tag(lv_name, add, rm, tag_options): | ||||
| 	return _tag('lvchange', lv_name, add, rm, tag_options) | ||||
|  | ||||
|  | ||||
| def vg_rename(vg_uuid, new_name, rename_options): | ||||
| 	cmd = ['vgrename'] | ||||
| 	cmd.extend(options_to_cli_args(rename_options)) | ||||
| 	cmd.extend([vg_uuid, new_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_remove(vg_name, remove_options): | ||||
| 	cmd = ['vgremove'] | ||||
| 	cmd.extend(options_to_cli_args(remove_options)) | ||||
| 	cmd.extend(['-f', vg_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['--size', '%dB' % size_bytes]) | ||||
| 	cmd.extend(['--name', name, vg_name, '--yes']) | ||||
| 	pv_dest_ranges(cmd, pv_dests) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(snapshot_options)) | ||||
| 	cmd.extend(["-s"]) | ||||
|  | ||||
| 	if size_bytes != 0: | ||||
| 		cmd.extend(['--size', '%dB' % size_bytes]) | ||||
|  | ||||
| 	cmd.extend(['--name', name, vg_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
|  | ||||
| 	if not thin_pool: | ||||
| 		cmd.extend(['--size', '%dB' % size_bytes]) | ||||
| 	else: | ||||
| 		cmd.extend(['--thin', '--size', '%dB' % size_bytes]) | ||||
|  | ||||
| 	cmd.extend(['--yes']) | ||||
| 	return cmd | ||||
|  | ||||
|  | ||||
| def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool): | ||||
| 	cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool) | ||||
| 	cmd.extend(['--name', name, vg_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_lv_create_striped(vg_name, create_options, name, size_bytes, | ||||
| 							num_stripes, stripe_size_kb, thin_pool): | ||||
| 	cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool) | ||||
| 	cmd.extend(['--stripes', str(int(num_stripes))]) | ||||
|  | ||||
| 	if stripe_size_kb != 0: | ||||
| 		cmd.extend(['--stripesize', str(int(stripe_size_kb))]) | ||||
|  | ||||
| 	cmd.extend(['--name', name, vg_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes, | ||||
| 						num_stripes, stripe_size_kb): | ||||
| 	cmd = ['lvcreate'] | ||||
|  | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
|  | ||||
| 	cmd.extend(['--type', raid_type]) | ||||
| 	cmd.extend(['--size', '%dB' % size_bytes]) | ||||
|  | ||||
| 	if num_stripes != 0: | ||||
| 		cmd.extend(['--stripes', str(int(num_stripes))]) | ||||
|  | ||||
| 	if stripe_size_kb != 0: | ||||
| 		cmd.extend(['--stripesize', str(int(stripe_size_kb))]) | ||||
|  | ||||
| 	cmd.extend(['--name', name, vg_name, '--yes']) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes, | ||||
| 						num_stripes, stripe_size_kb): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
|  | ||||
| 	return _vg_lv_create_raid(vg_name, create_options, name, raid_type, | ||||
| 								size_bytes, num_stripes, stripe_size_kb) | ||||
|  | ||||
|  | ||||
| def vg_lv_create_mirror( | ||||
| 		vg_name, create_options, name, size_bytes, num_copies): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
|  | ||||
| 	cmd.extend(['--type', 'mirror']) | ||||
| 	cmd.extend(['--mirrors', str(int(num_copies))]) | ||||
| 	cmd.extend(['--size', '%dB' % size_bytes]) | ||||
| 	cmd.extend(['--name', name, vg_name, '--yes']) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_create_cache_pool(md_full_name, data_full_name, create_options): | ||||
| 	cmd = ['lvconvert'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['--type', 'cache-pool', '--force', '-y', | ||||
| 				'--poolmetadata', md_full_name, data_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_create_thin_pool(md_full_name, data_full_name, create_options): | ||||
| 	cmd = ['lvconvert'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['--type', 'thin-pool', '--force', '-y', | ||||
| 				'--poolmetadata', md_full_name, data_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size, | ||||
| 									virtual_size, create_options): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['-y', '--type', 'vdo', '-n', lv_name, | ||||
| 				'-L', '%dB' % data_size, '-V', '%dB' % virtual_size, | ||||
| 				"%s/%s" % (vg_name, pool_name)]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options): | ||||
| 	cmd = ['lvconvert'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y', | ||||
| 				'-V', '%dB' % virtual_size, pool_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_remove(lv_path, remove_options): | ||||
| 	cmd = ['lvremove'] | ||||
| 	cmd.extend(options_to_cli_args(remove_options)) | ||||
| 	cmd.extend(['-f', lv_path]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_rename(lv_path, new_name, rename_options): | ||||
| 	cmd = ['lvrename'] | ||||
| 	cmd.extend(options_to_cli_args(rename_options)) | ||||
| 	cmd.extend([lv_path, new_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_resize(lv_full_name, size_change, pv_dests, | ||||
| 				resize_options): | ||||
| 	cmd = ['lvresize', '--force'] | ||||
|  | ||||
| 	cmd.extend(options_to_cli_args(resize_options)) | ||||
|  | ||||
| 	if size_change < 0: | ||||
| 		cmd.append("-L-%dB" % (-size_change)) | ||||
| 	else: | ||||
| 		cmd.append("-L+%dB" % (size_change)) | ||||
|  | ||||
| 	cmd.append(lv_full_name) | ||||
| 	pv_dest_ranges(cmd, pv_dests) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_lv_create(lv_full_name, create_options, name, size_bytes): | ||||
| 	cmd = ['lvcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(['--virtualsize', '%dB' % size_bytes, '-T']) | ||||
| 	cmd.extend(['--name', name, lv_full_name, '--yes']) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options): | ||||
| 	# lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV | ||||
| 	cmd = ['lvconvert'] | ||||
| 	cmd.extend(options_to_cli_args(cache_options)) | ||||
| 	cmd.extend(['-y', '--type', 'cache', '--cachepool', | ||||
| 				cache_pool_full_name, lv_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options): | ||||
| 	# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV | ||||
| 	cmd = ['lvconvert'] | ||||
| 	cmd.extend(options_to_cli_args(cache_options)) | ||||
| 	cmd.extend(['-y', '--type', 'writecache', '--cachevol', | ||||
| 				cache_lv_full_name, lv_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_detach_cache(lv_full_name, detach_options, destroy_cache): | ||||
| 	cmd = ['lvconvert'] | ||||
| 	if destroy_cache: | ||||
| 		option = '--uncache' | ||||
| 	else: | ||||
| 		# Currently fairly dangerous | ||||
| 		# see: https://bugzilla.redhat.com/show_bug.cgi?id=1248972 | ||||
| 		option = '--splitcache' | ||||
| 	cmd.extend(options_to_cli_args(detach_options)) | ||||
| 	# needed to prevent interactive questions | ||||
| 	cmd.extend(["--yes", "--force"]) | ||||
| 	cmd.extend([option, lv_full_name]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_vdo_compression(lv_path, enable, comp_options): | ||||
| 	cmd = ['lvchange', '--compression'] | ||||
| 	if enable: | ||||
| 		cmd.append('y') | ||||
| 	else: | ||||
| 		cmd.append('n') | ||||
| 	cmd.extend(options_to_cli_args(comp_options)) | ||||
| 	cmd.append(lv_path) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def lv_vdo_deduplication(lv_path, enable, dedup_options): | ||||
| 	cmd = ['lvchange', '--deduplication'] | ||||
| 	if enable: | ||||
| 		cmd.append('y') | ||||
| 	else: | ||||
| 		cmd.append('n') | ||||
| 	cmd.extend(options_to_cli_args(dedup_options)) | ||||
| 	cmd.append(lv_path) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def supports_json(): | ||||
| 	cmd = ['help'] | ||||
| 	rc, out, err = call(cmd) | ||||
| 	if rc == 0: | ||||
| 		if cfg.SHELL_IN_USE: | ||||
| 			return True | ||||
| 		else: | ||||
| 			if 'fullreport' in err: | ||||
| 				return True | ||||
| 	return False | ||||
|  | ||||
|  | ||||
| def supports_vdo(): | ||||
| 	cmd = ['segtypes'] | ||||
| 	rc, out, err = call(cmd) | ||||
| 	if rc == 0: | ||||
| 		if "vdo" in out: | ||||
| 			log_debug("We have VDO support") | ||||
| 			return True | ||||
| 	return False | ||||
|  | ||||
|  | ||||
| def lvm_full_report_json(): | ||||
| 	pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free', | ||||
| 					'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free', | ||||
| 					'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count', | ||||
| 					'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name', | ||||
| 					'vg_uuid', 'pv_missing'] | ||||
|  | ||||
| 	pv_seg_columns = ['pvseg_start', 'pvseg_size', 'segtype', | ||||
| 						'pv_uuid', 'lv_uuid', 'pv_name'] | ||||
|  | ||||
| 	vg_columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free', | ||||
| 					'vg_sysid', 'vg_extent_size', 'vg_extent_count', | ||||
| 					'vg_free_count', 'vg_profile', 'max_lv', 'max_pv', | ||||
| 					'pv_count', 'lv_count', 'snap_count', 'vg_seqno', | ||||
| 					'vg_mda_count', 'vg_mda_free', 'vg_mda_size', | ||||
| 					'vg_mda_used_count', 'vg_attr', 'vg_tags'] | ||||
|  | ||||
| 	lv_columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size', | ||||
| 				'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid', | ||||
| 				'origin', 'data_percent', | ||||
| 				'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv', | ||||
| 				'metadata_lv', 'lv_parent', 'lv_role', 'lv_layout', | ||||
| 				'snap_percent', 'metadata_percent', 'copy_percent', | ||||
| 				'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid'] | ||||
|  | ||||
| 	lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid'] | ||||
|  | ||||
| 	if cfg.vdo_support: | ||||
| 		lv_columns.extend( | ||||
| 			['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state', | ||||
| 				'vdo_used_size', 'vdo_saving_percent'] | ||||
| 		) | ||||
|  | ||||
| 		lv_seg_columns.extend( | ||||
| 			['vdo_compression', 'vdo_deduplication', | ||||
| 				'vdo_use_metadata_hints', 'vdo_minimum_io_size', | ||||
| 				'vdo_block_map_cache_size', 'vdo_block_map_era_length', | ||||
| 				'vdo_use_sparse_index', 'vdo_index_memory_size', | ||||
| 				'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads', | ||||
| 				'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads', | ||||
| 				'vdo_logical_threads', 'vdo_physical_threads', | ||||
| 				'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size']) | ||||
|  | ||||
| 	cmd = _dc('fullreport', [ | ||||
| 		'-a',		# Need hidden too | ||||
| 		'--configreport', 'pv', '-o', ','.join(pv_columns), | ||||
| 		'--configreport', 'vg', '-o', ','.join(vg_columns), | ||||
| 		'--configreport', 'lv', '-o', ','.join(lv_columns), | ||||
| 		'--configreport', 'seg', '-o', ','.join(lv_seg_columns), | ||||
| 		'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns), | ||||
| 		'--reportformat', 'json' | ||||
| 	]) | ||||
|  | ||||
| 	rc, out, err = call(cmd) | ||||
| 	# When we have an exported vg the exit code of lvs or fullreport will be 5 | ||||
| 	if rc == 0 or rc == 5: | ||||
| 		# With the current implementation, if we are using the shell then we | ||||
| 		# are using JSON and JSON is returned back to us as it was parsed to | ||||
| 		# figure out if we completed OK or not | ||||
| 		if cfg.SHELL_IN_USE: | ||||
| 			assert(type(out) == dict) | ||||
| 			return out | ||||
| 		else: | ||||
| 			return json.loads(out) | ||||
| 	return None | ||||
|  | ||||
|  | ||||
| def pv_retrieve_with_segs(device=None): | ||||
| 	d = [] | ||||
| 	err = "" | ||||
| 	out = "" | ||||
| 	rc = 0 | ||||
|  | ||||
| 	columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free', | ||||
| 				'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free', | ||||
| 				'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count', | ||||
| 				'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name', | ||||
| 				'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing'] | ||||
|  | ||||
| 	# Lvm has some issues where it returns failure when querying pvs when other | ||||
| 	# operations are in process, see: | ||||
| 	# https://bugzilla.redhat.com/show_bug.cgi?id=1274085 | ||||
| 	for i in range(0, 10): | ||||
| 		cmd = _dc('pvs', ['-o', ','.join(columns)]) | ||||
|  | ||||
| 		if device: | ||||
| 			cmd.extend(device) | ||||
|  | ||||
| 		rc, out, err = call(cmd) | ||||
|  | ||||
| 		if rc == 0: | ||||
| 			d = parse_column_names(out, columns) | ||||
| 			break | ||||
| 		else: | ||||
| 			time.sleep(0.2) | ||||
| 			log_debug("LVM Bug workaround, retrying pvs command...") | ||||
|  | ||||
| 	if rc != 0: | ||||
| 		msg = "We were unable to get pvs to return without error after " \ | ||||
| 			"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \ | ||||
| 			(rc, err, out) | ||||
| 		log_error(msg) | ||||
| 		raise RuntimeError(msg) | ||||
|  | ||||
| 	return d | ||||
|  | ||||
|  | ||||
| def pv_resize(device, size_bytes, create_options): | ||||
| 	cmd = ['pvresize'] | ||||
|  | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
|  | ||||
| 	if size_bytes != 0: | ||||
| 		cmd.extend(['--yes', '--setphysicalvolumesize', '%dB' % size_bytes]) | ||||
|  | ||||
| 	cmd.extend([device]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def pv_create(create_options, devices): | ||||
| 	cmd = ['pvcreate', '-ff'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.extend(devices) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def pv_allocatable(device, yes, allocation_options): | ||||
| 	yn = 'n' | ||||
|  | ||||
| 	if yes: | ||||
| 		yn = 'y' | ||||
|  | ||||
| 	cmd = ['pvchange'] | ||||
| 	cmd.extend(options_to_cli_args(allocation_options)) | ||||
| 	cmd.extend(['-x', yn, device]) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def pv_scan(activate, cache, device_paths, major_minors, scan_options): | ||||
| 	cmd = ['pvscan'] | ||||
| 	cmd.extend(options_to_cli_args(scan_options)) | ||||
|  | ||||
| 	if activate: | ||||
| 		cmd.extend(['--activate', "ay"]) | ||||
|  | ||||
| 	if cache: | ||||
| 		cmd.append('--cache') | ||||
|  | ||||
| 		if len(device_paths) > 0: | ||||
| 			for d in device_paths: | ||||
| 				cmd.append(d) | ||||
|  | ||||
| 		if len(major_minors) > 0: | ||||
| 			for mm in major_minors: | ||||
| 				cmd.append("%s:%s" % (mm)) | ||||
|  | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_create(create_options, pv_devices, name): | ||||
| 	cmd = ['vgcreate'] | ||||
| 	cmd.extend(options_to_cli_args(create_options)) | ||||
| 	cmd.append(name) | ||||
| 	cmd.extend(pv_devices) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_change(change_options, name): | ||||
| 	cmd = ['vgchange'] | ||||
| 	cmd.extend(options_to_cli_args(change_options)) | ||||
| 	cmd.append(name) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_reduce(vg_name, missing, pv_devices, reduce_options): | ||||
| 	cmd = ['vgreduce'] | ||||
| 	cmd.extend(options_to_cli_args(reduce_options)) | ||||
|  | ||||
| 	if missing: | ||||
| 		cmd.append('--removemissing') | ||||
| 	elif len(pv_devices) == 0: | ||||
| 		cmd.append('--all') | ||||
|  | ||||
| 	cmd.append(vg_name) | ||||
| 	cmd.extend(pv_devices) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_extend(vg_name, extend_devices, extend_options): | ||||
| 	cmd = ['vgextend'] | ||||
| 	cmd.extend(options_to_cli_args(extend_options)) | ||||
| 	cmd.append(vg_name) | ||||
| 	cmd.extend(extend_devices) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def _vg_value_set(name, arguments, options): | ||||
| 	cmd = ['vgchange'] | ||||
| 	cmd.extend(options_to_cli_args(options)) | ||||
| 	cmd.append(name) | ||||
| 	cmd.extend(arguments) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_allocation_policy(vg_name, policy, policy_options): | ||||
| 	return _vg_value_set(vg_name, ['--alloc', policy], policy_options) | ||||
|  | ||||
|  | ||||
| def vg_max_pv(vg_name, number, max_options): | ||||
| 	return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(int(number))], | ||||
| 							max_options) | ||||
|  | ||||
|  | ||||
| def vg_max_lv(vg_name, number, max_options): | ||||
| 	return _vg_value_set(vg_name, ['-l', str(int(number))], max_options) | ||||
|  | ||||
|  | ||||
| def vg_uuid_gen(vg_name, ignore, options): | ||||
| 	assert ignore is None | ||||
| 	return _vg_value_set(vg_name, ['--uuid'], options) | ||||
|  | ||||
|  | ||||
| def activate_deactivate(op, name, activate, control_flags, options): | ||||
| 	cmd = [op] | ||||
| 	cmd.extend(options_to_cli_args(options)) | ||||
|  | ||||
| 	op = '-a' | ||||
|  | ||||
| 	if control_flags: | ||||
| 		# Autoactivation | ||||
| 		if (1 << 0) & control_flags: | ||||
| 			op += 'a' | ||||
| 		# Exclusive locking (Cluster) | ||||
| 		if (1 << 1) & control_flags: | ||||
| 			op += 'e' | ||||
|  | ||||
| 		# Local node activation | ||||
| 		if (1 << 2) & control_flags: | ||||
| 			op += 'l' | ||||
|  | ||||
| 		# Activation modes | ||||
| 		if (1 << 3) & control_flags: | ||||
| 			cmd.extend(['--activationmode', 'complete']) | ||||
| 		elif (1 << 4) & control_flags: | ||||
| 			cmd.extend(['--activationmode', 'partial']) | ||||
|  | ||||
| 		# Ignore activation skip | ||||
| 		if (1 << 5) & control_flags: | ||||
| 			cmd.append('--ignoreactivationskip') | ||||
|  | ||||
| 	if activate: | ||||
| 		op += 'y' | ||||
| 	else: | ||||
| 		op += 'n' | ||||
|  | ||||
| 	cmd.append(op) | ||||
| 	cmd.append("-y") | ||||
| 	cmd.append(name) | ||||
| 	return call(cmd) | ||||
|  | ||||
|  | ||||
| def vg_retrieve(vg_specific): | ||||
| 	if vg_specific: | ||||
| 		assert isinstance(vg_specific, list) | ||||
|  | ||||
| 	columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free', | ||||
| 				'vg_sysid', 'vg_extent_size', 'vg_extent_count', | ||||
| 				'vg_free_count', 'vg_profile', 'max_lv', 'max_pv', | ||||
| 				'pv_count', 'lv_count', 'snap_count', 'vg_seqno', | ||||
| 				'vg_mda_count', 'vg_mda_free', 'vg_mda_size', | ||||
| 				'vg_mda_used_count', 'vg_attr', 'vg_tags'] | ||||
|  | ||||
| 	cmd = _dc('vgs', ['-o', ','.join(columns)]) | ||||
|  | ||||
| 	if vg_specific: | ||||
| 		cmd.extend(vg_specific) | ||||
|  | ||||
| 	d = [] | ||||
| 	rc, out, err = call(cmd) | ||||
| 	if rc == 0: | ||||
| 		d = parse_column_names(out, columns) | ||||
|  | ||||
| 	return d | ||||
|  | ||||
|  | ||||
| def lv_retrieve_with_segments(): | ||||
| 	columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size', | ||||
| 				'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid', | ||||
| 				'origin', 'data_percent', | ||||
| 				'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv', | ||||
| 				'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent', | ||||
| 				'lv_role', 'lv_layout', | ||||
| 				'snap_percent', 'metadata_percent', 'copy_percent', | ||||
| 				'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid'] | ||||
|  | ||||
| 	cmd = _dc('lvs', ['-a', '-o', ','.join(columns)]) | ||||
| 	rc, out, err = call(cmd) | ||||
|  | ||||
| 	d = [] | ||||
|  | ||||
| 	if rc == 0: | ||||
| 		d = parse_column_names(out, columns) | ||||
|  | ||||
| 	return d | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
| 	pv_data = pv_retrieve_with_segs() | ||||
|  | ||||
| 	for p in pv_data: | ||||
| 		print(str(p)) | ||||
| @@ -1,200 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| from .pv import load_pvs | ||||
| from .vg import load_vgs | ||||
| from .lv import load_lvs | ||||
| from . import cfg | ||||
| from .utils import MThreadRunner, log_debug, log_error | ||||
| import threading | ||||
| import queue | ||||
| import time | ||||
| import traceback | ||||
|  | ||||
|  | ||||
| def _main_thread_load(refresh=True, emit_signal=True): | ||||
| 	num_total_changes = 0 | ||||
|  | ||||
| 	num_total_changes += load_pvs( | ||||
| 		refresh=refresh, | ||||
| 		emit_signal=emit_signal, | ||||
| 		cache_refresh=False)[1] | ||||
| 	num_total_changes += load_vgs( | ||||
| 		refresh=refresh, | ||||
| 		emit_signal=emit_signal, | ||||
| 		cache_refresh=False)[1] | ||||
|  | ||||
| 	lv_changes = load_lvs( | ||||
| 		refresh=refresh, | ||||
| 		emit_signal=emit_signal, | ||||
| 		cache_refresh=False)[1] | ||||
|  | ||||
| 	num_total_changes += lv_changes | ||||
|  | ||||
| 	# When the LVs change it can cause another change in the VGs which is | ||||
| 	# missed if we don't scan through the VGs again.  We could achieve this | ||||
| 	# the other way and re-scan the LVs, but in general there are more LVs than | ||||
| 	# VGs, thus this should be more efficient.  This happens when a LV interface | ||||
| 	# changes causing the dbus object representing it to be removed and | ||||
| 	# recreated. | ||||
| 	if refresh and lv_changes > 0: | ||||
| 		num_total_changes += load_vgs( | ||||
| 			refresh=refresh, | ||||
| 			emit_signal=emit_signal, | ||||
| 			cache_refresh=False)[1] | ||||
|  | ||||
| 	return num_total_changes | ||||
|  | ||||
|  | ||||
| def load(refresh=True, emit_signal=True, cache_refresh=True, log=True, | ||||
| 			need_main_thread=True): | ||||
| 	# Go through and load all the PVs, VGs and LVs | ||||
| 	if cache_refresh: | ||||
| 		cfg.db.refresh(log) | ||||
|  | ||||
| 	if need_main_thread: | ||||
| 		rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done() | ||||
| 	else: | ||||
| 		rc = _main_thread_load(refresh, emit_signal) | ||||
|  | ||||
| 	return rc | ||||
|  | ||||
|  | ||||
| # Even though lvm can handle multiple changes concurrently it really doesn't | ||||
| # make sense to make a 1-1 fetch of data for each change of lvm because when | ||||
| # we fetch the data once all previous changes are reflected. | ||||
| class StateUpdate(object): | ||||
|  | ||||
| 	class UpdateRequest(object): | ||||
|  | ||||
| 		def __init__(self, refresh, emit_signal, cache_refresh, log, | ||||
| 						need_main_thread): | ||||
| 			self.is_done = False | ||||
| 			self.refresh = refresh | ||||
| 			self.emit_signal = emit_signal | ||||
| 			self.cache_refresh = cache_refresh | ||||
| 			self.log = log | ||||
| 			self.need_main_thread = need_main_thread | ||||
| 			self.result = None | ||||
| 			self.cond = threading.Condition(threading.Lock()) | ||||
|  | ||||
| 		def done(self): | ||||
| 			with self.cond: | ||||
| 				if not self.is_done: | ||||
| 					self.cond.wait() | ||||
| 			return self.result | ||||
|  | ||||
| 		def set_result(self, result): | ||||
| 			with self.cond: | ||||
| 				self.result = result | ||||
| 				self.is_done = True | ||||
| 				self.cond.notify_all() | ||||
|  | ||||
| 	@staticmethod | ||||
| 	def update_thread(obj): | ||||
| 		exception_count = 0 | ||||
|  | ||||
| 		queued_requests = [] | ||||
| 		while cfg.run.value != 0: | ||||
| 			# noinspection PyBroadException | ||||
| 			try: | ||||
| 				refresh = True | ||||
| 				emit_signal = True | ||||
| 				cache_refresh = True | ||||
| 				log = True | ||||
| 				need_main_thread = True | ||||
|  | ||||
| 				with obj.lock: | ||||
| 					wait = not obj.deferred | ||||
| 					obj.deferred = False | ||||
|  | ||||
| 				if len(queued_requests) == 0 and wait: | ||||
| 					queued_requests.append(obj.queue.get(True, 2)) | ||||
|  | ||||
| 				# Ok we have one or the deferred queue has some, | ||||
| 				# check if any others | ||||
| 				try: | ||||
| 					while True: | ||||
| 						queued_requests.append(obj.queue.get(False)) | ||||
|  | ||||
| 				except queue.Empty: | ||||
| 					pass | ||||
|  | ||||
| 				if len(queued_requests) > 1: | ||||
| 					log_debug("Processing %d updates!" % len(queued_requests), | ||||
| 							'bg_black', 'fg_light_green') | ||||
|  | ||||
| 				# We have what we can, run the update with the needed options | ||||
| 				for i in queued_requests: | ||||
| 					if not i.refresh: | ||||
| 						refresh = False | ||||
| 					if not i.emit_signal: | ||||
| 						emit_signal = False | ||||
| 					if not i.cache_refresh: | ||||
| 						cache_refresh = False | ||||
| 					if not i.log: | ||||
| 						log = False | ||||
| 					if not i.need_main_thread: | ||||
| 						need_main_thread = False | ||||
|  | ||||
| 				num_changes = load(refresh, emit_signal, cache_refresh, log, | ||||
| 									need_main_thread) | ||||
| 				# Update is done, let everyone know! | ||||
| 				for i in queued_requests: | ||||
| 					i.set_result(num_changes) | ||||
|  | ||||
| 				# Only clear out the requests after we have given them a result | ||||
| 				# otherwise we can orphan the waiting threads and they never | ||||
| 				# wake up if we get an exception | ||||
| 				queued_requests = [] | ||||
|  | ||||
| 				# We retrieved OK, clear exception count | ||||
| 				exception_count = 0 | ||||
|  | ||||
| 			except queue.Empty: | ||||
| 				pass | ||||
| 			except Exception as e: | ||||
| 				st = traceback.format_exc() | ||||
| 				log_error("update_thread exception: \n%s" % st) | ||||
| 				cfg.blackbox.dump() | ||||
| 				exception_count += 1 | ||||
| 				if exception_count >= 5: | ||||
| 					for i in queued_requests: | ||||
| 						i.set_result(e) | ||||
|  | ||||
| 					log_error("Too many errors in update_thread, exiting daemon") | ||||
| 					cfg.exit_daemon() | ||||
|  | ||||
| 				else: | ||||
| 					# Slow things down when encountering errors | ||||
| 					time.sleep(1) | ||||
|  | ||||
| 	def __init__(self): | ||||
| 		self.lock = threading.RLock() | ||||
| 		self.queue = queue.Queue() | ||||
| 		self.deferred = False | ||||
|  | ||||
| 		# Do initial load | ||||
| 		load(refresh=False, emit_signal=False, need_main_thread=False) | ||||
|  | ||||
| 		self.thread = threading.Thread(target=StateUpdate.update_thread, | ||||
| 										args=(self,), | ||||
| 										name="StateUpdate.update_thread") | ||||
|  | ||||
| 	def load(self, refresh=True, emit_signal=True, cache_refresh=True, | ||||
| 					log=True, need_main_thread=True): | ||||
| 		# Place this request on the queue and wait for it to be completed | ||||
| 		req = StateUpdate.UpdateRequest(refresh, emit_signal, cache_refresh, | ||||
| 										log, need_main_thread) | ||||
| 		self.queue.put(req) | ||||
| 		return req.done() | ||||
|  | ||||
| 	def event(self): | ||||
| 		with self.lock: | ||||
| 			self.deferred = True | ||||
| @@ -1,228 +0,0 @@ | ||||
| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| from .automatedproperties import AutomatedProperties | ||||
| from .utils import job_obj_path_generate, mt_async_call | ||||
| from . import cfg | ||||
| from .cfg import JOB_INTERFACE | ||||
| import dbus | ||||
| import threading | ||||
| # noinspection PyUnresolvedReferences | ||||
| from gi.repository import GLib | ||||
|  | ||||
|  | ||||
| # Class that handles a client waiting for something to be complete.  We either | ||||
| # get a timeout or the operation is done. | ||||
| class WaitingClient(object): | ||||
|  | ||||
| 	# A timeout occurred | ||||
| 	@staticmethod | ||||
| 	def _timeout(wc): | ||||
| 		with wc.rlock: | ||||
| 			if wc.in_use: | ||||
| 				wc.in_use = False | ||||
| 				# Remove ourselves from waiting client | ||||
| 				wc.job_state.remove_waiting_client(wc) | ||||
| 				wc.timer_id = -1 | ||||
| 				mt_async_call(wc.cb, wc.job_state.Complete) | ||||
| 				wc.job_state = None | ||||
|  | ||||
| 	def __init__(self, job_state, tmo, cb, cbe): | ||||
| 		self.rlock = threading.RLock() | ||||
| 		self.job_state = job_state | ||||
| 		self.cb = cb | ||||
| 		self.cbe = cbe | ||||
| 		self.in_use = True		# Indicates if object is in play | ||||
| 		self.timer_id = -1 | ||||
| 		if tmo > 0: | ||||
| 			self.timer_id = GLib.timeout_add_seconds( | ||||
| 				tmo, WaitingClient._timeout, self) | ||||
|  | ||||
| 	# The job finished before the timer popped and we are being notified that | ||||
| 	# it's done | ||||
| 	def notify(self): | ||||
| 		with self.rlock: | ||||
| 			if self.in_use: | ||||
| 				self.in_use = False | ||||
| 				# Clear timer | ||||
| 				if self.timer_id != -1: | ||||
| 					GLib.source_remove(self.timer_id) | ||||
| 					self.timer_id = -1 | ||||
|  | ||||
| 				mt_async_call(self.cb, self.job_state.Complete) | ||||
| 				self.job_state = None | ||||
|  | ||||
|  | ||||
| # noinspection PyPep8Naming | ||||
| class JobState(object): | ||||
| 	def __init__(self, request=None): | ||||
| 		self.rlock = threading.RLock() | ||||
|  | ||||
| 		self._percent = 0 | ||||
| 		self._complete = False | ||||
| 		self._request = request | ||||
| 		self._ec = 0 | ||||
| 		self._stderr = '' | ||||
| 		self._waiting_clients = [] | ||||
|  | ||||
| 		# This is an lvm command that is just taking too long and doesn't | ||||
| 		# support background operation | ||||
| 		if self._request: | ||||
| 			# Faking the percentage when we don't have one | ||||
| 			self._percent = 1 | ||||
|  | ||||
| 	@property | ||||
| 	def Percent(self): | ||||
| 		with self.rlock: | ||||
| 			return self._percent | ||||
|  | ||||
| 	@Percent.setter | ||||
| 	def Percent(self, value): | ||||
| 		with self.rlock: | ||||
| 			self._percent = value | ||||
|  | ||||
| 	@property | ||||
| 	def Complete(self): | ||||
| 		with self.rlock: | ||||
| 			if self._request: | ||||
| 				self._complete = self._request.is_done() | ||||
|  | ||||
| 			return self._complete | ||||
|  | ||||
| 	@Complete.setter | ||||
| 	def Complete(self, value): | ||||
| 		with self.rlock: | ||||
| 			self._complete = value | ||||
| 			self._percent = 100 | ||||
| 			self.notify_waiting_clients() | ||||
|  | ||||
| 	@property | ||||
| 	def GetError(self): | ||||
| 		with self.rlock: | ||||
| 			if self.Complete: | ||||
| 				if self._request: | ||||
| 					(rc, error) = self._request.get_errors() | ||||
| 					return (rc, str(error)) | ||||
| 				else: | ||||
| 					return (self._ec, self._stderr) | ||||
| 			else: | ||||
| 				return (-1, 'Job is not complete!') | ||||
|  | ||||
| 	def dtor(self): | ||||
| 		with self.rlock: | ||||
| 			self._request = None | ||||
|  | ||||
| 	@property | ||||
| 	def Result(self): | ||||
| 		with self.rlock: | ||||
| 			if self._request: | ||||
| 				return self._request.result() | ||||
| 			return '/' | ||||
|  | ||||
| 	def add_waiting_client(self, client): | ||||
| 		with self.rlock: | ||||
| 			# Avoid race condition where it goes complete before we get added | ||||
| 			# to the list of waiting clients | ||||
| 			if self.Complete: | ||||
| 				client.notify() | ||||
| 			else: | ||||
| 				self._waiting_clients.append(client) | ||||
|  | ||||
| 	def remove_waiting_client(self, client): | ||||
| 		# If a waiting client timer pops before the job is done we will allow | ||||
| 		# the client to remove themselves from the list.  As we have a lock | ||||
| 		# here and a lock in the waiting client too, and they can be obtained | ||||
| 		# in different orders, a dead lock can occur. | ||||
| 		# As this remove is really optional, we will try to acquire the lock | ||||
| 		# and remove.  If we are unsuccessful it's not fatal, we just delay | ||||
| 		# the time when the objects can be garbage collected by python | ||||
| 		if self.rlock.acquire(False): | ||||
| 			try: | ||||
| 				self._waiting_clients.remove(client) | ||||
| 			finally: | ||||
| 				self.rlock.release() | ||||
|  | ||||
| 	def notify_waiting_clients(self): | ||||
| 		with self.rlock: | ||||
| 			for c in self._waiting_clients: | ||||
| 				c.notify() | ||||
|  | ||||
| 			self._waiting_clients = [] | ||||
|  | ||||
|  | ||||
| # noinspection PyPep8Naming | ||||
| class Job(AutomatedProperties): | ||||
| 	_Percent_meta = ('d', JOB_INTERFACE) | ||||
| 	_Complete_meta = ('b', JOB_INTERFACE) | ||||
| 	_Result_meta = ('o', JOB_INTERFACE) | ||||
| 	_GetError_meta = ('(is)', JOB_INTERFACE) | ||||
|  | ||||
| 	def __init__(self, request, job_state=None): | ||||
| 		super(Job, self).__init__(job_obj_path_generate()) | ||||
| 		self.set_interface(JOB_INTERFACE) | ||||
|  | ||||
| 		if job_state: | ||||
| 			self.state = job_state | ||||
| 		else: | ||||
| 			self.state = JobState(request) | ||||
|  | ||||
| 	@property | ||||
| 	def Percent(self): | ||||
| 		return dbus.Double(float(self.state.Percent)) | ||||
|  | ||||
| 	@property | ||||
| 	def Complete(self): | ||||
| 		return dbus.Boolean(self.state.Complete) | ||||
|  | ||||
| 	@staticmethod | ||||
| 	def _signal_complete(obj): | ||||
| 		obj.PropertiesChanged( | ||||
| 			JOB_INTERFACE, dict(Complete=dbus.Boolean(obj.state.Complete)), []) | ||||
|  | ||||
| 	@Complete.setter | ||||
| 	def Complete(self, value): | ||||
| 		self.state.Complete = value | ||||
| 		mt_async_call(Job._signal_complete, self) | ||||
|  | ||||
| 	@property | ||||
| 	def GetError(self): | ||||
| 		return dbus.Struct(self.state.GetError, signature="(is)") | ||||
|  | ||||
| 	@dbus.service.method(dbus_interface=JOB_INTERFACE) | ||||
| 	def Remove(self): | ||||
| 		if self.state.Complete: | ||||
| 			cfg.om.remove_object(self, True) | ||||
| 			self.state.dtor() | ||||
| 		else: | ||||
| 			raise dbus.exceptions.DBusException( | ||||
| 				JOB_INTERFACE, 'Job is not complete!') | ||||
|  | ||||
| 	@dbus.service.method(dbus_interface=JOB_INTERFACE, | ||||
| 							in_signature='i', | ||||
| 							out_signature='b', | ||||
| 							async_callbacks=('cb', 'cbe')) | ||||
| 	def Wait(self, timeout, cb, cbe): | ||||
| 		if timeout == 0 or self.state.Complete: | ||||
| 			cb(dbus.Boolean(self.state.Complete)) | ||||
| 		else: | ||||
| 			self.state.add_waiting_client( | ||||
| 				WaitingClient(self.state, timeout, cb, cbe)) | ||||
|  | ||||
| 	@property | ||||
| 	def Result(self): | ||||
| 		return dbus.ObjectPath(self.state.Result) | ||||
|  | ||||
| 	@property | ||||
| 	def lvm_id(self): | ||||
| 		return str(id(self)) | ||||
|  | ||||
| 	@property | ||||
| 	def Uuid(self): | ||||
| 		import uuid | ||||
| 		return uuid.uuid1() | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user