mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			852 Commits
		
	
	
		
			dev-bmr-dm
			...
			beta4_1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 | 
							
								
								
									
										32
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,32 +0,0 @@
 | 
			
		||||
*.5
 | 
			
		||||
*.7
 | 
			
		||||
*.8
 | 
			
		||||
*.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
 | 
			
		||||
/config.log
 | 
			
		||||
/config.status
 | 
			
		||||
/configure.scan
 | 
			
		||||
/cscope.out
 | 
			
		||||
/tags
 | 
			
		||||
/tmp/
 | 
			
		||||
							
								
								
									
										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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								INSTALL
									
									
									
									
									
								
							@@ -1,31 +1,36 @@
 | 
			
		||||
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 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 don't want to include the LVM1 backwards-compatibility code use:
 | 
			
		||||
     ./configure --with-lvm1=none 
 | 
			
		||||
   If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
 | 
			
		||||
   installed use
 | 
			
		||||
     ./configure --disable-readline
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
3) Build and install LVM2.
 | 
			
		||||
 | 
			
		||||
2) Build and install.
 | 
			
		||||
   Run 'make install' from the top directory.
 | 
			
		||||
 | 
			
		||||
   Run 'make' from the top directory to build everything you configured.
 | 
			
		||||
   Run 'make install' to build and install everything you configured.
 | 
			
		||||
 | 
			
		||||
   If you only want the device-mapper libraries and tools use
 | 
			
		||||
   'make device-mapper' or 'make install_device-mapper'.
 | 
			
		||||
 | 
			
		||||
3) If using LVM2, create a configuration file.
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
Please also refer to the WHATS_NEW file and the manual pages for the 
 | 
			
		||||
individual commands.
 | 
			
		||||
   For example, specifying the devices that LVM2 is to use should
 | 
			
		||||
   make the tools run more efficiently - and avoid scanning /dev/cdrom!
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								INTRO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								INTRO
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
An introduction to LVM2
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
Background
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Compatibility with LVM1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
New features
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Missing features
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Future enhancements
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										245
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										245
									
								
								Makefile.in
									
									
									
									
									
								
							@@ -1,243 +1,34 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
# Copyright (C) 2004-2015 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 = conf daemons include lib libdaemon libdm man scripts tools
 | 
			
		||||
SUBDIRS = include man lib tools
 | 
			
		||||
 | 
			
		||||
ifeq ("@UDEV_RULES@", "yes")
 | 
			
		||||
  SUBDIRS += udev
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@INTL@", "yes")
 | 
			
		||||
  SUBDIRS += po
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@APPLIB@", "yes")
 | 
			
		||||
  SUBDIRS += liblvm
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
  SUBDIRS += python
 | 
			
		||||
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 liblvm python \
 | 
			
		||||
    unit-tests/datastruct unit-tests/mm unit-tests/regex
 | 
			
		||||
tools.distclean: test.distclean
 | 
			
		||||
  SUBDIRS += 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
 | 
			
		||||
 | 
			
		||||
libdm: include
 | 
			
		||||
libdaemon: include
 | 
			
		||||
lib: libdm libdaemon
 | 
			
		||||
liblvm: lib
 | 
			
		||||
daemons: lib libdaemon tools
 | 
			
		||||
tools: lib libdaemon device-mapper
 | 
			
		||||
po: tools daemons
 | 
			
		||||
scripts: liblvm libdm
 | 
			
		||||
lib: include
 | 
			
		||||
tools: include lib
 | 
			
		||||
 | 
			
		||||
lib.device-mapper: include.device-mapper
 | 
			
		||||
libdm.device-mapper: include.device-mapper
 | 
			
		||||
liblvm.device-mapper: include.device-mapper
 | 
			
		||||
daemons.device-mapper: libdm.device-mapper
 | 
			
		||||
tools.device-mapper: libdm.device-mapper
 | 
			
		||||
scripts.device-mapper: include.device-mapper
 | 
			
		||||
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
 | 
			
		||||
 | 
			
		||||
ifeq ("@INTL@", "yes")
 | 
			
		||||
lib.pofile: include.pofile
 | 
			
		||||
tools.pofile: lib.pofile
 | 
			
		||||
daemons.pofile: lib.pofile
 | 
			
		||||
po.pofile: tools.pofile daemons.pofile
 | 
			
		||||
pofile: po.pofile
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
python: liblvm
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
tools.cflow: libdm.cflow lib.cflow
 | 
			
		||||
daemons.cflow: tools.cflow
 | 
			
		||||
cflow: include.cflow
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("@CSCOPE_CMD@", "")
 | 
			
		||||
cscope.out:
 | 
			
		||||
	@CSCOPE_CMD@ -b -R -s$(top_srcdir)
 | 
			
		||||
all: cscope.out
 | 
			
		||||
endif
 | 
			
		||||
DISTCLEAN_TARGETS += cscope.out
 | 
			
		||||
CLEAN_DIRS += autom4te.cache
 | 
			
		||||
 | 
			
		||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
 | 
			
		||||
	$(MAKE) -C test $(@)
 | 
			
		||||
 | 
			
		||||
conf.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
 | 
			
		||||
	rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
 | 
			
		||||
 | 
			
		||||
generate: conf.generate
 | 
			
		||||
	$(MAKE) -C conf 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
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
install_python_bindings:
 | 
			
		||||
	$(MAKE) -C liblvm/python install_python_bindings
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_tmpfiles_configuration:
 | 
			
		||||
	$(MAKE) -C scripts install_tmpfiles_configuration
 | 
			
		||||
 | 
			
		||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
 | 
			
		||||
	libdaemon/client.info libdaemon/server.info \
 | 
			
		||||
	daemons/clvmd.info \
 | 
			
		||||
	daemons/dmeventd.info \
 | 
			
		||||
	daemons/lvmetad.info \
 | 
			
		||||
	daemons/lvmlockd.info \
 | 
			
		||||
	daemons/lvmpolld.info
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS += $(LCOV_TRACES)
 | 
			
		||||
 | 
			
		||||
ifneq ("$(LCOV)", "")
 | 
			
		||||
.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
 | 
			
		||||
 | 
			
		||||
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 $(addprefix -d , $(basename $(LCOV_TRACES)))
 | 
			
		||||
 | 
			
		||||
# maybe use subdirs processing to create tracefiles...
 | 
			
		||||
$(LCOV_TRACES):
 | 
			
		||||
	$(LCOV) -b $(basename $@) -d $(basename $@) \
 | 
			
		||||
		--ignore-errors source -c -o - | $(SED) \
 | 
			
		||||
		-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
 | 
			
		||||
		-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
 | 
			
		||||
		>$@
 | 
			
		||||
 | 
			
		||||
ifneq ("$(GENHTML)", "")
 | 
			
		||||
lcov: $(LCOV_TRACES)
 | 
			
		||||
	$(RM) -r $(LCOV_REPORTS_DIR)
 | 
			
		||||
	$(MKDIR_P) $(LCOV_REPORTS_DIR)
 | 
			
		||||
	for i in $(LCOV_TRACES); do \
 | 
			
		||||
		test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
 | 
			
		||||
	done; \
 | 
			
		||||
	test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
 | 
			
		||||
		-o $(LCOV_REPORTS_DIR) $$lc
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("$(TESTING)", "yes")
 | 
			
		||||
# testing and report generation
 | 
			
		||||
RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
 | 
			
		||||
 | 
			
		||||
.PHONY: unit-test ruby-test test-programs
 | 
			
		||||
 | 
			
		||||
# FIXME: put dependencies on libdm and liblvm
 | 
			
		||||
# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
 | 
			
		||||
test-programs:
 | 
			
		||||
	cd unit-tests/regex && $(MAKE)
 | 
			
		||||
	cd unit-tests/datastruct && $(MAKE)
 | 
			
		||||
	cd unit-tests/mm && $(MAKE)
 | 
			
		||||
 | 
			
		||||
unit-test: test-programs
 | 
			
		||||
	$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
 | 
			
		||||
	$(RUBY) report-generators/title_page.rb
 | 
			
		||||
 | 
			
		||||
memcheck: test-programs
 | 
			
		||||
	$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
 | 
			
		||||
	$(RUBY) report-generators/title_page.rb
 | 
			
		||||
 | 
			
		||||
ruby-test:
 | 
			
		||||
	$(RUBY) report-generators/test/ts.rb
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ($(shell which ctags),)
 | 
			
		||||
.PHONY: tags
 | 
			
		||||
tags:
 | 
			
		||||
	test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
 | 
			
		||||
	test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS += tags
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README
									
									
									
									
									
								
							@@ -1,33 +1,25 @@
 | 
			
		||||
This tree contains the LVM2 and device-mapper tools and libraries.
 | 
			
		||||
This directory contains a beta release of LMV2, the new version of 
 | 
			
		||||
the userland LVM tools designed for the new device-mapper for 
 | 
			
		||||
the Linux kernel.
 | 
			
		||||
 | 
			
		||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
 | 
			
		||||
The device-mapper needs to be installed before compiling these LVM2 tools.
 | 
			
		||||
 | 
			
		||||
For more information about LVM2 read the INTRO 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://sources.redhat.com/pub/lvm2/
 | 
			
		||||
  ftp://ftp.sistina.com/pub/LVM2/tools/
 | 
			
		||||
  ftp://ftp.sistina.com/pub/LVM2/device-mapper/
 | 
			
		||||
 | 
			
		||||
The source code is stored in git:
 | 
			
		||||
  http://git.fedorahosted.org/git/lvm2.git
 | 
			
		||||
  git clone git://git.fedorahosted.org/git/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 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
 | 
			
		||||
 | 
			
		||||
The source code repository used until 7th June 2012 is accessible here:
 | 
			
		||||
  http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
 | 
			
		||||
Mailing list for discussion/bug reports etc.
 | 
			
		||||
  lvm-devel@sistina.com
 | 
			
		||||
  Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
before 2.0
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
vgexport
 | 
			
		||||
vgimport
 | 
			
		||||
snapshots
 | 
			
		||||
pvmove
 | 
			
		||||
device-mapper support for 2.5 kernel series
 | 
			
		||||
review FIXMEs
 | 
			
		||||
extra validation & full consistency checks in format1 with LVM1
 | 
			
		||||
partial activation (aka VG quorum)
 | 
			
		||||
error message review
 | 
			
		||||
locking during metadata changes
 | 
			
		||||
format2 with atomic transactions
 | 
			
		||||
bidirectional format1/format2 migration tool
 | 
			
		||||
persistent minors
 | 
			
		||||
statistics target and tool support
 | 
			
		||||
review tool exit codes for LVM1 compatibility
 | 
			
		||||
 | 
			
		||||
before 2.1
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
e2fsadm
 | 
			
		||||
lvmsadc
 | 
			
		||||
lvmsar
 | 
			
		||||
pvdata
 | 
			
		||||
vgsplit
 | 
			
		||||
vgmknodes
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
1.02.138-git (2016-11-30)
 | 
			
		||||
							
								
								
									
										1338
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										1338
									
								
								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])
 | 
			
		||||
])
 | 
			
		||||
							
								
								
									
										540
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										540
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							@@ -1,540 +0,0 @@
 | 
			
		||||
# generated automatically by aclocal 1.15 -*- Autoconf -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1996-2014 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($@)])])
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#     http://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 8
 | 
			
		||||
 | 
			
		||||
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 1 (pkg-config-0.24)
 | 
			
		||||
# 
 | 
			
		||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful, but
 | 
			
		||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
# General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software
 | 
			
		||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
 | 
			
		||||
# ----------------------------------
 | 
			
		||||
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
 | 
			
		||||
])# PKG_PROG_PKG_CONFIG
 | 
			
		||||
 | 
			
		||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
			
		||||
#
 | 
			
		||||
# Check to see whether a particular set of modules exists.  Similar
 | 
			
		||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
 | 
			
		||||
#
 | 
			
		||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
			
		||||
# only at the first occurence in configure.ac, so if the first place
 | 
			
		||||
# it's called might be skipped (such as if it is within an "if", you
 | 
			
		||||
# 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])
 | 
			
		||||
 | 
			
		||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
 | 
			
		||||
# ---------------------------------------------
 | 
			
		||||
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
 | 
			
		||||
])# _PKG_CONFIG
 | 
			
		||||
 | 
			
		||||
# _PKG_SHORT_ERRORS_SUPPORTED
 | 
			
		||||
# -----------------------------
 | 
			
		||||
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
 | 
			
		||||
])# _PKG_SHORT_ERRORS_SUPPORTED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 | 
			
		||||
# [ACTION-IF-NOT-FOUND])
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# Note that if there is a possibility the first call to
 | 
			
		||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
 | 
			
		||||
# 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
 | 
			
		||||
])# PKG_CHECK_MODULES
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# PKG_INSTALLDIR(DIRECTORY)
 | 
			
		||||
# -------------------------
 | 
			
		||||
# Substitutes the variable pkgconfigdir as the location where a module
 | 
			
		||||
# should install pkg-config .pc files. By default the directory is
 | 
			
		||||
# $libdir/pkgconfig, but the default can be changed by passing
 | 
			
		||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
 | 
			
		||||
# -------------------------
 | 
			
		||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
 | 
			
		||||
# module should install arch-independent pkg-config .pc files. By
 | 
			
		||||
# default the directory is $datadir/pkgconfig, but the default can be
 | 
			
		||||
# changed by passing DIRECTORY. The user can override through the
 | 
			
		||||
# --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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
 | 
			
		||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
			
		||||
# -------------------------------------------
 | 
			
		||||
# 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
 | 
			
		||||
])# PKG_CHECK_VAR
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1999-2014 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 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
 | 
			
		||||
 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 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.  Getting [:3] seems to be
 | 
			
		||||
  dnl the best way to do this; it's what "site.py" does in the standard
 | 
			
		||||
  dnl library.
 | 
			
		||||
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
 | 
			
		||||
    [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
 | 
			
		||||
  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-2014 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:
 | 
			
		||||
							
								
								
									
										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,58 +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@
 | 
			
		||||
 | 
			
		||||
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)/lvmdbusd.profile
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
.PHONY: install_conf install_localconf install_profiles
 | 
			
		||||
 | 
			
		||||
generate:
 | 
			
		||||
	(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
 | 
			
		||||
	(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --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)
 | 
			
		||||
	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
 | 
			
		||||
	$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
 | 
			
		||||
 | 
			
		||||
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 settins 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
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
# This is an example configuration file for the LVM2 system.
 | 
			
		||||
# It contains the default settings that would be used if there was no
 | 
			
		||||
# @DEFAULT_SYS_DIR@/lvm.conf file.
 | 
			
		||||
#
 | 
			
		||||
# Refer to 'man lvm.conf' for further information including the file layout.
 | 
			
		||||
#
 | 
			
		||||
# Refer to 'man lvm.conf' for information about how settings configured in
 | 
			
		||||
# this file are combined with built-in values and command line options to
 | 
			
		||||
# arrive at the final values used by LVM.
 | 
			
		||||
#
 | 
			
		||||
# Refer to 'man lvmconfig' for information about displaying the built-in
 | 
			
		||||
# and configured values used by LVM.
 | 
			
		||||
#
 | 
			
		||||
# If a default value is set in this file (not commented out), then a
 | 
			
		||||
# new version of LVM using this file will continue using that value,
 | 
			
		||||
# even if the new version of LVM changes the built-in default value.
 | 
			
		||||
#
 | 
			
		||||
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
 | 
			
		||||
# the environment variable LVM_SYSTEM_DIR before running the tools.
 | 
			
		||||
#
 | 
			
		||||
# N.B. Take care that each setting only appears once if uncommenting
 | 
			
		||||
# example settings in this file.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2104
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
							
						
						
									
										2104
									
								
								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,19 +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.
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2303
									
								
								configure.in
									
									
									
									
									
								
							
							
						
						
									
										2303
									
								
								configure.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,122 +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];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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,59 +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 clvmd cmirrord lvmetad lvmpolld lvmlockd
 | 
			
		||||
 | 
			
		||||
ifneq ("@CLVMD@", "none")
 | 
			
		||||
  SUBDIRS += clvmd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_CMIRRORD@", "yes")
 | 
			
		||||
  SUBDIRS += cmirrord
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_DMEVENTD@", "yes")
 | 
			
		||||
  SUBDIRS += dmeventd
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
daemons.cflow: dmeventd.cflow
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LVMETAD@", "yes")
 | 
			
		||||
  SUBDIRS += lvmetad
 | 
			
		||||
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 = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_DMEVENTD@", "yes")
 | 
			
		||||
device-mapper: dmeventd.device-mapper
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
clvmd
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of LVM2.
 | 
			
		||||
#
 | 
			
		||||
# This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
# of the GNU General Public License v.2.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
CMAN_LIBS = @CMAN_LIBS@
 | 
			
		||||
CMAN_CFLAGS = @CMAN_CFLAGS@
 | 
			
		||||
CMAP_LIBS = @CMAP_LIBS@
 | 
			
		||||
CMAP_CFLAGS = @CMAP_CFLAGS@
 | 
			
		||||
CONFDB_LIBS = @CONFDB_LIBS@
 | 
			
		||||
CONFDB_CFLAGS = @CONFDB_CFLAGS@
 | 
			
		||||
CPG_LIBS = @CPG_LIBS@
 | 
			
		||||
CPG_CFLAGS = @CPG_CFLAGS@
 | 
			
		||||
DLM_LIBS = @DLM_LIBS@
 | 
			
		||||
DLM_CFLAGS = @DLM_CFLAGS@
 | 
			
		||||
QUORUM_LIBS = @QUORUM_LIBS@
 | 
			
		||||
QUORUM_CFLAGS = @QUORUM_CFLAGS@
 | 
			
		||||
SALCK_LIBS = @SALCK_LIBS@
 | 
			
		||||
SALCK_CFLAGS = @SALCK_CFLAGS@
 | 
			
		||||
 | 
			
		||||
SOURCES = \
 | 
			
		||||
	clvmd-command.c  \
 | 
			
		||||
	clvmd.c          \
 | 
			
		||||
	lvm-functions.c  \
 | 
			
		||||
	refresh_clvmd.c
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-cman.c
 | 
			
		||||
	LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
 | 
			
		||||
	CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_CMAN
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring openais,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-openais.c
 | 
			
		||||
	LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS)
 | 
			
		||||
	CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_OPENAIS
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring corosync,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-corosync.c
 | 
			
		||||
	LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
 | 
			
		||||
	CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_COROSYNC
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring singlenode,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-singlenode.c
 | 
			
		||||
	DEFS += -DUSE_SINGLENODE
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
	SOURCES += clvmd-cman.c
 | 
			
		||||
	SOURCES += clvmd-openais.c
 | 
			
		||||
	SOURCES += clvmd-corosync.c
 | 
			
		||||
	SOURCES += clvmd-singlenode.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
TARGETS = \
 | 
			
		||||
	clvmd
 | 
			
		||||
 | 
			
		||||
LVMLIBS = $(LVMINTERNAL_LIBS)
 | 
			
		||||
 | 
			
		||||
ifeq ("@DMEVENTD@", "yes")
 | 
			
		||||
	LVMLIBS += -ldevmapper-event
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LVMLIBS += -ldevmapper
 | 
			
		||||
LIBS += $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
 | 
			
		||||
 | 
			
		||||
INSTALL_TARGETS = \
 | 
			
		||||
	install_clvmd
 | 
			
		||||
 | 
			
		||||
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o clvmd $(OBJECTS) \
 | 
			
		||||
		$(LVMLIBS) $(LMLIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
.PHONY: install_clvmd
 | 
			
		||||
 | 
			
		||||
install_clvmd: $(TARGETS)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
 | 
			
		||||
 | 
			
		||||
install: $(INSTALL_TARGETS)
 | 
			
		||||
 | 
			
		||||
install_cluster: $(INSTALL_TARGETS)
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Definitions for CLVMD server and clients */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The protocol spoken over the cluster and across the local socket.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVM_H
 | 
			
		||||
#define _CLVM_H
 | 
			
		||||
 | 
			
		||||
#include "configure.h"
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
struct clvm_header {
 | 
			
		||||
	uint8_t  cmd;	        /* See below */
 | 
			
		||||
	uint8_t  flags;	        /* See below */
 | 
			
		||||
	uint16_t xid;	        /* Transaction ID */
 | 
			
		||||
	uint32_t clientid;	/* Only used in Daemon->Daemon comms */
 | 
			
		||||
	int32_t  status;	/* For replies, whether request succeeded */
 | 
			
		||||
	uint32_t arglen;	/* Length of argument below.
 | 
			
		||||
				   If >1500 then it will be passed
 | 
			
		||||
				   around the cluster in the system LV */
 | 
			
		||||
	char node[1];		/* Actually a NUL-terminated string, node name.
 | 
			
		||||
				   If this is empty then the command is
 | 
			
		||||
				   forwarded to all cluster nodes unless
 | 
			
		||||
				   FLAG_LOCAL or FLAG_REMOTE is also set. */
 | 
			
		||||
	char args[1];		/* Arguments for the command follow the
 | 
			
		||||
				   node name, This member is only
 | 
			
		||||
				   valid if the node name is empty */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* Flags */
 | 
			
		||||
#define CLVMD_FLAG_LOCAL	1	/* Only do this on the local node */
 | 
			
		||||
#define CLVMD_FLAG_SYSTEMLV	2	/* Data in system LV under my node name */
 | 
			
		||||
#define CLVMD_FLAG_NODEERRS	4	/* Reply has errors in node-specific portion */
 | 
			
		||||
#define CLVMD_FLAG_REMOTE	8	/* Do this on all nodes except for the local node */
 | 
			
		||||
 | 
			
		||||
/* Name of the local socket to communicate between lvm and clvmd */
 | 
			
		||||
#define CLVMD_SOCKNAME		DEFAULT_RUN_DIR "/clvmd.sock"
 | 
			
		||||
 | 
			
		||||
/* Internal commands & replies */
 | 
			
		||||
#define CLVMD_CMD_REPLY    1
 | 
			
		||||
#define CLVMD_CMD_VERSION  2	/* Send version around cluster when we start */
 | 
			
		||||
#define CLVMD_CMD_GOAWAY   3	/* Die if received this - we are running
 | 
			
		||||
				   an incompatible version */
 | 
			
		||||
#define CLVMD_CMD_TEST     4	/* Just for mucking about */
 | 
			
		||||
 | 
			
		||||
#define CLVMD_CMD_LOCK              30
 | 
			
		||||
#define CLVMD_CMD_UNLOCK            31
 | 
			
		||||
 | 
			
		||||
/* Lock/Unlock commands */
 | 
			
		||||
#define CLVMD_CMD_LOCK_LV           50
 | 
			
		||||
#define CLVMD_CMD_LOCK_VG           51
 | 
			
		||||
#define CLVMD_CMD_LOCK_QUERY	    52
 | 
			
		||||
 | 
			
		||||
/* Misc functions */
 | 
			
		||||
#define CLVMD_CMD_REFRESH	    40
 | 
			
		||||
#define CLVMD_CMD_GET_CLUSTERNAME   41
 | 
			
		||||
#define CLVMD_CMD_SET_DEBUG	    42
 | 
			
		||||
#define CLVMD_CMD_VG_BACKUP	    43
 | 
			
		||||
#define CLVMD_CMD_RESTART	    44
 | 
			
		||||
#define CLVMD_CMD_SYNC_NAMES	    45
 | 
			
		||||
 | 
			
		||||
/* Used internally by some callers, but not part of the protocol.*/
 | 
			
		||||
#ifndef NODE_ALL
 | 
			
		||||
#  define NODE_ALL	"*"
 | 
			
		||||
#  define NODE_LOCAL	"."
 | 
			
		||||
#  define NODE_REMOTE	"^"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,505 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CMAN communication layer for clvmd.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include <libdlm.h>
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#define LOCKSPACE_NAME "clvmd"
 | 
			
		||||
 | 
			
		||||
struct clvmd_node
 | 
			
		||||
{
 | 
			
		||||
	struct cman_node *node;
 | 
			
		||||
	int clvmd_up;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static struct cman_node *nodes = NULL;
 | 
			
		||||
static struct cman_node this_node;
 | 
			
		||||
static int count_nodes; /* size of allocated nodes array */
 | 
			
		||||
static struct dm_hash_table *node_updown_hash;
 | 
			
		||||
static dlm_lshandle_t *lockspace;
 | 
			
		||||
static cman_handle_t c_handle;
 | 
			
		||||
 | 
			
		||||
static void count_clvmds_running(void);
 | 
			
		||||
static void get_members(void);
 | 
			
		||||
static int nodeid_from_csid(const char *csid);
 | 
			
		||||
static int name_from_nodeid(int nodeid, char *name);
 | 
			
		||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
 | 
			
		||||
static void data_callback(cman_handle_t handle, void *private,
 | 
			
		||||
			  char *buf, int len, uint8_t port, int nodeid);
 | 
			
		||||
 | 
			
		||||
struct lock_wait {
 | 
			
		||||
	pthread_cond_t cond;
 | 
			
		||||
	pthread_mutex_t mutex;
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	node_updown_hash = dm_hash_create(100);
 | 
			
		||||
 | 
			
		||||
	/* Open the cluster communication socket */
 | 
			
		||||
	c_handle = cman_init(NULL);
 | 
			
		||||
	if (!c_handle) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't open cluster manager socket: %m");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Connected to CMAN\n");
 | 
			
		||||
 | 
			
		||||
	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't bind cluster socket: %m");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cman_start_notification(c_handle, event_callback)) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't start cluster event listening");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the cluster members list */
 | 
			
		||||
	get_members();
 | 
			
		||||
	count_clvmds_running();
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("CMAN initialisation complete\n");
 | 
			
		||||
 | 
			
		||||
	/* Create a lockspace for LV & VG locks to live in */
 | 
			
		||||
	lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
 | 
			
		||||
	if (!lockspace) {
 | 
			
		||||
		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
 | 
			
		||||
		if (!lockspace) {
 | 
			
		||||
			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		DEBUGLOG("Created DLM lockspace for CLVMD.\n");
 | 
			
		||||
	} else
 | 
			
		||||
		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
 | 
			
		||||
 | 
			
		||||
	dlm_ls_pthread_init(lockspace);
 | 
			
		||||
	DEBUGLOG("DLM initialisation complete\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_init_completed(void)
 | 
			
		||||
{
 | 
			
		||||
	clvmd_cluster_init_completed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	return cman_get_fd(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int nnodes = 0;
 | 
			
		||||
 | 
			
		||||
	/* return number of ACTIVE nodes */
 | 
			
		||||
	for (i=0; i<num_nodes; i++) {
 | 
			
		||||
		if (nodes[i].cn_member && nodes[i].cn_nodeid)
 | 
			
		||||
			nnodes++;
 | 
			
		||||
	}
 | 
			
		||||
	return nnodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* send_message with the fd check removed */
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid = 0;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		log_error("%s", errtext);
 | 
			
		||||
	}
 | 
			
		||||
	return msglen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	if (this_node.cn_nodeid == 0) {
 | 
			
		||||
		cman_get_node(c_handle, 0, &this_node);
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *client,
 | 
			
		||||
				     void (*callback) (struct local_client *,
 | 
			
		||||
						       const char *,
 | 
			
		||||
						       int))
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int somedown = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _get_num_nodes(); i++) {
 | 
			
		||||
		if (nodes[i].cn_member && nodes[i].cn_nodeid) {
 | 
			
		||||
			int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
 | 
			
		||||
 | 
			
		||||
			callback(client, (char *)&nodes[i].cn_nodeid, up);
 | 
			
		||||
			if (!up)
 | 
			
		||||
				somedown = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return somedown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Process OOB messages from the cluster socket */
 | 
			
		||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
 | 
			
		||||
{
 | 
			
		||||
	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
 | 
			
		||||
	switch (reason) {
 | 
			
		||||
        case CMAN_REASON_PORTCLOSED:
 | 
			
		||||
		name_from_nodeid(arg, namebuf);
 | 
			
		||||
		log_notice("clvmd on node %s has died\n", namebuf);
 | 
			
		||||
		DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
 | 
			
		||||
 | 
			
		||||
		dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CMAN_REASON_STATECHANGE:
 | 
			
		||||
		DEBUGLOG("Got state change message, re-reading members list\n");
 | 
			
		||||
		get_members();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
 | 
			
		||||
	case CMAN_REASON_PORTOPENED:
 | 
			
		||||
		/* Ignore this, wait for startup message from clvmd itself */
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CMAN_REASON_TRY_SHUTDOWN:
 | 
			
		||||
		DEBUGLOG("Got try shutdown, sending OK\n");
 | 
			
		||||
		cman_replyto_shutdown(c_handle, 1);
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	default:
 | 
			
		||||
		/* ERROR */
 | 
			
		||||
		DEBUGLOG("Got unknown event callback message: %d\n", reason);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct local_client *cman_client;
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/* Save this for data_callback */
 | 
			
		||||
	cman_client = fd;
 | 
			
		||||
 | 
			
		||||
	/* We never return a new client */
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
 | 
			
		||||
	return cman_dispatch(c_handle, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void data_callback(cman_handle_t handle, void *private,
 | 
			
		||||
			  char *buf, int len, uint8_t port, int nodeid)
 | 
			
		||||
{
 | 
			
		||||
	/* Ignore looped back messages */
 | 
			
		||||
	if (nodeid == this_node.cn_nodeid)
 | 
			
		||||
		return;
 | 
			
		||||
	process_message(cman_client, buf, len, (char *)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	/* It's up ! */
 | 
			
		||||
	int nodeid = nodeid_from_csid(csid);
 | 
			
		||||
 | 
			
		||||
	dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
 | 
			
		||||
	DEBUGLOG("Added new node %d to updown list\n", nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
	cman_finish(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_listening(int nodeid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
 | 
			
		||||
		if (status < 0 && errno == EBUSY) {	/* Don't busywait */
 | 
			
		||||
			sleep(1);
 | 
			
		||||
			errno = EBUSY;	/* In case sleep trashes it */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	while (status < 0 && errno == EBUSY);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Populate the list of CLVMDs running.
 | 
			
		||||
   called only at startup time */
 | 
			
		||||
static void count_clvmds_running(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		int nodeid = nodes[i].cn_nodeid;
 | 
			
		||||
 | 
			
		||||
		if (is_listening(nodeid) == 1)
 | 
			
		||||
			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
 | 
			
		||||
		else
 | 
			
		||||
			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get a list of active cluster members */
 | 
			
		||||
static void get_members(void)
 | 
			
		||||
{
 | 
			
		||||
	int retnodes;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
	int high_nodeid = 0;
 | 
			
		||||
 | 
			
		||||
	num_nodes = cman_get_node_count(c_handle);
 | 
			
		||||
	if (num_nodes == -1) {
 | 
			
		||||
		log_error("Unable to get node count");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Not enough room for new nodes list ? */
 | 
			
		||||
	if (num_nodes > count_nodes && nodes) {
 | 
			
		||||
		free(nodes);
 | 
			
		||||
		nodes = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (nodes == NULL) {
 | 
			
		||||
		count_nodes = num_nodes + 10; /* Overallocate a little */
 | 
			
		||||
		nodes = malloc(count_nodes * sizeof(struct cman_node));
 | 
			
		||||
		if (!nodes) {
 | 
			
		||||
			log_error("Unable to allocate nodes array\n");
 | 
			
		||||
			exit(5);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
 | 
			
		||||
	if (status < 0) {
 | 
			
		||||
		log_error("Unable to get node details");
 | 
			
		||||
		exit(6);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the highest nodeid */
 | 
			
		||||
	for (i=0; i<retnodes; i++) {
 | 
			
		||||
		if (nodes[i].cn_nodeid > high_nodeid)
 | 
			
		||||
			high_nodeid = nodes[i].cn_nodeid;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Convert a node name to a CSID */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (strcmp(name, nodes[i].cn_name) == 0) {
 | 
			
		||||
			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a CSID to a node name */
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
 | 
			
		||||
			strcpy(name, nodes[i].cn_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Who?? */
 | 
			
		||||
	strcpy(name, "Unknown");
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a node ID to a node name */
 | 
			
		||||
static int name_from_nodeid(int nodeid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (nodeid == nodes[i].cn_nodeid) {
 | 
			
		||||
			strcpy(name, nodes[i].cn_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Who?? */
 | 
			
		||||
	strcpy(name, "Unknown");
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a CSID to a node ID */
 | 
			
		||||
static int nodeid_from_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
        int nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	return nodeid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	return cman_is_quorate(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sync_ast_routine(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct lock_wait *lwait = arg;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lwait->mutex);
 | 
			
		||||
	pthread_cond_signal(&lwait->cond);
 | 
			
		||||
	pthread_mutex_unlock(&lwait->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
 | 
			
		||||
	if (!lockid) {
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
 | 
			
		||||
	/* Conversions need the lockid in the LKSB */
 | 
			
		||||
	if (flags & LKF_CONVERT)
 | 
			
		||||
		lwait.lksb.sb_lkid = *lockid;
 | 
			
		||||
 | 
			
		||||
	pthread_cond_init(&lwait.cond, NULL);
 | 
			
		||||
	pthread_mutex_init(&lwait.mutex, NULL);
 | 
			
		||||
	pthread_mutex_lock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	status = dlm_ls_lock(lockspace,
 | 
			
		||||
			     mode,
 | 
			
		||||
			     &lwait.lksb,
 | 
			
		||||
			     flags,
 | 
			
		||||
			     resource,
 | 
			
		||||
			     strlen(resource),
 | 
			
		||||
			     0, sync_ast_routine, &lwait, NULL, NULL);
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
	pthread_cond_wait(&lwait.cond, &lwait.mutex);
 | 
			
		||||
	pthread_mutex_unlock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	*lockid = lwait.lksb.sb_lkid;
 | 
			
		||||
 | 
			
		||||
	errno = lwait.lksb.sb_status;
 | 
			
		||||
	DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
 | 
			
		||||
	if (lwait.lksb.sb_status)
 | 
			
		||||
		return -1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
 | 
			
		||||
 | 
			
		||||
	pthread_cond_init(&lwait.cond, NULL);
 | 
			
		||||
	pthread_mutex_init(&lwait.mutex, NULL);
 | 
			
		||||
	pthread_mutex_lock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
 | 
			
		||||
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
	pthread_cond_wait(&lwait.cond, &lwait.mutex);
 | 
			
		||||
	pthread_mutex_unlock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	errno = lwait.lksb.sb_status;
 | 
			
		||||
	if (lwait.lksb.sb_status != EUNLOCK)
 | 
			
		||||
		return -1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	cman_cluster_t cluster_info;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	status = cman_get_cluster(c_handle, &cluster_info);
 | 
			
		||||
	if (!status) {
 | 
			
		||||
		strncpy(buf, cluster_info.ci_name, buflen);
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_cman_ops = {
 | 
			
		||||
	.name                     = "cman",
 | 
			
		||||
	.cluster_init_completed   = _cluster_init_completed,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _sync_lock,
 | 
			
		||||
	.sync_unlock              = _sync_unlock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_cman_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,414 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2011 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  CLVMD Cluster LVM daemon command processor.
 | 
			
		||||
 | 
			
		||||
  To add commands to the daemon simply add a processor in do_command and return
 | 
			
		||||
  and messages back in buf and the length in *retlen. The initial value of
 | 
			
		||||
  buflen is the maximum size of the buffer. if buf is not large enough then it
 | 
			
		||||
  may be reallocated by the functions in here to a suitable size bearing in
 | 
			
		||||
  mind that anything larger than the passed-in size will have to be returned
 | 
			
		||||
  using the system LV and so performance will suffer.
 | 
			
		||||
 | 
			
		||||
  The status return will be negated and passed back to the originating node.
 | 
			
		||||
 | 
			
		||||
  pre- and post- command routines are called only on the local node. The
 | 
			
		||||
  purpose is primarily to get and release locks, though the pre- routine should
 | 
			
		||||
  also do any other local setups required by the command (if any) and can
 | 
			
		||||
  return a failure code that prevents the command from being distributed around
 | 
			
		||||
  the cluster
 | 
			
		||||
 | 
			
		||||
  The pre- and post- routines are run in their own thread so can block as long
 | 
			
		||||
  they like, do_command is run in the main clvmd thread so should not block for
 | 
			
		||||
  too long. If the pre-command returns an error code (!=0) then the command
 | 
			
		||||
  will not be propogated around the cluster but the post-command WILL be called
 | 
			
		||||
 | 
			
		||||
  Also note that the pre and post routine are *always* called on the local
 | 
			
		||||
  node, even if the command to be executed was only requested to run on a
 | 
			
		||||
  remote node. It may peek inside the client structure to check the status of
 | 
			
		||||
  the command.
 | 
			
		||||
 | 
			
		||||
  The clients of the daemon must, naturally, understand the return messages and
 | 
			
		||||
  codes.
 | 
			
		||||
 | 
			
		||||
  Routines in here may only READ the values in the client structure passed in
 | 
			
		||||
  apart from client->private which they are free to do what they like with.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-globals.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
 | 
			
		||||
extern struct cluster_ops *clops;
 | 
			
		||||
static int restart_clvmd(void);
 | 
			
		||||
 | 
			
		||||
/* This is where all the real work happens:
 | 
			
		||||
   NOTE: client will be NULL when this is executed on a remote node */
 | 
			
		||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
 | 
			
		||||
	       char **buf, int buflen, int *retlen)
 | 
			
		||||
{
 | 
			
		||||
	char *args = msg->node + strlen(msg->node) + 1;
 | 
			
		||||
	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
	const char *locktype;
 | 
			
		||||
	struct utsname nodeinfo;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
 | 
			
		||||
	/* Do the command */
 | 
			
		||||
	switch (msg->cmd) {
 | 
			
		||||
		/* Just a test message */
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		if (arglen > buflen) {
 | 
			
		||||
			char *new_buf;
 | 
			
		||||
			buflen = arglen + 200;
 | 
			
		||||
			new_buf = realloc(*buf, buflen);
 | 
			
		||||
			if (new_buf == NULL) {
 | 
			
		||||
				status = errno;
 | 
			
		||||
				free (*buf);
 | 
			
		||||
			}
 | 
			
		||||
			*buf = new_buf;
 | 
			
		||||
		}
 | 
			
		||||
		if (*buf) {
 | 
			
		||||
			if (uname(&nodeinfo))
 | 
			
		||||
				memset(&nodeinfo, 0, sizeof(nodeinfo));
 | 
			
		||||
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen,
 | 
			
		||||
						  "TEST from %s: %s v%s",
 | 
			
		||||
						  nodeinfo.nodename, args,
 | 
			
		||||
						  nodeinfo.release);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_VG:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		/* Check to see if the VG is in use by LVM1 */
 | 
			
		||||
		status = do_check_lvm1(lockname);
 | 
			
		||||
		do_lock_vg(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		/* This is the biggie */
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = do_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		/* Replace EIO with something less scary */
 | 
			
		||||
		if (status == EIO) {
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen, "%s",
 | 
			
		||||
						  get_last_lvm_error());
 | 
			
		||||
			return EIO;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_QUERY:
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		if (buflen < 3)
 | 
			
		||||
			return EIO;
 | 
			
		||||
		if ((locktype = do_lock_query(lockname)))
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_REFRESH:
 | 
			
		||||
		do_refresh_cache();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_SYNC_NAMES:
 | 
			
		||||
		lvm_do_fs_unlock();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_SET_DEBUG:
 | 
			
		||||
		clvmd_set_debug((debug_t) args[0]);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_RESTART:
 | 
			
		||||
		status = restart_clvmd();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_GET_CLUSTERNAME:
 | 
			
		||||
		status = clops->get_cluster_name(*buf, buflen);
 | 
			
		||||
		if (!status)
 | 
			
		||||
			*retlen = strlen(*buf)+1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_VG_BACKUP:
 | 
			
		||||
		/*
 | 
			
		||||
		 * Do not run backup on local node, caller should do that.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!client)
 | 
			
		||||
			lvm_do_backup(&args[2]);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		/* Won't get here because command is validated in pre_command */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check the status of the command and return the error text */
 | 
			
		||||
	if (status) {
 | 
			
		||||
		*retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s",
 | 
			
		||||
						    strerror(status)) : -1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lock_vg(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_table *lock_hash;
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
		(struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	int lkid;
 | 
			
		||||
	int status;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Keep a track of VG locks in our own hash table. In current
 | 
			
		||||
	 * practice there should only ever be more than two VGs locked
 | 
			
		||||
	 * if a user tries to merge lots of them at once
 | 
			
		||||
	 */
 | 
			
		||||
	if (!client->bits.localsock.private) {
 | 
			
		||||
		if (!(lock_hash = dm_hash_create(3)))
 | 
			
		||||
			return ENOMEM;
 | 
			
		||||
		client->bits.localsock.private = (void *) lock_hash;
 | 
			
		||||
	} else
 | 
			
		||||
		lock_hash = (struct dm_hash_table *) client->bits.localsock.private;
 | 
			
		||||
 | 
			
		||||
	lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
 | 
			
		||||
	lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
 | 
			
		||||
	/* lock_flags = args[1]; */
 | 
			
		||||
	lockname = &args[2];
 | 
			
		||||
	DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
 | 
			
		||||
 | 
			
		||||
	if (lock_mode == LCK_UNLOCK) {
 | 
			
		||||
		if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_unlock(lockname, lkid)))
 | 
			
		||||
			status = errno;
 | 
			
		||||
		else
 | 
			
		||||
			dm_hash_remove(lock_hash, lockname);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Read locks need to be PR; other modes get passed through */
 | 
			
		||||
		if (lock_mode == LCK_READ)
 | 
			
		||||
			lock_mode = LCK_PREAD;
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid)))
 | 
			
		||||
			status = errno;
 | 
			
		||||
		else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid))
 | 
			
		||||
			return ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Pre-command is a good place to get locks that are needed only for the duration
 | 
			
		||||
   of the commands around the cluster (don't forget to free them in post-command),
 | 
			
		||||
   and to sanity check the command arguments */
 | 
			
		||||
int do_pre_command(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
	    (struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	int lockid = 0;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	switch (header->cmd) {
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
 | 
			
		||||
		client->bits.localsock.private = (void *)(long)lockid;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_VG:
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		/* We take out a real lock unless LCK_CACHE was set */
 | 
			
		||||
		if (!strncmp(lockname, "V_", 2) ||
 | 
			
		||||
		    !strncmp(lockname, "P_#", 3))
 | 
			
		||||
			status = lock_vg(client);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = pre_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_REFRESH:
 | 
			
		||||
	case CLVMD_CMD_GET_CLUSTERNAME:
 | 
			
		||||
	case CLVMD_CMD_SET_DEBUG:
 | 
			
		||||
	case CLVMD_CMD_VG_BACKUP:
 | 
			
		||||
	case CLVMD_CMD_SYNC_NAMES:
 | 
			
		||||
	case CLVMD_CMD_LOCK_QUERY:
 | 
			
		||||
	case CLVMD_CMD_RESTART:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unknown command %d received\n", header->cmd);
 | 
			
		||||
		status = EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Note that the post-command routine is called even if the pre-command or the real command
 | 
			
		||||
   failed */
 | 
			
		||||
int do_post_command(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
	    (struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	switch (header->cmd) {
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
 | 
			
		||||
		client->bits.localsock.private = NULL;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = post_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		/* Nothing to do here */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Called when the client is about to be deleted */
 | 
			
		||||
void cmd_client_cleanup(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *v;
 | 
			
		||||
	struct dm_hash_table *lock_hash;
 | 
			
		||||
	int lkid;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Client thread cleanup (%p)\n", client);
 | 
			
		||||
	if (!client->bits.localsock.private)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(v, lock_hash) {
 | 
			
		||||
		lkid = (int)(long)dm_hash_get_data(lock_hash, v);
 | 
			
		||||
		lockname = dm_hash_get_key(lock_hash, v);
 | 
			
		||||
		DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
 | 
			
		||||
		(void) sync_unlock(lockname, lkid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_hash_destroy(lock_hash);
 | 
			
		||||
	client->bits.localsock.private = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int restart_clvmd(void)
 | 
			
		||||
{
 | 
			
		||||
	const char **argv;
 | 
			
		||||
	char *lv_name;
 | 
			
		||||
	int argc = 0, max_locks = 0;
 | 
			
		||||
	struct dm_hash_node *hn = NULL;
 | 
			
		||||
	char debug_arg[16];
 | 
			
		||||
	const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("clvmd restart requested\n");
 | 
			
		||||
 | 
			
		||||
	/* Count exclusively-open LVs */
 | 
			
		||||
	do {
 | 
			
		||||
		hn = get_next_excl_lock(hn, &lv_name);
 | 
			
		||||
		if (lv_name) {
 | 
			
		||||
			max_locks++;
 | 
			
		||||
			if (!*lv_name)
 | 
			
		||||
				break; /* FIXME: Is this error ? */
 | 
			
		||||
		}
 | 
			
		||||
	} while (hn);
 | 
			
		||||
 | 
			
		||||
	/* clvmd + locks (-E uuid) + debug (-d X) + NULL */
 | 
			
		||||
	if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv))))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Build the command-line
 | 
			
		||||
	 */
 | 
			
		||||
	argv[argc++] = "clvmd";
 | 
			
		||||
 | 
			
		||||
	/* Propagate debug options */
 | 
			
		||||
	if (clvmd_get_debug()) {
 | 
			
		||||
		if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
 | 
			
		||||
			goto_out;
 | 
			
		||||
		argv[argc++] = debug_arg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Propagate foreground options */
 | 
			
		||||
	if (clvmd_get_foreground())
 | 
			
		||||
		argv[argc++] = "-f";
 | 
			
		||||
 | 
			
		||||
	argv[argc++] = "-I";
 | 
			
		||||
	argv[argc++] = clops->name;
 | 
			
		||||
 | 
			
		||||
	/* Now add the exclusively-open LVs */
 | 
			
		||||
	hn = NULL;
 | 
			
		||||
	do {
 | 
			
		||||
		hn = get_next_excl_lock(hn, &lv_name);
 | 
			
		||||
		if (lv_name) {
 | 
			
		||||
			if (!*lv_name)
 | 
			
		||||
				break; /* FIXME: Is this error ? */
 | 
			
		||||
			argv[argc++] = "-E";
 | 
			
		||||
			argv[argc++] = lv_name;
 | 
			
		||||
			DEBUGLOG("excl lock: %s\n", lv_name);
 | 
			
		||||
		}
 | 
			
		||||
	} while (hn);
 | 
			
		||||
	argv[argc] = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Exec new clvmd */
 | 
			
		||||
	DEBUGLOG("--- Restarting %s ---\n", clvmd);
 | 
			
		||||
	for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
 | 
			
		||||
 | 
			
		||||
	/* NOTE: This will fail when downgrading! */
 | 
			
		||||
	execvp(clvmd, (char **)argv);
 | 
			
		||||
out:
 | 
			
		||||
	/* We failed */
 | 
			
		||||
	DEBUGLOG("Restart of clvmd failed.\n");
 | 
			
		||||
 | 
			
		||||
	free(argv);
 | 
			
		||||
 | 
			
		||||
	return EIO;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file must be included first by every clvmd source file.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _LVM_CLVMD_COMMON_H
 | 
			
		||||
#define _LVM_CLVMD_COMMON_H
 | 
			
		||||
 | 
			
		||||
#define _REENTRANT
 | 
			
		||||
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "lvm-logging.h"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,119 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2011 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Abstraction layer for clvmd cluster communications
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVMD_COMMS_H
 | 
			
		||||
#define _CLVMD_COMMS_H
 | 
			
		||||
 | 
			
		||||
struct local_client;
 | 
			
		||||
 | 
			
		||||
struct cluster_ops {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	void (*cluster_init_completed) (void);
 | 
			
		||||
 | 
			
		||||
	int (*cluster_send_message) (const void *buf, int msglen,
 | 
			
		||||
				     const char *csid,
 | 
			
		||||
				     const char *errtext);
 | 
			
		||||
	int (*name_from_csid) (const char *csid, char *name);
 | 
			
		||||
	int (*csid_from_name) (char *csid, const char *name);
 | 
			
		||||
	int (*get_num_nodes) (void);
 | 
			
		||||
	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
 | 
			
		||||
				    const char *csid,
 | 
			
		||||
				    struct local_client **new_client);
 | 
			
		||||
	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */
 | 
			
		||||
	int (*cluster_do_node_callback) (struct local_client *client,
 | 
			
		||||
					 void (*callback) (struct local_client *,
 | 
			
		||||
							   const char *csid,
 | 
			
		||||
							   int node_up));
 | 
			
		||||
	int (*is_quorate) (void);
 | 
			
		||||
 | 
			
		||||
	void (*get_our_csid) (char *csid);
 | 
			
		||||
	void (*add_up_node) (const char *csid);
 | 
			
		||||
	void (*reread_config) (void);
 | 
			
		||||
	void (*cluster_closedown) (void);
 | 
			
		||||
 | 
			
		||||
	int (*get_cluster_name)(char *buf, int buflen);
 | 
			
		||||
 | 
			
		||||
	int (*sync_lock) (const char *resource, int mode,
 | 
			
		||||
			  int flags, int *lockid);
 | 
			
		||||
	int (*sync_unlock) (const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef USE_CMAN
 | 
			
		||||
#  include <netinet/in.h>
 | 
			
		||||
#  include "libcman.h"
 | 
			
		||||
#  define CMAN_MAX_CSID_LEN 4
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN CMAN_MAX_CSID_LEN
 | 
			
		||||
#  endif
 | 
			
		||||
#  undef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN
 | 
			
		||||
#  define CMAN_MAX_CLUSTER_MESSAGE 1500
 | 
			
		||||
#  define CLUSTER_PORT_CLVMD 11
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_OPENAIS
 | 
			
		||||
#  include <openais/saAis.h>
 | 
			
		||||
#  include <corosync/totem/totem.h>
 | 
			
		||||
#  define OPENAIS_CSID_LEN (sizeof(int))
 | 
			
		||||
#  define OPENAIS_MAX_CLUSTER_MESSAGE         MESSAGE_SIZE_MAX
 | 
			
		||||
#  define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       SA_MAX_NAME_LENGTH
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef CMAN_MAX_CLUSTER_MESSAGE
 | 
			
		||||
#    define CMAN_MAX_CLUSTER_MESSAGE          MESSAGE_SIZE_MAX
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_openais_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_COROSYNC
 | 
			
		||||
#  include <corosync/corotypes.h>
 | 
			
		||||
#  define COROSYNC_CSID_LEN (sizeof(int))
 | 
			
		||||
#  define COROSYNC_MAX_CLUSTER_MESSAGE         65535
 | 
			
		||||
#  define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       CS_MAX_NAME_LENGTH
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef CMAN_MAX_CLUSTER_MESSAGE
 | 
			
		||||
#    define CMAN_MAX_CLUSTER_MESSAGE          65535
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_corosync_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SINGLENODE
 | 
			
		||||
#  define SINGLENODE_CSID_LEN (sizeof(int))
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       64
 | 
			
		||||
#  endif
 | 
			
		||||
#  define SINGLENODE_MAX_CLUSTER_MESSAGE          65535
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_singlenode_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,658 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009-2012 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This provides the interface between clvmd and corosync/DLM as the cluster
 | 
			
		||||
 * and lock manager.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
 | 
			
		||||
#include <corosync/cpg.h>
 | 
			
		||||
#include <corosync/quorum.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COROSYNC_CONFDB_H
 | 
			
		||||
#  include <corosync/confdb.h>
 | 
			
		||||
#elif defined HAVE_COROSYNC_CMAP_H
 | 
			
		||||
#  include <corosync/cmap.h>
 | 
			
		||||
#else
 | 
			
		||||
#  error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <libdlm.h>
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
/* Timeout value for several corosync calls */
 | 
			
		||||
#define LOCKSPACE_NAME "clvmd"
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len);
 | 
			
		||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries);
 | 
			
		||||
static void _cluster_closedown(void);
 | 
			
		||||
 | 
			
		||||
/* Hash list of nodes in the cluster */
 | 
			
		||||
static struct dm_hash_table *node_hash;
 | 
			
		||||
 | 
			
		||||
/* Number of active nodes */
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static unsigned int our_nodeid;
 | 
			
		||||
 | 
			
		||||
static struct local_client *cluster_client;
 | 
			
		||||
 | 
			
		||||
/* Corosync handles */
 | 
			
		||||
static cpg_handle_t cpg_handle;
 | 
			
		||||
static quorum_handle_t quorum_handle;
 | 
			
		||||
 | 
			
		||||
/* DLM Handle */
 | 
			
		||||
static dlm_lshandle_t *lockspace;
 | 
			
		||||
 | 
			
		||||
static struct cpg_name cpg_group_name;
 | 
			
		||||
 | 
			
		||||
/* Corosync callback structs */
 | 
			
		||||
cpg_callbacks_t corosync_cpg_callbacks = {
 | 
			
		||||
	.cpg_deliver_fn =            corosync_cpg_deliver_callback,
 | 
			
		||||
	.cpg_confchg_fn =            corosync_cpg_confchg_callback,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
quorum_callbacks_t quorum_callbacks = {
 | 
			
		||||
	.quorum_notify_fn = NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node_info
 | 
			
		||||
{
 | 
			
		||||
	enum {NODE_DOWN, NODE_CLVMD} state;
 | 
			
		||||
	int nodeid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set errno to something approximating the right value and return 0 or -1 */
 | 
			
		||||
static int cs_to_errno(cs_error_t err)
 | 
			
		||||
{
 | 
			
		||||
	switch(err)
 | 
			
		||||
	{
 | 
			
		||||
	case CS_OK:
 | 
			
		||||
		return 0;
 | 
			
		||||
        case CS_ERR_LIBRARY:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_VERSION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INIT:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TIMEOUT:
 | 
			
		||||
		errno = ETIME;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TRY_AGAIN:
 | 
			
		||||
		errno = EAGAIN;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INVALID_PARAM:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_MEMORY:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_HANDLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BUSY:
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_ACCESS:
 | 
			
		||||
		errno = EPERM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NOT_EXIST:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NAME_TOO_LONG:
 | 
			
		||||
		errno = ENAMETOOLONG;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_EXIST:
 | 
			
		||||
		errno = EEXIST;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_SPACE:
 | 
			
		||||
		errno = ENOSPC;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INTERRUPT:
 | 
			
		||||
		errno = EINTR;
 | 
			
		||||
		break;
 | 
			
		||||
	case CS_ERR_NAME_NOT_FOUND:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_RESOURCES:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NOT_SUPPORTED:
 | 
			
		||||
		errno = EOPNOTSUPP;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_OPERATION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_FAILED_OPERATION:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_MESSAGE_ERROR:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_QUEUE_FULL:
 | 
			
		||||
		errno = EXFULL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_QUEUE_NOT_AVAILABLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_FLAGS:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TOO_BIG:
 | 
			
		||||
		errno = E2BIG;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_SECTIONS:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *print_corosync_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int id;
 | 
			
		||||
 | 
			
		||||
	memcpy(&id, csid, sizeof(int));
 | 
			
		||||
	sprintf(buf, "%d", id);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len)
 | 
			
		||||
{
 | 
			
		||||
	int target_nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n",
 | 
			
		||||
		 our_nodeid, nodeid, target_nodeid, msg_len-4);
 | 
			
		||||
 | 
			
		||||
	if (nodeid != our_nodeid)
 | 
			
		||||
		if (target_nodeid == our_nodeid || target_nodeid == 0)
 | 
			
		||||
			process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN,
 | 
			
		||||
					msg_len-COROSYNC_CSID_LEN, (char*)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n",
 | 
			
		||||
		 joined_list_entries, left_list_entries, member_list_entries);
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<joined_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&joined_list[i].nodeid,
 | 
			
		||||
					      COROSYNC_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = joined_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						      (char *)&ninfo->nodeid,
 | 
			
		||||
						      COROSYNC_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<left_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&left_list[i].nodeid,
 | 
			
		||||
					      COROSYNC_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			ninfo->state = NODE_DOWN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_nodes = member_list_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	cs_error_t err;
 | 
			
		||||
 | 
			
		||||
#ifdef QUORUM_SET	/* corosync/quorum.h */
 | 
			
		||||
	uint32_t quorum_type;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	node_hash = dm_hash_create(100);
 | 
			
		||||
 | 
			
		||||
	err = cpg_initialize(&cpg_handle,
 | 
			
		||||
			     &corosync_cpg_callbacks);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise Corosync CPG service: %d", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef QUORUM_SET
 | 
			
		||||
	err = quorum_initialize(&quorum_handle,
 | 
			
		||||
				&quorum_callbacks,
 | 
			
		||||
				&quorum_type);
 | 
			
		||||
 | 
			
		||||
	if (quorum_type != QUORUM_SET) {
 | 
			
		||||
		syslog(LOG_ERR, "Corosync quorum service is not configured");
 | 
			
		||||
		DEBUGLOG("Corosync quorum service is not configured");
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	err = quorum_initialize(&quorum_handle,
 | 
			
		||||
				&quorum_callbacks);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise Corosync quorum service: %d", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create a lockspace for LV & VG locks to live in */
 | 
			
		||||
	lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
 | 
			
		||||
	if (!lockspace) {
 | 
			
		||||
		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
 | 
			
		||||
		if (!lockspace) {
 | 
			
		||||
			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		DEBUGLOG("Created DLM lockspace for CLVMD.\n");
 | 
			
		||||
	} else
 | 
			
		||||
		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
 | 
			
		||||
 | 
			
		||||
	dlm_ls_pthread_init(lockspace);
 | 
			
		||||
	DEBUGLOG("DLM initialisation complete\n");
 | 
			
		||||
 | 
			
		||||
	/* Connect to the clvmd group */
 | 
			
		||||
	strcpy((char *)cpg_group_name.value, "clvmd");
 | 
			
		||||
	cpg_group_name.length = strlen((char *)cpg_group_name.value);
 | 
			
		||||
	err = cpg_join(cpg_handle, &cpg_group_name);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		quorum_finalize(quorum_handle);
 | 
			
		||||
		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot join clvmd process group");
 | 
			
		||||
		DEBUGLOG("Cannot join clvmd process group: %d\n", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = cpg_local_get(cpg_handle,
 | 
			
		||||
			    &our_nodeid);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		quorum_finalize(quorum_handle);
 | 
			
		||||
		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot get local node id\n");
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Our local node id is %d\n", our_nodeid);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Connected to Corosync\n");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
	cpg_finalize(cpg_handle);
 | 
			
		||||
	quorum_finalize(quorum_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(csid, &our_nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Corosync doesn't really have nmode names so we
 | 
			
		||||
   just use the node ID in hex instead */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(name, "%x", &nodeid) == 1) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			return nodeid;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	if (!ninfo)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(name, "UNKNOWN %s", print_corosync_csid(csid));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(name, "%x", ninfo->nodeid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("num_nodes = %d\n", num_nodes);
 | 
			
		||||
	return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	if (!ninfo) {
 | 
			
		||||
		DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n",
 | 
			
		||||
			 print_corosync_csid(csid));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid);
 | 
			
		||||
 | 
			
		||||
	ninfo->state = NODE_CLVMD;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
						      const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *hn;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(hn, node_hash)
 | 
			
		||||
	{
 | 
			
		||||
		char csid[COROSYNC_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
		ninfo = dm_hash_get_data(node_hash, hn);
 | 
			
		||||
		memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
 | 
			
		||||
			 ninfo->state);
 | 
			
		||||
 | 
			
		||||
		if (ninfo->state == NODE_CLVMD)
 | 
			
		||||
			callback(master_client, csid, 1);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
 | 
			
		||||
 | 
			
		||||
	if (flags & LKF_CONVERT)
 | 
			
		||||
		lksb.sb_lkid = *lockid;
 | 
			
		||||
 | 
			
		||||
	err = dlm_ls_lock_wait(lockspace,
 | 
			
		||||
			       mode,
 | 
			
		||||
			       &lksb,
 | 
			
		||||
			       flags,
 | 
			
		||||
			       resource,
 | 
			
		||||
			       strlen(resource),
 | 
			
		||||
			       0,
 | 
			
		||||
			       NULL, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	if (err != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_lock returned %d\n", errno);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	if (lksb.sb_status != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status);
 | 
			
		||||
		errno = lksb.sb_status;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid);
 | 
			
		||||
 | 
			
		||||
	*lockid = lksb.sb_lkid;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
 | 
			
		||||
	lksb.sb_lkid = lockid;
 | 
			
		||||
 | 
			
		||||
	err = dlm_ls_unlock_wait(lockspace,
 | 
			
		||||
				 lockid,
 | 
			
		||||
				 0,
 | 
			
		||||
				 &lksb);
 | 
			
		||||
	if (err != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("Unlock returned %d\n", err);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	if (lksb.sb_status != EUNLOCK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status);
 | 
			
		||||
		errno = lksb.sb_status;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	int quorate;
 | 
			
		||||
	if (quorum_getquorate(quorum_handle, &quorate) == CS_OK)
 | 
			
		||||
		return quorate;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	cpg_fd_get(cpg_handle, &select_fd);
 | 
			
		||||
	return select_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	cluster_client = fd;
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	cpg_dispatch(cpg_handle, CS_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
	cs_error_t err;
 | 
			
		||||
	int target_node;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&target_node, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	else
 | 
			
		||||
		target_node = 0;
 | 
			
		||||
 | 
			
		||||
	iov[0].iov_base = &target_node;
 | 
			
		||||
	iov[0].iov_len = sizeof(int);
 | 
			
		||||
	iov[1].iov_base = (char *)buf;
 | 
			
		||||
	iov[1].iov_len = msglen;
 | 
			
		||||
 | 
			
		||||
	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
 | 
			
		||||
	return cs_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COROSYNC_CONFDB_H
 | 
			
		||||
/*
 | 
			
		||||
 * We are not necessarily connected to a Red Hat Cluster system,
 | 
			
		||||
 * but if we are, this returns the cluster name from cluster.conf.
 | 
			
		||||
 * I've used confdb rather than ccs to reduce the inter-package
 | 
			
		||||
 * dependancies as well as to allow people to set a cluster name
 | 
			
		||||
 * for themselves even if they are not running on RH cluster.
 | 
			
		||||
 */
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	confdb_handle_t handle;
 | 
			
		||||
	int result;
 | 
			
		||||
	size_t namelen = buflen;
 | 
			
		||||
	hdb_handle_t cluster_handle;
 | 
			
		||||
	confdb_callbacks_t callbacks = {
 | 
			
		||||
		.confdb_key_change_notify_fn = NULL,
 | 
			
		||||
		.confdb_object_create_change_notify_fn = NULL,
 | 
			
		||||
		.confdb_object_delete_change_notify_fn = NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* This is a default in case everything else fails */
 | 
			
		||||
	strncpy(buf, "Corosync", buflen);
 | 
			
		||||
 | 
			
		||||
	/* Look for a cluster name in confdb */
 | 
			
		||||
	result = confdb_initialize (&handle, &callbacks);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
        result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
        result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
        result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	buf[namelen] = '\0';
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	confdb_finalize(handle);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined HAVE_COROSYNC_CMAP_H
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	cmap_handle_t cmap_handle = 0;
 | 
			
		||||
	int result;
 | 
			
		||||
	char *name = NULL;
 | 
			
		||||
 | 
			
		||||
	/* This is a default in case everything else fails */
 | 
			
		||||
	strncpy(buf, "Corosync", buflen);
 | 
			
		||||
 | 
			
		||||
	/* Look for a cluster name in cmap */
 | 
			
		||||
	result = cmap_initialize(&cmap_handle);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	memset(buf, 0, buflen);
 | 
			
		||||
	strncpy(buf, name, buflen - 1);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	if (name)
 | 
			
		||||
		free(name);
 | 
			
		||||
	cmap_finalize(cmap_handle);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_corosync_ops = {
 | 
			
		||||
	.name                     = "corosync",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _lock_resource,
 | 
			
		||||
	.sync_unlock              = _unlock_resource,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_corosync_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_corosync_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,689 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2007-2009 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This provides the interface between clvmd and OpenAIS as the cluster
 | 
			
		||||
 * and lock manager.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#include <openais/saAis.h>
 | 
			
		||||
#include <openais/saLck.h>
 | 
			
		||||
 | 
			
		||||
#include <corosync/corotypes.h>
 | 
			
		||||
#include <corosync/cpg.h>
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
 | 
			
		||||
/* Timeout value for several openais calls */
 | 
			
		||||
#define TIMEOUT 10
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len);
 | 
			
		||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries);
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void);
 | 
			
		||||
 | 
			
		||||
/* Hash list of nodes in the cluster */
 | 
			
		||||
static struct dm_hash_table *node_hash;
 | 
			
		||||
 | 
			
		||||
/* For associating lock IDs & resource handles */
 | 
			
		||||
static struct dm_hash_table *lock_hash;
 | 
			
		||||
 | 
			
		||||
/* Number of active nodes */
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static unsigned int our_nodeid;
 | 
			
		||||
 | 
			
		||||
static struct local_client *cluster_client;
 | 
			
		||||
 | 
			
		||||
/* OpenAIS handles */
 | 
			
		||||
static cpg_handle_t cpg_handle;
 | 
			
		||||
static SaLckHandleT lck_handle;
 | 
			
		||||
 | 
			
		||||
static struct cpg_name cpg_group_name;
 | 
			
		||||
 | 
			
		||||
/* Openais callback structs */
 | 
			
		||||
cpg_callbacks_t openais_cpg_callbacks = {
 | 
			
		||||
	.cpg_deliver_fn =            openais_cpg_deliver_callback,
 | 
			
		||||
	.cpg_confchg_fn =            openais_cpg_confchg_callback,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node_info
 | 
			
		||||
{
 | 
			
		||||
	enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
 | 
			
		||||
	int nodeid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lock_info
 | 
			
		||||
{
 | 
			
		||||
	SaLckResourceHandleT res_handle;
 | 
			
		||||
	SaLckLockIdT         lock_id;
 | 
			
		||||
	SaNameT              lock_name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Set errno to something approximating the right value and return 0 or -1 */
 | 
			
		||||
static int ais_to_errno(SaAisErrorT err)
 | 
			
		||||
{
 | 
			
		||||
	switch(err)
 | 
			
		||||
	{
 | 
			
		||||
	case SA_AIS_OK:
 | 
			
		||||
		return 0;
 | 
			
		||||
        case SA_AIS_ERR_LIBRARY:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_VERSION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INIT:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TIMEOUT:
 | 
			
		||||
		errno = ETIME;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TRY_AGAIN:
 | 
			
		||||
		errno = EAGAIN;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INVALID_PARAM:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_MEMORY:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_HANDLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BUSY:
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_ACCESS:
 | 
			
		||||
		errno = EPERM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NOT_EXIST:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NAME_TOO_LONG:
 | 
			
		||||
		errno = ENAMETOOLONG;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_EXIST:
 | 
			
		||||
		errno = EEXIST;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_SPACE:
 | 
			
		||||
		errno = ENOSPC;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INTERRUPT:
 | 
			
		||||
		errno = EINTR;
 | 
			
		||||
		break;
 | 
			
		||||
	case SA_AIS_ERR_NAME_NOT_FOUND:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_RESOURCES:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NOT_SUPPORTED:
 | 
			
		||||
		errno = EOPNOTSUPP;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_OPERATION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_FAILED_OPERATION:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_MESSAGE_ERROR:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_QUEUE_FULL:
 | 
			
		||||
		errno = EXFULL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_FLAGS:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TOO_BIG:
 | 
			
		||||
		errno = E2BIG;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_SECTIONS:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *print_openais_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int id;
 | 
			
		||||
 | 
			
		||||
	memcpy(&id, csid, sizeof(int));
 | 
			
		||||
	sprintf(buf, "%d", id);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int add_internal_client(int fd, fd_callback_t callback)
 | 
			
		||||
{
 | 
			
		||||
	struct local_client *client;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Add_internal_client, fd = %d\n", fd);
 | 
			
		||||
 | 
			
		||||
	if (!(client = dm_zalloc(sizeof(*client)))) {
 | 
			
		||||
		DEBUGLOG("malloc failed\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client->fd = fd;
 | 
			
		||||
	client->type = CLUSTER_INTERNAL;
 | 
			
		||||
	client->callback = callback;
 | 
			
		||||
	add_client(client);
 | 
			
		||||
 | 
			
		||||
	/* Set Close-on-exec */
 | 
			
		||||
	fcntl(fd, F_SETFD, 1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len)
 | 
			
		||||
{
 | 
			
		||||
	int target_nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
 | 
			
		||||
		 our_nodeid, nodeid, target_nodeid, msg_len-4);
 | 
			
		||||
 | 
			
		||||
	if (nodeid != our_nodeid)
 | 
			
		||||
		if (target_nodeid == our_nodeid || target_nodeid == 0)
 | 
			
		||||
			process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
 | 
			
		||||
					msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
 | 
			
		||||
		 FMTsize_t " left, %" PRIsize_t " members\n",
 | 
			
		||||
		 joined_list_entries, left_list_entries, member_list_entries);
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<joined_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&joined_list[i].nodeid,
 | 
			
		||||
					      OPENAIS_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = joined_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						      (char *)&ninfo->nodeid,
 | 
			
		||||
						      OPENAIS_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<left_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&left_list[i].nodeid,
 | 
			
		||||
					      OPENAIS_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			ninfo->state = NODE_DOWN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<member_list_entries; i++) {
 | 
			
		||||
		if (member_list[i].nodeid == 0) continue;
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
				(char *)&member_list[i].nodeid,
 | 
			
		||||
				OPENAIS_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = member_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						(char *)&ninfo->nodeid,
 | 
			
		||||
						OPENAIS_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_nodes = member_list_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
 | 
			
		||||
			const char *csid, struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	saLckDispatch(lck_handle, SA_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	SaVersionT  ver = { 'B', 1, 1 };
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	node_hash = dm_hash_create(100);
 | 
			
		||||
	lock_hash = dm_hash_create(10);
 | 
			
		||||
 | 
			
		||||
	err = cpg_initialize(&cpg_handle,
 | 
			
		||||
			     &openais_cpg_callbacks);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = saLckInitialize(&lck_handle,
 | 
			
		||||
					NULL,
 | 
			
		||||
			      &ver);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_initialize(&cpg_handle, &openais_cpg_callbacks);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Connect to the clvmd group */
 | 
			
		||||
	strcpy((char *)cpg_group_name.value, "clvmd");
 | 
			
		||||
	cpg_group_name.length = strlen((char *)cpg_group_name.value);
 | 
			
		||||
	err = cpg_join(cpg_handle, &cpg_group_name);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		saLckFinalize(lck_handle);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot join clvmd process group");
 | 
			
		||||
		DEBUGLOG("Cannot join clvmd process group: %d\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = cpg_local_get(cpg_handle,
 | 
			
		||||
			    &our_nodeid);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		saLckFinalize(lck_handle);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot get local node id\n");
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Our local node id is %d\n", our_nodeid);
 | 
			
		||||
 | 
			
		||||
	saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
 | 
			
		||||
	add_internal_client(select_fd, lck_dispatch);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Connected to OpenAIS\n");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	saLckFinalize(lck_handle);
 | 
			
		||||
	cpg_finalize(cpg_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(csid, &our_nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* OpenAIS doesn't really have nmode names so we
 | 
			
		||||
   just use the node ID in hex instead */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(name, "%x", &nodeid) == 1) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			return nodeid;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	if (!ninfo)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(name, "UNKNOWN %s", print_openais_csid(csid));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(name, "%x", ninfo->nodeid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes()
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("num_nodes = %d\n", num_nodes);
 | 
			
		||||
	return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	if (!ninfo) {
 | 
			
		||||
		DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
 | 
			
		||||
			 print_openais_csid(csid));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
 | 
			
		||||
 | 
			
		||||
	ninfo->state = NODE_CLVMD;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
						      const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *hn;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
	int somedown = 0;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(hn, node_hash)
 | 
			
		||||
	{
 | 
			
		||||
		char csid[OPENAIS_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
		ninfo = dm_hash_get_data(node_hash, hn);
 | 
			
		||||
		memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
 | 
			
		||||
			 ninfo->state);
 | 
			
		||||
 | 
			
		||||
		if (ninfo->state != NODE_DOWN)
 | 
			
		||||
			callback(master_client, csid, ninfo->state == NODE_CLVMD);
 | 
			
		||||
		if (ninfo->state != NODE_CLVMD)
 | 
			
		||||
			somedown = -1;
 | 
			
		||||
	}
 | 
			
		||||
	return somedown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct lock_info *linfo;
 | 
			
		||||
	SaLckResourceHandleT res_handle;
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	SaLckLockIdT lock_id;
 | 
			
		||||
	SaLckLockStatusT lockStatus;
 | 
			
		||||
 | 
			
		||||
	/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
 | 
			
		||||
	if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
 | 
			
		||||
 | 
			
		||||
	linfo = malloc(sizeof(struct lock_info));
 | 
			
		||||
	if (!linfo)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
 | 
			
		||||
 | 
			
		||||
	linfo->lock_name.length = strlen(resource)+1;
 | 
			
		||||
	strcpy((char *)linfo->lock_name.value, resource);
 | 
			
		||||
 | 
			
		||||
	err = saLckResourceOpen(lck_handle, &linfo->lock_name,
 | 
			
		||||
				SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
 | 
			
		||||
	if (err != SA_AIS_OK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("ResourceOpen returned %d\n", err);
 | 
			
		||||
		free(linfo);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = saLckResourceLock(
 | 
			
		||||
			res_handle,
 | 
			
		||||
			&lock_id,
 | 
			
		||||
			mode,
 | 
			
		||||
			flags,
 | 
			
		||||
			0,
 | 
			
		||||
			SA_TIME_END,
 | 
			
		||||
			&lockStatus);
 | 
			
		||||
	if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED)
 | 
			
		||||
	{
 | 
			
		||||
		free(linfo);
 | 
			
		||||
		saLckResourceClose(res_handle);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
 | 
			
		||||
		 err, lock_id);
 | 
			
		||||
 | 
			
		||||
	linfo->lock_id = lock_id;
 | 
			
		||||
	linfo->res_handle = res_handle;
 | 
			
		||||
 | 
			
		||||
	dm_hash_insert(lock_hash, resource, linfo);
 | 
			
		||||
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	struct lock_info *linfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource %s\n", resource);
 | 
			
		||||
	linfo = dm_hash_lookup(lock_hash, resource);
 | 
			
		||||
	if (!linfo)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
 | 
			
		||||
	err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
 | 
			
		||||
	if (err != SA_AIS_OK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("Unlock returned %d\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Release the resource */
 | 
			
		||||
	dm_hash_remove(lock_hash, resource);
 | 
			
		||||
	saLckResourceClose(linfo->res_handle);
 | 
			
		||||
	free(linfo);
 | 
			
		||||
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	char lock1[strlen(resource)+3];
 | 
			
		||||
	char lock2[strlen(resource)+3];
 | 
			
		||||
 | 
			
		||||
	snprintf(lock1, sizeof(lock1), "%s-1", resource);
 | 
			
		||||
	snprintf(lock2, sizeof(lock2), "%s-2", resource);
 | 
			
		||||
 | 
			
		||||
	switch (mode)
 | 
			
		||||
	{
 | 
			
		||||
	case LCK_EXCL:
 | 
			
		||||
		status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		/* If we can't get this lock too then bail out */
 | 
			
		||||
		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
 | 
			
		||||
					lockid);
 | 
			
		||||
		if (status == SA_LCK_LOCK_NOT_QUEUED)
 | 
			
		||||
		{
 | 
			
		||||
			_unlock_resource(lock1, *lockid);
 | 
			
		||||
			status = -1;
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_PREAD:
 | 
			
		||||
	case LCK_READ:
 | 
			
		||||
		status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
		_unlock_resource(lock2, *lockid);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_WRITE:
 | 
			
		||||
		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
		_unlock_resource(lock1, *lockid);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		status = -1;
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	*lockid = mode;
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_unlock(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char lock1[strlen(resource)+3];
 | 
			
		||||
	char lock2[strlen(resource)+3];
 | 
			
		||||
 | 
			
		||||
	snprintf(lock1, sizeof(lock1), "%s-1", resource);
 | 
			
		||||
	snprintf(lock2, sizeof(lock2), "%s-2", resource);
 | 
			
		||||
 | 
			
		||||
	_unlock_resource(lock1, lockid);
 | 
			
		||||
	_unlock_resource(lock2, lockid);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We are always quorate ! */
 | 
			
		||||
static int _is_quorate()
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	cpg_fd_get(cpg_handle, &select_fd);
 | 
			
		||||
	return select_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	cluster_client = fd;
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	int target_node;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&target_node, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	else
 | 
			
		||||
		target_node = 0;
 | 
			
		||||
 | 
			
		||||
	iov[0].iov_base = &target_node;
 | 
			
		||||
	iov[0].iov_len = sizeof(int);
 | 
			
		||||
	iov[1].iov_base = (char *)buf;
 | 
			
		||||
	iov[1].iov_len = msglen;
 | 
			
		||||
 | 
			
		||||
	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We don't have a cluster name to report here */
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	strncpy(buf, "OpenAIS", buflen);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_openais_ops = {
 | 
			
		||||
	.name                     = "openais",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _sync_lock,
 | 
			
		||||
	.sync_unlock              = _sync_unlock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_openais_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_openais_ops;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,382 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009-2013 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 "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
 | 
			
		||||
static int listen_fd = -1;
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_table *_locks;
 | 
			
		||||
static int _lockid;
 | 
			
		||||
 | 
			
		||||
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
/* Using one common condition for all locks for simplicity */
 | 
			
		||||
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
struct lock {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	int lockid;
 | 
			
		||||
	int mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void close_comms(void)
 | 
			
		||||
{
 | 
			
		||||
	if (listen_fd != -1 && close(listen_fd))
 | 
			
		||||
		stack;
 | 
			
		||||
	(void)unlink(SINGLENODE_CLVMD_SOCKNAME);
 | 
			
		||||
	listen_fd = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int init_comms(void)
 | 
			
		||||
{
 | 
			
		||||
	mode_t old_mask;
 | 
			
		||||
	struct sockaddr_un addr = { .sun_family = AF_UNIX };
 | 
			
		||||
 | 
			
		||||
	if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
 | 
			
		||||
			sizeof(addr.sun_path))) {
 | 
			
		||||
		DEBUGLOG("%s: singlenode socket name too long.",
 | 
			
		||||
			 SINGLENODE_CLVMD_SOCKNAME);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	close_comms();
 | 
			
		||||
 | 
			
		||||
	(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
 | 
			
		||||
	old_mask = umask(0077);
 | 
			
		||||
 | 
			
		||||
	listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
	if (listen_fd < 0) {
 | 
			
		||||
		DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	/* Set Close-on-exec */
 | 
			
		||||
	if (fcntl(listen_fd, F_SETFD, 1)) {
 | 
			
		||||
		DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
 | 
			
		||||
		DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	if (listen(listen_fd, 10) < 0) {
 | 
			
		||||
		DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	umask(old_mask);
 | 
			
		||||
	(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
error:
 | 
			
		||||
	umask(old_mask);
 | 
			
		||||
	(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
	close_comms();
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!(_locks = dm_hash_create(128))) {
 | 
			
		||||
		DEBUGLOG("Failed to allocate single-node hash table.\n");
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = init_comms();
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dm_hash_destroy(_locks);
 | 
			
		||||
		_locks = NULL;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Single-node cluster initialised.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	close_comms();
 | 
			
		||||
 | 
			
		||||
	/* If there is any awaited resource, kill it softly */
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
	dm_hash_destroy(_locks);
 | 
			
		||||
	_locks = NULL;
 | 
			
		||||
	_lockid = 0;
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid = 1;
 | 
			
		||||
	memcpy(csid, &nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	strcpy(name, "SINGLENODE");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
				     const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _lock_file(const char *file, uint32_t flags);
 | 
			
		||||
 | 
			
		||||
static const char *_get_mode(int mode)
 | 
			
		||||
{
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
	case LCK_NULL: return "NULL";
 | 
			
		||||
	case LCK_READ: return "READ";
 | 
			
		||||
	case LCK_PREAD: return "PREAD";
 | 
			
		||||
	case LCK_WRITE: return "WRITE";
 | 
			
		||||
	case LCK_EXCL: return "EXCLUSIVE";
 | 
			
		||||
	case LCK_UNLOCK: return "UNLOCK";
 | 
			
		||||
	default: return "????";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	/* DLM table of allowed transition states */
 | 
			
		||||
	static const int _dlm_table[6][6] = {
 | 
			
		||||
	/* Mode	   NL	CR	CW	PR	PW	EX */
 | 
			
		||||
	/* NL */ { 1,	 1,	 1,	 1,	 1,	 1},
 | 
			
		||||
	/* CR */ { 1,	 1,	 1,	 1,	 1,	 0},
 | 
			
		||||
	/* CW */ { 1,	 1,	 1,	 0,	 0,	 0},
 | 
			
		||||
	/* PR */ { 1,	 1,	 0,	 1,	 0,	 0},
 | 
			
		||||
	/* PW */ { 1,	 1,	 0,	 0,	 0,	 0},
 | 
			
		||||
	/* EX */ { 1,	 0,	 0,	 0,	 0,	 0}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct lock *lck = NULL, *lckt;
 | 
			
		||||
	struct dm_list *head;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n",
 | 
			
		||||
		 resource, flags,
 | 
			
		||||
		 (flags & LCKF_NOQUEUE) ? "NOQUEUE" : "",
 | 
			
		||||
		 ((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) ==
 | 
			
		||||
		  (LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "",
 | 
			
		||||
		 (flags & LCKF_CONVERT) ? "CONVERT" : "",
 | 
			
		||||
		 _get_mode(mode), mode);
 | 
			
		||||
 | 
			
		||||
	mode &= LCK_TYPE_MASK;
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	if (!(head = dm_hash_lookup(_locks, resource))) {
 | 
			
		||||
		if (flags & LCKF_CONVERT) {
 | 
			
		||||
			/* In real DLM, lock is identified only by lockid, resource is not used */
 | 
			
		||||
			DEBUGLOG("Unlocked resource %s cannot be converted\n", resource);
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		}
 | 
			
		||||
		/* Add new locked resource */
 | 
			
		||||
		if (!(head = dm_malloc(sizeof(struct dm_list))) ||
 | 
			
		||||
		    !dm_hash_insert(_locks, resource, head)) {
 | 
			
		||||
			dm_free(head);
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dm_list_init(head);
 | 
			
		||||
	} else	/* Update/convert locked resource */
 | 
			
		||||
		dm_list_iterate_items(lck, head) {
 | 
			
		||||
			/* Check is all locks are compatible with requested lock */
 | 
			
		||||
			if (flags & LCKF_CONVERT) {
 | 
			
		||||
				if (lck->lockid != *lockid)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n",
 | 
			
		||||
					 resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode));
 | 
			
		||||
				dm_list_iterate_items(lckt, head) {
 | 
			
		||||
					if ((lckt->lockid != *lockid) &&
 | 
			
		||||
					    !_dlm_table[mode][lckt->mode]) {
 | 
			
		||||
						if (!(flags & LCKF_NOQUEUE) &&
 | 
			
		||||
						    /* TODO: Real dlm uses here conversion queues */
 | 
			
		||||
						    !pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
 | 
			
		||||
						    _locks) /* End of the game? */
 | 
			
		||||
							goto retry;
 | 
			
		||||
						goto bad;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				lck->mode = mode; /* Lock is now converted */
 | 
			
		||||
				goto out;
 | 
			
		||||
			} else if (!_dlm_table[mode][lck->mode]) {
 | 
			
		||||
				DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n",
 | 
			
		||||
					 resource, lck->lockid, _get_mode(lck->mode));
 | 
			
		||||
				if (!(flags & LCKF_NOQUEUE) &&
 | 
			
		||||
				    !pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
 | 
			
		||||
				    _locks) { /* End of the game? */
 | 
			
		||||
					DEBUGLOG("Resource %s retrying lock in mode:%s...\n",
 | 
			
		||||
						 resource, _get_mode(mode));
 | 
			
		||||
					goto retry;
 | 
			
		||||
				}
 | 
			
		||||
				goto bad;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (!(flags & LCKF_CONVERT)) {
 | 
			
		||||
		if (!(lck = dm_malloc(sizeof(struct lock))))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
 | 
			
		||||
		*lockid = lck->lockid = ++_lockid;
 | 
			
		||||
		lck->mode = mode;
 | 
			
		||||
		dm_list_add(head, &lck->list);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
	DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
 | 
			
		||||
		 resource, lck->lockid, _get_mode(lck->mode));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
bad:
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
	DEBUGLOG("Failed to lock resource %s\n", resource);
 | 
			
		||||
 | 
			
		||||
	return 1; /* fail */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct lock *lck;
 | 
			
		||||
	struct dm_list *head;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	if (lockid < 0) {
 | 
			
		||||
		DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
 | 
			
		||||
			 resource, lockid);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
 | 
			
		||||
 | 
			
		||||
	if (!(head = dm_hash_lookup(_locks, resource))) {
 | 
			
		||||
		pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
		DEBUGLOG("Resource %s is not locked.\n", resource);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_list_iterate_items(lck, head)
 | 
			
		||||
		if (lck->lockid == lockid) {
 | 
			
		||||
			dm_list_del(&lck->list);
 | 
			
		||||
			dm_free(lck);
 | 
			
		||||
			r = 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid);
 | 
			
		||||
out:
 | 
			
		||||
	if (dm_list_empty(head)) {
 | 
			
		||||
		//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid);
 | 
			
		||||
		dm_hash_remove(_locks, resource);
 | 
			
		||||
		dm_free(head);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	return listen_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen,
 | 
			
		||||
				 const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_singlenode_ops = {
 | 
			
		||||
	.name                     = "singlenode",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _lock_resource,
 | 
			
		||||
	.sync_unlock              = _unlock_resource,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_singlenode_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_singlenode_ops;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,126 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVMD_H
 | 
			
		||||
#define _CLVMD_H
 | 
			
		||||
 | 
			
		||||
#define CLVMD_MAJOR_VERSION 0
 | 
			
		||||
#define CLVMD_MINOR_VERSION 2
 | 
			
		||||
#define CLVMD_PATCH_VERSION 1
 | 
			
		||||
 | 
			
		||||
/* Default time (in seconds) we will wait for all remote commands to execute
 | 
			
		||||
   before declaring them dead */
 | 
			
		||||
#define DEFAULT_CMD_TIMEOUT 60
 | 
			
		||||
 | 
			
		||||
/* One of these for each reply we get from command execution on a node */
 | 
			
		||||
struct node_reply {
 | 
			
		||||
	char node[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
	char *replymsg;
 | 
			
		||||
	int status;
 | 
			
		||||
	struct node_reply *next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These exist for the use of local sockets only when we are
 | 
			
		||||
 * collecting responses from all cluster nodes
 | 
			
		||||
 */
 | 
			
		||||
struct localsock_bits {
 | 
			
		||||
	struct node_reply *replies;
 | 
			
		||||
	int num_replies;
 | 
			
		||||
	int expected_replies;
 | 
			
		||||
	time_t sent_time;	/* So we can check for timeouts */
 | 
			
		||||
	int in_progress;	/* Only execute one cmd at a time per client */
 | 
			
		||||
	int sent_out;		/* Flag to indicate that a command was sent
 | 
			
		||||
				   to remote nodes */
 | 
			
		||||
	void *private;		/* Private area for command processor use */
 | 
			
		||||
	void *cmd;		/* Whole command as passed down local socket */
 | 
			
		||||
	int cmd_len;		/* Length of above */
 | 
			
		||||
	int pipe;		/* Pipe to send PRE completion status down */
 | 
			
		||||
	int finished;		/* Flag to tell subthread to exit */
 | 
			
		||||
	int all_success;	/* Set to 0 if any node (or the pre_command)
 | 
			
		||||
				   failed */
 | 
			
		||||
	int cleanup_needed;     /* helper for cleanup_zombie */
 | 
			
		||||
	struct local_client *pipe_client;
 | 
			
		||||
	pthread_t threadid;
 | 
			
		||||
	enum { PRE_COMMAND, POST_COMMAND } state;
 | 
			
		||||
	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */
 | 
			
		||||
	pthread_cond_t cond;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Entries for PIPE clients */
 | 
			
		||||
struct pipe_bits {
 | 
			
		||||
	struct local_client *client;	/* Actual (localsock) client */
 | 
			
		||||
	pthread_t threadid;		/* Our own copy of the thread id */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Entries for Network socket clients */
 | 
			
		||||
struct netsock_bits {
 | 
			
		||||
	void *private;
 | 
			
		||||
	int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
 | 
			
		||||
			      const char *csid,
 | 
			
		||||
			      struct local_client ** new_client);
 | 
			
		||||
 | 
			
		||||
/* One of these for each fd we are listening on */
 | 
			
		||||
struct local_client {
 | 
			
		||||
	int fd;
 | 
			
		||||
	enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
 | 
			
		||||
		    LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
 | 
			
		||||
	struct local_client *next;
 | 
			
		||||
	unsigned short xid;
 | 
			
		||||
	fd_callback_t callback;
 | 
			
		||||
	uint8_t removeme;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct localsock_bits localsock;
 | 
			
		||||
		struct pipe_bits pipe;
 | 
			
		||||
		struct netsock_bits net;
 | 
			
		||||
	} bits;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args)
 | 
			
		||||
 | 
			
		||||
#ifndef max
 | 
			
		||||
#define max(a,b) ((a)>(b)?(a):(b))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* The real command processor is in clvmd-command.c */
 | 
			
		||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
 | 
			
		||||
		      int msglen, char **buf, int buflen, int *retlen);
 | 
			
		||||
 | 
			
		||||
/* Pre and post command routines are called only on the local node */
 | 
			
		||||
extern int do_pre_command(struct local_client *client);
 | 
			
		||||
extern int do_post_command(struct local_client *client);
 | 
			
		||||
extern void cmd_client_cleanup(struct local_client *client);
 | 
			
		||||
extern int add_client(struct local_client *new_client);
 | 
			
		||||
 | 
			
		||||
extern void clvmd_cluster_init_completed(void);
 | 
			
		||||
extern void process_message(struct local_client *client, char *buf,
 | 
			
		||||
			    int len, const char *csid);
 | 
			
		||||
extern void debuglog(const char *fmt, ... )
 | 
			
		||||
  __attribute__ ((format(printf, 1, 2)));
 | 
			
		||||
 | 
			
		||||
void clvmd_set_debug(debug_t new_de);
 | 
			
		||||
debug_t clvmd_get_debug(void);
 | 
			
		||||
int clvmd_get_foreground(void);
 | 
			
		||||
 | 
			
		||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
 | 
			
		||||
int sync_unlock(const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,939 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2012 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
/* LVM2 headers */
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "lvm-globals.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "archiver.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
static struct cmd_context *cmd = NULL;
 | 
			
		||||
static struct dm_hash_table *lv_hash = NULL;
 | 
			
		||||
static pthread_mutex_t lv_hash_lock;
 | 
			
		||||
static pthread_mutex_t lvm_lock;
 | 
			
		||||
static char last_error[1024];
 | 
			
		||||
 | 
			
		||||
struct lv_info {
 | 
			
		||||
	int lock_id;
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *decode_full_locking_cmd(uint32_t cmdl)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	const char *type;
 | 
			
		||||
	const char *scope;
 | 
			
		||||
	const char *command;
 | 
			
		||||
 | 
			
		||||
	switch (cmdl & LCK_TYPE_MASK) {
 | 
			
		||||
	case LCK_NULL:
 | 
			
		||||
		type = "NULL";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_READ:
 | 
			
		||||
		type = "READ";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_PREAD:
 | 
			
		||||
		type = "PREAD";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_WRITE:
 | 
			
		||||
		type = "WRITE";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_EXCL:
 | 
			
		||||
		type = "EXCL";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_UNLOCK:
 | 
			
		||||
		type = "UNLOCK";
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		type = "unknown";
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (cmdl & LCK_SCOPE_MASK) {
 | 
			
		||||
	case LCK_VG:
 | 
			
		||||
		scope = "VG";
 | 
			
		||||
		command = "LCK_VG";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_LV:
 | 
			
		||||
		scope = "LV";
 | 
			
		||||
		switch (cmdl & LCK_MASK) {
 | 
			
		||||
		case LCK_LV_EXCLUSIVE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_EXCLUSIVE";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_SUSPEND & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_SUSPEND";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_RESUME & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_RESUME";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_ACTIVATE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_ACTIVATE";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_DEACTIVATE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_DEACTIVATE";
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			command = "unknown";
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		scope = "unknown";
 | 
			
		||||
		command = "unknown";
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
 | 
			
		||||
		cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "",
 | 
			
		||||
		cmdl & LCK_HOLD       ? "|HOLD" : "",
 | 
			
		||||
		cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
 | 
			
		||||
		cmdl & LCK_CACHE      ? "|CACHE" : "");
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Only processes 8 bits: excludes LCK_CACHE.
 | 
			
		||||
 */
 | 
			
		||||
static const char *decode_locking_cmd(unsigned char cmdl)
 | 
			
		||||
{
 | 
			
		||||
	return decode_full_locking_cmd((uint32_t) cmdl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *decode_flags(unsigned char flags)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags,
 | 
			
		||||
		flags & LCK_PARTIAL_MODE	  ? "PARTIAL_MODE|" : "",
 | 
			
		||||
		flags & LCK_MIRROR_NOSYNC_MODE	  ? "MIRROR_NOSYNC|" : "",
 | 
			
		||||
		flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
 | 
			
		||||
		flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
 | 
			
		||||
		flags & LCK_TEST_MODE ? "TEST|" : "",
 | 
			
		||||
		flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
 | 
			
		||||
		flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
 | 
			
		||||
		flags & LCK_REVERT_MODE ? "REVERT|" : "");
 | 
			
		||||
 | 
			
		||||
	if (len > 1)
 | 
			
		||||
		buf[len - 2] = ' ';
 | 
			
		||||
	else
 | 
			
		||||
		buf[0] = '\0';
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *get_last_lvm_error(void)
 | 
			
		||||
{
 | 
			
		||||
	return last_error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hash lock info helpers
 | 
			
		||||
 */
 | 
			
		||||
static struct lv_info *lookup_info(const char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	lvi = dm_hash_lookup(lv_hash, resource);
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	return lvi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int insert_info(const char *resource, struct lv_info *lvi)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	ret = dm_hash_insert(lv_hash, resource, lvi);
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void remove_info(const char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int num_open;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	dm_hash_remove(lv_hash, resource);
 | 
			
		||||
 | 
			
		||||
	/* When last lock is remove, validate there are not left opened devices */
 | 
			
		||||
	if (!dm_hash_get_first(lv_hash)) {
 | 
			
		||||
		if (critical_section())
 | 
			
		||||
			log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section.");
 | 
			
		||||
		if ((num_open = dev_cache_check_for_open_devices()))
 | 
			
		||||
			log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the mode a lock is currently held at (or -1 if not held)
 | 
			
		||||
 */
 | 
			
		||||
static int get_current_lock(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	if ((lvi = lookup_info(resource)))
 | 
			
		||||
		return lvi->lock_mode;
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void init_lvhash(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Create hash table for keeping LV locks & status */
 | 
			
		||||
	lv_hash = dm_hash_create(1024);
 | 
			
		||||
	pthread_mutex_init(&lv_hash_lock, NULL);
 | 
			
		||||
	pthread_mutex_init(&lvm_lock, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called at shutdown to tidy the lockspace */
 | 
			
		||||
void destroy_lvhash(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *v;
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
	char *resource;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(v, lv_hash) {
 | 
			
		||||
		lvi = dm_hash_get_data(lv_hash, v);
 | 
			
		||||
		resource = dm_hash_get_key(lv_hash, v);
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_unlock(resource, lvi->lock_id)))
 | 
			
		||||
			DEBUGLOG("unlock_all. unlock failed(%d): %s\n",
 | 
			
		||||
				 status,  strerror(errno));
 | 
			
		||||
		dm_free(lvi);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_hash_destroy(lv_hash);
 | 
			
		||||
	lv_hash = NULL;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Gets a real lock and keeps the info in the hash table */
 | 
			
		||||
static int hold_lock(char *resource, int mode, int flags)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	/* Mask off invalid options */
 | 
			
		||||
	flags &= LCKF_NOQUEUE | LCKF_CONVERT;
 | 
			
		||||
 | 
			
		||||
	lvi = lookup_info(resource);
 | 
			
		||||
 | 
			
		||||
	if (lvi) {
 | 
			
		||||
		if (lvi->lock_mode == mode) {
 | 
			
		||||
			DEBUGLOG("hold_lock, lock mode %d already held\n",
 | 
			
		||||
				 mode);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
 | 
			
		||||
			DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
 | 
			
		||||
				 "ignoring LCK_WRITE request\n");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Only allow explicit conversions */
 | 
			
		||||
	if (lvi && !(flags & LCKF_CONVERT)) {
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (lvi) {
 | 
			
		||||
		/* Already exists - convert it */
 | 
			
		||||
		status = sync_lock(resource, mode, flags, &lvi->lock_id);
 | 
			
		||||
		saved_errno = errno;
 | 
			
		||||
		if (!status)
 | 
			
		||||
			lvi->lock_mode = mode;
 | 
			
		||||
		else
 | 
			
		||||
			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
 | 
			
		||||
				 strerror(errno));
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(lvi = dm_malloc(sizeof(struct lv_info)))) {
 | 
			
		||||
			errno = ENOMEM;
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lvi->lock_mode = mode;
 | 
			
		||||
		lvi->lock_id = 0;
 | 
			
		||||
		status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
 | 
			
		||||
		saved_errno = errno;
 | 
			
		||||
		if (status) {
 | 
			
		||||
			dm_free(lvi);
 | 
			
		||||
			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
 | 
			
		||||
				 strerror(errno));
 | 
			
		||||
		} else
 | 
			
		||||
			if (!insert_info(resource, lvi)) {
 | 
			
		||||
				errno = ENOMEM;
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Unlock and remove it from the hash table */
 | 
			
		||||
static int hold_unlock(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
	int status;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
 | 
			
		||||
	if (!(lvi = lookup_info(resource))) {
 | 
			
		||||
		DEBUGLOG("hold_unlock, lock not already held\n");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = sync_unlock(resource, lvi->lock_id);
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	if (!status) {
 | 
			
		||||
		remove_info(resource);
 | 
			
		||||
		dm_free(lvi);
 | 
			
		||||
	} else {
 | 
			
		||||
		DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
 | 
			
		||||
			 strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Watch the return codes here.
 | 
			
		||||
   liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
 | 
			
		||||
   libdlm API functions return 0 for success, -1 for failure and do set errno.
 | 
			
		||||
   These functions here return 0 for success or >0 for failure (where the retcode is errno)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* Activate LV exclusive or non-exclusive */
 | 
			
		||||
static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	int status;
 | 
			
		||||
	int activate_lv;
 | 
			
		||||
	int exclusive = 0;
 | 
			
		||||
	struct lvinfo lvi;
 | 
			
		||||
 | 
			
		||||
	/* Is it already open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
 | 
			
		||||
		return 0;	/* Nothing to do */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Does the config file want us to activate this LV ? */
 | 
			
		||||
	if (!lv_activation_filter(cmd, resource, &activate_lv, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	if (!activate_lv)
 | 
			
		||||
		return 0;	/* Success, we did nothing! */
 | 
			
		||||
 | 
			
		||||
	/* Do we need to activate exclusively? */
 | 
			
		||||
	if ((activate_lv == 2) || (mode == LCK_EXCL)) {
 | 
			
		||||
		exclusive = 1;
 | 
			
		||||
		mode = LCK_EXCL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try to get the lock if it's a clustered volume group.
 | 
			
		||||
	 * Use lock conversion only if requested, to prevent implicit conversion
 | 
			
		||||
	 * of exclusive lock to shared one during activation.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!test_mode() && command & LCK_CLUSTER_VG) {
 | 
			
		||||
		status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
 | 
			
		||||
		if (status) {
 | 
			
		||||
			/* Return an LVM-sensible error for this.
 | 
			
		||||
			 * Forcing EIO makes the upper level return this text
 | 
			
		||||
			 * rather than the strerror text for EAGAIN.
 | 
			
		||||
			 */
 | 
			
		||||
			if (errno == EAGAIN) {
 | 
			
		||||
				sprintf(last_error, "Volume is busy on another node");
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
			}
 | 
			
		||||
			return errno;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If it's suspended then resume it */
 | 
			
		||||
	if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (lvi.suspended) {
 | 
			
		||||
		critical_section_inc(cmd, "resuming");
 | 
			
		||||
		if (!lv_resume(cmd, resource, 0, NULL)) {
 | 
			
		||||
			critical_section_dec(cmd, "resumed");
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Now activate it */
 | 
			
		||||
	if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	if (!test_mode() && (oldmode == -1 || oldmode != mode))
 | 
			
		||||
		(void)hold_unlock(resource);
 | 
			
		||||
	return EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Resume the LV if it was active */
 | 
			
		||||
static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode, origin_only, exclusive, revert;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_resume_lv, lock not already held\n");
 | 
			
		||||
		return 0;	/* We don't need to do anything */
 | 
			
		||||
	}
 | 
			
		||||
	origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
	exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
 | 
			
		||||
	revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Suspend the device if active */
 | 
			
		||||
static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
	unsigned exclusive;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_suspend_lv, lock not already held\n");
 | 
			
		||||
		return 0; /* Not active, so it's OK */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* Always call lv_suspend to read commited and precommited data */
 | 
			
		||||
	if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_deactivate_lock, lock not already held\n");
 | 
			
		||||
		return 0;	/* We don't need to do anything */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_deactivate(cmd, resource, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	if (!test_mode() && command & LCK_CLUSTER_VG) {
 | 
			
		||||
		status = hold_unlock(resource);
 | 
			
		||||
		if (status)
 | 
			
		||||
			return errno;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *do_lock_query(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int mode;
 | 
			
		||||
	const char *type;
 | 
			
		||||
 | 
			
		||||
	mode = get_current_lock(resource);
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
	case LCK_NULL: type = "NL"; break;
 | 
			
		||||
	case LCK_READ: type = "CR"; break;
 | 
			
		||||
	case LCK_PREAD:type = "PR"; break;
 | 
			
		||||
	case LCK_WRITE:type = "PW"; break;
 | 
			
		||||
	case LCK_EXCL: type = "EX"; break;
 | 
			
		||||
	default: type = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--");
 | 
			
		||||
 | 
			
		||||
	return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
 | 
			
		||||
   it is responsible for the interaction with device-mapper and LVM */
 | 
			
		||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int status = 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
 | 
			
		||||
		 resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
 | 
			
		||||
 | 
			
		||||
	if (!cmd->initialized.config || config_files_changed(cmd)) {
 | 
			
		||||
		/* Reinitialise various settings inc. logging, filters */
 | 
			
		||||
		if (do_refresh_cache()) {
 | 
			
		||||
			log_error("Updated config file invalid. Aborting.");
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 | 
			
		||||
		init_mirror_in_sync(1);
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
 | 
			
		||||
		init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
 | 
			
		||||
	else {
 | 
			
		||||
		if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
 | 
			
		||||
			init_dmeventd_monitor(1);
 | 
			
		||||
		else
 | 
			
		||||
			init_dmeventd_monitor(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* clvmd should never try to read suspended device */
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	switch (command & LCK_MASK) {
 | 
			
		||||
	case LCK_LV_EXCLUSIVE:
 | 
			
		||||
		status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_SUSPEND:
 | 
			
		||||
		status = do_suspend_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_UNLOCK:
 | 
			
		||||
	case LCK_LV_RESUME:	/* if active */
 | 
			
		||||
		status = do_resume_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_ACTIVATE:
 | 
			
		||||
		status = do_activate_lv(resource, command, lock_flags, LCK_READ);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_DEACTIVATE:
 | 
			
		||||
		status = do_deactivate_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		DEBUGLOG("Invalid LV command 0x%x\n", command);
 | 
			
		||||
		status = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 | 
			
		||||
		init_mirror_in_sync(0);
 | 
			
		||||
 | 
			
		||||
	cmd->partial_activation = 0;
 | 
			
		||||
 | 
			
		||||
	/* clean the pool for another command */
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
	init_test(0);
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
 | 
			
		||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
 | 
			
		||||
	   lock out on this node (because we are the node modifying the metadata)
 | 
			
		||||
	   before suspending cluster-wide.
 | 
			
		||||
	   LCKF_CONVERT is used always, local node is going to modify metadata
 | 
			
		||||
	 */
 | 
			
		||||
	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
 | 
			
		||||
	    (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
 | 
			
		||||
			 resource, decode_locking_cmd(command), decode_flags(lock_flags));
 | 
			
		||||
 | 
			
		||||
		if (!(lock_flags & LCK_TEST_MODE) &&
 | 
			
		||||
		    hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT))
 | 
			
		||||
			return errno;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
 | 
			
		||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
 | 
			
		||||
		 char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* Opposite of above, done on resume after a metadata update */
 | 
			
		||||
	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
 | 
			
		||||
	    (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		int oldmode;
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n",
 | 
			
		||||
			 resource, decode_locking_cmd(command), decode_flags(lock_flags));
 | 
			
		||||
 | 
			
		||||
		/* If the lock state is PW then restore it to what it was */
 | 
			
		||||
		oldmode = get_current_lock(resource);
 | 
			
		||||
		if (oldmode == LCK_WRITE) {
 | 
			
		||||
			struct lvinfo lvi;
 | 
			
		||||
 | 
			
		||||
			pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
			status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0);
 | 
			
		||||
			pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
			if (!status)
 | 
			
		||||
				return EIO;
 | 
			
		||||
 | 
			
		||||
			if (!(lock_flags & LCK_TEST_MODE)) {
 | 
			
		||||
				if (lvi.exists) {
 | 
			
		||||
					if (hold_lock(resource, LCK_READ, LCKF_CONVERT))
 | 
			
		||||
						return errno;
 | 
			
		||||
				} else if (hold_unlock(resource))
 | 
			
		||||
					return errno;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check if a VG is in use by LVM1 so we don't stomp on it */
 | 
			
		||||
int do_check_lvm1(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	status = check_lvm1_vg_inactive(cmd, vgname);
 | 
			
		||||
 | 
			
		||||
	return status == 1 ? 0 : EBUSY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int do_refresh_cache(void)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("Refreshing context\n");
 | 
			
		||||
	log_notice("Refreshing context");
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	if (!refresh_toolcontext(cmd)) {
 | 
			
		||||
		pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init_full_scan_done(0);
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
	lvmcache_force_next_label_scan();
 | 
			
		||||
	lvmcache_label_scan(cmd);
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Handle VG lock - drop metadata or update lvmcache state
 | 
			
		||||
 */
 | 
			
		||||
void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t lock_cmd = command;
 | 
			
		||||
	char *vgname = resource + 2;
 | 
			
		||||
 | 
			
		||||
	lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check if LCK_CACHE should be set. All P_ locks except # are cache related.
 | 
			
		||||
	 */
 | 
			
		||||
	if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
 | 
			
		||||
		lock_cmd |= LCK_CACHE;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
 | 
			
		||||
		 resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
 | 
			
		||||
 | 
			
		||||
	/* P_#global causes a full cache refresh */
 | 
			
		||||
	if (!strcmp(resource, "P_" VG_GLOBAL)) {
 | 
			
		||||
		do_refresh_cache();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	switch (lock_cmd) {
 | 
			
		||||
		case LCK_VG_COMMIT:
 | 
			
		||||
			DEBUGLOG("vg_commit notification for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_commit_metadata(vgname);
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_VG_REVERT:
 | 
			
		||||
			DEBUGLOG("vg_revert notification for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_drop_metadata(vgname, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_VG_DROP_CACHE:
 | 
			
		||||
		default:
 | 
			
		||||
			DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_drop_metadata(vgname, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init_test(0);
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Ideally, clvmd should be started before any LVs are active
 | 
			
		||||
 * but this may not be the case...
 | 
			
		||||
 * I suppose this also comes in handy if clvmd crashes, not that it would!
 | 
			
		||||
 */
 | 
			
		||||
static int get_initial_state(struct dm_hash_table *excl_uuid)
 | 
			
		||||
{
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
	char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */
 | 
			
		||||
	char uuid[65];
 | 
			
		||||
	char line[255];
 | 
			
		||||
	char *lvs_cmd;
 | 
			
		||||
	const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
 | 
			
		||||
	FILE *lvs;
 | 
			
		||||
 | 
			
		||||
	if (dm_asprintf(&lvs_cmd, "%s lvs  --config 'log{command_names=0 prefix=\"\"}' "
 | 
			
		||||
			"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
 | 
			
		||||
			lvm_binary) < 0)
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
 | 
			
		||||
	if (!(lvs = popen(lvs_cmd, "r"))) {
 | 
			
		||||
		dm_free(lvs_cmd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (fgets(line, sizeof(line), lvs)) {
 | 
			
		||||
	        if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
 | 
			
		||||
 | 
			
		||||
			/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
 | 
			
		||||
		        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */
 | 
			
		||||
			    (flags[4] == 'a' || flags[4] == 's') &&	/* is it active or suspended? */
 | 
			
		||||
			    vg_flags[5] == 'c') {			/* is it clustered ? */
 | 
			
		||||
				/* Convert hyphen-separated UUIDs into one */
 | 
			
		||||
				memcpy(&uuid[0], &vg[0], 6);
 | 
			
		||||
				memcpy(&uuid[6], &vg[7], 4);
 | 
			
		||||
				memcpy(&uuid[10], &vg[12], 4);
 | 
			
		||||
				memcpy(&uuid[14], &vg[17], 4);
 | 
			
		||||
				memcpy(&uuid[18], &vg[22], 4);
 | 
			
		||||
				memcpy(&uuid[22], &vg[27], 4);
 | 
			
		||||
				memcpy(&uuid[26], &vg[32], 6);
 | 
			
		||||
				memcpy(&uuid[32], &lv[0], 6);
 | 
			
		||||
				memcpy(&uuid[38], &lv[7], 4);
 | 
			
		||||
				memcpy(&uuid[42], &lv[12], 4);
 | 
			
		||||
				memcpy(&uuid[46], &lv[17], 4);
 | 
			
		||||
				memcpy(&uuid[50], &lv[22], 4);
 | 
			
		||||
				memcpy(&uuid[54], &lv[27], 4);
 | 
			
		||||
				memcpy(&uuid[58], &lv[32], 6);
 | 
			
		||||
				uuid[64] = '\0';
 | 
			
		||||
 | 
			
		||||
				/* Look for this lock in the list of EX locks
 | 
			
		||||
				   we were passed on the command-line */
 | 
			
		||||
				lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
 | 
			
		||||
					LCK_EXCL : LCK_READ;
 | 
			
		||||
 | 
			
		||||
				DEBUGLOG("getting initial lock for %s\n", uuid);
 | 
			
		||||
				if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
 | 
			
		||||
					DEBUGLOG("Failed to hold lock %s\n", uuid);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (pclose(lvs))
 | 
			
		||||
		DEBUGLOG("lvs pclose failed: %s\n", strerror(errno));
 | 
			
		||||
 | 
			
		||||
	dm_free(lvs_cmd);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
 | 
			
		||||
			const char *message)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/* Send messages to the normal LVM2 logging system too,
 | 
			
		||||
	   so we get debug output when it's asked for.
 | 
			
		||||
 	   We need to NULL the function ptr otherwise it will just call
 | 
			
		||||
	   back into here! */
 | 
			
		||||
	init_log_fn(NULL);
 | 
			
		||||
	print_log(level, file, line, dm_errno, "%s", message);
 | 
			
		||||
	init_log_fn(lvm2_log_fn);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Ignore non-error messages, but store the latest one for returning
 | 
			
		||||
	 * to the user.
 | 
			
		||||
	 */
 | 
			
		||||
	if (level != _LOG_ERR && level != _LOG_FATAL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	strncpy(last_error, message, sizeof(last_error));
 | 
			
		||||
	last_error[sizeof(last_error)-1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This checks some basic cluster-LVM configuration stuff */
 | 
			
		||||
static void check_config(void)
 | 
			
		||||
{
 | 
			
		||||
	int locking_type;
 | 
			
		||||
 | 
			
		||||
	locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
 | 
			
		||||
 | 
			
		||||
	if (locking_type == 3) /* compiled-in cluster support */
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (locking_type == 2) { /* External library, check name */
 | 
			
		||||
		const char *libname;
 | 
			
		||||
 | 
			
		||||
		libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL);
 | 
			
		||||
		if (libname && strstr(libname, "liblvm2clusterlock.so"))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Backups up the LVM metadata if it's changed */
 | 
			
		||||
void lvm_do_backup(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct volume_group * vg;
 | 
			
		||||
	int consistent = 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, WARN_PV_READ, &consistent);
 | 
			
		||||
 | 
			
		||||
	if (vg && consistent)
 | 
			
		||||
		check_current_backup(vg);
 | 
			
		||||
	else
 | 
			
		||||
		log_error("Error backing up metadata, can't find VG for group %s", vgname);
 | 
			
		||||
 | 
			
		||||
	release_vg(vg);
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	*name = NULL;
 | 
			
		||||
	if (!v)
 | 
			
		||||
		v = dm_hash_get_first(lv_hash);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		if (v) {
 | 
			
		||||
			lvi = dm_hash_get_data(lv_hash, v);
 | 
			
		||||
			DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode);
 | 
			
		||||
 | 
			
		||||
			if (lvi->lock_mode == LCK_EXCL) {
 | 
			
		||||
				*name = dm_hash_get_key(lv_hash, v);
 | 
			
		||||
			}
 | 
			
		||||
			v = dm_hash_get_next(lv_hash, v);
 | 
			
		||||
		}
 | 
			
		||||
	} while (v && !*name);
 | 
			
		||||
 | 
			
		||||
	if (*name)
 | 
			
		||||
		DEBUGLOG("returning EXclusive UUID %s\n", *name);
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvm_do_fs_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	DEBUGLOG("Syncing device names\n");
 | 
			
		||||
	fs_unlock();
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called to initialise the LVM context of the daemon */
 | 
			
		||||
int init_clvm(struct dm_hash_table *excl_uuid)
 | 
			
		||||
{
 | 
			
		||||
	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
 | 
			
		||||
	init_syslog(LOG_DAEMON);
 | 
			
		||||
	openlog("clvmd", LOG_PID, LOG_DAEMON);
 | 
			
		||||
 | 
			
		||||
	/* Initialise already held locks */
 | 
			
		||||
	if (!get_initial_state(excl_uuid))
 | 
			
		||||
		log_error("Cannot load initial lock states.");
 | 
			
		||||
 | 
			
		||||
	if (!udev_init_library_context())
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
 | 
			
		||||
		log_error("Failed to allocate command context");
 | 
			
		||||
		udev_fin_library_context();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (stored_errno()) {
 | 
			
		||||
		destroy_toolcontext(cmd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd->cmd_line = "clvmd";
 | 
			
		||||
 | 
			
		||||
	/* Check lvm.conf is setup for cluster-LVM */
 | 
			
		||||
	check_config();
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	/* Trap log messages so we can pass them back to the user */
 | 
			
		||||
	init_log_fn(lvm2_log_fn);
 | 
			
		||||
	memlock_inc_daemon(cmd);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_lvm(void)
 | 
			
		||||
{
 | 
			
		||||
	if (cmd) {
 | 
			
		||||
		memlock_dec_daemon(cmd);
 | 
			
		||||
		destroy_toolcontext(cmd);
 | 
			
		||||
		udev_fin_library_context();
 | 
			
		||||
		cmd = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-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 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Functions in lvm-functions.c */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_FUNCTIONS_H
 | 
			
		||||
#define _LVM_FUNCTIONS_H
 | 
			
		||||
 | 
			
		||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
		       char *resource);
 | 
			
		||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
		      char *resource);
 | 
			
		||||
extern const char *do_lock_query(char *resource);
 | 
			
		||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
			char *resource);
 | 
			
		||||
extern int do_check_lvm1(const char *vgname);
 | 
			
		||||
extern int do_refresh_cache(void);
 | 
			
		||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
 | 
			
		||||
extern void destroy_lvm(void);
 | 
			
		||||
extern void init_lvhash(void);
 | 
			
		||||
extern void destroy_lvhash(void);
 | 
			
		||||
extern void lvm_do_backup(const char *vgname);
 | 
			
		||||
extern char *get_last_lvm_error(void);
 | 
			
		||||
extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
 | 
			
		||||
		      char *resource);
 | 
			
		||||
extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
 | 
			
		||||
void lvm_do_fs_unlock(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,382 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-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 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* FIXME Remove duplicated functions from this file. */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Send a command to a running clvmd from the command-line
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "refresh_clvmd.h"
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
 | 
			
		||||
typedef struct lvm_response {
 | 
			
		||||
	char node[255];
 | 
			
		||||
	char *response;
 | 
			
		||||
	int status;
 | 
			
		||||
	int len;
 | 
			
		||||
} lvm_response_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This gets stuck at the start of memory we allocate so we
 | 
			
		||||
 * can sanity-check it at deallocation time
 | 
			
		||||
 */
 | 
			
		||||
#define LVM_SIGNATURE 0x434C564D
 | 
			
		||||
 | 
			
		||||
static int _clvmd_sock = -1;
 | 
			
		||||
 | 
			
		||||
/* Open connection to the clvm daemon */
 | 
			
		||||
static int _open_local_sock(void)
 | 
			
		||||
{
 | 
			
		||||
	int local_socket;
 | 
			
		||||
	struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
 | 
			
		||||
 | 
			
		||||
	if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
 | 
			
		||||
		fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Open local socket */
 | 
			
		||||
	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
 | 
			
		||||
		fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (connect(local_socket,(struct sockaddr *) &sockaddr,
 | 
			
		||||
		    sizeof(sockaddr))) {
 | 
			
		||||
		int saved_errno = errno;
 | 
			
		||||
 | 
			
		||||
		fprintf(stderr, "connect() failed on local socket: %s\n",
 | 
			
		||||
			  strerror(errno));
 | 
			
		||||
		if (close(local_socket))
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return local_socket;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send a request and return the status */
 | 
			
		||||
static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response)
 | 
			
		||||
{
 | 
			
		||||
	char outbuf[PIPE_BUF];
 | 
			
		||||
	struct clvm_header *outheader = (struct clvm_header *) outbuf;
 | 
			
		||||
	int len;
 | 
			
		||||
	unsigned off;
 | 
			
		||||
	int buflen;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* Send it to CLVMD */
 | 
			
		||||
 rewrite:
 | 
			
		||||
	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
 | 
			
		||||
	        if (err == -1 && errno == EINTR)
 | 
			
		||||
		        goto rewrite;
 | 
			
		||||
		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (no_response)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	/* Get the response */
 | 
			
		||||
 reread:
 | 
			
		||||
	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
 | 
			
		||||
	        if (errno == EINTR)
 | 
			
		||||
		        goto reread;
 | 
			
		||||
		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (len == 0) {
 | 
			
		||||
		fprintf(stderr, "EOF reading CLVMD");
 | 
			
		||||
		errno = ENOTCONN;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate buffer */
 | 
			
		||||
	buflen = len + outheader->arglen;
 | 
			
		||||
	*retbuf = dm_malloc(buflen);
 | 
			
		||||
	if (!*retbuf) {
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Copy the header */
 | 
			
		||||
	memcpy(*retbuf, outbuf, len);
 | 
			
		||||
	outheader = (struct clvm_header *) *retbuf;
 | 
			
		||||
 | 
			
		||||
	/* Read the returned values */
 | 
			
		||||
	off = 1;		/* we've already read the first byte */
 | 
			
		||||
	while (off <= outheader->arglen && len > 0) {
 | 
			
		||||
		len = read(_clvmd_sock, outheader->args + off,
 | 
			
		||||
			   buflen - off - offsetof(struct clvm_header, args));
 | 
			
		||||
		if (len > 0)
 | 
			
		||||
			off += len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Was it an error ? */
 | 
			
		||||
	if (outheader->status != 0) {
 | 
			
		||||
		errno = outheader->status;
 | 
			
		||||
 | 
			
		||||
		/* Only return an error here if there are no node-specific
 | 
			
		||||
		   errors present in the message that might have more detail */
 | 
			
		||||
		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
 | 
			
		||||
			fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Build the structure header and parse-out wildcard node names */
 | 
			
		||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
 | 
			
		||||
			  unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	head->cmd = cmd;
 | 
			
		||||
	head->status = 0;
 | 
			
		||||
	head->flags = 0;
 | 
			
		||||
	head->xid = 0;
 | 
			
		||||
	head->clientid = 0;
 | 
			
		||||
	if (len)
 | 
			
		||||
		/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
 | 
			
		||||
		head->arglen = len - 1;
 | 
			
		||||
	else {
 | 
			
		||||
		head->arglen = 0;
 | 
			
		||||
		*head->args = '\0';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Translate special node names.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!node || !strcmp(node, NODE_ALL))
 | 
			
		||||
		head->node[0] = '\0';
 | 
			
		||||
	else if (!strcmp(node, NODE_LOCAL)) {
 | 
			
		||||
		head->node[0] = '\0';
 | 
			
		||||
		head->flags = CLVMD_FLAG_LOCAL;
 | 
			
		||||
	} else
 | 
			
		||||
		strcpy(head->node, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Send a message to a(or all) node(s) in the cluster and wait for replies
 | 
			
		||||
 */
 | 
			
		||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
 | 
			
		||||
			    lvm_response_t ** response, int *num, int no_response)
 | 
			
		||||
{
 | 
			
		||||
	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
 | 
			
		||||
	char *inptr;
 | 
			
		||||
	char *retbuf = NULL;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
	int num_responses = 0;
 | 
			
		||||
	struct clvm_header *head = (struct clvm_header *) outbuf;
 | 
			
		||||
	lvm_response_t *rarray;
 | 
			
		||||
 | 
			
		||||
	*num = 0;
 | 
			
		||||
 | 
			
		||||
	if (_clvmd_sock == -1)
 | 
			
		||||
		_clvmd_sock = _open_local_sock();
 | 
			
		||||
 | 
			
		||||
	if (_clvmd_sock == -1)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_build_header(head, cmd, node, len);
 | 
			
		||||
	if (len)
 | 
			
		||||
		memcpy(head->node + strlen(head->node) + 1, data, len);
 | 
			
		||||
 | 
			
		||||
	status = _send_request(outbuf, sizeof(struct clvm_header) +
 | 
			
		||||
			       strlen(head->node) + len, &retbuf, no_response);
 | 
			
		||||
	if (!status || no_response)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* Count the number of responses we got */
 | 
			
		||||
	head = (struct clvm_header *) retbuf;
 | 
			
		||||
	inptr = head->args;
 | 
			
		||||
	while (inptr[0]) {
 | 
			
		||||
		num_responses++;
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
		inptr += sizeof(int);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allocate response array.
 | 
			
		||||
	 * With an extra pair of INTs on the front to sanity
 | 
			
		||||
	 * check the pointer when we are given it back to free
 | 
			
		||||
	 */
 | 
			
		||||
	*response = NULL;
 | 
			
		||||
	if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses +
 | 
			
		||||
				 sizeof(int) * 2))) {
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		status = 0;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Unpack the response into an lvm_response_t array */
 | 
			
		||||
	inptr = head->args;
 | 
			
		||||
	i = 0;
 | 
			
		||||
	while (inptr[0]) {
 | 
			
		||||
		strcpy(rarray[i].node, inptr);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
 | 
			
		||||
		memcpy(&rarray[i].status, inptr, sizeof(int));
 | 
			
		||||
		inptr += sizeof(int);
 | 
			
		||||
 | 
			
		||||
		rarray[i].response = dm_malloc(strlen(inptr) + 1);
 | 
			
		||||
		if (rarray[i].response == NULL) {
 | 
			
		||||
			/* Free up everything else and return error */
 | 
			
		||||
			int j;
 | 
			
		||||
			for (j = 0; j < i; j++)
 | 
			
		||||
				dm_free(rarray[i].response);
 | 
			
		||||
			dm_free(rarray);
 | 
			
		||||
			errno = ENOMEM;
 | 
			
		||||
			status = 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strcpy(rarray[i].response, inptr);
 | 
			
		||||
		rarray[i].len = strlen(inptr);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
	*num = num_responses;
 | 
			
		||||
	*response = rarray;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	dm_free(retbuf);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Free reply array */
 | 
			
		||||
static int _cluster_free_request(lvm_response_t * response, int num)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num; i++) {
 | 
			
		||||
		dm_free(response[i].response);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_free(response);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int refresh_clvmd(int all_nodes)
 | 
			
		||||
{
 | 
			
		||||
	int num_responses;
 | 
			
		||||
	char args[1]; // No args really.
 | 
			
		||||
	lvm_response_t *response = NULL;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
 | 
			
		||||
 | 
			
		||||
	/* If any nodes were down then display them and return an error */
 | 
			
		||||
	for (i = 0; i < num_responses; i++) {
 | 
			
		||||
		if (response[i].status == EHOSTDOWN) {
 | 
			
		||||
			fprintf(stderr, "clvmd not running on node %s",
 | 
			
		||||
				  response[i].node);
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		} else if (response[i].status) {
 | 
			
		||||
			fprintf(stderr, "Error resetting node %s: %s",
 | 
			
		||||
				  response[i].node,
 | 
			
		||||
				  response[i].response[0] ?
 | 
			
		||||
				  	response[i].response :
 | 
			
		||||
				  	strerror(response[i].status));
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	_cluster_free_request(response, num_responses);
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int restart_clvmd(int all_nodes)
 | 
			
		||||
{
 | 
			
		||||
	int dummy, status;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * FIXME: we cannot receive response, clvmd re-exec before it.
 | 
			
		||||
	 *        but also should not close socket too early (the whole rq is dropped then).
 | 
			
		||||
	 * FIXME: This should be handled this way:
 | 
			
		||||
	 *  - client waits for RESTART ack (and socket close)
 | 
			
		||||
	 *  - server restarts
 | 
			
		||||
	 *  - client checks that server is ready again (VERSION command?)
 | 
			
		||||
	 */
 | 
			
		||||
	usleep(500000);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int debug_clvmd(int level, int clusterwide)
 | 
			
		||||
{
 | 
			
		||||
	int num_responses;
 | 
			
		||||
	char args[1];
 | 
			
		||||
	const char *nodes;
 | 
			
		||||
	lvm_response_t *response = NULL;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	args[0] = level;
 | 
			
		||||
	if (clusterwide)
 | 
			
		||||
		nodes = NODE_ALL;
 | 
			
		||||
	else
 | 
			
		||||
		nodes = NODE_LOCAL;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
 | 
			
		||||
 | 
			
		||||
	/* If any nodes were down then display them and return an error */
 | 
			
		||||
	for (i = 0; i < num_responses; i++) {
 | 
			
		||||
		if (response[i].status == EHOSTDOWN) {
 | 
			
		||||
			fprintf(stderr, "clvmd not running on node %s",
 | 
			
		||||
				  response[i].node);
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		} else if (response[i].status) {
 | 
			
		||||
			fprintf(stderr, "Error setting debug on node %s: %s",
 | 
			
		||||
				  response[i].node,
 | 
			
		||||
				  response[i].response[0] ?
 | 
			
		||||
				  	response[i].response :
 | 
			
		||||
				  	strerror(response[i].status));
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	_cluster_free_request(response, num_responses);
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int refresh_clvmd(int all_nodes);
 | 
			
		||||
int restart_clvmd(int all_nodes);
 | 
			
		||||
int debug_clvmd(int level, int clusterwide);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
cmirrord
 | 
			
		||||
@@ -1,39 +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@
 | 
			
		||||
SACKPT_LIBS = @SACKPT_LIBS@
 | 
			
		||||
SACKPT_CFLAGS = @SACKPT_CFLAGS@
 | 
			
		||||
 | 
			
		||||
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
 | 
			
		||||
 | 
			
		||||
TARGETS = cmirrord
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper
 | 
			
		||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
 | 
			
		||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
 | 
			
		||||
 | 
			
		||||
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
			
		||||
		$(LVMLIBS) $(LMLIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
install: $(TARGETS)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
 | 
			
		||||
@@ -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 "dm-log-userspace.h"
 | 
			
		||||
#include "libdevmapper.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 {
 | 
			
		||||
		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 "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,34 +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 "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,77 +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
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#define _FILE_OFFSET_BITS 64
 | 
			
		||||
 | 
			
		||||
#include "configure.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,110 +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@
 | 
			
		||||
 | 
			
		||||
SOURCES = libdevmapper-event.c
 | 
			
		||||
SOURCES2 = dmeventd.c
 | 
			
		||||
 | 
			
		||||
TARGETS = dmeventd
 | 
			
		||||
 | 
			
		||||
.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)
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
 | 
			
		||||
 | 
			
		||||
ifneq ($(MAKECMDGOALS),device-mapper)
 | 
			
		||||
  SUBDIRS+=plugins
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
CFLOW_TARGET = dmeventd
 | 
			
		||||
 | 
			
		||||
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
 | 
			
		||||
EXPORTED_FN_PREFIX = dm_event
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
all: device-mapper
 | 
			
		||||
device-mapper: $(TARGETS)
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper
 | 
			
		||||
LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
 | 
			
		||||
dmeventd: $(LIB_SHARED) dmeventd.o
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
 | 
			
		||||
	$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
 | 
			
		||||
 | 
			
		||||
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
 | 
			
		||||
	dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
 | 
			
		||||
 | 
			
		||||
ifeq ("@PKGCONFIG@", "yes")
 | 
			
		||||
  INSTALL_LIB_TARGETS += install_pkgconfig
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
			
		||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
 | 
			
		||||
-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_include: $(srcdir)/libdevmapper-event.h
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_pkgconfig: libdevmapper-event.pc
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
			
		||||
 | 
			
		||||
install_lib_dynamic: install_lib_shared
 | 
			
		||||
 | 
			
		||||
install_lib_static: $(LIB_STATIC)
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lib: $(INSTALL_LIB_TARGETS)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_dynamic: dmeventd
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_static: dmeventd.static
 | 
			
		||||
	$(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__ */
 | 
			
		||||
@@ -1,995 +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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dm-logging.h"
 | 
			
		||||
#include "dmlib.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "dmeventd.h"
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <arpa/inet.h>		/* for htonl, ntohl */
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
static int _debug_level = 0;
 | 
			
		||||
static int _use_syslog = 0;
 | 
			
		||||
static int _sequence_nr = 0;
 | 
			
		||||
 | 
			
		||||
struct dm_event_handler {
 | 
			
		||||
	char *dso;
 | 
			
		||||
 | 
			
		||||
	char *dmeventd_path;
 | 
			
		||||
 | 
			
		||||
	char *dev_name;
 | 
			
		||||
 | 
			
		||||
	char *uuid;
 | 
			
		||||
	int major;
 | 
			
		||||
	int minor;
 | 
			
		||||
	uint32_t timeout;
 | 
			
		||||
 | 
			
		||||
	enum dm_event_mask mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	dm_free(dmevh->dev_name);
 | 
			
		||||
	dm_free(dmevh->uuid);
 | 
			
		||||
	dmevh->dev_name = dmevh->uuid = NULL;
 | 
			
		||||
	dmevh->major = dmevh->minor = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_event_handler *dm_event_handler_create(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_event_handler *dmevh;
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
 | 
			
		||||
		log_error("Failed to allocate event handler.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dmevh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
	dm_free(dmevh->dso);
 | 
			
		||||
	dm_free(dmevh->dmeventd_path);
 | 
			
		||||
	dm_free(dmevh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
 | 
			
		||||
{
 | 
			
		||||
	if (!dmeventd_path) /* noop */
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	dm_free(dmevh->dmeventd_path);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
 | 
			
		||||
{
 | 
			
		||||
	if (!path) /* noop */
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	dm_free(dmevh->dso);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dso = dm_strdup(path)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
 | 
			
		||||
{
 | 
			
		||||
	if (!dev_name)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dev_name = dm_strdup(dev_name)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
 | 
			
		||||
{
 | 
			
		||||
	if (!uuid)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->uuid = dm_strdup(uuid)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
 | 
			
		||||
{
 | 
			
		||||
	int minor = dmevh->minor;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	dmevh->major = major;
 | 
			
		||||
	dmevh->minor = minor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
 | 
			
		||||
{
 | 
			
		||||
	int major = dmevh->major;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	dmevh->major = major;
 | 
			
		||||
	dmevh->minor = minor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
 | 
			
		||||
				     enum dm_event_mask evmask)
 | 
			
		||||
{
 | 
			
		||||
	dmevh->mask = evmask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
 | 
			
		||||
{
 | 
			
		||||
	dmevh->timeout = timeout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->dso;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->dev_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->uuid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->major;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->minor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->timeout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	return dmevh->mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _check_message_id(struct dm_event_daemon_message *msg)
 | 
			
		||||
{
 | 
			
		||||
	int pid, seq_nr;
 | 
			
		||||
 | 
			
		||||
	if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
 | 
			
		||||
	    (pid != getpid()) || (seq_nr != _sequence_nr)) {
 | 
			
		||||
		log_error("Ignoring out-of-sequence reply from dmeventd. "
 | 
			
		||||
			  "Expected %d:%d but received %s.", getpid(),
 | 
			
		||||
			  _sequence_nr, msg->data);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * daemon_read
 | 
			
		||||
 * @fifos
 | 
			
		||||
 * @msg
 | 
			
		||||
 *
 | 
			
		||||
 * Read message from daemon.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 0 on failure, 1 on success
 | 
			
		||||
 */
 | 
			
		||||
static int _daemon_read(struct dm_event_fifos *fifos,
 | 
			
		||||
			struct dm_event_daemon_message *msg)
 | 
			
		||||
{
 | 
			
		||||
	unsigned bytes = 0;
 | 
			
		||||
	int ret, i;
 | 
			
		||||
	fd_set fds;
 | 
			
		||||
	size_t size = 2 * sizeof(uint32_t);	/* status + size */
 | 
			
		||||
	uint32_t *header = alloca(size);
 | 
			
		||||
	char *buf = (char *)header;
 | 
			
		||||
 | 
			
		||||
	while (bytes < size) {
 | 
			
		||||
		for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) {
 | 
			
		||||
			/* Watch daemon read FIFO for input. */
 | 
			
		||||
			struct timeval tval = { .tv_sec = 1 };
 | 
			
		||||
			FD_ZERO(&fds);
 | 
			
		||||
			FD_SET(fifos->server, &fds);
 | 
			
		||||
			ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
 | 
			
		||||
			if (ret < 0 && errno != EINTR) {
 | 
			
		||||
				log_error("Unable to read from event server.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			if ((ret == 0) && (i > 4) && !bytes) {
 | 
			
		||||
				log_error("No input from event server.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (ret < 1) {
 | 
			
		||||
			log_error("Unable to read from event server.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = read(fifos->server, buf + bytes, size);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
			
		||||
				continue;
 | 
			
		||||
			else {
 | 
			
		||||
				log_error("Unable to read from event server.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bytes += ret;
 | 
			
		||||
		if (header && (bytes == 2 * sizeof(uint32_t))) {
 | 
			
		||||
			msg->cmd = ntohl(header[0]);
 | 
			
		||||
			msg->size = ntohl(header[1]);
 | 
			
		||||
			buf = msg->data = dm_malloc(msg->size);
 | 
			
		||||
			size = msg->size;
 | 
			
		||||
			bytes = 0;
 | 
			
		||||
			header = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bytes != size) {
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return bytes == size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write message to daemon. */
 | 
			
		||||
static int _daemon_write(struct dm_event_fifos *fifos,
 | 
			
		||||
			 struct dm_event_daemon_message *msg)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	fd_set fds;
 | 
			
		||||
	size_t bytes = 0;
 | 
			
		||||
	size_t size = 2 * sizeof(uint32_t) + msg->size;
 | 
			
		||||
	uint32_t *header = alloca(size);
 | 
			
		||||
	char *buf = (char *)header;
 | 
			
		||||
	char drainbuf[128];
 | 
			
		||||
 | 
			
		||||
	header[0] = htonl(msg->cmd);
 | 
			
		||||
	header[1] = htonl(msg->size);
 | 
			
		||||
	memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
 | 
			
		||||
 | 
			
		||||
	/* drain the answer fifo */
 | 
			
		||||
	while (1) {
 | 
			
		||||
		struct timeval tval = { .tv_usec = 100 };
 | 
			
		||||
		FD_ZERO(&fds);
 | 
			
		||||
		FD_SET(fifos->server, &fds);
 | 
			
		||||
		ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			if (errno == EINTR)
 | 
			
		||||
				continue;
 | 
			
		||||
			log_error("Unable to talk to event daemon.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (ret == 0)
 | 
			
		||||
			break;
 | 
			
		||||
		ret = read(fifos->server, drainbuf, sizeof(drainbuf));
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
			
		||||
				continue;
 | 
			
		||||
			log_error("Unable to talk to event daemon.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (bytes < size) {
 | 
			
		||||
		do {
 | 
			
		||||
			/* Watch daemon write FIFO to be ready for output. */
 | 
			
		||||
			FD_ZERO(&fds);
 | 
			
		||||
			FD_SET(fifos->client, &fds);
 | 
			
		||||
			ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
 | 
			
		||||
			if ((ret < 0) && (errno != EINTR)) {
 | 
			
		||||
				log_error("Unable to talk to event daemon.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		} while (ret < 1);
 | 
			
		||||
 | 
			
		||||
		ret = write(fifos->client, buf + bytes, size - bytes);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
			
		||||
				continue;
 | 
			
		||||
			else {
 | 
			
		||||
				log_error("Unable to talk to event daemon.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bytes += ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bytes == size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 msg_size;
 | 
			
		||||
	memset(msg, 0, sizeof(*msg));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Set command and pack the arguments
 | 
			
		||||
	 * into ASCII message string.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((msg_size =
 | 
			
		||||
	     ((cmd == DM_EVENT_CMD_HELLO) ?
 | 
			
		||||
	      dm_asprintf(&(msg->data), "%d:%d HELLO", getpid(), _sequence_nr) :
 | 
			
		||||
	      dm_asprintf(&(msg->data), "%d:%d %s %s %u %" PRIu32,
 | 
			
		||||
			  getpid(), _sequence_nr,
 | 
			
		||||
			  dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
 | 
			
		||||
	    < 0) {
 | 
			
		||||
		log_error("_daemon_talk: message allocation failed.");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	msg->cmd = cmd;
 | 
			
		||||
	msg->size = msg_size;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Write command and message to and
 | 
			
		||||
	 * read status return code from daemon.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!_daemon_write(fifos, msg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
 | 
			
		||||
		if (!_daemon_read(fifos, msg)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
	} while (!_check_message_id(msg));
 | 
			
		||||
 | 
			
		||||
	_sequence_nr++;
 | 
			
		||||
 | 
			
		||||
	return (int32_t) msg->cmd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * start_daemon
 | 
			
		||||
 *
 | 
			
		||||
 * This function forks off a process (dmeventd) that will handle
 | 
			
		||||
 * the events.  I am currently test opening one of the fifos to
 | 
			
		||||
 * ensure that the daemon is running and listening...  I thought
 | 
			
		||||
 * this would be less expensive than fork/exec'ing every time.
 | 
			
		||||
 * Perhaps there is an even quicker/better way (no, checking the
 | 
			
		||||
 * lock file is _not_ a better way).
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 1 on success, 0 otherwise
 | 
			
		||||
 */
 | 
			
		||||
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	int pid, ret = 0;
 | 
			
		||||
	int status;
 | 
			
		||||
	struct stat statbuf;
 | 
			
		||||
	char default_dmeventd_path[] = DMEVENTD_PATH;
 | 
			
		||||
	char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * FIXME Explicitly verify the code's requirement that client_path is secure:
 | 
			
		||||
	 * - All parent directories owned by root without group/other write access unless sticky.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */
 | 
			
		||||
	if ((lstat(fifos->client_path, &statbuf) < 0)) {
 | 
			
		||||
		if (errno == ENOENT)
 | 
			
		||||
			/* Jump ahead if fifo does not already exist. */
 | 
			
		||||
			goto start_server;
 | 
			
		||||
		else {
 | 
			
		||||
			log_sys_error("stat", fifos->client_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (!S_ISFIFO(statbuf.st_mode)) {
 | 
			
		||||
		log_error("%s must be a fifo.", fifos->client_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (statbuf.st_uid) {
 | 
			
		||||
		log_error("%s must be owned by uid 0.", fifos->client_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO)) {
 | 
			
		||||
		log_error("%s must have mode 0600.", fifos->client_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Anyone listening?  If not, errno will be ENXIO */
 | 
			
		||||
	fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
 | 
			
		||||
	if (fifos->client >= 0) {
 | 
			
		||||
		/* Should never happen if all the above checks passed. */
 | 
			
		||||
		if ((fstat(fifos->client, &statbuf) < 0) ||
 | 
			
		||||
		    !S_ISFIFO(statbuf.st_mode) || statbuf.st_uid ||
 | 
			
		||||
		    (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
 | 
			
		||||
			log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
 | 
			
		||||
			if (close(fifos->client))
 | 
			
		||||
				log_sys_debug("close", fifos->client_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* server is running and listening */
 | 
			
		||||
		if (close(fifos->client))
 | 
			
		||||
			log_sys_debug("close", fifos->client_path);
 | 
			
		||||
		return 1;
 | 
			
		||||
	} else if (errno != ENXIO && errno != ENOENT)  {
 | 
			
		||||
		/* problem */
 | 
			
		||||
		log_sys_error("open", fifos->client_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
start_server:
 | 
			
		||||
	/* server is not running */
 | 
			
		||||
 | 
			
		||||
	if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
 | 
			
		||||
		log_sys_error("stat", args[0]);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pid = fork();
 | 
			
		||||
 | 
			
		||||
	if (pid < 0)
 | 
			
		||||
		log_sys_error("fork", "");
 | 
			
		||||
 | 
			
		||||
	else if (!pid) {
 | 
			
		||||
		execvp(args[0], args);
 | 
			
		||||
		log_error("Unable to exec dmeventd: %s.", strerror(errno));
 | 
			
		||||
		_exit(EXIT_FAILURE);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (waitpid(pid, &status, 0) < 0)
 | 
			
		||||
			log_error("Unable to start dmeventd: %s.",
 | 
			
		||||
				  strerror(errno));
 | 
			
		||||
		else if (WEXITSTATUS(status))
 | 
			
		||||
			log_error("Unable to start dmeventd.");
 | 
			
		||||
		else
 | 
			
		||||
			ret = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int init_fifos(struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME? Is fifo the most suitable method? Why not share
 | 
			
		||||
	   comms/daemon code with something else e.g. multipath? */
 | 
			
		||||
 | 
			
		||||
	/* Open the fifo used to read from the daemon. */
 | 
			
		||||
	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
 | 
			
		||||
		log_sys_error("open", fifos->server_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Lock out anyone else trying to do communication with the daemon. */
 | 
			
		||||
	if (flock(fifos->server, LOCK_EX) < 0) {
 | 
			
		||||
		log_sys_error("flock", fifos->server_path);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*	if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
 | 
			
		||||
	if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) {
 | 
			
		||||
		log_sys_error("open", fifos->client_path);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
bad:
 | 
			
		||||
	if (close(fifos->server))
 | 
			
		||||
		log_sys_debug("close", fifos->server_path);
 | 
			
		||||
	fifos->server = -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize client. */
 | 
			
		||||
static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	if (!_start_daemon(dmeventd_path, fifos))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	return init_fifos(fifos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fini_fifos(struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	if (fifos->client >= 0 && close(fifos->client))
 | 
			
		||||
		log_sys_debug("close", fifos->client_path);
 | 
			
		||||
 | 
			
		||||
	if (fifos->server >= 0) {
 | 
			
		||||
		if (flock(fifos->server, LOCK_UN))
 | 
			
		||||
			log_sys_debug("flock unlock", fifos->server_path);
 | 
			
		||||
 | 
			
		||||
		if (close(fifos->server))
 | 
			
		||||
			log_sys_debug("close", fifos->server_path);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get uuid of a device */
 | 
			
		||||
static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
 | 
			
		||||
		log_error("_get_device_info: dm_task creation for info failed.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dmevh->uuid) {
 | 
			
		||||
		if (!dm_task_set_uuid(dmt, dmevh->uuid))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
	} else if (dmevh->dev_name) {
 | 
			
		||||
		if (!dm_task_set_name(dmt, dmevh->dev_name))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
	} else if (dmevh->major && dmevh->minor) {
 | 
			
		||||
		if (!dm_task_set_major(dmt, dmevh->major) ||
 | 
			
		||||
		    !dm_task_set_minor(dmt, dmevh->minor))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME Add name or uuid or devno to messages */
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
		log_error("_get_device_info: dm_task_run() failed.");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_get_info(dmt, &info)) {
 | 
			
		||||
		log_error("_get_device_info: failed to get info for device.");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!info.exists) {
 | 
			
		||||
		log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
 | 
			
		||||
			  dmevh->uuid ? : "",
 | 
			
		||||
			  (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? dmevh->major : 0,
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ":" : "",
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->minor > 0) ? dmevh->minor : 0,
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) && dmevh->minor == 0 ? "0" : "",
 | 
			
		||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ") " : "");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dmt;
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Handle the event (de)registration call and return negative error codes. */
 | 
			
		||||
static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_message *msg,
 | 
			
		||||
		     const char *dso_name, const char *dev_name,
 | 
			
		||||
		     enum dm_event_mask evmask, uint32_t timeout)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct dm_event_fifos fifos = {
 | 
			
		||||
		.server = -1,
 | 
			
		||||
		.client = -1,
 | 
			
		||||
		/* FIXME Make these either configurable or depend directly on dmeventd_path */
 | 
			
		||||
		.client_path = DM_EVENT_FIFO_CLIENT,
 | 
			
		||||
		.server_path = DM_EVENT_FIFO_SERVER
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (!_init_client(dmeventd_path, &fifos)) {
 | 
			
		||||
		ret = -ESRCH;
 | 
			
		||||
		goto_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 | 
			
		||||
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	msg->data = 0;
 | 
			
		||||
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
 | 
			
		||||
out:
 | 
			
		||||
	/* what is the opposite of init? */
 | 
			
		||||
	fini_fifos(&fifos);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* External library interface. */
 | 
			
		||||
int dm_event_register_handler(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 1, err;
 | 
			
		||||
	const char *uuid;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _get_device_info(dmevh)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	uuid = dm_task_get_uuid(dmt);
 | 
			
		||||
 | 
			
		||||
	if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") &&
 | 
			
		||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
 | 
			
		||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
 | 
			
		||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
 | 
			
		||||
		log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
			
		||||
			     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
			
		||||
		log_error("%s: event registration failed: %s.",
 | 
			
		||||
			  dm_task_get_name(dmt),
 | 
			
		||||
			  msg.data ? msg.data : strerror(-err));
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 1, err;
 | 
			
		||||
	const char *uuid;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _get_device_info(dmevh)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	uuid = dm_task_get_uuid(dmt);
 | 
			
		||||
 | 
			
		||||
	if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
			
		||||
			    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
			
		||||
		log_error("%s: event deregistration failed: %s.",
 | 
			
		||||
			  dm_task_get_name(dmt),
 | 
			
		||||
			  msg.data ? msg.data : strerror(-err));
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Fetch a string off src and duplicate it into *dest. */
 | 
			
		||||
/* FIXME: move to separate module to share with the daemon. */
 | 
			
		||||
static char *_fetch_string(char **src, const int delimiter)
 | 
			
		||||
{
 | 
			
		||||
	char *p, *ret;
 | 
			
		||||
 | 
			
		||||
	if ((p = strchr(*src, delimiter)))
 | 
			
		||||
		*p = 0;
 | 
			
		||||
 | 
			
		||||
	if ((ret = dm_strdup(*src)))
 | 
			
		||||
		*src += strlen(ret) + 1;
 | 
			
		||||
 | 
			
		||||
	if (p)
 | 
			
		||||
		*p = delimiter;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Parse a device message from the daemon. */
 | 
			
		||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
 | 
			
		||||
			 char **uuid, enum dm_event_mask *evmask)
 | 
			
		||||
{
 | 
			
		||||
	char *id;
 | 
			
		||||
	char *p = msg->data;
 | 
			
		||||
 | 
			
		||||
	if ((id = _fetch_string(&p, ' ')) &&
 | 
			
		||||
	    (*dso_name = _fetch_string(&p, ' ')) &&
 | 
			
		||||
	    (*uuid = _fetch_string(&p, ' '))) {
 | 
			
		||||
		*evmask = atoi(p);
 | 
			
		||||
		dm_free(id);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_free(id);
 | 
			
		||||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise.
 | 
			
		||||
 */
 | 
			
		||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	const char *uuid = NULL;
 | 
			
		||||
	char *reply_dso = NULL, *reply_uuid = NULL;
 | 
			
		||||
	enum dm_event_mask reply_mask = 0;
 | 
			
		||||
	struct dm_task *dmt = NULL;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _get_device_info(dmevh))) {
 | 
			
		||||
		log_debug("Device does not exists (uuid=%s, name=%s, %d:%d).",
 | 
			
		||||
			  dmevh->uuid, dmevh->dev_name,
 | 
			
		||||
			  dmevh->major, dmevh->minor);
 | 
			
		||||
		ret = -ENODEV;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uuid = dm_task_get_uuid(dmt);
 | 
			
		||||
 | 
			
		||||
	/* FIXME Distinguish errors connecting to daemon */
 | 
			
		||||
	if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
 | 
			
		||||
		      DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
 | 
			
		||||
		      &msg, dmevh->dso, uuid, dmevh->mask, 0)) {
 | 
			
		||||
		log_debug("%s: device not registered.", dm_task_get_name(dmt));
 | 
			
		||||
		ret = -ENOENT;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME this will probably horribly break if we get
 | 
			
		||||
	   ill-formatted reply */
 | 
			
		||||
	ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	dmt = NULL;
 | 
			
		||||
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
	msg.data = NULL;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
	if (!reply_uuid) {
 | 
			
		||||
		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _get_device_info(dmevh))) {
 | 
			
		||||
		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_event_handler_set_dso(dmevh, reply_dso);
 | 
			
		||||
	dm_event_handler_set_event_mask(dmevh, reply_mask);
 | 
			
		||||
 | 
			
		||||
	dm_free(reply_dso);
 | 
			
		||||
	reply_dso = NULL;
 | 
			
		||||
 | 
			
		||||
	dm_free(reply_uuid);
 | 
			
		||||
	reply_uuid = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_get_info(dmt, &info)) {
 | 
			
		||||
		ret = -1;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dmevh->major = info.major;
 | 
			
		||||
	dmevh->minor = info.minor;
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
	dm_free(reply_dso);
 | 
			
		||||
	dm_free(reply_uuid);
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
	if (dmt)
 | 
			
		||||
		dm_task_destroy(dmt);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * You can (and have to) call this at the stage of the protocol where
 | 
			
		||||
 *     daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)
 | 
			
		||||
 *
 | 
			
		||||
 * would be normally sent. This call will parse the version reply from
 | 
			
		||||
 * dmeventd, in addition to above call. It is not safe to call this at any
 | 
			
		||||
 * other place in the protocol.
 | 
			
		||||
 *
 | 
			
		||||
 * This is an internal function, not exposed in the public API.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
 | 
			
		||||
	char *p;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
 | 
			
		||||
		return 0;
 | 
			
		||||
	p = msg.data;
 | 
			
		||||
	*version = 0;
 | 
			
		||||
 | 
			
		||||
	if (!p || !(p = strchr(p, ' '))) /* Message ID */
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (!(p = strchr(p + 1, ' '))) /* HELLO */
 | 
			
		||||
		return 0;
 | 
			
		||||
	if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
 | 
			
		||||
		*version = atoi(p);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_log_set(int debug_log_level, int use_syslog)
 | 
			
		||||
{
 | 
			
		||||
	_debug_level = debug_log_level;
 | 
			
		||||
	_use_syslog = use_syslog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	static int _abort_on_internal_errors = -1;
 | 
			
		||||
	static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
	static time_t start = 0;
 | 
			
		||||
	const char *indent = "";
 | 
			
		||||
	FILE *stream = log_stderr(level) ? stderr : stdout;
 | 
			
		||||
	int prio;
 | 
			
		||||
	time_t now;
 | 
			
		||||
	int log_with_debug = 0;
 | 
			
		||||
 | 
			
		||||
	if (subsys[0] == '#') {
 | 
			
		||||
		/* Subsystems starting with '#' are logged
 | 
			
		||||
		 * only when debugging is enabled. */
 | 
			
		||||
		log_with_debug++;
 | 
			
		||||
		subsys++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (log_level(level)) {
 | 
			
		||||
	case _LOG_DEBUG:
 | 
			
		||||
		/* Never shown without -ddd */
 | 
			
		||||
		if (_debug_level < 3)
 | 
			
		||||
			return;
 | 
			
		||||
		prio = LOG_DEBUG;
 | 
			
		||||
		indent = "      ";
 | 
			
		||||
		break;
 | 
			
		||||
	case _LOG_INFO:
 | 
			
		||||
		if (log_with_debug && _debug_level < 2)
 | 
			
		||||
			return;
 | 
			
		||||
		prio = LOG_INFO;
 | 
			
		||||
		indent = "    ";
 | 
			
		||||
		break;
 | 
			
		||||
	case _LOG_NOTICE:
 | 
			
		||||
		if (log_with_debug && _debug_level < 1)
 | 
			
		||||
			return;
 | 
			
		||||
		prio = LOG_NOTICE;
 | 
			
		||||
		indent = "  ";
 | 
			
		||||
		break;
 | 
			
		||||
	case _LOG_WARN:
 | 
			
		||||
		prio = LOG_WARNING;
 | 
			
		||||
		break;
 | 
			
		||||
	case _LOG_ERR:
 | 
			
		||||
		prio = LOG_ERR;
 | 
			
		||||
		stream = stderr;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		prio = LOG_CRIT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Serialize to keep lines readable */
 | 
			
		||||
	pthread_mutex_lock(&_log_mutex);
 | 
			
		||||
 | 
			
		||||
	if (_use_syslog) {
 | 
			
		||||
		vsyslog(prio, format, ap);
 | 
			
		||||
	} else {
 | 
			
		||||
		now = time(NULL);
 | 
			
		||||
		if (!start)
 | 
			
		||||
			start = now;
 | 
			
		||||
		now -= start;
 | 
			
		||||
		if (_debug_level)
 | 
			
		||||
			fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
 | 
			
		||||
				(int)now / 60, (int)now % 60,
 | 
			
		||||
				// TODO: Maybe use shorter ID
 | 
			
		||||
				// ((int)(pthread_self()) >> 6) & 0xffff,
 | 
			
		||||
				(int)pthread_self(), subsys,
 | 
			
		||||
				(_debug_level > 3) ? "" : indent);
 | 
			
		||||
		if (_debug_level > 3)
 | 
			
		||||
			fprintf(stream, "%28s:%4d %s", file, line, indent);
 | 
			
		||||
		vfprintf(stream, _(format), ap);
 | 
			
		||||
		fputc('\n', stream);
 | 
			
		||||
		fflush(stream);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&_log_mutex);
 | 
			
		||||
 | 
			
		||||
	if (_abort_on_internal_errors < 0)
 | 
			
		||||
		/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
 | 
			
		||||
		_abort_on_internal_errors =
 | 
			
		||||
			strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
 | 
			
		||||
 | 
			
		||||
	if (_abort_on_internal_errors &&
 | 
			
		||||
	    !strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
 | 
			
		||||
		abort();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0				/* left out for now */
 | 
			
		||||
 | 
			
		||||
static char *_skip_string(char *src, const int delimiter)
 | 
			
		||||
{
 | 
			
		||||
	src = srtchr(src, delimiter);
 | 
			
		||||
	if (src && *(src + 1))
 | 
			
		||||
		return src + 1;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (!device_exists(device_path))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
 | 
			
		||||
			 NULL, device_path, 0, timeout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (!device_exists(device_path))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
 | 
			
		||||
			     0, 0))) {
 | 
			
		||||
		char *p = _skip_string(msg.data, ' ');
 | 
			
		||||
		if (!p) {
 | 
			
		||||
			log_error("Malformed reply from dmeventd '%s'.",
 | 
			
		||||
				  msg.data);
 | 
			
		||||
			dm_free(msg.data);
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
		*timeout = atoi(p);
 | 
			
		||||
	}
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,135 +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 <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,11 +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
 | 
			
		||||
Requires.private: devmapper
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
# Copyright (C) 2004-2005, 2011 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
 | 
			
		||||
 | 
			
		||||
ifneq ("@MIRRORS@", "none")
 | 
			
		||||
  SUBDIRS += mirror
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("@SNAPSHOTS@", "none")
 | 
			
		||||
  SUBDIRS += snapshot
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("@RAID@", "none")
 | 
			
		||||
  SUBDIRS += raid
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("@THIN@", "none")
 | 
			
		||||
  SUBDIRS += thin
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
  SUBDIRS = lvm2 mirror snapshot raid thin
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
snapshot: lvm2
 | 
			
		||||
mirror: lvm2
 | 
			
		||||
raid: lvm2
 | 
			
		||||
thin: 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,31 +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
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_lvm.c
 | 
			
		||||
 | 
			
		||||
LIB_SHARED = libdevmapper-event-lvm2.$(LIB_SUFFIX)
 | 
			
		||||
LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lib_shared
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
@@ -1,164 +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.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "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;
 | 
			
		||||
 | 
			
		||||
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()))
 | 
			
		||||
			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;
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
	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)) {
 | 
			
		||||
		dmeventd_lvm2_lock();
 | 
			
		||||
		/* output of internal command passed via env var */
 | 
			
		||||
		if (!dmeventd_lvm2_run(cmd))
 | 
			
		||||
			cmd = NULL;
 | 
			
		||||
		else if ((cmd = getenv(cmd)))
 | 
			
		||||
			cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
 | 
			
		||||
		dmeventd_lvm2_unlock();
 | 
			
		||||
 | 
			
		||||
		if (!cmd) {
 | 
			
		||||
			log_error("Unable to find configured command.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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,37 +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@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_mirror.c
 | 
			
		||||
 | 
			
		||||
LIB_NAME = libdevmapper-event-lvm2mirror
 | 
			
		||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
 | 
			
		||||
LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
@@ -1,222 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2005-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.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "activate.h"	/* For TARGET_NAME* */
 | 
			
		||||
 | 
			
		||||
/* 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_lvscan[512];
 | 
			
		||||
	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_lvscan, const char *cmd_lvconvert,
 | 
			
		||||
				  const char *device)
 | 
			
		||||
{
 | 
			
		||||
	if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
 | 
			
		||||
		log_warn("WARNING: Re-scan of mirrored device %s failed.", 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_lvscan,
 | 
			
		||||
						    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;
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
 | 
			
		||||
				   "lvscan --cache", device)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
 | 
			
		||||
				   "lvconvert --repair --use-policies", device)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*user = state;
 | 
			
		||||
 | 
			
		||||
	log_info("Monitoring mirror device %s for events.", device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
bad:
 | 
			
		||||
	log_error("Failed to monitor mirror %s.", device);
 | 
			
		||||
 | 
			
		||||
	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,36 +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@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_raid.c
 | 
			
		||||
 | 
			
		||||
LIB_NAME = libdevmapper-event-lvm2raid
 | 
			
		||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
 | 
			
		||||
LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
@@ -1,172 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2005-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 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.h"
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.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_lvscan[512];
 | 
			
		||||
	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 (dead) {
 | 
			
		||||
		if (status->insync_regions < status->total_regions) {
 | 
			
		||||
			if (!state->warned) {
 | 
			
		||||
				state->warned = 1;
 | 
			
		||||
				log_warn("WARNING: waiting for resynchronization to finish "
 | 
			
		||||
					 "before initiating repair on RAID device %s.", device);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			goto out; /* Not yet done syncing with accessible devices */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (state->failed)
 | 
			
		||||
			goto out; /* already reported */
 | 
			
		||||
 | 
			
		||||
		state->failed = 1;
 | 
			
		||||
		if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
 | 
			
		||||
			log_warn("WARNING: Re-scan of RAID device %s failed.", device);
 | 
			
		||||
 | 
			
		||||
		/* 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;
 | 
			
		||||
		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_lvscan, sizeof(state->cmd_lvscan),
 | 
			
		||||
				   "lvscan --cache", device) ||
 | 
			
		||||
	    !dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
 | 
			
		||||
				   "lvconvert --config devices{ignore_suspended_devices=1} "
 | 
			
		||||
				   "--repair --use-policies", device)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*user = state;
 | 
			
		||||
 | 
			
		||||
	log_info("Monitoring RAID device %s for events.", device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
bad:
 | 
			
		||||
	log_error("Failed to monitor RAID %s.", device);
 | 
			
		||||
 | 
			
		||||
	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,33 +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@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_snapshot.c
 | 
			
		||||
 | 
			
		||||
LIB_SHARED = libdevmapper-event-lvm2snapshot.$(LIB_SUFFIX)
 | 
			
		||||
LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
@@ -1,286 +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.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "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;
 | 
			
		||||
 | 
			
		||||
	/* 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
 | 
			
		||||
		pthread_kill(pthread_self(), SIGALRM);
 | 
			
		||||
		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);
 | 
			
		||||
		pthread_kill(pthread_self(), SIGALRM);
 | 
			
		||||
		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_float(percent));
 | 
			
		||||
 | 
			
		||||
		/* 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)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
	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,36 +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@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_thin.c
 | 
			
		||||
 | 
			
		||||
LIB_NAME = libdevmapper-event-lvm2thin
 | 
			
		||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
 | 
			
		||||
LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
@@ -1,431 +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.h"	/* using here lvm log */
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
/* TODO - move this mountinfo code into library to be reusable */
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#  include "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 metadata_warn_once;
 | 
			
		||||
	int data_percent_check;
 | 
			
		||||
	int data_percent;
 | 
			
		||||
	int data_warn_once;
 | 
			
		||||
	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;
 | 
			
		||||
	char cmd_str[1024];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DM_EVENT_LOG_FN("thin")
 | 
			
		||||
 | 
			
		||||
#define UUID_PREFIX "LVM-"
 | 
			
		||||
 | 
			
		||||
static int _run_command(struct dso_state *state)
 | 
			
		||||
{
 | 
			
		||||
	char val[3][36];
 | 
			
		||||
	char *env[] = { val[0], val[1], val[2], NULL };
 | 
			
		||||
	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) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
 | 
			
		||||
 | 
			
		||||
	if (state->data_percent) {
 | 
			
		||||
		/* Prepare some known data to env vars for easy use */
 | 
			
		||||
		(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
 | 
			
		||||
				   state->data_percent / DM_PERCENT_1);
 | 
			
		||||
		(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
 | 
			
		||||
				   state->metadata_percent / DM_PERCENT_1);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* For an error event it's for a user to check status and decide */
 | 
			
		||||
		env[1] = NULL;
 | 
			
		||||
		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);
 | 
			
		||||
		execve(state->argv[0], state->argv, env);
 | 
			
		||||
		_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)
 | 
			
		||||
		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_float(state->data_percent_check),
 | 
			
		||||
		  dm_percent_to_float(state->metadata_percent_check));
 | 
			
		||||
#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_warn_once = 0; /* Dropped bellow threshold, reset warn once */
 | 
			
		||||
	else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
 | 
			
		||||
		log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
 | 
			
		||||
			 device, dm_percent_to_float(state->metadata_percent));
 | 
			
		||||
	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_warn_once = 0;
 | 
			
		||||
	else if (!state->data_warn_once++)
 | 
			
		||||
		log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
 | 
			
		||||
			 device, dm_percent_to_float(state->data_percent));
 | 
			
		||||
	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);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		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;
 | 
			
		||||
	int maxcmd;
 | 
			
		||||
	char *str;
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
 | 
			
		||||
				   sizeof(state->cmd_str),
 | 
			
		||||
				   "_dmeventd_thin_command", device)) {
 | 
			
		||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strncmp(state->cmd_str, "lvm ", 4)) {
 | 
			
		||||
		maxcmd = 2; /* space for last NULL element */
 | 
			
		||||
		for (str = state->cmd_str; *str; str++)
 | 
			
		||||
			if (*str == ' ')
 | 
			
		||||
				maxcmd++;
 | 
			
		||||
		if (!(str = dm_pool_strdup(state->mem, state->cmd_str)) ||
 | 
			
		||||
		    !(state->argv = dm_pool_zalloc(state->mem, maxcmd * sizeof(char *)))) {
 | 
			
		||||
			log_error("Failed to allocate memory for command.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dm_split_words(str, maxcmd - 1, 0, state->argv);
 | 
			
		||||
		_init_thread_signals(state);
 | 
			
		||||
	} else
 | 
			
		||||
		memmove(state->cmd_str, state->cmd_str + 4, strlen(state->cmd_str + 4) + 1);
 | 
			
		||||
 | 
			
		||||
	state->pid = -1;
 | 
			
		||||
	*user = state;
 | 
			
		||||
 | 
			
		||||
	log_info("Monitoring thin pool %s.", device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
bad:
 | 
			
		||||
	log_error("Failed to monitor thin pool %s.", device);
 | 
			
		||||
 | 
			
		||||
	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
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
path.py
 | 
			
		||||
@@ -1,66 +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@
 | 
			
		||||
 | 
			
		||||
lvmdbusdir = $(python3dir)/lvmdbusd
 | 
			
		||||
 | 
			
		||||
LVMDBUS_SRCDIR_FILES = \
 | 
			
		||||
	automatedproperties.py \
 | 
			
		||||
	background.py \
 | 
			
		||||
	cfg.py \
 | 
			
		||||
	cmdhandler.py \
 | 
			
		||||
	fetch.py \
 | 
			
		||||
	__init__.py \
 | 
			
		||||
	job.py \
 | 
			
		||||
	loader.py \
 | 
			
		||||
	lvmdb.py \
 | 
			
		||||
	main.py \
 | 
			
		||||
	lvm_shell_proxy.py \
 | 
			
		||||
	lv.py \
 | 
			
		||||
	manager.py \
 | 
			
		||||
	objectmanager.py \
 | 
			
		||||
	pv.py \
 | 
			
		||||
	request.py \
 | 
			
		||||
	state.py \
 | 
			
		||||
	udevwatch.py \
 | 
			
		||||
	utils.py \
 | 
			
		||||
	vg.py
 | 
			
		||||
 | 
			
		||||
LVMDBUS_BUILDDIR_FILES = \
 | 
			
		||||
	path.py
 | 
			
		||||
 | 
			
		||||
LVMDBUSD = $(srcdir)/lvmdbusd
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
.PHONY: install_lvmdbusd
 | 
			
		||||
 | 
			
		||||
install_lvmdbusd:
 | 
			
		||||
	$(INSTALL_DIR) $(sbindir)
 | 
			
		||||
	$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
 | 
			
		||||
	$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
 | 
			
		||||
	$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
 | 
			
		||||
	$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
 | 
			
		||||
	$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmdbusd
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 | 
			
		||||
DISTCLEAN_TARGETS+= \
 | 
			
		||||
	$(LVMDBUS_BUILDDIR_FILES)
 | 
			
		||||
@@ -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,173 +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] = self.GetAll(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
 | 
			
		||||
 | 
			
		||||
	# Properties
 | 
			
		||||
	# noinspection PyUnusedLocal
 | 
			
		||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
			
		||||
							in_signature='ss', out_signature='v')
 | 
			
		||||
	def Get(self, interface_name, property_name):
 | 
			
		||||
		value = getattr(self, 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
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
			
		||||
							in_signature='s', out_signature='a{sv}')
 | 
			
		||||
	def GetAll(self, interface_name):
 | 
			
		||||
		if interface_name in self.interface(True):
 | 
			
		||||
			# Using introspection, lets build this dynamically
 | 
			
		||||
			properties = get_properties(self)
 | 
			
		||||
			if interface_name in properties:
 | 
			
		||||
				return properties[interface_name][1]
 | 
			
		||||
			return {}
 | 
			
		||||
		raise dbus.exceptions.DBusException(
 | 
			
		||||
			self._ap_interface,
 | 
			
		||||
			'The object %s does not implement the %s interface'
 | 
			
		||||
			% (self.__class__, interface_name))
 | 
			
		||||
 | 
			
		||||
	@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
 | 
			
		||||
 | 
			
		||||
		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,142 +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
 | 
			
		||||
import dbus
 | 
			
		||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
 | 
			
		||||
import os
 | 
			
		||||
import threading
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
	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)
 | 
			
		||||
		except ValueError:
 | 
			
		||||
			log_error("Trying to parse percentage which failed for %s" %
 | 
			
		||||
				line_str)
 | 
			
		||||
 | 
			
		||||
	out = process.communicate()
 | 
			
		||||
 | 
			
		||||
	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,))
 | 
			
		||||
	t.start()
 | 
			
		||||
@@ -1,86 +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
 | 
			
		||||
ee = 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'
 | 
			
		||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
 | 
			
		||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
 | 
			
		||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
 | 
			
		||||
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"
 | 
			
		||||
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()
 | 
			
		||||
cache_pool_id = itertools.count()
 | 
			
		||||
job_id = itertools.count()
 | 
			
		||||
hidden_lv = itertools.count()
 | 
			
		||||
 | 
			
		||||
# Used to prevent circular imports...
 | 
			
		||||
load = None
 | 
			
		||||
event = None
 | 
			
		||||
 | 
			
		||||
# Global cached state
 | 
			
		||||
db = None
 | 
			
		||||
 | 
			
		||||
# lvm flight recorder
 | 
			
		||||
blackbox = None
 | 
			
		||||
@@ -1,751 +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
 | 
			
		||||
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.start = start
 | 
			
		||||
		self.ended = ended
 | 
			
		||||
		self.cmd = cmd
 | 
			
		||||
		self.ec = ec
 | 
			
		||||
		self.stdout_txt = stdout_txt
 | 
			
		||||
		self.stderr_txt = stderr_txt
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		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 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)
 | 
			
		||||
 | 
			
		||||
	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 != "":
 | 
			
		||||
			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, new_name, rename_options):
 | 
			
		||||
	cmd = ['vgrename']
 | 
			
		||||
	cmd.extend(options_to_cli_args(rename_options))
 | 
			
		||||
	cmd.extend([vg, 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', str(size_bytes) + 'B'])
 | 
			
		||||
	cmd.extend(['--name', name, vg_name])
 | 
			
		||||
	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', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--name', name, vg_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
 | 
			
		||||
	cmd = ['lvcreate']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	if not thin_pool:
 | 
			
		||||
		cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	else:
 | 
			
		||||
		cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
 | 
			
		||||
	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 = ['lvcreate']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	if not thin_pool:
 | 
			
		||||
		cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	else:
 | 
			
		||||
		cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--stripes', str(num_stripes)])
 | 
			
		||||
 | 
			
		||||
	if stripe_size_kb != 0:
 | 
			
		||||
		cmd.extend(['--stripesize', str(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', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	if num_stripes != 0:
 | 
			
		||||
		cmd.extend(['--stripes', str(num_stripes)])
 | 
			
		||||
 | 
			
		||||
	if stripe_size_kb != 0:
 | 
			
		||||
		cmd.extend(['--stripesize', str(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))
 | 
			
		||||
 | 
			
		||||
	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(num_copies)])
 | 
			
		||||
	cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	cmd.extend(['--name', name, vg_name])
 | 
			
		||||
	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 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', str(size_bytes) + 'B', '-T'])
 | 
			
		||||
	cmd.extend(['--name', name, lv_full_name])
 | 
			
		||||
	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_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 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 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']
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		# 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(['--setphysicalvolumesize', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	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 len(pv_devices) == 0:
 | 
			
		||||
		cmd.append('--all')
 | 
			
		||||
	if missing:
 | 
			
		||||
		cmd.append('--removemissing')
 | 
			
		||||
 | 
			
		||||
	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(number)],
 | 
			
		||||
							max_options)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_max_lv(vg_name, number, max_options):
 | 
			
		||||
	return _vg_value_set(vg_name, ['-l', str(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(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))
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user