mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			887 Commits
		
	
	
		
			dev-dct-cm
			...
			old-beta4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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.177-git (2021-01-08)
 | 
			
		||||
							
								
								
									
										1487
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										1487
									
								
								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])
 | 
			
		||||
							
								
								
									
										1652
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1652
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										911
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										911
									
								
								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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2364
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
							
						
						
									
										2364
									
								
								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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1993
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										1993
									
								
								configure.ac
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										164
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
################################################################################
 | 
			
		||||
##
 | 
			
		||||
##    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 -- 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;
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
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 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, HAVE_RL_COMPLETION_MATCHES=yes,
 | 
			
		||||
		HAVE_RL_COMPLETION_MATCHES=no)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "-f VERSION"; then
 | 
			
		||||
  LVM_VERSION="\"`cat VERSION`\""
 | 
			
		||||
else
 | 
			
		||||
  LVM_VERSION="Unknown"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_SUBST(JOBS)
 | 
			
		||||
AC_SUBST(STATIC_LINK)
 | 
			
		||||
AC_SUBST(READLINE)
 | 
			
		||||
AC_SUBST(LVM1)
 | 
			
		||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
 | 
			
		||||
AC_SUBST(OWNER)
 | 
			
		||||
AC_SUBST(GROUP)
 | 
			
		||||
AC_SUBST(LIBS)
 | 
			
		||||
AC_SUBST(LVM_VERSION)
 | 
			
		||||
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