mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			376 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1e5e26dbff | ||
| 
						 | 
					742fc54864 | ||
| 
						 | 
					49738f43c0 | ||
| 
						 | 
					9f85f61010 | ||
| 
						 | 
					239f422039 | ||
| 
						 | 
					67af3c37be | ||
| 
						 | 
					a9442385c4 | ||
| 
						 | 
					8c9cd10b8b | ||
| 
						 | 
					72542059dd | ||
| 
						 | 
					a843fc6d40 | ||
| 
						 | 
					4beed60c08 | ||
| 
						 | 
					4049c1e480 | ||
| 
						 | 
					8449314da2 | ||
| 
						 | 
					63ad057028 | ||
| 
						 | 
					e720464330 | ||
| 
						 | 
					24036afef9 | ||
| 
						 | 
					c78fa1a1bc | ||
| 
						 | 
					faa8b9022c | ||
| 
						 | 
					729bafef7a | ||
| 
						 | 
					590b028632 | ||
| 
						 | 
					8150d00f36 | ||
| 
						 | 
					060065926f | ||
| 
						 | 
					70babe8a28 | ||
| 
						 | 
					c36e09664f | ||
| 
						 | 
					a9672246f3 | ||
| 
						 | 
					ff571884e9 | ||
| 
						 | 
					475138bceb | ||
| 
						 | 
					4a8af199c2 | ||
| 
						 | 
					bdabf5db72 | ||
| 
						 | 
					6a5f21b34e | ||
| 
						 | 
					d608be103c | ||
| 
						 | 
					374bb5d18a | ||
| 
						 | 
					031d6c25ff | ||
| 
						 | 
					223fb7b075 | ||
| 
						 | 
					a746741971 | ||
| 
						 | 
					120faf2a58 | ||
| 
						 | 
					990bca0dc6 | ||
| 
						 | 
					3406472db7 | ||
| 
						 | 
					1bd733c9f6 | ||
| 
						 | 
					238c7f982e | ||
| 
						 | 
					fcb81147cb | ||
| 
						 | 
					1915b73783 | ||
| 
						 | 
					ee79e621fb | ||
| 
						 | 
					d203275a3b | ||
| 
						 | 
					9e8a996222 | ||
| 
						 | 
					0126b0b3ed | ||
| 
						 | 
					458928612c | ||
| 
						 | 
					e33f88e28d | ||
| 
						 | 
					be570bbf9e | ||
| 
						 | 
					f59b4be110 | ||
| 
						 | 
					37336e41be | ||
| 
						 | 
					d24a1a3f0a | ||
| 
						 | 
					f7258955bd | ||
| 
						 | 
					2a1eae5d6f | ||
| 
						 | 
					50ee0a4adb | ||
| 
						 | 
					955a26584e | ||
| 
						 | 
					1d3e407c8f | ||
| 
						 | 
					cb809c4596 | ||
| 
						 | 
					53bbe2888e | ||
| 
						 | 
					7246f476a5 | ||
| 
						 | 
					0785d1c390 | ||
| 
						 | 
					85d2c49d14 | ||
| 
						 | 
					8b77d62b7f | ||
| 
						 | 
					373058a32a | ||
| 
						 | 
					e6293c2c8c | ||
| 
						 | 
					eff181c959 | ||
| 
						 | 
					54752c2305 | ||
| 
						 | 
					b4753c044f | ||
| 
						 | 
					26493424ae | ||
| 
						 | 
					0282fd1332 | ||
| 
						 | 
					b9a019a08b | ||
| 
						 | 
					66f6a0e687 | ||
| 
						 | 
					2dd1b9f97d | ||
| 
						 | 
					89615f3045 | ||
| 
						 | 
					7e46192f67 | ||
| 
						 | 
					e78d985cdf | ||
| 
						 | 
					e8c4bf56fe | ||
| 
						 | 
					e6aa7d323d | ||
| 
						 | 
					fca8e25929 | ||
| 
						 | 
					8e8ac286b4 | ||
| 
						 | 
					7d9770b9a2 | ||
| 
						 | 
					1996230460 | ||
| 
						 | 
					de7897a864 | ||
| 
						 | 
					e2884dcdb7 | ||
| 
						 | 
					544a53a42b | ||
| 
						 | 
					2e4787bfc8 | ||
| 
						 | 
					1829eeb171 | ||
| 
						 | 
					c7488e3c4a | ||
| 
						 | 
					3bf9606383 | ||
| 
						 | 
					4f43f18f0a | ||
| 
						 | 
					5b7f197397 | ||
| 
						 | 
					018141c97f | ||
| 
						 | 
					4d7813e57c | ||
| 
						 | 
					605c60208f | ||
| 
						 | 
					884fafcc30 | ||
| 
						 | 
					56baa90320 | ||
| 
						 | 
					6bb20ee09e | ||
| 
						 | 
					541356430c | ||
| 
						 | 
					2f4d91fd69 | ||
| 
						 | 
					f58c5e6b30 | ||
| 
						 | 
					0311d0132c | ||
| 
						 | 
					c946c97402 | ||
| 
						 | 
					84a6f51318 | ||
| 
						 | 
					24a1501b0d | ||
| 
						 | 
					383b6f5fcc | ||
| 
						 | 
					633dd7ff9b | ||
| 
						 | 
					580624fad6 | ||
| 
						 | 
					a8190f7efa | ||
| 
						 | 
					dd2157534b | ||
| 
						 | 
					38a90e7669 | ||
| 
						 | 
					6bfc526dcd | ||
| 
						 | 
					aadb8a7405 | ||
| 
						 | 
					27082bf77e | ||
| 
						 | 
					a2903c80cd | ||
| 
						 | 
					9a77c5369c | ||
| 
						 | 
					3c30741a19 | ||
| 
						 | 
					7028ad4ec0 | ||
| 
						 | 
					8de750c6aa | ||
| 
						 | 
					04f98de9ee | ||
| 
						 | 
					a1a019784b | ||
| 
						 | 
					4aeeae77bd | ||
| 
						 | 
					651cfc2b78 | ||
| 
						 | 
					2ef8af25e2 | ||
| 
						 | 
					0b13852a5b | ||
| 
						 | 
					13427578c9 | ||
| 
						 | 
					d89ca2087e | ||
| 
						 | 
					8b0ea9fba6 | ||
| 
						 | 
					9f0b653d5a | ||
| 
						 | 
					659a339233 | ||
| 
						 | 
					4c29f177a0 | ||
| 
						 | 
					d664e63d55 | ||
| 
						 | 
					2493509dbe | ||
| 
						 | 
					1c8b27f554 | ||
| 
						 | 
					68297b7186 | ||
| 
						 | 
					34dd8d0a91 | ||
| 
						 | 
					81c44790d5 | ||
| 
						 | 
					d557b335cf | ||
| 
						 | 
					e2adc28cff | ||
| 
						 | 
					0fef6a6ecc | ||
| 
						 | 
					f2fd4b8a1f | ||
| 
						 | 
					95bd5605a8 | ||
| 
						 | 
					497cca7eca | ||
| 
						 | 
					54f78feedd | ||
| 
						 | 
					76408e53ae | ||
| 
						 | 
					be19e74d30 | ||
| 
						 | 
					dac578a775 | ||
| 
						 | 
					04732ce74b | ||
| 
						 | 
					a6c95a2374 | ||
| 
						 | 
					f68622abe9 | ||
| 
						 | 
					83a9a7bdb2 | ||
| 
						 | 
					6500afc0ca | ||
| 
						 | 
					c69b7ecc96 | ||
| 
						 | 
					615ef1e2d2 | ||
| 
						 | 
					cf69a0cd7f | ||
| 
						 | 
					06e892fb33 | ||
| 
						 | 
					e6c5dd6865 | ||
| 
						 | 
					247efdebdb | ||
| 
						 | 
					76f3792287 | ||
| 
						 | 
					64d8e2c727 | ||
| 
						 | 
					ead0bd9cb0 | ||
| 
						 | 
					66fc13b2ec | ||
| 
						 | 
					f3af4128b0 | ||
| 
						 | 
					0e43107c87 | ||
| 
						 | 
					1ee3e7997e | ||
| 
						 | 
					50fd61d91f | ||
| 
						 | 
					e4cdc051a9 | ||
| 
						 | 
					778e846e96 | ||
| 
						 | 
					a27759b647 | ||
| 
						 | 
					b75eceab41 | ||
| 
						 | 
					e748a5d5f4 | ||
| 
						 | 
					99c5a3ae46 | ||
| 
						 | 
					51da710f5a | ||
| 
						 | 
					569d69b3d2 | ||
| 
						 | 
					059a6b1d90 | ||
| 
						 | 
					990af7548a | ||
| 
						 | 
					a38aefdfc8 | ||
| 
						 | 
					3bcb12e7d1 | ||
| 
						 | 
					7904ecb462 | ||
| 
						 | 
					9ba4d45109 | ||
| 
						 | 
					56b8afe19d | ||
| 
						 | 
					f7aed9a94c | ||
| 
						 | 
					e12a7e881d | ||
| 
						 | 
					5afb65325d | ||
| 
						 | 
					135f520f32 | ||
| 
						 | 
					bc251f4ff6 | ||
| 
						 | 
					b8769751f6 | ||
| 
						 | 
					eff96d839e | ||
| 
						 | 
					aa34c23807 | ||
| 
						 | 
					195acdac8c | ||
| 
						 | 
					903e03c56c | ||
| 
						 | 
					0892767b8a | ||
| 
						 | 
					83ebfa772c | ||
| 
						 | 
					1583641322 | ||
| 
						 | 
					9510e2c256 | ||
| 
						 | 
					a9dbabe07e | ||
| 
						 | 
					12884008fa | ||
| 
						 | 
					02543bad1c | ||
| 
						 | 
					a8c56a5251 | ||
| 
						 | 
					4e5a855f3f | ||
| 
						 | 
					7e497a951e | ||
| 
						 | 
					cd08eabbfa | ||
| 
						 | 
					f7e62d9f81 | ||
| 
						 | 
					9a3761e86e | ||
| 
						 | 
					3619a68693 | ||
| 
						 | 
					efaf3c3bf9 | ||
| 
						 | 
					0e4e6a6f67 | ||
| 
						 | 
					42458e6278 | ||
| 
						 | 
					41ec995377 | ||
| 
						 | 
					4f37599326 | ||
| 
						 | 
					4144520e5c | ||
| 
						 | 
					6c4800546c | ||
| 
						 | 
					733733c8a7 | ||
| 
						 | 
					2aa67cc946 | ||
| 
						 | 
					9385981a9d | ||
| 
						 | 
					fff780035d | ||
| 
						 | 
					46127e673d | ||
| 
						 | 
					70df59b224 | ||
| 
						 | 
					0fdbaa803f | ||
| 
						 | 
					6af1830eff | ||
| 
						 | 
					6f860e2bd5 | ||
| 
						 | 
					20a492f7ee | ||
| 
						 | 
					63875e7591 | ||
| 
						 | 
					0ad98cabde | ||
| 
						 | 
					668879d2e1 | ||
| 
						 | 
					2e09783302 | ||
| 
						 | 
					49734114b3 | ||
| 
						 | 
					950d9d6ee7 | ||
| 
						 | 
					f7974aee2e | ||
| 
						 | 
					c870a82621 | ||
| 
						 | 
					984929a001 | ||
| 
						 | 
					7f9e2c1db8 | ||
| 
						 | 
					324e8389dc | ||
| 
						 | 
					6f448c5a38 | ||
| 
						 | 
					ec43efbb20 | ||
| 
						 | 
					3ed065de37 | ||
| 
						 | 
					8152f0d72c | ||
| 
						 | 
					f8047f4736 | ||
| 
						 | 
					b93c66dc2d | ||
| 
						 | 
					ac877b3065 | ||
| 
						 | 
					dee8abfdde | ||
| 
						 | 
					cef3841d73 | ||
| 
						 | 
					3cd5e8a041 | ||
| 
						 | 
					515b5f866e | ||
| 
						 | 
					321f62bf92 | ||
| 
						 | 
					f94fa47b52 | ||
| 
						 | 
					c502f8a722 | ||
| 
						 | 
					59b4868ac3 | ||
| 
						 | 
					3634e12cce | ||
| 
						 | 
					6d45445391 | ||
| 
						 | 
					4f47e268cc | ||
| 
						 | 
					0035b31cdb | ||
| 
						 | 
					f2565aee03 | ||
| 
						 | 
					5bd85668dd | ||
| 
						 | 
					20f990b6ce | ||
| 
						 | 
					6821379586 | ||
| 
						 | 
					73b040eb49 | ||
| 
						 | 
					49aa4b2e1e | ||
| 
						 | 
					972241c74c | ||
| 
						 | 
					680750e3c2 | ||
| 
						 | 
					5e7d4d9d15 | ||
| 
						 | 
					1e57e60613 | ||
| 
						 | 
					3ac7ce605a | ||
| 
						 | 
					b720dea9f0 | ||
| 
						 | 
					c80722aefe | ||
| 
						 | 
					a84fa69f28 | ||
| 
						 | 
					e33781e59f | ||
| 
						 | 
					8824bc7ece | ||
| 
						 | 
					c2e3b0e448 | ||
| 
						 | 
					f61a38e85a | ||
| 
						 | 
					d23e948216 | ||
| 
						 | 
					58bdaa31f0 | ||
| 
						 | 
					b6491d88a6 | ||
| 
						 | 
					f6061ba62e | ||
| 
						 | 
					427899ddce | ||
| 
						 | 
					c4ab7d2dbd | ||
| 
						 | 
					0fd2ba033f | ||
| 
						 | 
					ed38939a93 | ||
| 
						 | 
					c7ee26ce5a | ||
| 
						 | 
					909b8cb303 | ||
| 
						 | 
					b0277370cf | ||
| 
						 | 
					2ec8656bea | ||
| 
						 | 
					b2ef256910 | ||
| 
						 | 
					63d6ce95db | ||
| 
						 | 
					a9532b189c | ||
| 
						 | 
					844545411f | ||
| 
						 | 
					4e23a2b9b8 | ||
| 
						 | 
					5deba027eb | ||
| 
						 | 
					fc8b7efc6f | ||
| 
						 | 
					a1c2d9c0f3 | ||
| 
						 | 
					4ca49a0501 | ||
| 
						 | 
					493c53d090 | ||
| 
						 | 
					b27e956d35 | ||
| 
						 | 
					35ebed75c6 | ||
| 
						 | 
					7bfdb5f77f | ||
| 
						 | 
					8d8c02317f | ||
| 
						 | 
					a34482feab | ||
| 
						 | 
					cbdc8fd4a6 | ||
| 
						 | 
					8d3afaa53c | ||
| 
						 | 
					7ced9ef3df | ||
| 
						 | 
					e8a9ae7e80 | ||
| 
						 | 
					73a88ab3d3 | ||
| 
						 | 
					aaed82738a | ||
| 
						 | 
					de7f7b96db | ||
| 
						 | 
					1a669b3e68 | ||
| 
						 | 
					333af9b13a | ||
| 
						 | 
					a5bca5e240 | ||
| 
						 | 
					c885633e02 | ||
| 
						 | 
					ca7e20b7ca | ||
| 
						 | 
					545e11a3d7 | ||
| 
						 | 
					44f5287664 | ||
| 
						 | 
					cf510897f1 | ||
| 
						 | 
					1d171345f8 | ||
| 
						 | 
					4fa7e1cd49 | ||
| 
						 | 
					acd008298e | ||
| 
						 | 
					83a8021515 | ||
| 
						 | 
					cf88dfb1db | ||
| 
						 | 
					8937c4b481 | ||
| 
						 | 
					cc6af10a4d | ||
| 
						 | 
					6d94578955 | ||
| 
						 | 
					08442ab71e | ||
| 
						 | 
					10d91d213f | ||
| 
						 | 
					b7a3b06994 | ||
| 
						 | 
					5f12c37f23 | ||
| 
						 | 
					585edebccd | ||
| 
						 | 
					9921c62234 | ||
| 
						 | 
					1ac76d2e16 | ||
| 
						 | 
					6e983bf400 | ||
| 
						 | 
					6a8fd4fa6e | ||
| 
						 | 
					3698eaa2d2 | ||
| 
						 | 
					8d97ca433c | ||
| 
						 | 
					23cc65e537 | ||
| 
						 | 
					2f5a3c2bbe | ||
| 
						 | 
					f6485616cd | ||
| 
						 | 
					6544fb43d9 | ||
| 
						 | 
					a954b32dcc | ||
| 
						 | 
					426dc7836c | ||
| 
						 | 
					ff941ffc16 | ||
| 
						 | 
					a063c201df | ||
| 
						 | 
					e2be3fa0aa | ||
| 
						 | 
					609da6fb50 | ||
| 
						 | 
					fc9f3ccec3 | ||
| 
						 | 
					f7baa67a0a | ||
| 
						 | 
					e8d78c2cdb | ||
| 
						 | 
					9d33366092 | ||
| 
						 | 
					f5d61515c2 | ||
| 
						 | 
					711a04a972 | ||
| 
						 | 
					e5b470a3f1 | ||
| 
						 | 
					31820e1e22 | ||
| 
						 | 
					4849e8cd6d | ||
| 
						 | 
					77e3b460aa | ||
| 
						 | 
					b5321001f8 | ||
| 
						 | 
					38eba9f5ea | ||
| 
						 | 
					ea6f399454 | ||
| 
						 | 
					f8bf2d7b7d | ||
| 
						 | 
					c4856caebb | ||
| 
						 | 
					fc1030bb22 | ||
| 
						 | 
					9eb6cad8dc | ||
| 
						 | 
					0fa2a78dce | ||
| 
						 | 
					a56fa1558b | ||
| 
						 | 
					261c73a997 | ||
| 
						 | 
					929c1333ca | ||
| 
						 | 
					286a79d94d | ||
| 
						 | 
					8b951f99da | ||
| 
						 | 
					abb449bca0 | ||
| 
						 | 
					bd084028d1 | ||
| 
						 | 
					138a27570b | ||
| 
						 | 
					c2ed40a74f | ||
| 
						 | 
					a7e7a00cab | ||
| 
						 | 
					64a31ab3cd | ||
| 
						 | 
					71958bc0f1 | ||
| 
						 | 
					366ec35612 | ||
| 
						 | 
					3738f6e8ae | ||
| 
						 | 
					051a8e2af1 | ||
| 
						 | 
					2f43f28d5e | ||
| 
						 | 
					b64769754b | ||
| 
						 | 
					a97daa18d1 | 
							
								
								
									
										3
									
								
								BUGS
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								BUGS
									
									
									
									
									
								
							@@ -1 +1,2 @@
 | 
			
		||||
LVM2's device-mapper driver and ext3 are incompatible at the moment.
 | 
			
		||||
Snapshots under 2.4.18 can deadlock due to a bug in the VM system.
 | 
			
		||||
2.4.19-pre8 is fine.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								INSTALL
									
									
									
									
									
								
							@@ -6,8 +6,8 @@ LVM2 installation
 | 
			
		||||
   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.
 | 
			
		||||
   messages in the kernel logs) and /usr/include/libdevmapper.h 
 | 
			
		||||
   and libdevmapper.so should be present.
 | 
			
		||||
 | 
			
		||||
   The device-mapper is available from:
 | 
			
		||||
     ftp://ftp.sistina.com/pub/LVM2/device-mapper/
 | 
			
		||||
@@ -17,9 +17,15 @@ LVM2 installation
 | 
			
		||||
 | 
			
		||||
   Run the 'configure' script from the top directory.
 | 
			
		||||
 | 
			
		||||
   If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
 | 
			
		||||
   installed use
 | 
			
		||||
     ./configure --disable-readline
 | 
			
		||||
   If you wish to use the built-in LVM2 shell and have GNU readline 
 | 
			
		||||
   installed (http://www.gnu.org/directory/readline.html) use:
 | 
			
		||||
     ./configure --enable-readline
 | 
			
		||||
 | 
			
		||||
   If you don't want to include the LVM1 backwards-compatibility code use:
 | 
			
		||||
     ./configure --with-lvm1=none 
 | 
			
		||||
 | 
			
		||||
   To separate the LVM1 support into a shared library loaded by lvm.conf use:
 | 
			
		||||
     ./configure --with-lvm1=shared
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
3) Build and install LVM2.
 | 
			
		||||
@@ -31,6 +37,9 @@ LVM2 installation
 | 
			
		||||
 | 
			
		||||
   The tools will work fine without a configuration file being
 | 
			
		||||
   present, but you ought to review the example file in doc/example.conf.
 | 
			
		||||
   For example, specifying the devices that LVM2 is to use should
 | 
			
		||||
   For example, specifying the devices that LVM2 is to use can
 | 
			
		||||
   make the tools run more efficiently - and avoid scanning /dev/cdrom!
 | 
			
		||||
 | 
			
		||||
Please also refer to the WHATS_NEW file and the manual pages for the 
 | 
			
		||||
individual commands.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								INTRO
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								INTRO
									
									
									
									
									
								
							@@ -1,18 +0,0 @@
 | 
			
		||||
An introduction to LVM2
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
Background
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Compatibility with LVM1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
New features
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Missing features
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Future enhancements
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -23,7 +23,8 @@ VPATH = @srcdir@
 | 
			
		||||
SUBDIRS = include man lib tools
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
  SUBDIRS += test/mm test/device test/format1 test/regex test/filters
 | 
			
		||||
  SUBDIRS += lib/format1 \
 | 
			
		||||
	     test/mm test/device test/format1 test/regex test/filters
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
include make.tmpl
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README
									
									
									
									
									
								
							@@ -1,13 +1,11 @@
 | 
			
		||||
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.
 | 
			
		||||
This directory contains LVM2, the new version of the userland LVM
 | 
			
		||||
tools designed for the new device-mapper for the Linux kernel.
 | 
			
		||||
 | 
			
		||||
The device-mapper needs to be installed before compiling these LVM2 tools.
 | 
			
		||||
 | 
			
		||||
For more information about LVM2 read the INTRO file.
 | 
			
		||||
For more information about LVM2 read the WHATS_NEW file.
 | 
			
		||||
Installation instructions are in INSTALL.
 | 
			
		||||
 | 
			
		||||
This is beta-quality software, released for testing purposes only.
 | 
			
		||||
There is no warranty - see COPYING and COPYING.LIB.
 | 
			
		||||
 | 
			
		||||
Tarballs are available from:
 | 
			
		||||
@@ -20,6 +18,6 @@ To access the CVS tree use:
 | 
			
		||||
  cvs -d :pserver:cvs@tech.sistina.com:/data/cvs checkout LVM2
 | 
			
		||||
 | 
			
		||||
Mailing list for discussion/bug reports etc.
 | 
			
		||||
  lvm-devel@sistina.com
 | 
			
		||||
  Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
 | 
			
		||||
  linux-lvm@sistina.com
 | 
			
		||||
  Subscribe from http://lists.sistina.com/mailman/listinfo/linux-lvm
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								TODO
									
									
									
									
									
								
							@@ -1,29 +0,0 @@
 | 
			
		||||
before 2.0
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
vgexport
 | 
			
		||||
vgimport
 | 
			
		||||
snapshots
 | 
			
		||||
device-mapper support for 2.5 kernel series
 | 
			
		||||
review FIXMEs
 | 
			
		||||
extra validation & full consistency checks in format1 with LVM1
 | 
			
		||||
partial activation
 | 
			
		||||
error message review
 | 
			
		||||
locking during metadata changes
 | 
			
		||||
format2 with atomic transactions
 | 
			
		||||
bidirectional format1/format2 migration tool
 | 
			
		||||
persistent minors
 | 
			
		||||
stats
 | 
			
		||||
pvmove
 | 
			
		||||
review tool exit codes for LVM1 compatibility
 | 
			
		||||
 | 
			
		||||
before 2.1
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
e2fsadm
 | 
			
		||||
lvmdiskscan
 | 
			
		||||
lvmsadc
 | 
			
		||||
lvmsar
 | 
			
		||||
pvdata
 | 
			
		||||
vgsplit
 | 
			
		||||
vgmknodes
 | 
			
		||||
							
								
								
									
										94
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								WHATS_NEW
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
Wednesday 30th April 2003
 | 
			
		||||
=========================
 | 
			
		||||
A pvmove implementation is now available for the new metadata format.
 | 
			
		||||
 | 
			
		||||
When running a command that allocates space (e.g. lvcreate), you can now
 | 
			
		||||
restrict not only which disk(s) may be used but also the Physical Extents 
 | 
			
		||||
on those disks.  e.g. lvcreate -L 10 vg1 /dev/hda6:1000-2000:3000-4000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Monday 18th November 2002
 | 
			
		||||
========================
 | 
			
		||||
 | 
			
		||||
The new format of LVM metadata is ready for you to test!
 | 
			
		||||
  We expect it to be more efficient and more robust than the original format.
 | 
			
		||||
  It's more compact and supports transactional changes and replication.
 | 
			
		||||
  Should things go wrong on a system, it's human-readable (and editable).
 | 
			
		||||
 | 
			
		||||
Please report any problems you find to the mailing list, 
 | 
			
		||||
linux-lvm@sistina.com.  The software has NOT yet been thoroughly
 | 
			
		||||
tested and so quite possibly there'll still be some bugs in it.
 | 
			
		||||
Be aware of the disclaimer in the COPYING file.
 | 
			
		||||
 | 
			
		||||
While testing, we recommend turning logging on in the configuration file 
 | 
			
		||||
to provide us with diagnostic information:
 | 
			
		||||
  log {
 | 
			
		||||
        file="/tmp/lvm2.log"
 | 
			
		||||
	level=7
 | 
			
		||||
	activation=1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
You should schedule regular backups of your configuration file and
 | 
			
		||||
metadata backups and archives (normally kept under /etc/lvm).
 | 
			
		||||
 | 
			
		||||
Please read docs/example.conf and "man lvm.conf" to find out more about 
 | 
			
		||||
the configuration file.
 | 
			
		||||
 | 
			
		||||
To convert an existing volume group called vg1 to the new format using
 | 
			
		||||
the default settings, use "vgconvert -M2 vg1".  See "man vgconvert".
 | 
			
		||||
 | 
			
		||||
-M (or --metadatatype in its long form) is a new flag to indicate which
 | 
			
		||||
format of metadata the command should use for anything it creates.
 | 
			
		||||
Currently, the valid types are "lvm1" and "lvm2" and they can be
 | 
			
		||||
abbreviated to "1" and "2" respectively.  The default value for this
 | 
			
		||||
flag can be changed in the global section in the config file.
 | 
			
		||||
 | 
			
		||||
Backwards-compatible support for the original LVM1 metadata format is
 | 
			
		||||
maintained, but it can be moved into a shared library or removed
 | 
			
		||||
completely with configure's --with-lvm1 option.
 | 
			
		||||
 | 
			
		||||
Under LVM2, the basic unit of metadata is the volume group.  Different
 | 
			
		||||
volume groups can use different formats of metadata - vg1 could use
 | 
			
		||||
the original LVM1 format while vg2 used the new format - but you can't
 | 
			
		||||
mix formats within a volume group.  So to add a PV to an LVM2-format
 | 
			
		||||
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
 | 
			
		||||
 | 
			
		||||
With LVM2-format metadata, lvextend will let you specify striping
 | 
			
		||||
parameters.  So an LV could consist of two or more "segments" - the
 | 
			
		||||
first segment could have 3 stripes while the second segment has just 2.
 | 
			
		||||
 | 
			
		||||
LVM2 maintains a backup of the current metadata for each volume group
 | 
			
		||||
in /etc/lvm/backup, and puts copies of previous versions in
 | 
			
		||||
/etc/lvm/archive.  "vgcfgbackup" and "vgcfgrestore" can be used to
 | 
			
		||||
create and restore from these files.  If you fully understand what 
 | 
			
		||||
you're doing, metadata can be changed by editing a copy of a current
 | 
			
		||||
backup file and using vgcfgrestore to reload it.
 | 
			
		||||
 | 
			
		||||
Please read the pvcreate man page for more information on the new
 | 
			
		||||
format for metadata.
 | 
			
		||||
 | 
			
		||||
All tools that can change things have a --test flag which can be used
 | 
			
		||||
to check the effect  of a set of cmdline args without really making the
 | 
			
		||||
changes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
What's not finished?
 | 
			
		||||
====================
 | 
			
		||||
The internal cache.  If you turn on debugging output you'll see lots of
 | 
			
		||||
repeated messages, many of which will eventually get optimised out.
 | 
			
		||||
 | 
			
		||||
--test sometimes causes a command to fail (e.g. vgconvert --test) even 
 | 
			
		||||
though the real command would work: again, fixing this is waiting for 
 | 
			
		||||
the work on the cache.
 | 
			
		||||
 | 
			
		||||
Several of the tools do not yet contain the logic to handle full
 | 
			
		||||
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
 | 
			
		||||
needed to restore metadata if a tool gets interrupted or crashes or
 | 
			
		||||
finds something unexpected.  This applies particularly to tools that
 | 
			
		||||
work on more than one volume group at once (e.g. vgsplit).
 | 
			
		||||
 | 
			
		||||
Display output.  Some metadata information cannot yet be displayed.
 | 
			
		||||
 | 
			
		||||
Recovery tools to salvage "lost" metadata directly from the disks:
 | 
			
		||||
but we hope the new format will mean such tools are hardly ever needed!
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										777
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										777
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										373
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										373
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,10 @@
 | 
			
		||||
#! /bin/sh
 | 
			
		||||
# Configuration validation subroutine script, version 1.1.
 | 
			
		||||
#   Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
 | 
			
		||||
# Configuration validation subroutine script.
 | 
			
		||||
#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
 | 
			
		||||
#   Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
timestamp='2001-09-07'
 | 
			
		||||
 | 
			
		||||
# This file is (in principle) common to ALL GNU software.
 | 
			
		||||
# The presence of a machine in this file suggests that SOME GNU software
 | 
			
		||||
# can handle that machine.  It does not imply ALL GNU software can.
 | 
			
		||||
@@ -25,6 +29,8 @@
 | 
			
		||||
# configuration script generated by Autoconf, you may include it under
 | 
			
		||||
# the same distribution terms that you use for the rest of that program.
 | 
			
		||||
 | 
			
		||||
# Please send patches to <config-patches@gnu.org>.
 | 
			
		||||
#
 | 
			
		||||
# Configuration subroutine to validate and canonicalize a configuration type.
 | 
			
		||||
# Supply the specified configuration type as an argument.
 | 
			
		||||
# If it is invalid, we print an error message on stderr and exit with code 1.
 | 
			
		||||
@@ -45,30 +51,73 @@
 | 
			
		||||
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
 | 
			
		||||
# It is wrong to echo any other type of specification.
 | 
			
		||||
 | 
			
		||||
if [ x$1 = x ]
 | 
			
		||||
then
 | 
			
		||||
	echo Configuration name missing. 1>&2
 | 
			
		||||
	echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
 | 
			
		||||
	echo "or     $0 ALIAS" 1>&2
 | 
			
		||||
	echo where ALIAS is a recognized configuration type. 1>&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
me=`echo "$0" | sed -e 's,.*/,,'`
 | 
			
		||||
 | 
			
		||||
# First pass through any local machine types.
 | 
			
		||||
case $1 in
 | 
			
		||||
	*local*)
 | 
			
		||||
		echo $1
 | 
			
		||||
		exit 0
 | 
			
		||||
		;;
 | 
			
		||||
	*)
 | 
			
		||||
	;;
 | 
			
		||||
usage="\
 | 
			
		||||
Usage: $0 [OPTION] CPU-MFR-OPSYS
 | 
			
		||||
       $0 [OPTION] ALIAS
 | 
			
		||||
 | 
			
		||||
Canonicalize a configuration name.
 | 
			
		||||
 | 
			
		||||
Operation modes:
 | 
			
		||||
  -h, --help         print this help, then exit
 | 
			
		||||
  -t, --time-stamp   print date of last modification, then exit
 | 
			
		||||
  -v, --version      print version number, then exit
 | 
			
		||||
 | 
			
		||||
Report bugs and patches to <config-patches@gnu.org>."
 | 
			
		||||
 | 
			
		||||
version="\
 | 
			
		||||
GNU config.sub ($timestamp)
 | 
			
		||||
 | 
			
		||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
 | 
			
		||||
Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
This is free software; see the source for copying conditions.  There is NO
 | 
			
		||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 | 
			
		||||
 | 
			
		||||
help="
 | 
			
		||||
Try \`$me --help' for more information."
 | 
			
		||||
 | 
			
		||||
# Parse command line
 | 
			
		||||
while test $# -gt 0 ; do
 | 
			
		||||
  case $1 in
 | 
			
		||||
    --time-stamp | --time* | -t )
 | 
			
		||||
       echo "$timestamp" ; exit 0 ;;
 | 
			
		||||
    --version | -v )
 | 
			
		||||
       echo "$version" ; exit 0 ;;
 | 
			
		||||
    --help | --h* | -h )
 | 
			
		||||
       echo "$usage"; exit 0 ;;
 | 
			
		||||
    -- )     # Stop option processing
 | 
			
		||||
       shift; break ;;
 | 
			
		||||
    - )	# Use stdin as input.
 | 
			
		||||
       break ;;
 | 
			
		||||
    -* )
 | 
			
		||||
       echo "$me: invalid option $1$help"
 | 
			
		||||
       exit 1 ;;
 | 
			
		||||
 | 
			
		||||
    *local*)
 | 
			
		||||
       # First pass through any local machine types.
 | 
			
		||||
       echo $1
 | 
			
		||||
       exit 0;;
 | 
			
		||||
 | 
			
		||||
    * )
 | 
			
		||||
       break ;;
 | 
			
		||||
  esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
case $# in
 | 
			
		||||
 0) echo "$me: missing argument$help" >&2
 | 
			
		||||
    exit 1;;
 | 
			
		||||
 1) ;;
 | 
			
		||||
 *) echo "$me: too many arguments$help" >&2
 | 
			
		||||
    exit 1;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
 | 
			
		||||
# Here we must recognize all the valid KERNEL-OS combinations.
 | 
			
		||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 | 
			
		||||
case $maybe_os in
 | 
			
		||||
  linux-gnu*)
 | 
			
		||||
  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
 | 
			
		||||
    os=-$maybe_os
 | 
			
		||||
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
 | 
			
		||||
    ;;
 | 
			
		||||
@@ -94,7 +143,7 @@ case $os in
 | 
			
		||||
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
 | 
			
		||||
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
 | 
			
		||||
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
 | 
			
		||||
	-apple)
 | 
			
		||||
	-apple | -axis)
 | 
			
		||||
		os=
 | 
			
		||||
		basic_machine=$1
 | 
			
		||||
		;;
 | 
			
		||||
@@ -105,9 +154,17 @@ case $os in
 | 
			
		||||
	-scout)
 | 
			
		||||
		;;
 | 
			
		||||
	-wrs)
 | 
			
		||||
		os=vxworks
 | 
			
		||||
		os=-vxworks
 | 
			
		||||
		basic_machine=$1
 | 
			
		||||
		;;
 | 
			
		||||
	-chorusos*)
 | 
			
		||||
		os=-chorusos
 | 
			
		||||
		basic_machine=$1
 | 
			
		||||
		;;
 | 
			
		||||
 	-chorusrdb)
 | 
			
		||||
 		os=-chorusrdb
 | 
			
		||||
		basic_machine=$1
 | 
			
		||||
 		;;
 | 
			
		||||
	-hiux*)
 | 
			
		||||
		os=-hiuxwe2
 | 
			
		||||
		;;
 | 
			
		||||
@@ -156,33 +213,60 @@ case $os in
 | 
			
		||||
	-psos*)
 | 
			
		||||
		os=-psos
 | 
			
		||||
		;;
 | 
			
		||||
	-mint | -mint[0-9]*)
 | 
			
		||||
		basic_machine=m68k-atari
 | 
			
		||||
		os=-mint
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# Decode aliases for certain CPU-COMPANY combinations.
 | 
			
		||||
case $basic_machine in
 | 
			
		||||
	# Recognize the basic CPU types without company name.
 | 
			
		||||
	# Some are omitted here because they have special meanings below.
 | 
			
		||||
	tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
 | 
			
		||||
		| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
 | 
			
		||||
		| 580 | i960 | h8300 \
 | 
			
		||||
		| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
 | 
			
		||||
		| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
 | 
			
		||||
		| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
 | 
			
		||||
		| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
 | 
			
		||||
		| mips64orion | mips64orionel | mipstx39 | mipstx39el \
 | 
			
		||||
		| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
 | 
			
		||||
		| mips64vr5000 | miprs64vr5000el | mcore \
 | 
			
		||||
		| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
 | 
			
		||||
		| thumb | d10v)
 | 
			
		||||
	1750a | 580 \
 | 
			
		||||
	| a29k \
 | 
			
		||||
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
 | 
			
		||||
	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
 | 
			
		||||
	| c4x | clipper \
 | 
			
		||||
	| d10v | d30v | dsp16xx \
 | 
			
		||||
	| fr30 \
 | 
			
		||||
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 | 
			
		||||
	| i370 | i860 | i960 | ia64 \
 | 
			
		||||
	| m32r | m68000 | m68k | m88k | mcore \
 | 
			
		||||
	| mips16 | mips64 | mips64el | mips64orion | mips64orionel \
 | 
			
		||||
	| mips64vr4100 | mips64vr4100el | mips64vr4300 \
 | 
			
		||||
	| mips64vr4300el | mips64vr5000 | mips64vr5000el \
 | 
			
		||||
	| mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \
 | 
			
		||||
	| mipsisa32 \
 | 
			
		||||
	| mn10200 | mn10300 \
 | 
			
		||||
	| ns16k | ns32k \
 | 
			
		||||
	| openrisc \
 | 
			
		||||
	| pdp10 | pdp11 | pj | pjl \
 | 
			
		||||
	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
 | 
			
		||||
	| pyramid \
 | 
			
		||||
	| s390 | s390x \
 | 
			
		||||
	| sh | sh[34] | sh[34]eb | shbe | shle \
 | 
			
		||||
	| sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \
 | 
			
		||||
	| stormy16 | strongarm \
 | 
			
		||||
	| tahoe | thumb | tic80 | tron \
 | 
			
		||||
	| v850 \
 | 
			
		||||
	| we32k \
 | 
			
		||||
	| x86 | xscale \
 | 
			
		||||
	| z8k)
 | 
			
		||||
		basic_machine=$basic_machine-unknown
 | 
			
		||||
		;;
 | 
			
		||||
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65)
 | 
			
		||||
	m6811 | m68hc11 | m6812 | m68hc12)
 | 
			
		||||
		# Motorola 68HC11/12.
 | 
			
		||||
		basic_machine=$basic_machine-unknown
 | 
			
		||||
		os=-none
 | 
			
		||||
		;;
 | 
			
		||||
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
 | 
			
		||||
		;;
 | 
			
		||||
 | 
			
		||||
	# We use `pc' rather than `unknown'
 | 
			
		||||
	# because (1) that's what they normally are, and
 | 
			
		||||
	# (2) the word "unknown" tends to confuse beginning users.
 | 
			
		||||
	i[34567]86)
 | 
			
		||||
	i*86 | x86_64)
 | 
			
		||||
	  basic_machine=$basic_machine-pc
 | 
			
		||||
	  ;;
 | 
			
		||||
	# Object if more than one company name word.
 | 
			
		||||
@@ -191,24 +275,43 @@ case $basic_machine in
 | 
			
		||||
		exit 1
 | 
			
		||||
		;;
 | 
			
		||||
	# Recognize the basic CPU types with company name.
 | 
			
		||||
	# FIXME: clean up the formatting here.
 | 
			
		||||
	vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
 | 
			
		||||
	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
 | 
			
		||||
	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
 | 
			
		||||
	      | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
 | 
			
		||||
	      | xmp-* | ymp-* \
 | 
			
		||||
	      | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
 | 
			
		||||
	      | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
 | 
			
		||||
	      | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
 | 
			
		||||
	      | clipper-* | orion-* \
 | 
			
		||||
	      | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
 | 
			
		||||
	      | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
 | 
			
		||||
	      | mips64el-* | mips64orion-* | mips64orionel-* \
 | 
			
		||||
	      | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
 | 
			
		||||
	      | mipstx39-* | mipstx39el-* | mcore-* \
 | 
			
		||||
	      | f301-* | armv*-* | t3e-* \
 | 
			
		||||
	      | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
 | 
			
		||||
	      | thumb-* | v850-* | d30v-* | tic30-* | c30-* )
 | 
			
		||||
	580-* \
 | 
			
		||||
	| a29k-* \
 | 
			
		||||
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
 | 
			
		||||
	| alphapca5[67]-* | arc-* \
 | 
			
		||||
	| arm-*  | armbe-* | armle-* | armv*-* \
 | 
			
		||||
	| bs2000-* \
 | 
			
		||||
	| c[123]* | c30-* | [cjt]90-* | c54x-* \
 | 
			
		||||
	| clipper-* | cray2-* | cydra-* \
 | 
			
		||||
	| d10v-* | d30v-* \
 | 
			
		||||
	| elxsi-* \
 | 
			
		||||
	| f30[01]-* | f700-* | fr30-* | fx80-* \
 | 
			
		||||
	| h8300-* | h8500-* \
 | 
			
		||||
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
 | 
			
		||||
	| i*86-* | i860-* | i960-* | ia64-* \
 | 
			
		||||
	| m32r-* \
 | 
			
		||||
	| m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
 | 
			
		||||
	| m88110-* | m88k-* | mcore-* \
 | 
			
		||||
	| mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
 | 
			
		||||
	| mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
 | 
			
		||||
	| mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \
 | 
			
		||||
	| mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \
 | 
			
		||||
	| none-* | np1-* | ns16k-* | ns32k-* \
 | 
			
		||||
	| orion-* \
 | 
			
		||||
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 | 
			
		||||
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
 | 
			
		||||
	| pyramid-* \
 | 
			
		||||
	| romp-* | rs6000-* \
 | 
			
		||||
	| s390-* | s390x-* \
 | 
			
		||||
	| sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \
 | 
			
		||||
	| sparc-* | sparc64-* | sparc86x-* | sparclite-* \
 | 
			
		||||
	| sparcv9-* | sparcv9b-* | stormy16-* | strongarm-* | sv1-* \
 | 
			
		||||
	| t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
 | 
			
		||||
	| v850-* | vax-* \
 | 
			
		||||
	| we32k-* \
 | 
			
		||||
	| x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \
 | 
			
		||||
	| ymp-* \
 | 
			
		||||
	| z8k-*)
 | 
			
		||||
		;;
 | 
			
		||||
	# Recognize the various machine names and aliases which stand
 | 
			
		||||
	# for a CPU type and a company and sometimes even an OS.
 | 
			
		||||
@@ -245,14 +348,14 @@ case $basic_machine in
 | 
			
		||||
		os=-sysv
 | 
			
		||||
		;;
 | 
			
		||||
	amiga | amiga-*)
 | 
			
		||||
		basic_machine=m68k-cbm
 | 
			
		||||
		basic_machine=m68k-unknown
 | 
			
		||||
		;;
 | 
			
		||||
	amigaos | amigados)
 | 
			
		||||
		basic_machine=m68k-cbm
 | 
			
		||||
		basic_machine=m68k-unknown
 | 
			
		||||
		os=-amigaos
 | 
			
		||||
		;;
 | 
			
		||||
	amigaunix | amix)
 | 
			
		||||
		basic_machine=m68k-cbm
 | 
			
		||||
		basic_machine=m68k-unknown
 | 
			
		||||
		os=-sysv4
 | 
			
		||||
		;;
 | 
			
		||||
	apollo68)
 | 
			
		||||
@@ -299,13 +402,16 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=cray2-cray
 | 
			
		||||
		os=-unicos
 | 
			
		||||
		;;
 | 
			
		||||
	[ctj]90-cray)
 | 
			
		||||
		basic_machine=c90-cray
 | 
			
		||||
	[cjt]90)
 | 
			
		||||
		basic_machine=${basic_machine}-cray
 | 
			
		||||
		os=-unicos
 | 
			
		||||
		;;
 | 
			
		||||
	crds | unos)
 | 
			
		||||
		basic_machine=m68k-crds
 | 
			
		||||
		;;
 | 
			
		||||
	cris | cris-* | etrax*)
 | 
			
		||||
		basic_machine=cris-axis
 | 
			
		||||
		;;
 | 
			
		||||
	da30 | da30-*)
 | 
			
		||||
		basic_machine=m68k-da30
 | 
			
		||||
		;;
 | 
			
		||||
@@ -353,6 +459,10 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=tron-gmicro
 | 
			
		||||
		os=-sysv
 | 
			
		||||
		;;
 | 
			
		||||
	go32)
 | 
			
		||||
		basic_machine=i386-pc
 | 
			
		||||
		os=-go32
 | 
			
		||||
		;;
 | 
			
		||||
	h3050r* | hiux*)
 | 
			
		||||
		basic_machine=hppa1.1-hitachi
 | 
			
		||||
		os=-hiuxwe2
 | 
			
		||||
@@ -426,22 +536,21 @@ case $basic_machine in
 | 
			
		||||
		;;
 | 
			
		||||
	i370-ibm* | ibm*)
 | 
			
		||||
		basic_machine=i370-ibm
 | 
			
		||||
		os=-mvs
 | 
			
		||||
		;;
 | 
			
		||||
# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
 | 
			
		||||
	i[34567]86v32)
 | 
			
		||||
	i*86v32)
 | 
			
		||||
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 | 
			
		||||
		os=-sysv32
 | 
			
		||||
		;;
 | 
			
		||||
	i[34567]86v4*)
 | 
			
		||||
	i*86v4*)
 | 
			
		||||
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 | 
			
		||||
		os=-sysv4
 | 
			
		||||
		;;
 | 
			
		||||
	i[34567]86v)
 | 
			
		||||
	i*86v)
 | 
			
		||||
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 | 
			
		||||
		os=-sysv
 | 
			
		||||
		;;
 | 
			
		||||
	i[34567]86sol2)
 | 
			
		||||
	i*86sol2)
 | 
			
		||||
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 | 
			
		||||
		os=-solaris2
 | 
			
		||||
		;;
 | 
			
		||||
@@ -453,14 +562,6 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=i386-unknown
 | 
			
		||||
		os=-vsta
 | 
			
		||||
		;;
 | 
			
		||||
	i386-go32 | go32)
 | 
			
		||||
		basic_machine=i386-unknown
 | 
			
		||||
		os=-go32
 | 
			
		||||
		;;
 | 
			
		||||
	i386-mingw32 | mingw32)
 | 
			
		||||
		basic_machine=i386-unknown
 | 
			
		||||
		os=-mingw32
 | 
			
		||||
		;;
 | 
			
		||||
	iris | iris4d)
 | 
			
		||||
		basic_machine=mips-sgi
 | 
			
		||||
		case $os in
 | 
			
		||||
@@ -486,10 +587,14 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=ns32k-utek
 | 
			
		||||
		os=-sysv
 | 
			
		||||
		;;
 | 
			
		||||
	mingw32)
 | 
			
		||||
		basic_machine=i386-pc
 | 
			
		||||
		os=-mingw32
 | 
			
		||||
		;;
 | 
			
		||||
	miniframe)
 | 
			
		||||
		basic_machine=m68000-convergent
 | 
			
		||||
		;;
 | 
			
		||||
	*mint | *MiNT)
 | 
			
		||||
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
 | 
			
		||||
		basic_machine=m68k-atari
 | 
			
		||||
		os=-mint
 | 
			
		||||
		;;
 | 
			
		||||
@@ -507,14 +612,22 @@ case $basic_machine in
 | 
			
		||||
	mips3*)
 | 
			
		||||
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
 | 
			
		||||
		;;
 | 
			
		||||
	mmix*)
 | 
			
		||||
		basic_machine=mmix-knuth
 | 
			
		||||
		os=-mmixware
 | 
			
		||||
		;;
 | 
			
		||||
	monitor)
 | 
			
		||||
		basic_machine=m68k-rom68k
 | 
			
		||||
		os=-coff
 | 
			
		||||
		;;
 | 
			
		||||
	msdos)
 | 
			
		||||
		basic_machine=i386-unknown
 | 
			
		||||
		basic_machine=i386-pc
 | 
			
		||||
		os=-msdos
 | 
			
		||||
		;;
 | 
			
		||||
	mvs)
 | 
			
		||||
		basic_machine=i370-ibm
 | 
			
		||||
		os=-mvs
 | 
			
		||||
		;;
 | 
			
		||||
	ncr3000)
 | 
			
		||||
		basic_machine=i486-ncr
 | 
			
		||||
		os=-sysv4
 | 
			
		||||
@@ -524,7 +637,7 @@ case $basic_machine in
 | 
			
		||||
		os=-netbsd
 | 
			
		||||
		;;
 | 
			
		||||
	netwinder)
 | 
			
		||||
		basic_machine=armv4l-corel
 | 
			
		||||
		basic_machine=armv4l-rebel
 | 
			
		||||
		os=-linux
 | 
			
		||||
		;;
 | 
			
		||||
	news | news700 | news800 | news900)
 | 
			
		||||
@@ -572,9 +685,16 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=i960-intel
 | 
			
		||||
		os=-mon960
 | 
			
		||||
		;;
 | 
			
		||||
	nonstopux)
 | 
			
		||||
		basic_machine=mips-compaq
 | 
			
		||||
		os=-nonstopux
 | 
			
		||||
		;;
 | 
			
		||||
	np1)
 | 
			
		||||
		basic_machine=np1-gould
 | 
			
		||||
		;;
 | 
			
		||||
	nsr-tandem)
 | 
			
		||||
		basic_machine=nsr-tandem
 | 
			
		||||
		;;
 | 
			
		||||
	op50n-* | op60c-*)
 | 
			
		||||
		basic_machine=hppa1.1-oki
 | 
			
		||||
		os=-proelf
 | 
			
		||||
@@ -604,28 +724,28 @@ case $basic_machine in
 | 
			
		||||
        pc532 | pc532-*)
 | 
			
		||||
		basic_machine=ns32k-pc532
 | 
			
		||||
		;;
 | 
			
		||||
	pentium | p5 | k5 | k6 | nexen)
 | 
			
		||||
	pentium | p5 | k5 | k6 | nexgen)
 | 
			
		||||
		basic_machine=i586-pc
 | 
			
		||||
		;;
 | 
			
		||||
	pentiumpro | p6 | 6x86)
 | 
			
		||||
	pentiumpro | p6 | 6x86 | athlon)
 | 
			
		||||
		basic_machine=i686-pc
 | 
			
		||||
		;;
 | 
			
		||||
	pentiumii | pentium2)
 | 
			
		||||
		basic_machine=i786-pc
 | 
			
		||||
		basic_machine=i686-pc
 | 
			
		||||
		;;
 | 
			
		||||
	pentium-* | p5-* | k5-* | k6-* | nexen-*)
 | 
			
		||||
	pentium-* | p5-* | k5-* | k6-* | nexgen-*)
 | 
			
		||||
		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	pentiumpro-* | p6-* | 6x86-*)
 | 
			
		||||
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
 | 
			
		||||
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	pentiumii-* | pentium2-*)
 | 
			
		||||
		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	pn)
 | 
			
		||||
		basic_machine=pn-gould
 | 
			
		||||
		;;
 | 
			
		||||
	power)	basic_machine=rs6000-ibm
 | 
			
		||||
	power)	basic_machine=power-ibm
 | 
			
		||||
		;;
 | 
			
		||||
	ppc)	basic_machine=powerpc-unknown
 | 
			
		||||
	        ;;
 | 
			
		||||
@@ -637,9 +757,23 @@ case $basic_machine in
 | 
			
		||||
	ppcle-* | powerpclittle-*)
 | 
			
		||||
		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	ppc64)	basic_machine=powerpc64-unknown
 | 
			
		||||
	        ;;
 | 
			
		||||
	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
 | 
			
		||||
		basic_machine=powerpc64le-unknown
 | 
			
		||||
	        ;;
 | 
			
		||||
	ppc64le-* | powerpc64little-*)
 | 
			
		||||
		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
 | 
			
		||||
		;;
 | 
			
		||||
	ps2)
 | 
			
		||||
		basic_machine=i386-ibm
 | 
			
		||||
		;;
 | 
			
		||||
	pw32)
 | 
			
		||||
		basic_machine=i586-unknown
 | 
			
		||||
		os=-pw32
 | 
			
		||||
		;;
 | 
			
		||||
	rom68k)
 | 
			
		||||
		basic_machine=m68k-rom68k
 | 
			
		||||
		os=-coff
 | 
			
		||||
@@ -719,6 +853,10 @@ case $basic_machine in
 | 
			
		||||
	sun386 | sun386i | roadrunner)
 | 
			
		||||
		basic_machine=i386-sun
 | 
			
		||||
		;;
 | 
			
		||||
	sv1)
 | 
			
		||||
		basic_machine=sv1-cray
 | 
			
		||||
		os=-unicos
 | 
			
		||||
		;;
 | 
			
		||||
	symmetry)
 | 
			
		||||
		basic_machine=i386-sequent
 | 
			
		||||
		os=-dynix
 | 
			
		||||
@@ -727,6 +865,10 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=t3e-cray
 | 
			
		||||
		os=-unicos
 | 
			
		||||
		;;
 | 
			
		||||
	tic54x | c54x*)
 | 
			
		||||
		basic_machine=tic54x-unknown
 | 
			
		||||
		os=-coff
 | 
			
		||||
		;;
 | 
			
		||||
	tx39)
 | 
			
		||||
		basic_machine=mipstx39-unknown
 | 
			
		||||
		;;
 | 
			
		||||
@@ -779,6 +921,10 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=hppa1.1-winbond
 | 
			
		||||
		os=-proelf
 | 
			
		||||
		;;
 | 
			
		||||
	windows32)
 | 
			
		||||
		basic_machine=i386-pc
 | 
			
		||||
		os=-windows32-msvcrt
 | 
			
		||||
		;;
 | 
			
		||||
	xmp)
 | 
			
		||||
		basic_machine=xmp-cray
 | 
			
		||||
		os=-unicos
 | 
			
		||||
@@ -822,13 +968,20 @@ case $basic_machine in
 | 
			
		||||
	vax)
 | 
			
		||||
		basic_machine=vax-dec
 | 
			
		||||
		;;
 | 
			
		||||
	pdp10)
 | 
			
		||||
		# there are many clones, so DEC is not a safe bet
 | 
			
		||||
		basic_machine=pdp10-unknown
 | 
			
		||||
		;;
 | 
			
		||||
	pdp11)
 | 
			
		||||
		basic_machine=pdp11-dec
 | 
			
		||||
		;;
 | 
			
		||||
	we32k)
 | 
			
		||||
		basic_machine=we32k-att
 | 
			
		||||
		;;
 | 
			
		||||
	sparc | sparcv9)
 | 
			
		||||
	sh3 | sh4 | sh3eb | sh4eb)
 | 
			
		||||
		basic_machine=sh-unknown
 | 
			
		||||
		;;
 | 
			
		||||
	sparc | sparcv9 | sparcv9b)
 | 
			
		||||
		basic_machine=sparc-sun
 | 
			
		||||
		;;
 | 
			
		||||
        cydra)
 | 
			
		||||
@@ -850,6 +1003,9 @@ case $basic_machine in
 | 
			
		||||
		basic_machine=c4x-none
 | 
			
		||||
		os=-coff
 | 
			
		||||
		;;
 | 
			
		||||
	*-unknown)
 | 
			
		||||
		# Make sure to match an already-canonicalized machine name.
 | 
			
		||||
		;;
 | 
			
		||||
	*)
 | 
			
		||||
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
 | 
			
		||||
		exit 1
 | 
			
		||||
@@ -906,14 +1062,30 @@ case $os in
 | 
			
		||||
	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 | 
			
		||||
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 | 
			
		||||
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
 | 
			
		||||
	      | -chorusos* | -chorusrdb* \
 | 
			
		||||
	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
 | 
			
		||||
	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
 | 
			
		||||
	      | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*)
 | 
			
		||||
	      | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
 | 
			
		||||
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
 | 
			
		||||
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
 | 
			
		||||
	      | -os2* | -vos*)
 | 
			
		||||
	# Remember, each alternative MUST END IN *, to match a version number.
 | 
			
		||||
		;;
 | 
			
		||||
	-qnx*)
 | 
			
		||||
		case $basic_machine in
 | 
			
		||||
		    x86-* | i*86-*)
 | 
			
		||||
			;;
 | 
			
		||||
		    *)
 | 
			
		||||
			os=-nto$os
 | 
			
		||||
			;;
 | 
			
		||||
		esac
 | 
			
		||||
		;;
 | 
			
		||||
	-nto*)
 | 
			
		||||
		os=-nto-qnx
 | 
			
		||||
		;;
 | 
			
		||||
	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
 | 
			
		||||
	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
 | 
			
		||||
	      | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
 | 
			
		||||
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
 | 
			
		||||
		;;
 | 
			
		||||
	-mac*)
 | 
			
		||||
		os=`echo $os | sed -e 's|mac|macos|'`
 | 
			
		||||
@@ -927,6 +1099,12 @@ case $os in
 | 
			
		||||
	-sunos6*)
 | 
			
		||||
		os=`echo $os | sed -e 's|sunos6|solaris3|'`
 | 
			
		||||
		;;
 | 
			
		||||
	-opened*)
 | 
			
		||||
		os=-openedition
 | 
			
		||||
		;;
 | 
			
		||||
	-wince*)
 | 
			
		||||
		os=-wince
 | 
			
		||||
		;;
 | 
			
		||||
	-osfrose*)
 | 
			
		||||
		os=-osfrose
 | 
			
		||||
		;;
 | 
			
		||||
@@ -951,6 +1129,9 @@ case $os in
 | 
			
		||||
	-ns2 )
 | 
			
		||||
	        os=-nextstep2
 | 
			
		||||
		;;
 | 
			
		||||
	-nsk*)
 | 
			
		||||
		os=-nsk
 | 
			
		||||
		;;
 | 
			
		||||
	# Preserve the version number of sinix5.
 | 
			
		||||
	-sinix5.*)
 | 
			
		||||
		os=`echo $os | sed -e 's|sinix|sysv|'`
 | 
			
		||||
@@ -985,7 +1166,7 @@ case $os in
 | 
			
		||||
	-xenix)
 | 
			
		||||
		os=-xenix
 | 
			
		||||
		;;
 | 
			
		||||
        -*mint | -*MiNT)
 | 
			
		||||
        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
 | 
			
		||||
	        os=-mint
 | 
			
		||||
		;;
 | 
			
		||||
	-none)
 | 
			
		||||
@@ -1013,12 +1194,15 @@ case $basic_machine in
 | 
			
		||||
	*-acorn)
 | 
			
		||||
		os=-riscix1.2
 | 
			
		||||
		;;
 | 
			
		||||
	arm*-corel)
 | 
			
		||||
	arm*-rebel)
 | 
			
		||||
		os=-linux
 | 
			
		||||
		;;
 | 
			
		||||
	arm*-semi)
 | 
			
		||||
		os=-aout
 | 
			
		||||
		;;
 | 
			
		||||
	pdp10-*)
 | 
			
		||||
		os=-tops20
 | 
			
		||||
		;;
 | 
			
		||||
        pdp11-*)
 | 
			
		||||
		os=-none
 | 
			
		||||
		;;
 | 
			
		||||
@@ -1127,7 +1311,7 @@ case $basic_machine in
 | 
			
		||||
	*-masscomp)
 | 
			
		||||
		os=-rtu
 | 
			
		||||
		;;
 | 
			
		||||
	f301-fujitsu)
 | 
			
		||||
	f30[01]-fujitsu | f700-fujitsu)
 | 
			
		||||
		os=-uxpv
 | 
			
		||||
		;;
 | 
			
		||||
	*-rom68k)
 | 
			
		||||
@@ -1187,7 +1371,7 @@ case $basic_machine in
 | 
			
		||||
			-genix*)
 | 
			
		||||
				vendor=ns
 | 
			
		||||
				;;
 | 
			
		||||
			-mvs*)
 | 
			
		||||
			-mvs* | -opened*)
 | 
			
		||||
				vendor=ibm
 | 
			
		||||
				;;
 | 
			
		||||
			-ptx*)
 | 
			
		||||
@@ -1205,12 +1389,23 @@ case $basic_machine in
 | 
			
		||||
			-mpw* | -macos*)
 | 
			
		||||
				vendor=apple
 | 
			
		||||
				;;
 | 
			
		||||
			-*mint | -*MiNT)
 | 
			
		||||
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
 | 
			
		||||
				vendor=atari
 | 
			
		||||
				;;
 | 
			
		||||
			-vos*)
 | 
			
		||||
				vendor=stratus
 | 
			
		||||
				;;
 | 
			
		||||
		esac
 | 
			
		||||
		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
echo $basic_machine$os
 | 
			
		||||
exit 0
 | 
			
		||||
 | 
			
		||||
# Local variables:
 | 
			
		||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
 | 
			
		||||
# time-stamp-start: "timestamp='"
 | 
			
		||||
# time-stamp-format: "%:y-%02m-%02d"
 | 
			
		||||
# time-stamp-end: "'"
 | 
			
		||||
# End:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										443
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										443
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@@ -16,13 +16,20 @@ ac_help="$ac_help
 | 
			
		||||
  --with-user=USER        Set the owner of installed files "
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --with-group=GROUP      Set the group owner of installed files "
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none
 | 
			
		||||
                          [TYPE=internal] "
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --enable-jobs=NUM       Number of jobs to run simultaneously"
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --enable-static_link    Use this to link the tools to the liblvm library
 | 
			
		||||
                          statically.  Default is dynamic linking"
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --disable-readline      Disable readline support"
 | 
			
		||||
  --enable-readline       Enable readline support"
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --enable-debug          Enable debugging"
 | 
			
		||||
ac_help="$ac_help
 | 
			
		||||
  --disable-devmapper     Disable device-mapper interaction"
 | 
			
		||||
 | 
			
		||||
# Initialize some variables set by options.
 | 
			
		||||
# The variables have the same names as the options, with
 | 
			
		||||
@@ -559,7 +566,7 @@ do
 | 
			
		||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
 | 
			
		||||
set dummy $ac_prog; ac_word=$2
 | 
			
		||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:563: checking for $ac_word" >&5
 | 
			
		||||
echo "configure:570: checking for $ac_word" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -591,7 +598,7 @@ done
 | 
			
		||||
# Extract the first word of "gcc", so it can be a program name with args.
 | 
			
		||||
set dummy gcc; ac_word=$2
 | 
			
		||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:595: checking for $ac_word" >&5
 | 
			
		||||
echo "configure:602: checking for $ac_word" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -621,7 +628,7 @@ if test -z "$CC"; then
 | 
			
		||||
  # Extract the first word of "cc", so it can be a program name with args.
 | 
			
		||||
set dummy cc; ac_word=$2
 | 
			
		||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:625: checking for $ac_word" >&5
 | 
			
		||||
echo "configure:632: checking for $ac_word" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -672,7 +679,7 @@ fi
 | 
			
		||||
      # Extract the first word of "cl", so it can be a program name with args.
 | 
			
		||||
set dummy cl; ac_word=$2
 | 
			
		||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:676: checking for $ac_word" >&5
 | 
			
		||||
echo "configure:683: checking for $ac_word" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -704,7 +711,7 @@ fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:708: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 | 
			
		||||
echo "configure:715: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 | 
			
		||||
 | 
			
		||||
ac_ext=c
 | 
			
		||||
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 | 
			
		||||
@@ -715,12 +722,12 @@ cross_compiling=$ac_cv_prog_cc_cross
 | 
			
		||||
 | 
			
		||||
cat > conftest.$ac_ext << EOF
 | 
			
		||||
 | 
			
		||||
#line 719 "configure"
 | 
			
		||||
#line 726 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
 | 
			
		||||
main(){return(0);}
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  ac_cv_prog_cc_works=yes
 | 
			
		||||
  # If we can't run a trivial program, we are probably using a cross compiler.
 | 
			
		||||
  if (./conftest; exit) 2>/dev/null; then
 | 
			
		||||
@@ -746,12 +753,12 @@ if test $ac_cv_prog_cc_works = no; then
 | 
			
		||||
  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 | 
			
		||||
fi
 | 
			
		||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 | 
			
		||||
echo "configure:757: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 | 
			
		||||
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 | 
			
		||||
cross_compiling=$ac_cv_prog_cc_cross
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:755: checking whether we are using GNU C" >&5
 | 
			
		||||
echo "configure:762: checking whether we are using GNU C" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -760,7 +767,7 @@ else
 | 
			
		||||
  yes;
 | 
			
		||||
#endif
 | 
			
		||||
EOF
 | 
			
		||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:764: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
 | 
			
		||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:771: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
 | 
			
		||||
  ac_cv_prog_gcc=yes
 | 
			
		||||
else
 | 
			
		||||
  ac_cv_prog_gcc=no
 | 
			
		||||
@@ -779,7 +786,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
 | 
			
		||||
ac_save_CFLAGS="$CFLAGS"
 | 
			
		||||
CFLAGS=
 | 
			
		||||
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:783: checking whether ${CC-cc} accepts -g" >&5
 | 
			
		||||
echo "configure:790: checking whether ${CC-cc} accepts -g" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -822,7 +829,7 @@ fi
 | 
			
		||||
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 | 
			
		||||
# ./install, which can be erroneously created by make from ./install.sh.
 | 
			
		||||
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:826: checking for a BSD compatible install" >&5
 | 
			
		||||
echo "configure:833: checking for a BSD compatible install" >&5
 | 
			
		||||
if test -z "$INSTALL"; then
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
@@ -875,7 +882,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 | 
			
		||||
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:879: checking whether ln -s works" >&5
 | 
			
		||||
echo "configure:886: checking whether ln -s works" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -896,7 +903,7 @@ else
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:900: checking whether ${MAKE-make} sets \${MAKE}" >&5
 | 
			
		||||
echo "configure:907: checking whether ${MAKE-make} sets \${MAKE}" >&5
 | 
			
		||||
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
@@ -925,7 +932,7 @@ fi
 | 
			
		||||
# Extract the first word of "ranlib", so it can be a program name with args.
 | 
			
		||||
set dummy ranlib; ac_word=$2
 | 
			
		||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:929: checking for $ac_word" >&5
 | 
			
		||||
echo "configure:936: checking for $ac_word" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
@@ -958,12 +965,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
 | 
			
		||||
do
 | 
			
		||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 | 
			
		||||
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:962: checking for $ac_hdr that defines DIR" >&5
 | 
			
		||||
echo "configure:969: checking for $ac_hdr that defines DIR" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 967 "configure"
 | 
			
		||||
#line 974 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <$ac_hdr>
 | 
			
		||||
@@ -971,7 +978,7 @@ int main() {
 | 
			
		||||
DIR *dirp = 0;
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:975: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:982: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_header_dirent_$ac_safe=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -996,7 +1003,7 @@ done
 | 
			
		||||
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
 | 
			
		||||
if test $ac_header_dirent = dirent.h; then
 | 
			
		||||
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1000: checking for opendir in -ldir" >&5
 | 
			
		||||
echo "configure:1007: checking for opendir in -ldir" >&5
 | 
			
		||||
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
@@ -1004,7 +1011,7 @@ else
 | 
			
		||||
  ac_save_LIBS="$LIBS"
 | 
			
		||||
LIBS="-ldir  $LIBS"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1008 "configure"
 | 
			
		||||
#line 1015 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
@@ -1015,7 +1022,7 @@ int main() {
 | 
			
		||||
opendir()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:1026: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_lib_$ac_lib_var=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -1037,7 +1044,7 @@ fi
 | 
			
		||||
 | 
			
		||||
else
 | 
			
		||||
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1041: checking for opendir in -lx" >&5
 | 
			
		||||
echo "configure:1048: checking for opendir in -lx" >&5
 | 
			
		||||
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
@@ -1045,7 +1052,7 @@ else
 | 
			
		||||
  ac_save_LIBS="$LIBS"
 | 
			
		||||
LIBS="-lx  $LIBS"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1049 "configure"
 | 
			
		||||
#line 1056 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
@@ -1056,7 +1063,7 @@ int main() {
 | 
			
		||||
opendir()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:1067: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_lib_$ac_lib_var=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -1079,7 +1086,7 @@ fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1083: checking how to run the C preprocessor" >&5
 | 
			
		||||
echo "configure:1090: checking how to run the C preprocessor" >&5
 | 
			
		||||
# On Suns, sometimes $CPP names a directory.
 | 
			
		||||
if test -n "$CPP" && test -d "$CPP"; then
 | 
			
		||||
  CPP=
 | 
			
		||||
@@ -1094,13 +1101,13 @@ else
 | 
			
		||||
  # On the NeXT, cc -E runs the code through the compiler's parser,
 | 
			
		||||
  # not just through cpp.
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1098 "configure"
 | 
			
		||||
#line 1105 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
Syntax Error
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
{ (eval echo configure:1111: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  :
 | 
			
		||||
@@ -1111,13 +1118,13 @@ else
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  CPP="${CC-cc} -E -traditional-cpp"
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1115 "configure"
 | 
			
		||||
#line 1122 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
Syntax Error
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:1121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
{ (eval echo configure:1128: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  :
 | 
			
		||||
@@ -1128,13 +1135,13 @@ else
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  CPP="${CC-cc} -nologo -E"
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1132 "configure"
 | 
			
		||||
#line 1139 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
Syntax Error
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:1138: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
{ (eval echo configure:1145: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  :
 | 
			
		||||
@@ -1159,12 +1166,12 @@ fi
 | 
			
		||||
echo "$ac_t""$CPP" 1>&6
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1163: checking for ANSI C header files" >&5
 | 
			
		||||
echo "configure:1170: checking for ANSI C header files" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1168 "configure"
 | 
			
		||||
#line 1175 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
@@ -1172,7 +1179,7 @@ else
 | 
			
		||||
#include <float.h>
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:1176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
{ (eval echo configure:1183: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
@@ -1189,7 +1196,7 @@ rm -f conftest*
 | 
			
		||||
if test $ac_cv_header_stdc = yes; then
 | 
			
		||||
  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1193 "configure"
 | 
			
		||||
#line 1200 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
EOF
 | 
			
		||||
@@ -1207,7 +1214,7 @@ fi
 | 
			
		||||
if test $ac_cv_header_stdc = yes; then
 | 
			
		||||
  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1211 "configure"
 | 
			
		||||
#line 1218 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
EOF
 | 
			
		||||
@@ -1228,7 +1235,7 @@ if test "$cross_compiling" = yes; then
 | 
			
		||||
  :
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1232 "configure"
 | 
			
		||||
#line 1239 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
 | 
			
		||||
@@ -1239,7 +1246,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 | 
			
		||||
exit (0); }
 | 
			
		||||
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 | 
			
		||||
if { (eval echo configure:1250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 | 
			
		||||
then
 | 
			
		||||
  :
 | 
			
		||||
else
 | 
			
		||||
@@ -1266,17 +1273,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
 | 
			
		||||
do
 | 
			
		||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 | 
			
		||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1270: checking for $ac_hdr" >&5
 | 
			
		||||
echo "configure:1277: checking for $ac_hdr" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1275 "configure"
 | 
			
		||||
#line 1282 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <$ac_hdr>
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:1280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
{ (eval echo configure:1287: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
@@ -1304,12 +1311,12 @@ done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for working const""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1308: checking for working const" >&5
 | 
			
		||||
echo "configure:1315: checking for working const" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1313 "configure"
 | 
			
		||||
#line 1320 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
@@ -1358,7 +1365,7 @@ ccp = (char const *const *) p;
 | 
			
		||||
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:1369: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_c_const=yes
 | 
			
		||||
else
 | 
			
		||||
@@ -1379,21 +1386,21 @@ EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for inline""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1383: checking for inline" >&5
 | 
			
		||||
echo "configure:1390: checking for inline" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  ac_cv_c_inline=no
 | 
			
		||||
for ac_kw in inline __inline__ __inline; do
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1390 "configure"
 | 
			
		||||
#line 1397 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
} int $ac_kw foo() {
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1397: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:1404: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_c_inline=$ac_kw; break
 | 
			
		||||
else
 | 
			
		||||
@@ -1419,12 +1426,12 @@ EOF
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for off_t""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1423: checking for off_t" >&5
 | 
			
		||||
echo "configure:1430: checking for off_t" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1428 "configure"
 | 
			
		||||
#line 1435 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#if STDC_HEADERS
 | 
			
		||||
@@ -1452,12 +1459,12 @@ EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1456: checking for pid_t" >&5
 | 
			
		||||
echo "configure:1463: checking for pid_t" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1461 "configure"
 | 
			
		||||
#line 1468 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#if STDC_HEADERS
 | 
			
		||||
@@ -1485,12 +1492,12 @@ EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for size_t""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1489: checking for size_t" >&5
 | 
			
		||||
echo "configure:1496: checking for size_t" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1494 "configure"
 | 
			
		||||
#line 1501 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#if STDC_HEADERS
 | 
			
		||||
@@ -1518,12 +1525,12 @@ EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1522: checking for st_rdev in struct stat" >&5
 | 
			
		||||
echo "configure:1529: checking for st_rdev in struct stat" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1527 "configure"
 | 
			
		||||
#line 1534 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
@@ -1531,7 +1538,7 @@ int main() {
 | 
			
		||||
struct stat s; s.st_rdev;
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:1542: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_struct_st_rdev=yes
 | 
			
		||||
else
 | 
			
		||||
@@ -1552,12 +1559,12 @@ EOF
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1556: checking whether time.h and sys/time.h may both be included" >&5
 | 
			
		||||
echo "configure:1563: checking whether time.h and sys/time.h may both be included" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1561 "configure"
 | 
			
		||||
#line 1568 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
@@ -1566,7 +1573,7 @@ int main() {
 | 
			
		||||
struct tm *tp;
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1570: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:1577: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_header_time=yes
 | 
			
		||||
else
 | 
			
		||||
@@ -1588,6 +1595,101 @@ fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Do some error checking and defaulting for the host and target type.
 | 
			
		||||
# The inputs are:
 | 
			
		||||
#    configure --host=HOST --target=TARGET --build=BUILD NONOPT
 | 
			
		||||
#
 | 
			
		||||
# The rules are:
 | 
			
		||||
# 1. You are not allowed to specify --host, --target, and nonopt at the
 | 
			
		||||
#    same time.
 | 
			
		||||
# 2. Host defaults to nonopt.
 | 
			
		||||
# 3. If nonopt is not specified, then host defaults to the current host,
 | 
			
		||||
#    as determined by config.guess.
 | 
			
		||||
# 4. Target and build default to nonopt.
 | 
			
		||||
# 5. If nonopt is not specified, then target and build default to host.
 | 
			
		||||
 | 
			
		||||
# The aliases save the names the user supplied, while $host etc.
 | 
			
		||||
# will get canonicalized.
 | 
			
		||||
case $host---$target---$nonopt in
 | 
			
		||||
NONE---*---* | *---NONE---* | *---*---NONE) ;;
 | 
			
		||||
*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Make sure we can run config.sub.
 | 
			
		||||
if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
 | 
			
		||||
else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking host system type""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1626: checking host system type" >&5
 | 
			
		||||
 | 
			
		||||
host_alias=$host
 | 
			
		||||
case "$host_alias" in
 | 
			
		||||
NONE)
 | 
			
		||||
  case $nonopt in
 | 
			
		||||
  NONE)
 | 
			
		||||
    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
 | 
			
		||||
    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
 | 
			
		||||
    fi ;;
 | 
			
		||||
  *) host_alias=$nonopt ;;
 | 
			
		||||
  esac ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
 | 
			
		||||
host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 | 
			
		||||
host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
 | 
			
		||||
host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 | 
			
		||||
echo "$ac_t""$host" 1>&6
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking target system type""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1647: checking target system type" >&5
 | 
			
		||||
 | 
			
		||||
target_alias=$target
 | 
			
		||||
case "$target_alias" in
 | 
			
		||||
NONE)
 | 
			
		||||
  case $nonopt in
 | 
			
		||||
  NONE) target_alias=$host_alias ;;
 | 
			
		||||
  *) target_alias=$nonopt ;;
 | 
			
		||||
  esac ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
 | 
			
		||||
target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 | 
			
		||||
target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
 | 
			
		||||
target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 | 
			
		||||
echo "$ac_t""$target" 1>&6
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking build system type""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1665: checking build system type" >&5
 | 
			
		||||
 | 
			
		||||
build_alias=$build
 | 
			
		||||
case "$build_alias" in
 | 
			
		||||
NONE)
 | 
			
		||||
  case $nonopt in
 | 
			
		||||
  NONE) build_alias=$host_alias ;;
 | 
			
		||||
  *) build_alias=$nonopt ;;
 | 
			
		||||
  esac ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
 | 
			
		||||
build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 | 
			
		||||
build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
 | 
			
		||||
build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 | 
			
		||||
echo "$ac_t""$build" 1>&6
 | 
			
		||||
 | 
			
		||||
test "$host_alias" != "$target_alias" &&
 | 
			
		||||
  test "$program_prefix$program_suffix$program_transform_name" = \
 | 
			
		||||
    NONENONEs,x,x, &&
 | 
			
		||||
  program_prefix=${target_alias}-
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
case "$host_os" in
 | 
			
		||||
	linux*)
 | 
			
		||||
		CFLAGS= ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Check whether --with-user or --without-user was given.
 | 
			
		||||
if test "${with_user+set}" = set; then
 | 
			
		||||
@@ -1607,12 +1709,31 @@ else
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Check whether --with-lvm1 or --without-lvm1 was given.
 | 
			
		||||
if test "${with_lvm1+set}" = set; then
 | 
			
		||||
  withval="$with_lvm1"
 | 
			
		||||
   LVM1="$withval" 
 | 
			
		||||
else
 | 
			
		||||
   LVM1="internal" 
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
 | 
			
		||||
 then  { echo "configure: error: --with-lvm1 parameter invalid
 | 
			
		||||
" 1>&2; exit 1; }
 | 
			
		||||
 exit
 | 
			
		||||
fi;
 | 
			
		||||
 | 
			
		||||
if test x$LVM1 = xinternal; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DLVM1_INTERNAL"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check whether --enable-jobs or --disable-jobs was given.
 | 
			
		||||
if test "${enable_jobs+set}" = set; then
 | 
			
		||||
  enableval="$enable_jobs"
 | 
			
		||||
  JOBS=-j$enableval
 | 
			
		||||
else
 | 
			
		||||
  JOBS=
 | 
			
		||||
  JOBS=-j2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1631,23 +1752,51 @@ if test "${enable_readline+set}" = set; then
 | 
			
		||||
  \
 | 
			
		||||
READLINE=$enableval
 | 
			
		||||
else
 | 
			
		||||
  READLINE=yes
 | 
			
		||||
  READLINE=no
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if test x$READLINE = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check whether --enable-debug or --disable-debug was given.
 | 
			
		||||
if test "${enable_debug+set}" = set; then
 | 
			
		||||
  enableval="$enable_debug"
 | 
			
		||||
  \
 | 
			
		||||
DEBUG=yes
 | 
			
		||||
else
 | 
			
		||||
  DEBUG=no
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Check whether --enable-devmapper or --disable-devmapper was given.
 | 
			
		||||
if test "${enable_devmapper+set}" = set; then
 | 
			
		||||
  enableval="$enable_devmapper"
 | 
			
		||||
  \
 | 
			
		||||
DEVMAPPER=no
 | 
			
		||||
else
 | 
			
		||||
  DEVMAPPER=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if test x$DEVMAPPER = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ];
 | 
			
		||||
 then  exec_prefix="";
 | 
			
		||||
fi;
 | 
			
		||||
 | 
			
		||||
if test $ac_cv_prog_gcc = yes; then
 | 
			
		||||
    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1645: checking whether ${CC-cc} needs -traditional" >&5
 | 
			
		||||
echo "configure:1794: checking whether ${CC-cc} needs -traditional" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
    ac_pattern="Autoconf.*'x'"
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1651 "configure"
 | 
			
		||||
#line 1800 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sgtty.h>
 | 
			
		||||
Autoconf TIOCGETP
 | 
			
		||||
@@ -1665,7 +1814,7 @@ rm -f conftest*
 | 
			
		||||
 | 
			
		||||
  if test $ac_cv_prog_gcc_traditional = no; then
 | 
			
		||||
    cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1669 "configure"
 | 
			
		||||
#line 1818 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <termio.h>
 | 
			
		||||
Autoconf TCGETA
 | 
			
		||||
@@ -1687,12 +1836,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1691: checking return type of signal handlers" >&5
 | 
			
		||||
echo "configure:1840: checking return type of signal handlers" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1696 "configure"
 | 
			
		||||
#line 1845 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
@@ -1709,7 +1858,7 @@ int main() {
 | 
			
		||||
int i;
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
if { (eval echo configure:1862: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_type_signal=void
 | 
			
		||||
else
 | 
			
		||||
@@ -1728,12 +1877,12 @@ EOF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for vprintf""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1732: checking for vprintf" >&5
 | 
			
		||||
echo "configure:1881: checking for vprintf" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1737 "configure"
 | 
			
		||||
#line 1886 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* System header to define __stub macros and hopefully few prototypes,
 | 
			
		||||
    which can conflict with char vprintf(); below.  */
 | 
			
		||||
@@ -1756,7 +1905,7 @@ vprintf();
 | 
			
		||||
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:1909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_func_vprintf=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -1780,12 +1929,12 @@ fi
 | 
			
		||||
 | 
			
		||||
if test "$ac_cv_func_vprintf" != yes; then
 | 
			
		||||
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1784: checking for _doprnt" >&5
 | 
			
		||||
echo "configure:1933: checking for _doprnt" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1789 "configure"
 | 
			
		||||
#line 1938 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* System header to define __stub macros and hopefully few prototypes,
 | 
			
		||||
    which can conflict with char _doprnt(); below.  */
 | 
			
		||||
@@ -1808,7 +1957,7 @@ _doprnt();
 | 
			
		||||
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:1961: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_func__doprnt=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -1835,12 +1984,12 @@ fi
 | 
			
		||||
for ac_func in mkdir rmdir uname
 | 
			
		||||
do
 | 
			
		||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1839: checking for $ac_func" >&5
 | 
			
		||||
echo "configure:1988: checking for $ac_func" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1844 "configure"
 | 
			
		||||
#line 1993 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* System header to define __stub macros and hopefully few prototypes,
 | 
			
		||||
    which can conflict with char $ac_func(); below.  */
 | 
			
		||||
@@ -1863,7 +2012,7 @@ $ac_func();
 | 
			
		||||
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:2016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_func_$ac_func=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -1891,14 +2040,14 @@ done
 | 
			
		||||
if test x$READLINE = xyes; then
 | 
			
		||||
	
 | 
			
		||||
echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1895: checking for library containing tgetent" >&5
 | 
			
		||||
echo "configure:2044: checking for library containing tgetent" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  ac_func_search_save_LIBS="$LIBS"
 | 
			
		||||
ac_cv_search_tgetent="no"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1902 "configure"
 | 
			
		||||
#line 2051 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
@@ -1909,7 +2058,7 @@ int main() {
 | 
			
		||||
tgetent()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:2062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_search_tgetent="none required"
 | 
			
		||||
else
 | 
			
		||||
@@ -1920,7 +2069,7 @@ rm -f conftest*
 | 
			
		||||
test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
 | 
			
		||||
LIBS="-l$i  $ac_func_search_save_LIBS"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1924 "configure"
 | 
			
		||||
#line 2073 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
@@ -1931,7 +2080,7 @@ int main() {
 | 
			
		||||
tgetent()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:2084: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  ac_cv_search_tgetent="-l$i"
 | 
			
		||||
break
 | 
			
		||||
@@ -1963,9 +2112,97 @@ Note: (n)curses also seems to work as a substitute for termcap.  This was
 | 
			
		||||
fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:2117: checking for dlopen in -ldl" >&5
 | 
			
		||||
ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  ac_save_LIBS="$LIBS"
 | 
			
		||||
LIBS="-ldl  $LIBS"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 2125 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
    builtin and then its argument prototype would still apply.  */
 | 
			
		||||
char dlopen();
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
dlopen()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:2136: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_lib_$ac_lib_var=yes"
 | 
			
		||||
else
 | 
			
		||||
  echo "configure: failed program was:" >&5
 | 
			
		||||
  cat conftest.$ac_ext >&5
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_lib_$ac_lib_var=no"
 | 
			
		||||
fi
 | 
			
		||||
rm -f conftest*
 | 
			
		||||
LIBS="$ac_save_LIBS"
 | 
			
		||||
 | 
			
		||||
fi
 | 
			
		||||
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 | 
			
		||||
  echo "$ac_t""yes" 1>&6
 | 
			
		||||
  HAVE_LIBDL=yes
 | 
			
		||||
else
 | 
			
		||||
  echo "$ac_t""no" 1>&6
 | 
			
		||||
HAVE_LIBDL=no
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if test x$HAVE_LIBDL = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DHAVE_LIBDL"
 | 
			
		||||
	LIBS="-ldl $LIBS"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
for ac_hdr in getopt.h
 | 
			
		||||
do
 | 
			
		||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 | 
			
		||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:2167: checking for $ac_hdr" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 2172 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
#include <$ac_hdr>
 | 
			
		||||
EOF
 | 
			
		||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
 | 
			
		||||
{ (eval echo configure:2177: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 | 
			
		||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 | 
			
		||||
if test -z "$ac_err"; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_header_$ac_safe=yes"
 | 
			
		||||
else
 | 
			
		||||
  echo "$ac_err" >&5
 | 
			
		||||
  echo "configure: failed program was:" >&5
 | 
			
		||||
  cat conftest.$ac_ext >&5
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_header_$ac_safe=no"
 | 
			
		||||
fi
 | 
			
		||||
rm -f conftest*
 | 
			
		||||
fi
 | 
			
		||||
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
 | 
			
		||||
  echo "$ac_t""yes" 1>&6
 | 
			
		||||
    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
 | 
			
		||||
  cat >> confdefs.h <<EOF
 | 
			
		||||
#define $ac_tr_hdr 1
 | 
			
		||||
EOF
 | 
			
		||||
 CFLAGS="$CFLAGS -DHAVE_GETOPTLONG"
 | 
			
		||||
else
 | 
			
		||||
  echo "$ac_t""no" 1>&6
 | 
			
		||||
fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if test x$READLINE = xyes; then
 | 
			
		||||
	echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:1969: checking for readline in -lreadline" >&5
 | 
			
		||||
echo "configure:2206: checking for readline in -lreadline" >&5
 | 
			
		||||
ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
@@ -1973,7 +2210,7 @@ else
 | 
			
		||||
  ac_save_LIBS="$LIBS"
 | 
			
		||||
LIBS="-lreadline  $LIBS"
 | 
			
		||||
cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 1977 "configure"
 | 
			
		||||
#line 2214 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* Override any gcc2 internal prototype to avoid an error.  */
 | 
			
		||||
/* We use char because int might match the return type of a gcc2
 | 
			
		||||
@@ -1984,7 +2221,7 @@ int main() {
 | 
			
		||||
readline()
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:2225: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_lib_$ac_lib_var=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -2021,12 +2258,12 @@ package as well (which may be called readline-devel or something similar).
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
	echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
 | 
			
		||||
echo "configure:2025: checking for rl_completion_matches" >&5
 | 
			
		||||
echo "configure:2262: checking for rl_completion_matches" >&5
 | 
			
		||||
if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
 | 
			
		||||
  echo $ac_n "(cached) $ac_c" 1>&6
 | 
			
		||||
else
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 2030 "configure"
 | 
			
		||||
#line 2267 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
/* System header to define __stub macros and hopefully few prototypes,
 | 
			
		||||
    which can conflict with char rl_completion_matches(); below.  */
 | 
			
		||||
@@ -2049,7 +2286,7 @@ rl_completion_matches();
 | 
			
		||||
 | 
			
		||||
; return 0; }
 | 
			
		||||
EOF
 | 
			
		||||
if { (eval echo configure:2053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
if { (eval echo configure:2290: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
 | 
			
		||||
  rm -rf conftest*
 | 
			
		||||
  eval "ac_cv_func_rl_completion_matches=yes"
 | 
			
		||||
else
 | 
			
		||||
@@ -2063,12 +2300,12 @@ fi
 | 
			
		||||
 | 
			
		||||
if eval "test \"`echo '$ac_cv_func_'rl_completion_matches`\" = yes"; then
 | 
			
		||||
  echo "$ac_t""yes" 1>&6
 | 
			
		||||
  HAVE_RL_COMPLETION_MATCHES=yes
 | 
			
		||||
  CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES"
 | 
			
		||||
else
 | 
			
		||||
  echo "$ac_t""no" 1>&6
 | 
			
		||||
HAVE_RL_COMPLETION_MATCHES=no
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "-f VERSION"; then
 | 
			
		||||
@@ -2085,6 +2322,9 @@ fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
trap '' 1 2 15
 | 
			
		||||
cat > confcache <<\EOF
 | 
			
		||||
# This file is a shell script that caches the results of configure
 | 
			
		||||
@@ -2203,6 +2443,7 @@ Makefile								\
 | 
			
		||||
make.tmpl                                                               \
 | 
			
		||||
include/Makefile						 	\
 | 
			
		||||
lib/Makefile							 	\
 | 
			
		||||
lib/format1/Makefile						 	\
 | 
			
		||||
man/Makefile							 	\
 | 
			
		||||
tools/Makefile							 	\
 | 
			
		||||
tools/version.h								\
 | 
			
		||||
@@ -2252,13 +2493,30 @@ s%@LN_S@%$LN_S%g
 | 
			
		||||
s%@SET_MAKE@%$SET_MAKE%g
 | 
			
		||||
s%@RANLIB@%$RANLIB%g
 | 
			
		||||
s%@CPP@%$CPP%g
 | 
			
		||||
s%@host@%$host%g
 | 
			
		||||
s%@host_alias@%$host_alias%g
 | 
			
		||||
s%@host_cpu@%$host_cpu%g
 | 
			
		||||
s%@host_vendor@%$host_vendor%g
 | 
			
		||||
s%@host_os@%$host_os%g
 | 
			
		||||
s%@target@%$target%g
 | 
			
		||||
s%@target_alias@%$target_alias%g
 | 
			
		||||
s%@target_cpu@%$target_cpu%g
 | 
			
		||||
s%@target_vendor@%$target_vendor%g
 | 
			
		||||
s%@target_os@%$target_os%g
 | 
			
		||||
s%@build@%$build%g
 | 
			
		||||
s%@build_alias@%$build_alias%g
 | 
			
		||||
s%@build_cpu@%$build_cpu%g
 | 
			
		||||
s%@build_vendor@%$build_vendor%g
 | 
			
		||||
s%@build_os@%$build_os%g
 | 
			
		||||
s%@JOBS@%$JOBS%g
 | 
			
		||||
s%@STATIC_LINK@%$STATIC_LINK%g
 | 
			
		||||
s%@READLINE@%$READLINE%g
 | 
			
		||||
s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
 | 
			
		||||
s%@LVM1@%$LVM1%g
 | 
			
		||||
s%@OWNER@%$OWNER%g
 | 
			
		||||
s%@GROUP@%$GROUP%g
 | 
			
		||||
s%@LVM_VERSION@%$LVM_VERSION%g
 | 
			
		||||
s%@DEBUG@%$DEBUG%g
 | 
			
		||||
s%@DEVMAPPER@%$DEVMAPPER%g
 | 
			
		||||
s%@HAVE_LIBDL@%$HAVE_LIBDL%g
 | 
			
		||||
 | 
			
		||||
CEOF
 | 
			
		||||
EOF
 | 
			
		||||
@@ -2305,6 +2563,7 @@ Makefile								\
 | 
			
		||||
make.tmpl                                                               \
 | 
			
		||||
include/Makefile						 	\
 | 
			
		||||
lib/Makefile							 	\
 | 
			
		||||
lib/format1/Makefile						 	\
 | 
			
		||||
man/Makefile							 	\
 | 
			
		||||
tools/Makefile							 	\
 | 
			
		||||
tools/version.h								\
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								configure.in
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								configure.in
									
									
									
									
									
								
							@@ -46,6 +46,14 @@ AC_TYPE_SIZE_T
 | 
			
		||||
AC_STRUCT_ST_RDEV
 | 
			
		||||
AC_HEADER_TIME
 | 
			
		||||
 | 
			
		||||
dnl Get system type
 | 
			
		||||
AC_CANONICAL_SYSTEM
 | 
			
		||||
 | 
			
		||||
case "$host_os" in
 | 
			
		||||
	linux*)
 | 
			
		||||
		CFLAGS= ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
dnl -- prefix is /usr by default, the exec_prefix default is setup later
 | 
			
		||||
AC_PREFIX_DEFAULT(/usr)
 | 
			
		||||
 | 
			
		||||
@@ -61,15 +69,49 @@ AC_ARG_WITH(group,
 | 
			
		||||
  [ GROUP="$withval" ],
 | 
			
		||||
  [ GROUP="root" ])
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
 | 
			
		||||
dnl -- format1 inclusion type
 | 
			
		||||
AC_ARG_WITH(lvm1,
 | 
			
		||||
  [  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none
 | 
			
		||||
                          [TYPE=internal] ],
 | 
			
		||||
  [ LVM1="$withval" ],
 | 
			
		||||
  [ LVM1="internal" ])
 | 
			
		||||
 | 
			
		||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
 | 
			
		||||
 then  AC_MSG_ERROR(
 | 
			
		||||
--with-lvm1 parameter invalid
 | 
			
		||||
)
 | 
			
		||||
 exit
 | 
			
		||||
fi;
 | 
			
		||||
 | 
			
		||||
if test x$LVM1 = xinternal; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DLVM1_INTERNAL"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
 | 
			
		||||
 | 
			
		||||
dnl Enables staticly linked tools
 | 
			
		||||
AC_ARG_ENABLE(static_link, [  --enable-static_link    Use this to link the tools to the liblvm library
 | 
			
		||||
                          statically.  Default is dynamic linking],  STATIC_LINK=$enableval, STATIC_LINK=no)
 | 
			
		||||
 | 
			
		||||
dnl Disable readline
 | 
			
		||||
AC_ARG_ENABLE(readline, [  --disable-readline      Disable readline support],  \
 | 
			
		||||
READLINE=$enableval, READLINE=yes)
 | 
			
		||||
dnl Enable readline
 | 
			
		||||
AC_ARG_ENABLE(readline, [  --enable-readline       Enable readline support],  \
 | 
			
		||||
READLINE=$enableval, READLINE=no)
 | 
			
		||||
 | 
			
		||||
if test x$READLINE = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl Enable Debugging
 | 
			
		||||
AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debugging],  \
 | 
			
		||||
DEBUG=yes, DEBUG=no)
 | 
			
		||||
 | 
			
		||||
dnl Disable devmapper
 | 
			
		||||
AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable device-mapper interaction],  \
 | 
			
		||||
DEVMAPPER=no, DEVMAPPER=yes)
 | 
			
		||||
 | 
			
		||||
if test x$DEVMAPPER = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl Mess with default exec_prefix
 | 
			
		||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
 | 
			
		||||
@@ -99,6 +141,17 @@ Note: (n)curses also seems to work as a substitute for termcap.  This was
 | 
			
		||||
	)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl Check for dlopen
 | 
			
		||||
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
 | 
			
		||||
 | 
			
		||||
if test x$HAVE_LIBDL = xyes; then
 | 
			
		||||
	CFLAGS="$CFLAGS -DHAVE_LIBDL"
 | 
			
		||||
	LIBS="-ldl $LIBS"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl Check for getopt
 | 
			
		||||
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
 | 
			
		||||
 | 
			
		||||
dnl Check for readline (Shamelessly copied from parted 1.4.17)
 | 
			
		||||
if test x$READLINE = xyes; then
 | 
			
		||||
	AC_CHECK_LIB(readline, readline, ,
 | 
			
		||||
@@ -112,8 +165,8 @@ package as well (which may be called readline-devel or something similar).
 | 
			
		||||
)
 | 
			
		||||
		exit
 | 
			
		||||
	)
 | 
			
		||||
	AC_CHECK_FUNC(rl_completion_matches, HAVE_RL_COMPLETION_MATCHES=yes,
 | 
			
		||||
		HAVE_RL_COMPLETION_MATCHES=no)
 | 
			
		||||
	AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
 | 
			
		||||
		
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "-f VERSION"; then
 | 
			
		||||
@@ -124,12 +177,15 @@ fi
 | 
			
		||||
 | 
			
		||||
AC_SUBST(JOBS)
 | 
			
		||||
AC_SUBST(STATIC_LINK)
 | 
			
		||||
AC_SUBST(READLINE)
 | 
			
		||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
 | 
			
		||||
AC_SUBST(LVM1)
 | 
			
		||||
AC_SUBST(OWNER)
 | 
			
		||||
AC_SUBST(GROUP)
 | 
			
		||||
AC_SUBST(CFLAGS)
 | 
			
		||||
AC_SUBST(LIBS)
 | 
			
		||||
AC_SUBST(LVM_VERSION)
 | 
			
		||||
AC_SUBST(DEBUG)
 | 
			
		||||
AC_SUBST(DEVMAPPER)
 | 
			
		||||
AC_SUBST(HAVE_LIBDL)
 | 
			
		||||
dnl First and last lines should not contain files to generate in order to 
 | 
			
		||||
dnl keep utility scripts running properly
 | 
			
		||||
AC_OUTPUT( 								\
 | 
			
		||||
@@ -137,6 +193,7 @@ Makefile								\
 | 
			
		||||
make.tmpl                                                               \
 | 
			
		||||
include/Makefile						 	\
 | 
			
		||||
lib/Makefile							 	\
 | 
			
		||||
lib/format1/Makefile						 	\
 | 
			
		||||
man/Makefile							 	\
 | 
			
		||||
tools/Makefile							 	\
 | 
			
		||||
tools/version.h								\
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
LVM2 requires the device-mapper kernel module (dm-mod).  This is
 | 
			
		||||
available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and
 | 
			
		||||
is distributed with linux 2.5 and above.  The LVM1 kernel module (lvm-mod)
 | 
			
		||||
will not work with lvm2 packages.  dm-mod and lvm-mod may both be loaded
 | 
			
		||||
in the kernel at the same time with no problems.  Without dm-mod, this
 | 
			
		||||
package is pretty useless.
 | 
			
		||||
							
								
								
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
lvm2 (1.95.15-1) unstable; urgency=low
 | 
			
		||||
  
 | 
			
		||||
  * New upstream release.
 | 
			
		||||
  * Remove undocumented manpage symlinks.
 | 
			
		||||
  * Update description to be more informative.  (Closes: #173499)
 | 
			
		||||
  * Add kernel-patch-device-mapper suggestion.
 | 
			
		||||
  * Update standards version.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 16 Feb 2002 04:21:26 -0400
 | 
			
		||||
 | 
			
		||||
lvm2 (1.95.11-1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * New upstream release.  (Closes: #171436)
 | 
			
		||||
  * Removed TODO and INTRO from debian/docs; added WHATS_NEW.
 | 
			
		||||
  * Remove vgcfgrestore.8 undocumented symlink.
 | 
			
		||||
  * Added a README.Debian, mentioning the device-mapper kernel module
 | 
			
		||||
    requirement that lvm2 has.  (Closes: #171674, #163020)
 | 
			
		||||
  * Get rid of debian/conffiles (debhelper's smart enough to figure that out).
 | 
			
		||||
  * debian/copyright fix to appease lintian.
 | 
			
		||||
  * Fix typo in tools/commands.h that caused /usr/sbin/; to be created.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  9 Dec 2002 02:51:02 -0400
 | 
			
		||||
 | 
			
		||||
lvm2 (1.95.10-2) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Fix software raid problems by ensuring lvm init script runs after
 | 
			
		||||
    raidtools init script.  (Closes: #152569)
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Tue,  3 Sep 2002 04:05:43 -0400
 | 
			
		||||
 | 
			
		||||
lvm2 (1.95.10-1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * New upstream release (Beta 3.2).
 | 
			
		||||
  * Change all references to /dev/device-mapper/control to
 | 
			
		||||
    /dev/mapper/control.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Sun,  1 Sep 2002 18:55:12 -0400
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.05-3) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Get rid of awk dependency in init script.  (Closes: #146257)
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 12 May 2002 04:39:06 -0500
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.05-2) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Use ${shlibs:Depends} in Depends.
 | 
			
		||||
  * Get rid of postinst/postrm scripts, use debhelper's init script instead.
 | 
			
		||||
  * Add Conflicts against lvm10, lvm-common.
 | 
			
		||||
  * Fix endian issues on big-endian machines.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Thu,  2 May 2002 23:53:53 -0500
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.05-1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * New release (Beta2).
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Thu, 25 Apr 2002 00:37:41 -0500
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * CVS updated.
 | 
			
		||||
  * Convert from debian native package.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Wed,  6 Mar 2002 00:43:21 -0500
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.04cvs20020304) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * CVS updated.
 | 
			
		||||
  * Enhance init script; create devmapper control device, etc.
 | 
			
		||||
  * Add dmsetup as a suggestion.
 | 
			
		||||
  * Add /etc/lvm/lvm.conf conffile.
 | 
			
		||||
  * Add undocumented(7) for the commands missing manpages.
 | 
			
		||||
  
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  4 Mar 2002 04:51:26 -0500
 | 
			
		||||
 | 
			
		||||
lvm2 (0.95.02cvs20020220) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Initial Release.
 | 
			
		||||
 | 
			
		||||
 -- Andres Salomon <dilinger@mp3revolution.net>  Wed, 20 Feb 2002 03:17:25 -0500
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
Source: lvm2
 | 
			
		||||
Section: admin
 | 
			
		||||
Priority: optional
 | 
			
		||||
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
 | 
			
		||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
 | 
			
		||||
Standards-Version: 3.5.8.0
 | 
			
		||||
 | 
			
		||||
Package: lvm2
 | 
			
		||||
Architecture: any
 | 
			
		||||
Depends: ${shlibs:Depends}
 | 
			
		||||
Conflicts: lvm10, lvm-common
 | 
			
		||||
Replaces: lvm10, lvm-common
 | 
			
		||||
Provides: lvm-binaries
 | 
			
		||||
Suggests: dmsetup, kernel-patch-device-mapper
 | 
			
		||||
Description: The Linux Logical Volume Manager
 | 
			
		||||
 This is LVM2, the rewrite of The Linux Logical Volume Manager.  LVM
 | 
			
		||||
 supports enterprise level volume management of disk and disk subsystems
 | 
			
		||||
 by grouping arbitrary disks into volume groups. The total capacity of
 | 
			
		||||
 volume groups can be allocated to logical volumes, which are accessed as
 | 
			
		||||
 regular block devices.
 | 
			
		||||
 .
 | 
			
		||||
 LVM2 is currently stable, but has some unimplemented features (most notably,
 | 
			
		||||
 pvmove and e2fsadm).  It is not yet recommended for production use.  It is
 | 
			
		||||
 backwards-compatible with LVM1 (lvm10), and requires Linux kernel 2.4.
 | 
			
		||||
							
								
								
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on
 | 
			
		||||
Wed, 20 Feb 2002 03:17:25 -0500.
 | 
			
		||||
 | 
			
		||||
It was downloaded from http://www.sistina.com/products_lvm.htm
 | 
			
		||||
 | 
			
		||||
Upstream Author: LVM Development Team
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2001-2002 LVM Development Team
 | 
			
		||||
 | 
			
		||||
LVM2 is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU General Public License as published by
 | 
			
		||||
the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
LVM2 is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU General Public License
 | 
			
		||||
along with this program; if not, write to the Free Software
 | 
			
		||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 | 
			
		||||
 | 
			
		||||
On Debian systems, the full text of the GPL can be found in
 | 
			
		||||
/usr/share/common-licenses/GPL
 | 
			
		||||
							
								
								
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
etc/lvm
 | 
			
		||||
usr/share/man/man5
 | 
			
		||||
usr/share/man/man8
 | 
			
		||||
sbin
 | 
			
		||||
							
								
								
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
BUGS
 | 
			
		||||
README
 | 
			
		||||
VERSION
 | 
			
		||||
WHATS_NEW
 | 
			
		||||
doc/*
 | 
			
		||||
							
								
								
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#! /bin/sh
 | 
			
		||||
#
 | 
			
		||||
# lvm2		This script handles LVM2 initialization/shutdown.
 | 
			
		||||
#
 | 
			
		||||
#		Written by Andres Salomon <dilinger@mp3revolution.net>.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
 | 
			
		||||
NAME=lvm2
 | 
			
		||||
DESC=LVM
 | 
			
		||||
 | 
			
		||||
test -x /sbin/vgchange || exit 0
 | 
			
		||||
modprobe dm-mod >/dev/null 2>&1
 | 
			
		||||
 | 
			
		||||
# Create necessary files in /dev for device-mapper
 | 
			
		||||
create_devfiles() {
 | 
			
		||||
	DIR="/dev/mapper"
 | 
			
		||||
	FILE="$DIR/control"
 | 
			
		||||
	major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
 | 
			
		||||
	minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
 | 
			
		||||
 | 
			
		||||
	if test ! -d $DIR; then
 | 
			
		||||
		mkdir --mode=755 $DIR >/dev/null 2>&1
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	if test ! -c $FILE -a ! -z "$minor"; then
 | 
			
		||||
		mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1
 | 
			
		||||
	fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
case "$1" in
 | 
			
		||||
  start)
 | 
			
		||||
	echo -n "Initializing $DESC: "
 | 
			
		||||
	create_devfiles
 | 
			
		||||
	vgchange -a y
 | 
			
		||||
 | 
			
		||||
#	# Mount all LVM devices
 | 
			
		||||
#	for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do
 | 
			
		||||
#		MTPT=$( grep $vg /etc/fstab | awk '{print $2}' )
 | 
			
		||||
#		mount $MTPT
 | 
			
		||||
#	done
 | 
			
		||||
	echo "$NAME."
 | 
			
		||||
	;;
 | 
			
		||||
  stop)
 | 
			
		||||
	echo -n "Shutting down $DESC: "
 | 
			
		||||
	# We don't really try all that hard to shut it down; far too many
 | 
			
		||||
	# things that can keep it from successfully shutting down.
 | 
			
		||||
	vgchange -a n
 | 
			
		||||
	echo "$NAME."
 | 
			
		||||
	;;
 | 
			
		||||
  restart|force-reload)
 | 
			
		||||
	echo -n "Restarting $DESC: "
 | 
			
		||||
	vgchange -a n
 | 
			
		||||
	sleep 1
 | 
			
		||||
	vgchange -a y
 | 
			
		||||
	echo "$NAME."
 | 
			
		||||
	;;
 | 
			
		||||
  *)
 | 
			
		||||
	echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
	;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
exit 0
 | 
			
		||||
							
								
								
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
debian/lvm2/usr/share/man/man5/lvm.conf.5
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvchange.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvcreate.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvdisplay.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvextend.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvm.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvmchange.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvreduce.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvremove.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvrename.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/lvscan.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/pvchange.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/pvcreate.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/pvdisplay.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/pvscan.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgcfgbackup.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgchange.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgck.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgcreate.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgdisplay.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgextend.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgmerge.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgreduce.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgremove.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgrename.8
 | 
			
		||||
debian/lvm2/usr/share/man/man8/vgscan.8
 | 
			
		||||
							
								
								
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
#!/usr/bin/make -f
 | 
			
		||||
# Sample debian/rules that uses debhelper. 
 | 
			
		||||
# GNU copyright 1997 by Joey Hess.
 | 
			
		||||
#
 | 
			
		||||
# This version is for a hypothetical package that builds an
 | 
			
		||||
# architecture-dependant package, as well as an architecture-independent
 | 
			
		||||
# package.
 | 
			
		||||
 | 
			
		||||
# Uncomment this to turn on verbose mode. 
 | 
			
		||||
#export DH_VERBOSE=1
 | 
			
		||||
 | 
			
		||||
# This is the debhelper compatibility version to use.
 | 
			
		||||
export DH_COMPAT=3
 | 
			
		||||
 | 
			
		||||
# These are used for cross-compiling and for saving the configure script
 | 
			
		||||
# from having to guess our platform (since we know it already)
 | 
			
		||||
DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
 | 
			
		||||
DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
 | 
			
		||||
	CFLAGS += -g
 | 
			
		||||
endif
 | 
			
		||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
 | 
			
		||||
	INSTALL_PROGRAM += -s
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
configure: configure-stamp
 | 
			
		||||
configure-stamp:
 | 
			
		||||
	dh_testdir
 | 
			
		||||
	# Add here commands to configure the package.
 | 
			
		||||
	./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info
 | 
			
		||||
 | 
			
		||||
	touch configure-stamp
 | 
			
		||||
 | 
			
		||||
build-arch: configure-stamp build-arch-stamp
 | 
			
		||||
build-arch-stamp:
 | 
			
		||||
	dh_testdir
 | 
			
		||||
 | 
			
		||||
	# Add here command to compile/build the package.
 | 
			
		||||
	$(MAKE)
 | 
			
		||||
 | 
			
		||||
	touch build-arch-stamp
 | 
			
		||||
 | 
			
		||||
build-indep: configure-stamp build-indep-stamp
 | 
			
		||||
build-indep-stamp:
 | 
			
		||||
	dh_testdir
 | 
			
		||||
 | 
			
		||||
	# Add here command to compile/build the arch indep package.
 | 
			
		||||
	# It's ok not to do anything here, if you don't need to build
 | 
			
		||||
	#  anything for this package.
 | 
			
		||||
	#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1
 | 
			
		||||
 | 
			
		||||
	touch build-indep-stamp
 | 
			
		||||
 | 
			
		||||
build: build-arch build-indep
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	dh_testdir
 | 
			
		||||
	dh_testroot
 | 
			
		||||
	rm -f build-stamp configure-stamp
 | 
			
		||||
 | 
			
		||||
	# Add here commands to clean up after the build process.
 | 
			
		||||
	-$(MAKE) distclean
 | 
			
		||||
	-test -r /usr/share/misc/config.sub && \
 | 
			
		||||
	  cp -f /usr/share/misc/config.sub config.sub
 | 
			
		||||
	-test -r /usr/share/misc/config.guess && \
 | 
			
		||||
	  cp -f /usr/share/misc/config.guess config.guess
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	dh_clean
 | 
			
		||||
 | 
			
		||||
install: DH_OPTIONS=
 | 
			
		||||
install: build
 | 
			
		||||
	dh_testdir
 | 
			
		||||
	dh_testroot
 | 
			
		||||
	dh_clean -k
 | 
			
		||||
	dh_installdirs
 | 
			
		||||
 | 
			
		||||
	# Add here commands to install the package into debian/lvm2.
 | 
			
		||||
	$(MAKE) install prefix=$(CURDIR)/debian/lvm2
 | 
			
		||||
	install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Build architecture-independent files here.
 | 
			
		||||
# Pass -i to all debhelper commands in this target to reduce clutter.
 | 
			
		||||
binary-indep: build install
 | 
			
		||||
# nada.
 | 
			
		||||
 | 
			
		||||
# Build architecture-dependent files here.
 | 
			
		||||
binary-arch: build install
 | 
			
		||||
	dh_testdir
 | 
			
		||||
	dh_testroot
 | 
			
		||||
 | 
			
		||||
#	dh_installdebconf
 | 
			
		||||
	dh_installdocs
 | 
			
		||||
	dh_installexamples
 | 
			
		||||
#	dh_installlogrotate -a
 | 
			
		||||
#	dh_installemacsen -a
 | 
			
		||||
#	dh_installpam -a
 | 
			
		||||
#	dh_installmime -a
 | 
			
		||||
	dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
 | 
			
		||||
	dh_installcron
 | 
			
		||||
	dh_installman
 | 
			
		||||
	dh_installinfo 
 | 
			
		||||
	dh_installchangelogs
 | 
			
		||||
	dh_strip
 | 
			
		||||
	dh_link
 | 
			
		||||
	dh_compress
 | 
			
		||||
	dh_fixperms
 | 
			
		||||
	dh_makeshlibs
 | 
			
		||||
	dh_installdeb
 | 
			
		||||
#	dh_perl -a
 | 
			
		||||
	dh_shlibdeps
 | 
			
		||||
	dh_gencontrol
 | 
			
		||||
	dh_md5sums
 | 
			
		||||
	dh_builddeb
 | 
			
		||||
 | 
			
		||||
binary: binary-indep binary-arch
 | 
			
		||||
.PHONY: build clean binary-indep binary-arch binary install configure
 | 
			
		||||
							
								
								
									
										196
									
								
								doc/example.conf
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								doc/example.conf
									
									
									
									
									
								
							@@ -1,72 +1,94 @@
 | 
			
		||||
# This is an example configuration file for the LVM2 system.  It
 | 
			
		||||
# contains the default settings that would be used if there was no
 | 
			
		||||
# This is an example configuration file for the LVM2 system.
 | 
			
		||||
# It contains the default settings that would be used if there was no
 | 
			
		||||
# /etc/lvm/lvm.conf file.
 | 
			
		||||
# Refer to 'man lvm.conf' for further information.
 | 
			
		||||
#
 | 
			
		||||
# Refer to 'man lvm.conf' for further information including the file layout.
 | 
			
		||||
#
 | 
			
		||||
# To put this file in a different directory and override /etc/lvm set
 | 
			
		||||
# the environment variable LVM_SYSTEM_DIR before running the tools.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# This section allows the user to configure which block devices should
 | 
			
		||||
# This section allows you to configure which block devices should
 | 
			
		||||
# be used by the LVM system.
 | 
			
		||||
devices {
 | 
			
		||||
 | 
			
		||||
    # where do you want your volume groups to appear ?
 | 
			
		||||
    # Where do you want your volume groups to appear ?
 | 
			
		||||
    dir = "/dev"
 | 
			
		||||
 | 
			
		||||
    # An array of directories that contain the device nodes you wish
 | 
			
		||||
    # to use with LVM2.
 | 
			
		||||
    scan = "/dev"
 | 
			
		||||
 | 
			
		||||
    # A very important option, that allows you to tune the LVM2 system
 | 
			
		||||
    # to just look at a restricted set of devices that you're
 | 
			
		||||
    # interested in.
 | 
			
		||||
    scan = [ "/dev" ]
 | 
			
		||||
 | 
			
		||||
    # A filter that tells LVM2 to only use a restricted set of devices.
 | 
			
		||||
    # The filter consists of an array of regular expressions.  These
 | 
			
		||||
    # expressions can be delimited by a character of your choice, and
 | 
			
		||||
    # prefixed with either an 'a' (for accept) or 'r' (for reject).
 | 
			
		||||
    # ATM you cannot use anchors (^ or $) in your regular expression.
 | 
			
		||||
    # The first expression found to match a device name determines if
 | 
			
		||||
    # the device will be accepted or rejected (ignored).  Devices that
 | 
			
		||||
    # don't match any patterns are accepted.
 | 
			
		||||
 | 
			
		||||
    # If using RAID md devices as physical volumes, you should
 | 
			
		||||
    # set up a filter here to reject the constituent devices.
 | 
			
		||||
 | 
			
		||||
    # Remember to run vgscan after you change this parameter to ensure 
 | 
			
		||||
    # that the cache file gets regenerated (see below).
 | 
			
		||||
 | 
			
		||||
    # By default we accept every block device:
 | 
			
		||||
    filter = "a/.*/"
 | 
			
		||||
    filter = [ "a/.*/" ]
 | 
			
		||||
 | 
			
		||||
    # Exclude the cdrom drive
 | 
			
		||||
    # filter = [ "r|/dev/cdrom|" ]
 | 
			
		||||
 | 
			
		||||
    # When testing I like to work with just loopback devices:
 | 
			
		||||
    # filter = ["a/loop/", "r/.*/"]
 | 
			
		||||
    # filter = [ "a/loop/", "r/.*/" ]
 | 
			
		||||
 | 
			
		||||
    # Or maybe all loops and ide drives except hdc:
 | 
			
		||||
    # filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
 | 
			
		||||
    # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
 | 
			
		||||
 | 
			
		||||
    # The results of all the filtering are cached on disk to avoid
 | 
			
		||||
    # Use anchors if you want to be really specific
 | 
			
		||||
    # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
 | 
			
		||||
 | 
			
		||||
    # The results of the filtering are cached on disk to avoid
 | 
			
		||||
    # rescanning dud devices (which can take a very long time).  By
 | 
			
		||||
    # default this cache file is hidden in the /etc/lvm directory, it
 | 
			
		||||
    # is human readable to aid filter debugging.
 | 
			
		||||
    # default this cache file is hidden in the /etc/lvm directory.
 | 
			
		||||
    # It is safe to delete this file: the tools regenerate it.
 | 
			
		||||
    cache = "/etc/lvm/.cache"
 | 
			
		||||
 | 
			
		||||
    # You can turn off writing this cache file by setting this to 0.
 | 
			
		||||
    write_cache_state = 1
 | 
			
		||||
 | 
			
		||||
    # An advanced setting.
 | 
			
		||||
    # List of pairs of additional acceptable block device types found 
 | 
			
		||||
    # in /proc/devices with maximum (non-zero) number of partitions.
 | 
			
		||||
    # types = [ "fd", 16 ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# A section that allows the user to configure the nature of the
 | 
			
		||||
# This section that allows you to configure the nature of the
 | 
			
		||||
# information that LVM2 reports.
 | 
			
		||||
log {
 | 
			
		||||
 | 
			
		||||
    # Where should the log of error and debug messages go ?  By
 | 
			
		||||
    # default there is no log.
 | 
			
		||||
    #file = "/var/log/lvm2.log"
 | 
			
		||||
 | 
			
		||||
    # Should we overwrite the last log.  By default we append.
 | 
			
		||||
    overwrite = 0
 | 
			
		||||
 | 
			
		||||
    # There are 9 log levels, with 9 being the most verbose.
 | 
			
		||||
    level = 3
 | 
			
		||||
    
 | 
			
		||||
    # Controls the messages sent to stdout or stderr while running 
 | 
			
		||||
    # LVM2.  There are three levels of verbosity, 3 being the most 
 | 
			
		||||
    # verbose.
 | 
			
		||||
    # Controls the messages sent to stdout or stderr.
 | 
			
		||||
    # There are three levels of verbosity, 3 being the most verbose.
 | 
			
		||||
    verbose = 0
 | 
			
		||||
 | 
			
		||||
    # Should we send log messages through syslog?
 | 
			
		||||
    # 1 is yes; 0 is no.
 | 
			
		||||
    syslog = 1
 | 
			
		||||
 | 
			
		||||
    # Choose format of output messages
 | 
			
		||||
    # Should we log error and debug messages to a file?
 | 
			
		||||
    # By default there is no log file.
 | 
			
		||||
    #file = "/var/log/lvm2.log"
 | 
			
		||||
 | 
			
		||||
    # Should we overwrite the log file each time the program is run?
 | 
			
		||||
    # By default we append.
 | 
			
		||||
    overwrite = 0
 | 
			
		||||
 | 
			
		||||
    # What level of log messages should we send to the log file and/or syslog?
 | 
			
		||||
    # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
 | 
			
		||||
    # 7 is the most verbose (LOG_DEBUG).
 | 
			
		||||
    level = 0
 | 
			
		||||
    
 | 
			
		||||
    # Format of output messages
 | 
			
		||||
    # Whether or not (1 or 0) to indent messages according to their severity
 | 
			
		||||
    indent = 1
 | 
			
		||||
 | 
			
		||||
@@ -74,13 +96,18 @@ log {
 | 
			
		||||
    command_names = 0
 | 
			
		||||
 | 
			
		||||
    # A prefix to use before the message text (but after the command name,
 | 
			
		||||
    # if selected)
 | 
			
		||||
    # if selected).  Default is two spaces, so you can see/grep the severity
 | 
			
		||||
    # of each message.
 | 
			
		||||
    prefix = "  "
 | 
			
		||||
 | 
			
		||||
    # To make the messages look similar to the original LVM use:
 | 
			
		||||
    # To make the messages look similar to the original LVM tools use:
 | 
			
		||||
    #   indent = 0
 | 
			
		||||
    #   command_names = 1
 | 
			
		||||
    #   prefix = " -- "
 | 
			
		||||
 | 
			
		||||
    # Set this if you want log messages during activation.
 | 
			
		||||
    # Don't use this in low memory situations (can deadlock).
 | 
			
		||||
    # activation = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Configuration of metadata backups and archiving.  In LVM2 when we
 | 
			
		||||
@@ -91,19 +118,20 @@ backup {
 | 
			
		||||
 | 
			
		||||
    # Should we maintain a backup of the current metadata configuration ?
 | 
			
		||||
    # Use 1 for Yes; 0 for No.
 | 
			
		||||
    # Think very hard before turning this off.
 | 
			
		||||
    # Think very hard before turning this off!
 | 
			
		||||
    backup = 1
 | 
			
		||||
 | 
			
		||||
    # Where shall we keep it ?
 | 
			
		||||
    # Remember to back up this directory regularly!
 | 
			
		||||
    backup_dir = "/etc/lvm/backup"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # Should we maintain an archive of old metadata configurations.
 | 
			
		||||
    # Use 1 for Yes; 0 for No.
 | 
			
		||||
    # On by default.  Think very hard before turning this off.
 | 
			
		||||
    archive = 1
 | 
			
		||||
 | 
			
		||||
    # Where should archived files go ?
 | 
			
		||||
    # Remember to back up this directory regularly!
 | 
			
		||||
    archive_dir = "/etc/lvm/archive"
 | 
			
		||||
    
 | 
			
		||||
    # What is the minimum number of archive files you wish to keep ?
 | 
			
		||||
@@ -113,14 +141,15 @@ backup {
 | 
			
		||||
    retain_days = 30
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Settings for the running LVM2 in shell mode.
 | 
			
		||||
# Settings for the running LVM2 in shell (readline) mode.
 | 
			
		||||
shell {
 | 
			
		||||
 | 
			
		||||
    # Number of lines of history to store in ~/.lvm_history
 | 
			
		||||
    history_size = 100
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Miscellaneous global settings
 | 
			
		||||
 | 
			
		||||
# Miscellaneous global LVM2 settings
 | 
			
		||||
global {
 | 
			
		||||
    
 | 
			
		||||
    # The file creation mask for any files and directories created.
 | 
			
		||||
@@ -134,4 +163,95 @@ global {
 | 
			
		||||
    # will be made.  Equivalent to having the -t option on every
 | 
			
		||||
    # command.  Defaults to off.
 | 
			
		||||
    test = 0
 | 
			
		||||
 | 
			
		||||
    # Whether or not to communicate with the kernel device-mapper.
 | 
			
		||||
    # Set to 0 if you want to use the tools to manipulate LVM metadata 
 | 
			
		||||
    # without activating any logical volumes.
 | 
			
		||||
    # If the device-mapper kernel driver is not present in your kernel
 | 
			
		||||
    # setting this to 0 should suppress the error messages.
 | 
			
		||||
    activation = 1
 | 
			
		||||
 | 
			
		||||
    # The default metadata format that commands should use - "lvm1" or "lvm2".
 | 
			
		||||
    # The command line override is -M1 or -M2.
 | 
			
		||||
    # Defaults to "lvm1" if compiled in, else "lvm2".
 | 
			
		||||
    # format = "lvm1"
 | 
			
		||||
 | 
			
		||||
    # Location of proc filesystem
 | 
			
		||||
    proc = "/proc"
 | 
			
		||||
 | 
			
		||||
    # Type of locking to use. Defaults to file-based locking (1).
 | 
			
		||||
    # Turn locking off by setting to 0 (dangerous: risks metadata corruption
 | 
			
		||||
    # if LVM2 commands get run concurrently).
 | 
			
		||||
    locking_type = 1
 | 
			
		||||
 | 
			
		||||
    # Local non-LV directory that holds file-based locks while commands are
 | 
			
		||||
    # in progress.  A directory like /tmp that may get wiped on reboot is OK.
 | 
			
		||||
    locking_dir = "/var/lock/lvm"
 | 
			
		||||
 | 
			
		||||
    # Other entries can go here to allow you to load shared libraries
 | 
			
		||||
    # e.g. if support for LVM1 metadata was compiled as a shared library use
 | 
			
		||||
    #   format_libraries = "liblvm2format1.so" 
 | 
			
		||||
    # Full pathnames can be given.
 | 
			
		||||
 | 
			
		||||
    # Search this directory first for shared libraries.
 | 
			
		||||
    #   library_dir = "/lib"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
activation {
 | 
			
		||||
    # Device used in place of missing stripes if activating incomplete volume.
 | 
			
		||||
    # For now, you need to set this up yourself first (e.g. with 'dmsetup')
 | 
			
		||||
    # For example, you could make it return I/O errors using the 'error' 
 | 
			
		||||
    # target or make it return zeros.
 | 
			
		||||
    missing_stripe_filler = "/dev/ioerror"
 | 
			
		||||
 | 
			
		||||
    # Size (in KB) of each copy operation when mirroring
 | 
			
		||||
    mirror_region_size = 512
 | 
			
		||||
 | 
			
		||||
    # How much stack (in KB) to reserve for use while devices suspended
 | 
			
		||||
    reserved_stack = 256
 | 
			
		||||
 | 
			
		||||
    # How much memory (in KB) to reserve for use while devices suspended
 | 
			
		||||
    reserved_memory = 8192
 | 
			
		||||
 | 
			
		||||
    # Nice value used while devices suspended
 | 
			
		||||
    process_priority = -18
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################
 | 
			
		||||
# Advanced section #
 | 
			
		||||
####################
 | 
			
		||||
 | 
			
		||||
# Metadata settings
 | 
			
		||||
#
 | 
			
		||||
# metadata {
 | 
			
		||||
    # Default number of copies of metadata to hold on each PV.  0, 1 or 2.
 | 
			
		||||
    # It's best to leave this at 2.
 | 
			
		||||
    # You might want to override it from the command line with 0 or 1 
 | 
			
		||||
    # when running pvcreate on new PVs which are to be added to large VGs.
 | 
			
		||||
 | 
			
		||||
    # pvmetadatacopies = 2
 | 
			
		||||
 | 
			
		||||
    # Approximate default size of on-disk metadata areas in sectors.
 | 
			
		||||
    # You should increase this if you have large volume groups or
 | 
			
		||||
    # you want to retain a large on-disk history of your metadata changes.
 | 
			
		||||
 | 
			
		||||
    # pvmetadatasize = 255
 | 
			
		||||
 | 
			
		||||
    # List of directories holding live copies of text format metadata.
 | 
			
		||||
    # These directories must not be on logical volumes!
 | 
			
		||||
    # It's possible to use LVM2 with a couple of directories here,
 | 
			
		||||
    # preferably on different (non-LV) filesystems, and with no other 
 | 
			
		||||
    # on-disk metadata (pvmetadatacopies = 0). Or this can be in
 | 
			
		||||
    # addition to on-disk metadata areas.
 | 
			
		||||
    # The feature was originally added to simplify testing and is not
 | 
			
		||||
    # supported under low memory situations - the machine could lock up.
 | 
			
		||||
    #
 | 
			
		||||
    # Never edit any files in these directories by hand unless you
 | 
			
		||||
    # you are absolutely sure you know what you are doing! Use
 | 
			
		||||
    # the supplied toolset to make changes (e.g. vgcfgrestore).
 | 
			
		||||
 | 
			
		||||
    # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
 | 
			
		||||
#}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
Here's how I test new LVM2 builds without interfering with the stable
 | 
			
		||||
LVM2 that is running the LV's on my development box.
 | 
			
		||||
 | 
			
		||||
1) Create a set of loopback devices.
 | 
			
		||||
 | 
			
		||||
2) Create a new directory to contain the LVM2 configuration files for
 | 
			
		||||
   this setup.  (I use /etc/lvm_loops)
 | 
			
		||||
 | 
			
		||||
3) Write a suitable lvm.conf file, this goes in the directory you just
 | 
			
		||||
   created.  eg, my /etc/lvm_loops/lvm.conf looks like:
 | 
			
		||||
 | 
			
		||||
   log {
 | 
			
		||||
        file="/tmp/lvm2_loop.log"
 | 
			
		||||
        level=9
 | 
			
		||||
        verbose=0
 | 
			
		||||
        overwrite=1
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   devices {
 | 
			
		||||
        scan = "/dev"
 | 
			
		||||
        filter = ["a/loop/", "r/.*/"]
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   The important this to note is the devices section which makes sure that
 | 
			
		||||
   only the loopback devices are considered for LVM2 operations.
 | 
			
		||||
 | 
			
		||||
4) When you want to use this test setup just set the environment
 | 
			
		||||
   variable LVM_SYSTEM_DIR to point to your config directory
 | 
			
		||||
   (/etc/lvm_loops in my case).
 | 
			
		||||
 | 
			
		||||
5) It's a good idea to do a vgscan to initialise the filters:
 | 
			
		||||
 | 
			
		||||
   export LVM_SYSTEM_DIR=/etc/lvm_loops
 | 
			
		||||
   ./lvm vgscan
 | 
			
		||||
 | 
			
		||||
   where ./lvm is the new build of LVM2 that I'm trying out.
 | 
			
		||||
 | 
			
		||||
7) Test away.  Make sure that you are explicit about which lvm
 | 
			
		||||
   executable you want to execute (eg, ./lvm if you are in
 | 
			
		||||
   LVM2/tools).
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
../lib/activate/activate.h
 | 
			
		||||
../lib/cache/lvmcache.h
 | 
			
		||||
../lib/commands/errors.h
 | 
			
		||||
../lib/commands/toolcontext.h
 | 
			
		||||
../lib/config/config.h
 | 
			
		||||
../lib/config/defaults.h
 | 
			
		||||
../lib/datastruct/bitset.h
 | 
			
		||||
../lib/datastruct/btree.h
 | 
			
		||||
../lib/datastruct/hash.h
 | 
			
		||||
@@ -13,17 +17,21 @@
 | 
			
		||||
../lib/filters/filter-regex.h
 | 
			
		||||
../lib/filters/filter.h
 | 
			
		||||
../lib/format1/format1.h
 | 
			
		||||
../lib/format1/lvm1_label.h
 | 
			
		||||
../lib/format1/lvm1-label.h
 | 
			
		||||
../lib/format_text/format-text.h
 | 
			
		||||
../lib/label/label.h
 | 
			
		||||
../lib/label/uuid-map.h
 | 
			
		||||
../lib/locking/locking.h
 | 
			
		||||
../lib/log/log.h
 | 
			
		||||
../lib/metadata/metadata.h
 | 
			
		||||
../lib/mm/dbg_malloc.h
 | 
			
		||||
../lib/mm/memlock.h
 | 
			
		||||
../lib/mm/pool.h
 | 
			
		||||
../lib/mm/xlate.h
 | 
			
		||||
../lib/misc/crc.h
 | 
			
		||||
../lib/misc/lib.h
 | 
			
		||||
../lib/misc/lvm-file.h
 | 
			
		||||
../lib/misc/lvm-string.h
 | 
			
		||||
../lib/misc/sharedlib.h
 | 
			
		||||
../lib/regex/matcher.h
 | 
			
		||||
../lib/report/report.h
 | 
			
		||||
../lib/uuid/uuid.h
 | 
			
		||||
../lib/vgcache/vgcache.h
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,14 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
VPATH = @srcdir@
 | 
			
		||||
 | 
			
		||||
ifeq ("@LVM1@", "shared")
 | 
			
		||||
  SUBDIRS = format1
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
SOURCES=\
 | 
			
		||||
	activate/activate.c \
 | 
			
		||||
	activate/fs.c \
 | 
			
		||||
	activate/names.c \
 | 
			
		||||
	cache/lvmcache.c \
 | 
			
		||||
	commands/toolcontext.c \
 | 
			
		||||
	config/config.c \
 | 
			
		||||
	datastruct/bitset.c \
 | 
			
		||||
	datastruct/btree.c \
 | 
			
		||||
@@ -24,33 +28,62 @@ SOURCES=\
 | 
			
		||||
	filters/filter-persistent.c \
 | 
			
		||||
	filters/filter-regex.c \
 | 
			
		||||
	filters/filter.c \
 | 
			
		||||
	format1/disk-rep.c \
 | 
			
		||||
	format1/format1.c \
 | 
			
		||||
	format1/import-export.c \
 | 
			
		||||
	format1/import-extents.c \
 | 
			
		||||
	format1/layout.c \
 | 
			
		||||
	format1/lvm1_label.c \
 | 
			
		||||
	format1/vg_number.c \
 | 
			
		||||
	format_text/archive.c \
 | 
			
		||||
	format_text/export.c \
 | 
			
		||||
	format_text/flags.c \
 | 
			
		||||
	format_text/format-text.c \
 | 
			
		||||
	format_text/import.c \
 | 
			
		||||
	format_text/import_vsn1.c \
 | 
			
		||||
	format_text/text_label.c \
 | 
			
		||||
	label/label.c \
 | 
			
		||||
	label/uuid-map.c \
 | 
			
		||||
	locking/file_locking.c \
 | 
			
		||||
	locking/locking.c \
 | 
			
		||||
	locking/no_locking.c \
 | 
			
		||||
	log/log.c \
 | 
			
		||||
	metadata/lv_manip.c \
 | 
			
		||||
	metadata/merge.c \
 | 
			
		||||
	metadata/metadata.c \
 | 
			
		||||
	metadata/mirror.c \
 | 
			
		||||
	metadata/pv_map.c \
 | 
			
		||||
	metadata/snapshot_manip.c \
 | 
			
		||||
	misc/crc.c \
 | 
			
		||||
	misc/lvm-file.c \
 | 
			
		||||
	mm/dbg_malloc.c \
 | 
			
		||||
	misc/lvm-string.c \
 | 
			
		||||
	mm/memlock.c \
 | 
			
		||||
	mm/pool.c \
 | 
			
		||||
	regex/matcher.c \
 | 
			
		||||
	regex/parse_rx.c \
 | 
			
		||||
	regex/ttree.c \
 | 
			
		||||
	uuid/uuid.c \
 | 
			
		||||
	vgcache/vgcache.c
 | 
			
		||||
	report/report.c \
 | 
			
		||||
	uuid/uuid.c 
 | 
			
		||||
 | 
			
		||||
ifeq ("@LVM1@", "internal")
 | 
			
		||||
  SOURCES+=\
 | 
			
		||||
	format1/disk-rep.c \
 | 
			
		||||
	format1/format1.c \
 | 
			
		||||
	format1/import-export.c \
 | 
			
		||||
	format1/import-extents.c \
 | 
			
		||||
	format1/layout.c \
 | 
			
		||||
	format1/lvm1-label.c \
 | 
			
		||||
	format1/vg_number.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@DEBUG@", "yes")
 | 
			
		||||
  SOURCES+=\
 | 
			
		||||
	mm/dbg_malloc.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@DEVMAPPER@", "yes")
 | 
			
		||||
  SOURCES+=\
 | 
			
		||||
	activate/dev_manager.c \
 | 
			
		||||
	activate/fs.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@HAVE_LIBDL@", "yes")
 | 
			
		||||
  SOURCES+=\
 | 
			
		||||
	locking/external_locking.c \
 | 
			
		||||
	misc/sharedlib.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
TARGETS=liblvm.a
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,56 +4,125 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "fs.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "names.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "dev_manager.h"
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
 | 
			
		||||
 | 
			
		||||
#ifndef DEVMAPPER_SUPPORT
 | 
			
		||||
void set_activation(int act)
 | 
			
		||||
{
 | 
			
		||||
	if (act)
 | 
			
		||||
		log_error("Compiled without libdevmapper support. "
 | 
			
		||||
			  "Can't enable activation.");
 | 
			
		||||
}
 | 
			
		||||
int activation(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int library_version(char *version, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int driver_version(char *version, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
 | 
			
		||||
		      uint32_t *event_nr)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lvs_in_vg_activated(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lvs_in_vg_opened(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
void activation_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else				/* DEVMAPPER_SUPPORT */
 | 
			
		||||
 | 
			
		||||
static int _activation = 1;
 | 
			
		||||
 | 
			
		||||
void set_activation(int act)
 | 
			
		||||
{
 | 
			
		||||
	if (act == _activation)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	_activation = act;
 | 
			
		||||
	if (_activation)
 | 
			
		||||
		log_verbose("Activation enabled. Device-mapper kernel "
 | 
			
		||||
			    "driver will be used.");
 | 
			
		||||
	else
 | 
			
		||||
		log_verbose("Activation disabled. No device-mapper "
 | 
			
		||||
			    "interaction will be attempted.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int activation(void)
 | 
			
		||||
{
 | 
			
		||||
	return _activation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int library_version(char *version, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!dm_get_library_version(version, size))
 | 
			
		||||
		return 0;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_task *_setup_task_with_name(struct logical_volume *lv,
 | 
			
		||||
					     const char *lv_name,
 | 
			
		||||
				   	     int task)
 | 
			
		||||
{
 | 
			
		||||
	char name[128];
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = dm_task_create(task))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!build_dm_name(name, sizeof(name), lv->vg->name, lv_name)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_task_set_name(dmt, name);
 | 
			
		||||
 | 
			
		||||
	return dmt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_task *_setup_task(struct logical_volume *lv, int task)
 | 
			
		||||
{
 | 
			
		||||
	return _setup_task_with_name(lv, lv->name, task);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int driver_version(char *version, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Getting driver version");
 | 
			
		||||
	if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -74,364 +143,176 @@ int driver_version(char *version, size_t size)
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_info(struct logical_volume *lv, struct dm_info *info)
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if info structure populated, else 0 on failure.
 | 
			
		||||
 */
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
	struct dm_info dminfo;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Getting device info for %s", lv->name);
 | 
			
		||||
	if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
	if (!(r = dev_manager_info(dm, lv, &dminfo)))
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_get_info(dmt, info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	r = 1;
 | 
			
		||||
	info->exists = dminfo.exists;
 | 
			
		||||
	info->suspended = dminfo.suspended;
 | 
			
		||||
	info->open_count = dminfo.open_count;
 | 
			
		||||
	info->major = dminfo.major;
 | 
			
		||||
	info->minor = dminfo.minor;
 | 
			
		||||
	info->read_only = dminfo.read_only;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_rename(const char *old_name, struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	char new_name[PATH_MAX];
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _setup_task_with_name(lv, old_name, DM_DEVICE_RENAME))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!build_dm_name(new_name, sizeof(new_name),
 | 
			
		||||
			   lv->vg->name, lv->name)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_set_newname(dmt, new_name)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		r = 0;
 | 
			
		||||
		goto end;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		r = 0;
 | 
			
		||||
		goto end;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fs_rename_lv(old_name, lv);
 | 
			
		||||
 | 
			
		||||
      end:
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_active(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int r = -1;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s is%s active", lv->name, info.exists ? "":" not");
 | 
			
		||||
	return info.exists;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_suspended(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int r = -1;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s is%s suspended", lv->name,
 | 
			
		||||
			 info.suspended ? "":" not");
 | 
			
		||||
	return info.suspended;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_open_count(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int r = -1;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s is open %d time(s)", lv->name, info.open_count);
 | 
			
		||||
	return info.open_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Emit a target for a given segment.
 | 
			
		||||
 * Returns 1 if percent set, else 0 on failure.
 | 
			
		||||
 */
 | 
			
		||||
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
 | 
			
		||||
{
 | 
			
		||||
	char params[1024];
 | 
			
		||||
	uint64_t esize = seg->lv->vg->extent_size;
 | 
			
		||||
	uint32_t s, stripes = seg->stripes;
 | 
			
		||||
	int w = 0, tw = 0, error = 0;
 | 
			
		||||
	const char *no_space =
 | 
			
		||||
		"Insufficient space to write target parameters.";
 | 
			
		||||
	char *filler = "/dev/ioerror";
 | 
			
		||||
	char *target;
 | 
			
		||||
 | 
			
		||||
	if (stripes == 1) {
 | 
			
		||||
		if (!seg->area[0].pv) {
 | 
			
		||||
			target = "error";
 | 
			
		||||
			error = 1;
 | 
			
		||||
		}
 | 
			
		||||
		else 
 | 
			
		||||
			target = "linear";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (stripes > 1) {
 | 
			
		||||
		target = "striped";
 | 
			
		||||
		tw = lvm_snprintf(params, sizeof(params), "%u %u ",
 | 
			
		||||
			      stripes, seg->stripe_size);
 | 
			
		||||
 | 
			
		||||
		if (tw < 0) {
 | 
			
		||||
			log_err(no_space);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		w = tw;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!error) {
 | 
			
		||||
		for (s = 0; s < stripes; s++, w += tw) {
 | 
			
		||||
			if (!seg->area[s].pv)
 | 
			
		||||
				tw = lvm_snprintf(
 | 
			
		||||
					params + w, sizeof(params) - w,
 | 
			
		||||
			      		"%s 0%s", filler,
 | 
			
		||||
			      		s == (stripes - 1) ? "" : " ");
 | 
			
		||||
			else
 | 
			
		||||
				tw = lvm_snprintf(
 | 
			
		||||
					params + w, sizeof(params) - w,
 | 
			
		||||
			      		"%s %" PRIu64 "%s",
 | 
			
		||||
					dev_name(seg->area[s].pv->dev),
 | 
			
		||||
			      		(seg->area[s].pv->pe_start +
 | 
			
		||||
			         	 (esize * seg->area[s].pe)),
 | 
			
		||||
			      		s == (stripes - 1) ? "" : " ");
 | 
			
		||||
 | 
			
		||||
			if (tw < 0) {
 | 
			
		||||
				log_err(no_space);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
 | 
			
		||||
		   esize * seg->le, esize * seg->len,
 | 
			
		||||
		   target, params);
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len,
 | 
			
		||||
				target, params)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _load(struct logical_volume *lv, int task)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Generating devmapper parameters for %s", lv->name);
 | 
			
		||||
	if (!(dmt = _setup_task(lv, task))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_iterate(segh, &lv->segments) {
 | 
			
		||||
		seg = list_item(segh, struct stripe_segment);
 | 
			
		||||
		if (!_emit_target(dmt, seg)) {
 | 
			
		||||
			log_error("Unable to activate logical volume '%s'",
 | 
			
		||||
				lv->name);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!((lv->status & LVM_WRITE) && (lv->vg->status & LVM_WRITE))) {
 | 
			
		||||
	    	if (!dm_task_set_ro(dmt))
 | 
			
		||||
			log_error("Failed to set %s read-only during "
 | 
			
		||||
				  "activation.", lv->name);
 | 
			
		||||
		else 
 | 
			
		||||
			log_very_verbose("Activating %s read-only", lv->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	log_verbose("Logical volume %s%s activated", lv->name,
 | 
			
		||||
		    r == 1 ? "" : " not");
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: Always display error msg */
 | 
			
		||||
int lv_activate(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Activating %s", lv->name);
 | 
			
		||||
	return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _suspend(struct logical_volume *lv, int sus)
 | 
			
		||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", lv->name);
 | 
			
		||||
	if (!(dmt = _setup_task(lv, task))) {
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt)))
 | 
			
		||||
		log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume",
 | 
			
		||||
			lv->name);
 | 
			
		||||
	if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_suspend(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	return _suspend(lv, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_reactivate(struct logical_volume *lv)
 | 
			
		||||
/* FIXME Merge with snapshot_percent */
 | 
			
		||||
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
 | 
			
		||||
		      uint32_t *event_nr)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!lv_suspended(lv) && !_suspend(lv, 1)) {
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = _load(lv, DM_DEVICE_RELOAD);
 | 
			
		||||
 | 
			
		||||
	if (!_suspend(lv, 0)) {
 | 
			
		||||
	if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lv_active(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
int lv_deactivate(struct logical_volume *lv)
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return info.exists;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lv_open_count(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return info.open_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME Need to detect and handle an lv rename */
 | 
			
		||||
static int _lv_activate(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Deactivating %s", lv->name);
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) {
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt)))
 | 
			
		||||
	if (!(r = dev_manager_activate(dm, lv)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
	fs_del_lv(lv);
 | 
			
		||||
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int activate_lvs_in_vg(struct volume_group *vg)
 | 
			
		||||
static int _lv_deactivate(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		count += (!lv_active(lv) && lv_activate(lv));
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
	if (!(r = dev_manager_deactivate(dm, lv)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_update_write_access(struct logical_volume *lv)
 | 
			
		||||
static int _lv_suspend(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
        struct dm_info info;
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
 | 
			
		||||
        if (!lv_info(lv, &info)) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!info.exists || info.suspended)
 | 
			
		||||
		/* Noop */
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return lv_reactivate(lv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int deactivate_lvs_in_vg(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		count += ((lv_active(lv) == 1) && lv_deactivate(lv));
 | 
			
		||||
	if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
	if (!(r = dev_manager_suspend(dm, lv)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dev_manager_destroy(dm);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These two functions return the number of LVs in the state,
 | 
			
		||||
 * or -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
int lvs_in_vg_activated(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		count += (lv_active(lv) == 1);
 | 
			
		||||
		count += (_lv_active(lv) == 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
@@ -443,10 +324,153 @@ int lvs_in_vg_opened(struct volume_group *vg)
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		count += (lv_open_count(lv) == 1);
 | 
			
		||||
		count += (_lv_open_count(lv) == 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* These return success if the device is not active */
 | 
			
		||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!(lv = lv_from_lvid(cmd, lvid_s)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (test_mode()) {
 | 
			
		||||
		_skip("Suspending '%s'.", lv->name);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!info.exists || info.suspended)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	memlock_inc();
 | 
			
		||||
	if (!_lv_suspend(lv)) {
 | 
			
		||||
		memlock_dec();
 | 
			
		||||
		fs_unlock();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!(lv = lv_from_lvid(cmd, lvid_s)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (test_mode()) {
 | 
			
		||||
		_skip("Resuming '%s'.", lv->name);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!info.exists || !info.suspended)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!_lv_activate(lv))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	memlock_dec();
 | 
			
		||||
	fs_unlock();
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!(lv = lv_from_lvid(cmd, lvid_s)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (test_mode()) {
 | 
			
		||||
		_skip("Deactivating '%s'.", lv->name);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!info.exists)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	memlock_inc();
 | 
			
		||||
	r = _lv_deactivate(lv);
 | 
			
		||||
	memlock_dec();
 | 
			
		||||
	fs_unlock();
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!(lv = lv_from_lvid(cmd, lvid_s)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (test_mode()) {
 | 
			
		||||
		_skip("Activating '%s'.", lv->name);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info.exists && !info.suspended)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	memlock_inc();
 | 
			
		||||
	r = _lv_activate(lv);
 | 
			
		||||
	memlock_dec();
 | 
			
		||||
	fs_unlock();
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void activation_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	dev_manager_exit();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the GPL.
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LVM_ACTIVATE_H
 | 
			
		||||
#define LVM_ACTIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <libdevmapper.h>
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
/* FIXME Snapshot handling? */
 | 
			
		||||
#ifdef DEVMAPPER_SUPPORT
 | 
			
		||||
#  include <libdevmapper.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct lvinfo {
 | 
			
		||||
	int exists;
 | 
			
		||||
	int suspended;
 | 
			
		||||
	unsigned int open_count;
 | 
			
		||||
	int major;
 | 
			
		||||
	int minor;
 | 
			
		||||
	int read_only;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void set_activation(int activation);
 | 
			
		||||
int activation(void);
 | 
			
		||||
 | 
			
		||||
int driver_version(char *version, size_t size);
 | 
			
		||||
int library_version(char *version, size_t size);
 | 
			
		||||
 | 
			
		||||
int lv_active(struct logical_volume *lv);
 | 
			
		||||
int lv_suspended(struct logical_volume *lv);
 | 
			
		||||
int lv_open_count(struct logical_volume *lv);
 | 
			
		||||
int lv_info(struct logical_volume *lv, struct dm_info *info);
 | 
			
		||||
int lv_rename(const char *old_name, struct logical_volume *lv);
 | 
			
		||||
void activation_exit(void);
 | 
			
		||||
 | 
			
		||||
int lv_activate(struct logical_volume *lv);
 | 
			
		||||
int lv_reactivate(struct logical_volume *lv);
 | 
			
		||||
int lv_deactivate(struct logical_volume *lv);
 | 
			
		||||
int lv_suspend(struct logical_volume *lv);
 | 
			
		||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
 | 
			
		||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
 | 
			
		||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
 | 
			
		||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return number of LVs in the VG that are
 | 
			
		||||
 * active.
 | 
			
		||||
 * Returns 1 if info structure has been populated, else 0.
 | 
			
		||||
 */
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if percent has been set, else 0.
 | 
			
		||||
 */
 | 
			
		||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
 | 
			
		||||
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
 | 
			
		||||
		      uint32_t *event_nr);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return number of LVs in the VG that are active.
 | 
			
		||||
 */
 | 
			
		||||
int lvs_in_vg_activated(struct volume_group *vg);
 | 
			
		||||
int lvs_in_vg_opened(struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Test for (lv->status & LVM_WRITE)
 | 
			
		||||
 */
 | 
			
		||||
int lv_update_write_access(struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Activate all LVs in the VG.  Ignore any that
 | 
			
		||||
 * are already active.  Return number
 | 
			
		||||
 * activated.
 | 
			
		||||
 */
 | 
			
		||||
int activate_lvs_in_vg(struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Deactivate all LVs in the VG
 | 
			
		||||
 */
 | 
			
		||||
int deactivate_lvs_in_vg(struct volume_group *vg);
 | 
			
		||||
int lv_setup_cow_store(struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2181
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2181
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_DEV_MANAGER_H
 | 
			
		||||
#define _LVM_DEV_MANAGER_H
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
struct dev_manager;
 | 
			
		||||
struct dm_info;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Constructor and destructor.
 | 
			
		||||
 */
 | 
			
		||||
struct dev_manager *dev_manager_create(const char *vg_name,
 | 
			
		||||
				       struct config_tree *cf);
 | 
			
		||||
void dev_manager_destroy(struct dev_manager *dm);
 | 
			
		||||
void dev_manager_exit(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The device handler is responsible for creating all the layered
 | 
			
		||||
 * dm devices, and ensuring that all constraints are maintained
 | 
			
		||||
 * (eg, an origin is created before its snapshot, but is not
 | 
			
		||||
 * unsuspended until the snapshot is also created.)
 | 
			
		||||
 */
 | 
			
		||||
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
 | 
			
		||||
		     struct dm_info *info);
 | 
			
		||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
 | 
			
		||||
				 struct logical_volume *lv, float *percent);
 | 
			
		||||
int dev_manager_mirror_percent(struct dev_manager *dm,
 | 
			
		||||
			       struct logical_volume *lv, int wait,
 | 
			
		||||
			       float *percent, uint32_t *event_nr);
 | 
			
		||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
 | 
			
		||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
 | 
			
		||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Put the desired changes into effect.
 | 
			
		||||
 */
 | 
			
		||||
int dev_manager_execute(struct dev_manager *dm);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the GPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef DMFS_INTERFACE_H
 | 
			
		||||
#define DMFS_INTERFACE_H
 | 
			
		||||
 | 
			
		||||
struct dmfs;
 | 
			
		||||
 | 
			
		||||
struct dmfs *dmfs_create(void);
 | 
			
		||||
void dmfs_destroy(struct dmfs *dm);
 | 
			
		||||
 | 
			
		||||
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
 | 
			
		||||
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
 | 
			
		||||
 | 
			
		||||
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
 | 
			
		||||
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
 | 
			
		||||
 | 
			
		||||
int dmfs_dev_create(struct dmfs *dm, const char *name);
 | 
			
		||||
int dmfs_dev_load_table(struct dmfs *dm, const char *dev, 
 | 
			
		||||
			const char *table, const char *file);
 | 
			
		||||
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
 | 
			
		||||
 | 
			
		||||
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
 | 
			
		||||
			    const char *table);
 | 
			
		||||
 | 
			
		||||
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -4,157 +4,334 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "fs.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "lvm-file.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "fs.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "names.h"
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <libdevmapper.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Lazy programmer: I'm just going to always try
 | 
			
		||||
 * and create/remove the vg directory, and not say
 | 
			
		||||
 * anything if it fails.
 | 
			
		||||
 */
 | 
			
		||||
static int _mk_dir(struct volume_group *vg)
 | 
			
		||||
static int _mk_dir(const char *dev_dir, const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	char vg_path[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	if (!build_vg_path(vg_path, sizeof(vg_path),
 | 
			
		||||
			   vg->cmd->dev_dir, vg->name)) {
 | 
			
		||||
		log_error("Couldn't construct name of volume group directory.");
 | 
			
		||||
	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 | 
			
		||||
			 dev_dir, vg_name) == -1) {
 | 
			
		||||
		log_error("Couldn't construct name of volume "
 | 
			
		||||
			  "group directory.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dir_exists(vg_path))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Creating directory %s", vg_path);
 | 
			
		||||
	mkdir(vg_path, 0555);
 | 
			
		||||
	if (mkdir(vg_path, 0555)) {
 | 
			
		||||
		log_sys_error("mkdir", vg_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _rm_dir(struct volume_group *vg)
 | 
			
		||||
static int _rm_dir(const char *dev_dir, const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	char vg_path[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	if (!build_vg_path(vg_path, sizeof(vg_path),
 | 
			
		||||
			   vg->cmd->dev_dir, vg->name)) {
 | 
			
		||||
		log_error("Couldn't construct name of volume group dir for %s",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 | 
			
		||||
			 dev_dir, vg_name) == -1) {
 | 
			
		||||
		log_error("Couldn't construct name of volume "
 | 
			
		||||
			  "group directory.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Removing directory %s", vg_path);
 | 
			
		||||
	rmdir(vg_path);
 | 
			
		||||
 | 
			
		||||
	if (is_empty_dir(vg_path))
 | 
			
		||||
		rmdir(vg_path);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _mk_link(struct logical_volume *lv)
 | 
			
		||||
static void _rm_blks(const char *dir)
 | 
			
		||||
{
 | 
			
		||||
	char lv_path[PATH_MAX], link_path[PATH_MAX];
 | 
			
		||||
	const char *name;
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	struct dirent *dirent;
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	DIR *d;
 | 
			
		||||
 | 
			
		||||
	if (!(d = opendir(dir))) {
 | 
			
		||||
		log_sys_error("opendir", dir);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((dirent = readdir(d))) {
 | 
			
		||||
		name = dirent->d_name;
 | 
			
		||||
 | 
			
		||||
		if (!strcmp(name, ".") || !strcmp(name, ".."))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
 | 
			
		||||
			log_error("Couldn't create path for %s", name);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!lstat(path, &buf)) {
 | 
			
		||||
			if (!S_ISBLK(buf.st_mode))
 | 
			
		||||
				continue;
 | 
			
		||||
			log_very_verbose("Removing %s", path);
 | 
			
		||||
			if (unlink(path) < 0)
 | 
			
		||||
				log_sys_error("unlink", path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _mk_link(const char *dev_dir, const char *vg_name,
 | 
			
		||||
		    const char *lv_name, const char *dev)
 | 
			
		||||
{
 | 
			
		||||
	char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
 | 
			
		||||
	char vg_path[PATH_MAX];
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
 | 
			
		||||
	if (!build_dm_path(lv_path, sizeof(lv_path), lv->vg->name, lv->name)) {
 | 
			
		||||
		log_error("Couldn't create destination pathname for "
 | 
			
		||||
			  "logical volume link for %s", lv->name);
 | 
			
		||||
	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 | 
			
		||||
			 dev_dir, vg_name) == -1) {
 | 
			
		||||
		log_error("Couldn't create path for volume group dir %s",
 | 
			
		||||
			  vg_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!build_lv_link_path(link_path, sizeof(link_path),
 | 
			
		||||
				lv->vg->cmd->dev_dir,
 | 
			
		||||
				lv->vg->name, lv->name)) {
 | 
			
		||||
	if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
 | 
			
		||||
			 lv_name) == -1) {
 | 
			
		||||
		log_error("Couldn't create source pathname for "
 | 
			
		||||
			  "logical volume link %s", lv->name);
 | 
			
		||||
			  "logical volume link %s", lv_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lstat(link_path, &buf)) {
 | 
			
		||||
		if (!S_ISLNK(buf.st_mode)) {
 | 
			
		||||
	if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
 | 
			
		||||
			 dm_dir(), dev) == -1) {
 | 
			
		||||
		log_error("Couldn't create destination pathname for "
 | 
			
		||||
			  "logical volume link for %s", lv_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
 | 
			
		||||
			 vg_path) == -1) {
 | 
			
		||||
		log_error("Couldn't create pathname for LVM1 group file for %s",
 | 
			
		||||
			  vg_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* To reach this point, the VG must have been locked.
 | 
			
		||||
	 * As locking fails if the VG is active under LVM1, it's 
 | 
			
		||||
	 * now safe to remove any LVM1 devices we find here
 | 
			
		||||
	 * (as well as any existing LVM2 symlink). */
 | 
			
		||||
	if (!lstat(lvm1_group_path, &buf)) {
 | 
			
		||||
		if (!S_ISCHR(buf.st_mode)) {
 | 
			
		||||
			log_error("Non-LVM1 character device found at %s",
 | 
			
		||||
				  lvm1_group_path);
 | 
			
		||||
		} else {
 | 
			
		||||
			_rm_blks(vg_path);
 | 
			
		||||
 | 
			
		||||
			log_very_verbose("Removing %s", lvm1_group_path);
 | 
			
		||||
			if (unlink(lvm1_group_path) < 0)
 | 
			
		||||
				log_sys_error("unlink", lvm1_group_path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lstat(lv_path, &buf)) {
 | 
			
		||||
		if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
 | 
			
		||||
			log_error("Symbolic link %s not created: file exists",
 | 
			
		||||
				  link_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (unlink(link_path) < 0) {
 | 
			
		||||
			log_sys_error("unlink", link_path);
 | 
			
		||||
 | 
			
		||||
		log_very_verbose("Removing %s", lv_path);
 | 
			
		||||
		if (unlink(lv_path) < 0) {
 | 
			
		||||
			log_sys_error("unlink", lv_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Linking %s to %s", link_path, lv_path);
 | 
			
		||||
	if (symlink(lv_path, link_path) < 0) {
 | 
			
		||||
		log_sys_error("symlink", link_path);
 | 
			
		||||
	log_very_verbose("Linking %s -> %s", lv_path, link_path);
 | 
			
		||||
	if (symlink(link_path, lv_path) < 0) {
 | 
			
		||||
		log_sys_error("symlink", lv_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _rm_link(struct logical_volume *lv, const char *lv_name)
 | 
			
		||||
static int _rm_link(const char *dev_dir, const char *vg_name,
 | 
			
		||||
		    const char *lv_name)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	char link_path[PATH_MAX];
 | 
			
		||||
	char lv_path[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	if (!lv_name)
 | 
			
		||||
		lv_name = lv->name;
 | 
			
		||||
 | 
			
		||||
	if (!build_lv_link_path(link_path, sizeof(link_path),
 | 
			
		||||
				lv->vg->cmd->dev_dir,
 | 
			
		||||
				lv->vg->name, lv->name)) {
 | 
			
		||||
	if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
 | 
			
		||||
			 dev_dir, vg_name, lv_name) == -1) {
 | 
			
		||||
		log_error("Couldn't determine link pathname.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Removing link %s", link_path);
 | 
			
		||||
	if (lstat(link_path, &buf) || !S_ISLNK(buf.st_mode)) {
 | 
			
		||||
			log_error("%s not symbolic link - not removing",
 | 
			
		||||
				  link_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
	if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
 | 
			
		||||
		log_error("%s not symbolic link - not removing", lv_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (unlink(link_path) < 0) {
 | 
			
		||||
		log_sys_error("unlink", link_path);
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Removing link %s", lv_path);
 | 
			
		||||
	if (unlink(lv_path) < 0) {
 | 
			
		||||
		log_sys_error("unlink", lv_path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fs_add_lv(struct logical_volume *lv)
 | 
			
		||||
typedef enum {
 | 
			
		||||
	FS_ADD,
 | 
			
		||||
	FS_DEL,
 | 
			
		||||
	FS_RENAME
 | 
			
		||||
} fs_op_t;
 | 
			
		||||
 | 
			
		||||
static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
 | 
			
		||||
		     const char *lv_name, const char *dev,
 | 
			
		||||
		     const char *old_lv_name)
 | 
			
		||||
{
 | 
			
		||||
	if (!_mk_dir(lv->vg) ||
 | 
			
		||||
	    !_mk_link(lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case FS_ADD:
 | 
			
		||||
		if (!_mk_dir(dev_dir, vg_name) ||
 | 
			
		||||
		    !_mk_link(dev_dir, vg_name, lv_name, dev)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case FS_DEL:
 | 
			
		||||
		if (!_rm_link(dev_dir, vg_name, lv_name) ||
 | 
			
		||||
		    !_rm_dir(dev_dir, vg_name)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
		/* FIXME Use rename() */
 | 
			
		||||
	case FS_RENAME:
 | 
			
		||||
		if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name))
 | 
			
		||||
			stack;
 | 
			
		||||
 | 
			
		||||
		if (!_mk_link(dev_dir, vg_name, lv_name, dev))
 | 
			
		||||
			stack;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LIST_INIT(_fs_ops);
 | 
			
		||||
 | 
			
		||||
struct fs_op_parms {
 | 
			
		||||
	struct list list;
 | 
			
		||||
	fs_op_t type;
 | 
			
		||||
	char *dev_dir;
 | 
			
		||||
	char *vg_name;
 | 
			
		||||
	char *lv_name;
 | 
			
		||||
	char *dev;
 | 
			
		||||
	char *old_lv_name;
 | 
			
		||||
	char names[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void _store_str(char **pos, char **ptr, const char *str)
 | 
			
		||||
{
 | 
			
		||||
	strcpy(*pos, str);
 | 
			
		||||
	*ptr = *pos;
 | 
			
		||||
	*pos += strlen(*ptr) + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
 | 
			
		||||
			const char *lv_name, const char *dev,
 | 
			
		||||
			const char *old_lv_name)
 | 
			
		||||
{
 | 
			
		||||
	struct fs_op_parms *fsp;
 | 
			
		||||
	size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
 | 
			
		||||
	    strlen(dev) + strlen(old_lv_name) + 5;
 | 
			
		||||
	char *pos;
 | 
			
		||||
 | 
			
		||||
	if (!(fsp = dbg_malloc(sizeof(*fsp) + len))) {
 | 
			
		||||
		log_error("No space to stack fs operation");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pos = fsp->names;
 | 
			
		||||
	fsp->type = type;
 | 
			
		||||
 | 
			
		||||
	_store_str(&pos, &fsp->dev_dir, dev_dir);
 | 
			
		||||
	_store_str(&pos, &fsp->vg_name, vg_name);
 | 
			
		||||
	_store_str(&pos, &fsp->lv_name, lv_name);
 | 
			
		||||
	_store_str(&pos, &fsp->dev, dev);
 | 
			
		||||
	_store_str(&pos, &fsp->old_lv_name, old_lv_name);
 | 
			
		||||
 | 
			
		||||
	list_add(&_fs_ops, &fsp->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _pop_fs_ops(void)
 | 
			
		||||
{
 | 
			
		||||
	struct list *fsph, *fspht;
 | 
			
		||||
	struct fs_op_parms *fsp;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(fsph, fspht, &_fs_ops) {
 | 
			
		||||
		fsp = list_item(fsph, struct fs_op_parms);
 | 
			
		||||
		_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
 | 
			
		||||
			  fsp->dev, fsp->old_lv_name);
 | 
			
		||||
		list_del(&fsp->list);
 | 
			
		||||
		dbg_free(fsp);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
 | 
			
		||||
		  const char *lv_name, const char *dev, const char *old_lv_name)
 | 
			
		||||
{
 | 
			
		||||
	if (memlock()) {
 | 
			
		||||
		if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
 | 
			
		||||
				  old_lv_name)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fs_add_lv(struct logical_volume *lv, const char *dev)
 | 
			
		||||
{
 | 
			
		||||
	return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
 | 
			
		||||
		      dev, "");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fs_del_lv(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	if (!_rm_link(lv, NULL) ||
 | 
			
		||||
	    !_rm_dir(lv->vg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
 | 
			
		||||
		      "", "");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fs_rename_lv(const char *old_name, struct logical_volume *lv)
 | 
			
		||||
int fs_rename_lv(struct logical_volume *lv,
 | 
			
		||||
		 const char *dev, const char *old_name)
 | 
			
		||||
{
 | 
			
		||||
	if (!_rm_link(lv, old_name))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	if (!_mk_link(lv))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
 | 
			
		||||
		      dev, old_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fs_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!memlock()) {
 | 
			
		||||
		dm_lib_release();
 | 
			
		||||
		_pop_fs_ops();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@
 | 
			
		||||
 * up the volume group directory in /dev and the
 | 
			
		||||
 * symbolic links to the dm device.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int fs_add_lv(struct logical_volume *lv);
 | 
			
		||||
int fs_add_lv(struct logical_volume *lv, const char *dev);
 | 
			
		||||
int fs_del_lv(struct logical_volume *lv);
 | 
			
		||||
int fs_rename_lv(const char *old_name, struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
int fs_rename_lv(struct logical_volume *lv,
 | 
			
		||||
		 const char *dev, const char *old_name);
 | 
			
		||||
void fs_unlock(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,88 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "names.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "limits.h"
 | 
			
		||||
 | 
			
		||||
#include <libdevmapper.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The volume group name and the logical volume name are
 | 
			
		||||
 * seperated by a single ':', any colons in the vg name are
 | 
			
		||||
 * doubled up to form a pair.
 | 
			
		||||
 */
 | 
			
		||||
int build_dm_name(char *buffer, size_t len,
 | 
			
		||||
		  const char *vg_name, const char *lv_name)
 | 
			
		||||
{
 | 
			
		||||
	char *out;
 | 
			
		||||
	const char *in;
 | 
			
		||||
 | 
			
		||||
	for (out = buffer, in = vg_name; len && *in; len--) {
 | 
			
		||||
		if (*in == ':') {
 | 
			
		||||
			*out++ = ':';
 | 
			
		||||
			if (!--len)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*out++ = *in++;
 | 
			
		||||
		len--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!len)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(out, len, ":%s", lv_name) == -1) {
 | 
			
		||||
		log_err("Couldn't build logical volume name.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build_dm_path(char *buffer, size_t len,
 | 
			
		||||
		  const char *vg_name, const char *lv_name)
 | 
			
		||||
{
 | 
			
		||||
	char dev_name[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	if (!build_dm_name(dev_name, sizeof(dev_name), vg_name, lv_name)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(buffer, len, "%s/%s", dm_dir(), dev_name) == -1) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build_vg_path(char *buffer, size_t len,
 | 
			
		||||
		  const char *dev_dir, const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	if (lvm_snprintf(buffer, len, "%s%s", dev_dir, vg_name) == -1) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build_lv_link_path(char *buffer, size_t len, const char *dev_dir,
 | 
			
		||||
		       const char *vg_name, const char *lv_name)
 | 
			
		||||
{
 | 
			
		||||
	if (lvm_snprintf(buffer, len, "%s%s/%s",
 | 
			
		||||
			 dev_dir, vg_name, lv_name) == -1) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_NAMES_H
 | 
			
		||||
#define _LVM_NAMES_H
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Functions that build up useful paths to devices, sym-links
 | 
			
		||||
 * etc.  Names are passed in as strings, rather than via the
 | 
			
		||||
 * appropriate metadata structures, so we can use it for renaming
 | 
			
		||||
 * devices.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The name of the device-mapper device for a particular LV.
 | 
			
		||||
 * eg, vg0:music
 | 
			
		||||
 */
 | 
			
		||||
int build_dm_name(char *buffer, size_t len,
 | 
			
		||||
		  const char *vg_name, const char *lv_name);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The path of the device-mapper device for a particular LV.
 | 
			
		||||
 * eg, /dev/device-mapper/vg0:music
 | 
			
		||||
 */
 | 
			
		||||
int build_dm_path(char *buffer, size_t len,
 | 
			
		||||
		  const char *vg_name, const char *lv_name);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Path to the volume group directory.
 | 
			
		||||
 * eg, /dev/vg0
 | 
			
		||||
 */
 | 
			
		||||
int build_vg_path(char *buffer, size_t len,
 | 
			
		||||
		  const char *dev_dir, const char *vg_name);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Path to the symbolic link that lives in the volume group
 | 
			
		||||
 * directory.
 | 
			
		||||
 * eg, /dev/vg0/music
 | 
			
		||||
 */
 | 
			
		||||
int build_lv_link_path(char *buffer, size_t len,
 | 
			
		||||
		       const char *dev_dir,
 | 
			
		||||
		       const char *vg_name, const char *lv_name);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "table-build.c"
 | 
			
		||||
 | 
			
		||||
static void _print_run(FILE *fp, struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
 | 
			
		||||
		const char *file)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	uint64_t sector = 0;
 | 
			
		||||
	uint64_t pe_size = vg->extent_size;
 | 
			
		||||
	uint64_t dest;
 | 
			
		||||
	struct pe_specifier *pes;
 | 
			
		||||
	FILE *fp = fopen(file, "w");
 | 
			
		||||
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		log_err("couldn't open '%s' to write table", file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < lv->le_count; i++) {
 | 
			
		||||
		pes = lv->map + i;
 | 
			
		||||
		dest = pes->pv->pe_start + (pe_size * pes->pe);
 | 
			
		||||
		fprintf(fp, "%ull %ull linear %s %ull\n",
 | 
			
		||||
			sector, pe_size, pes->pv->dev->name, dest);
 | 
			
		||||
		sector += pe_size;
 | 
			
		||||
	}
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the GPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TABLE_BUILD_H
 | 
			
		||||
#define TABLE_BUILD_H
 | 
			
		||||
 | 
			
		||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
 | 
			
		||||
		const char *file);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										580
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,580 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
static struct hash_table *_pvid_hash = NULL;
 | 
			
		||||
static struct hash_table *_vgid_hash = NULL;
 | 
			
		||||
static struct hash_table *_vgname_hash = NULL;
 | 
			
		||||
static struct hash_table *_lock_hash = NULL;
 | 
			
		||||
static struct list _vginfos;
 | 
			
		||||
static int _has_scanned = 0;
 | 
			
		||||
static int _vgs_locked = 0;
 | 
			
		||||
 | 
			
		||||
int lvmcache_init(void)
 | 
			
		||||
{
 | 
			
		||||
	list_init(&_vginfos);
 | 
			
		||||
 | 
			
		||||
	if (!(_vgname_hash = hash_create(128)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(_vgid_hash = hash_create(128)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(_pvid_hash = hash_create(128)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(_lock_hash = hash_create(128)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvmcache_lock_vgname(const char *vgname, int read_only)
 | 
			
		||||
{
 | 
			
		||||
	if (!_lock_hash && !lvmcache_init()) {
 | 
			
		||||
		log_error("Internal cache initialisation failed");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!hash_insert(_lock_hash, vgname, (void *) 1))
 | 
			
		||||
		log_error("Cache locking failure for %s", vgname);
 | 
			
		||||
 | 
			
		||||
	_vgs_locked++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _vgname_is_locked(const char *vgname) __attribute__ ((unused));
 | 
			
		||||
static int _vgname_is_locked(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	if (!_lock_hash)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return hash_lookup(_lock_hash, vgname) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvmcache_unlock_vgname(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME: Clear all CACHE_LOCKED flags in this vg */
 | 
			
		||||
	hash_remove(_lock_hash, vgname);
 | 
			
		||||
 | 
			
		||||
	/* FIXME Do this per-VG */
 | 
			
		||||
	if (!--_vgs_locked)
 | 
			
		||||
		dev_close_all();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int vgs_locked(void)
 | 
			
		||||
{
 | 
			
		||||
	return _vgs_locked;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
 | 
			
		||||
	if (!_vgname_hash)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return vginfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct format_type *fmt_from_vgname(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
 | 
			
		||||
	if (!(vginfo = vginfo_from_vgname(vgname)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return vginfo->fmt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
	char id[ID_LEN + 1];
 | 
			
		||||
 | 
			
		||||
	if (!_vgid_hash || !vgid)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* vgid not necessarily NULL-terminated */
 | 
			
		||||
	strncpy(&id[0], vgid, ID_LEN);
 | 
			
		||||
	id[ID_LEN] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (!(vginfo = hash_lookup(_vgid_hash, id)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return vginfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lvmcache_info *info_from_pvid(const char *pvid)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
	char id[ID_LEN + 1];
 | 
			
		||||
 | 
			
		||||
	if (!_pvid_hash || !pvid)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	strncpy(&id[0], pvid, ID_LEN);
 | 
			
		||||
	id[ID_LEN] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (!(info = hash_lookup(_pvid_hash, id)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _rescan_entry(struct lvmcache_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct label *label;
 | 
			
		||||
 | 
			
		||||
	if (info->status & CACHE_INVALID)
 | 
			
		||||
		label_read(info->dev, &label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _scan_invalid(void)
 | 
			
		||||
{
 | 
			
		||||
	hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
 | 
			
		||||
{
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	struct dev_iter *iter;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	struct list *fmth;
 | 
			
		||||
	struct format_type *fmt;
 | 
			
		||||
 | 
			
		||||
	static int _scanning_in_progress = 0;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
	/* Avoid recursion when a PVID can't be found! */
 | 
			
		||||
	if (_scanning_in_progress)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_scanning_in_progress = 1;
 | 
			
		||||
 | 
			
		||||
	if (!_vgname_hash && !lvmcache_init()) {
 | 
			
		||||
		log_error("Internal cache initialisation failed");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_has_scanned && !full_scan) {
 | 
			
		||||
		r = _scan_invalid();
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(iter = dev_iter_create(cmd->filter))) {
 | 
			
		||||
		log_error("dev_iter creation failed");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((dev = dev_iter_get(iter)))
 | 
			
		||||
		label_read(dev, &label);
 | 
			
		||||
 | 
			
		||||
	dev_iter_destroy(iter);
 | 
			
		||||
 | 
			
		||||
	_has_scanned = 1;
 | 
			
		||||
 | 
			
		||||
	/* Perform any format-specific scanning e.g. text files */
 | 
			
		||||
	list_iterate(fmth, &cmd->formats) {
 | 
			
		||||
		fmt = list_item(fmth, struct format_type);
 | 
			
		||||
		if (fmt->ops->scan && !fmt->ops->scan(fmt))
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	_scanning_in_progress = 0;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
 | 
			
		||||
{
 | 
			
		||||
	struct list *vgih, *vgnames;
 | 
			
		||||
	struct str_list *sl;
 | 
			
		||||
 | 
			
		||||
	lvmcache_label_scan(cmd, full_scan);
 | 
			
		||||
 | 
			
		||||
	if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) {
 | 
			
		||||
		log_error("vgnames list allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(vgnames);
 | 
			
		||||
 | 
			
		||||
	list_iterate(vgih, &_vginfos) {
 | 
			
		||||
		if (!(sl = pool_alloc(cmd->mem, sizeof(*sl)))) {
 | 
			
		||||
			log_error("strlist allocation failed");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(sl->str = pool_strdup(cmd->mem,
 | 
			
		||||
					    list_item(vgih,
 | 
			
		||||
						      struct lvmcache_vginfo)->
 | 
			
		||||
					    vgname))) {
 | 
			
		||||
			log_error("vgname allocation failed");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		list_add(vgnames, &sl->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vgnames;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
 | 
			
		||||
{
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
 | 
			
		||||
	/* Already cached ? */
 | 
			
		||||
	if ((info = info_from_pvid((char *) pvid))) {
 | 
			
		||||
		if (label_read(info->dev, &label)) {
 | 
			
		||||
			info = (struct lvmcache_info *) label->info;
 | 
			
		||||
			if (id_equal(pvid, (struct id *) &info->dev->pvid))
 | 
			
		||||
				return info->dev;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lvmcache_label_scan(cmd, 0);
 | 
			
		||||
 | 
			
		||||
	/* Try again */
 | 
			
		||||
	if ((info = info_from_pvid((char *) pvid))) {
 | 
			
		||||
		if (label_read(info->dev, &label)) {
 | 
			
		||||
			info = (struct lvmcache_info *) label->info;
 | 
			
		||||
			if (id_equal(pvid, (struct id *) &info->dev->pvid))
 | 
			
		||||
				return info->dev;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (memlock())
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	lvmcache_label_scan(cmd, 1);
 | 
			
		||||
 | 
			
		||||
	/* Try again */
 | 
			
		||||
	if ((info = info_from_pvid((char *) pvid))) {
 | 
			
		||||
		if (label_read(info->dev, &label)) {
 | 
			
		||||
			info = (struct lvmcache_info *) label->info;
 | 
			
		||||
			if (id_equal(pvid, (struct id *) &info->dev->pvid))
 | 
			
		||||
				return info->dev;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _drop_vginfo(struct lvmcache_info *info)
 | 
			
		||||
{
 | 
			
		||||
	if (!list_empty(&info->list)) {
 | 
			
		||||
		list_del(&info->list);
 | 
			
		||||
		list_init(&info->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info->vginfo && list_empty(&info->vginfo->infos)) {
 | 
			
		||||
		hash_remove(_vgname_hash, info->vginfo->vgname);
 | 
			
		||||
		if (info->vginfo->vgname)
 | 
			
		||||
			dbg_free(info->vginfo->vgname);
 | 
			
		||||
		if (*info->vginfo->vgid)
 | 
			
		||||
			hash_remove(_vgid_hash, info->vginfo->vgid);
 | 
			
		||||
		list_del(&info->vginfo->list);
 | 
			
		||||
		dbg_free(info->vginfo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->vginfo = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Unused
 | 
			
		||||
void lvmcache_del(struct lvmcache_info *info)
 | 
			
		||||
{
 | 
			
		||||
	if (info->dev->pvid[0] && _pvid_hash)
 | 
			
		||||
		hash_remove(_pvid_hash, info->dev->pvid);
 | 
			
		||||
 | 
			
		||||
	_drop_vginfo(info);
 | 
			
		||||
 | 
			
		||||
	info->label->labeller->ops->destroy_label(info->label->labeller,
 | 
			
		||||
						info->label); 
 | 
			
		||||
	dbg_free(info);
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
} */
 | 
			
		||||
 | 
			
		||||
static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
 | 
			
		||||
{
 | 
			
		||||
	if (!strcmp(info->dev->pvid, pvid))
 | 
			
		||||
		return 1;
 | 
			
		||||
	if (*info->dev->pvid) {
 | 
			
		||||
		hash_remove(_pvid_hash, info->dev->pvid);
 | 
			
		||||
	}
 | 
			
		||||
	strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
 | 
			
		||||
	if (!hash_insert(_pvid_hash, pvid, info)) {
 | 
			
		||||
		log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
 | 
			
		||||
{
 | 
			
		||||
	if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
 | 
			
		||||
					       sizeof(info->vginfo->vgid)))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (info->vginfo && *info->vginfo->vgid)
 | 
			
		||||
		hash_remove(_vgid_hash, info->vginfo->vgid);
 | 
			
		||||
	if (!vgid)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
 | 
			
		||||
	info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
 | 
			
		||||
	if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) {
 | 
			
		||||
		log_error("_lvmcache_update: vgid hash insertion failed: %s",
 | 
			
		||||
			  info->vginfo->vgid);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
 | 
			
		||||
	/* If vgname is NULL and we don't already have a vgname, 
 | 
			
		||||
	 * assume ORPHAN - we want every entry to have a vginfo
 | 
			
		||||
	 * attached for scanning reasons.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!vgname && !info->vginfo)
 | 
			
		||||
		vgname = ORPHAN;
 | 
			
		||||
 | 
			
		||||
	if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	/* Remove existing vginfo entry */
 | 
			
		||||
	_drop_vginfo(info);
 | 
			
		||||
 | 
			
		||||
	/* Get existing vginfo or create new one */
 | 
			
		||||
	if (!(vginfo = vginfo_from_vgname(vgname))) {
 | 
			
		||||
		if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
 | 
			
		||||
			log_error("lvmcache_update_vgname: list alloc failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		memset(vginfo, 0, sizeof(*vginfo));
 | 
			
		||||
		if (!(vginfo->vgname = dbg_strdup(vgname))) {
 | 
			
		||||
			dbg_free(vginfo);
 | 
			
		||||
			log_error("cache vgname alloc failed for %s", vgname);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		list_init(&vginfo->infos);
 | 
			
		||||
		if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
 | 
			
		||||
			log_error("cache_update: vg hash insertion failed: %s",
 | 
			
		||||
				  vginfo->vgname);
 | 
			
		||||
			dbg_free(vginfo->vgname);
 | 
			
		||||
			dbg_free(vginfo);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		/* Ensure orphans appear last on list_iterate */
 | 
			
		||||
		if (!*vgname)
 | 
			
		||||
			list_add(&_vginfos, &vginfo->list);
 | 
			
		||||
		else
 | 
			
		||||
			list_add_h(&_vginfos, &vginfo->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->vginfo = vginfo;
 | 
			
		||||
	list_add(&vginfo->infos, &info->list);
 | 
			
		||||
 | 
			
		||||
	/* FIXME Check consistency of list! */
 | 
			
		||||
	vginfo->fmt = info->fmt;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvmcache_update_vg(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvh;
 | 
			
		||||
	struct physical_volume *pv;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
	char pvid_s[ID_LEN + 1];
 | 
			
		||||
	int vgid_updated = 0;
 | 
			
		||||
 | 
			
		||||
	pvid_s[sizeof(pvid_s) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	list_iterate(pvh, &vg->pvs) {
 | 
			
		||||
		pv = list_item(pvh, struct pv_list)->pv;
 | 
			
		||||
		strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
 | 
			
		||||
		/* FIXME Could pv->dev->pvid ever be different? */
 | 
			
		||||
		if ((info = info_from_pvid(pvid_s))) {
 | 
			
		||||
			lvmcache_update_vgname(info, vg->name);
 | 
			
		||||
			if (!vgid_updated) {
 | 
			
		||||
				_lvmcache_update_vgid(info, (char *) &vg->id);
 | 
			
		||||
				vgid_updated = 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
 | 
			
		||||
				   struct device *dev,
 | 
			
		||||
				   const char *vgname, const char *vgid)
 | 
			
		||||
{
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	struct lvmcache_info *existing, *info;
 | 
			
		||||
	char pvid_s[ID_LEN + 1];
 | 
			
		||||
 | 
			
		||||
	if (!_vgname_hash && !lvmcache_init()) {
 | 
			
		||||
		log_error("Internal cache initialisation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	strncpy(pvid_s, pvid, sizeof(pvid_s));
 | 
			
		||||
	pvid_s[sizeof(pvid_s) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (!(existing = info_from_pvid(pvid_s)) &&
 | 
			
		||||
	    !(existing = info_from_pvid(dev->pvid))) {
 | 
			
		||||
		if (!(label = label_create(labeller))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(info = dbg_malloc(sizeof(*info)))) {
 | 
			
		||||
			log_error("lvmcache_info allocation failed");
 | 
			
		||||
			label_destroy(label);
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		memset(info, 0, sizeof(*info));
 | 
			
		||||
 | 
			
		||||
		label->info = info;
 | 
			
		||||
		info->label = label;
 | 
			
		||||
		list_init(&info->list);
 | 
			
		||||
		info->dev = dev;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (existing->dev != dev) {
 | 
			
		||||
			/* Is the existing entry a duplicate pvid e.g. md ? */
 | 
			
		||||
			if (MAJOR(existing->dev->dev) == md_major() &&
 | 
			
		||||
			    MAJOR(dev->dev) != md_major()) {
 | 
			
		||||
				log_very_verbose("Ignoring duplicate PV %s on "
 | 
			
		||||
						 "%s - using md %s",
 | 
			
		||||
						 pvid, dev_name(dev),
 | 
			
		||||
						 dev_name(existing->dev));
 | 
			
		||||
				return NULL;
 | 
			
		||||
			} else if (MAJOR(existing->dev->dev) != md_major() &&
 | 
			
		||||
				   MAJOR(dev->dev) == md_major())
 | 
			
		||||
				log_very_verbose("Duplicate PV %s on %s - "
 | 
			
		||||
						 "using md %s", pvid,
 | 
			
		||||
						 dev_name(existing->dev),
 | 
			
		||||
						 dev_name(dev));
 | 
			
		||||
			else
 | 
			
		||||
				log_error("Found duplicate PV %s: using %s not "
 | 
			
		||||
					  "%s", pvid, dev_name(dev),
 | 
			
		||||
					  dev_name(existing->dev));
 | 
			
		||||
		}
 | 
			
		||||
		info = existing;
 | 
			
		||||
		/* Has labeller changed? */
 | 
			
		||||
		if (info->label->labeller != labeller) {
 | 
			
		||||
			label_destroy(info->label);
 | 
			
		||||
			if (!(info->label = label_create(labeller))) {
 | 
			
		||||
				/* FIXME leaves info without label! */
 | 
			
		||||
				stack;
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			info->label->info = info;
 | 
			
		||||
		}
 | 
			
		||||
		label = info->label;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->fmt = (const struct format_type *) labeller->private;
 | 
			
		||||
	info->status |= CACHE_INVALID;
 | 
			
		||||
 | 
			
		||||
	if (!_lvmcache_update_pvid(info, pvid_s)) {
 | 
			
		||||
		if (!existing) {
 | 
			
		||||
			dbg_free(info);
 | 
			
		||||
			label_destroy(label);
 | 
			
		||||
		}
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lvmcache_update_vgname(info, vgname)) {
 | 
			
		||||
		if (!existing) {
 | 
			
		||||
			hash_remove(_pvid_hash, pvid_s);
 | 
			
		||||
			strcpy(info->dev->pvid, "");
 | 
			
		||||
			dbg_free(info);
 | 
			
		||||
			label_destroy(label);
 | 
			
		||||
		}
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_lvmcache_update_vgid(info, vgid))
 | 
			
		||||
		/* Non-critical */
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	return info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _lvmcache_destroy_entry(struct lvmcache_info *info)
 | 
			
		||||
{
 | 
			
		||||
	if (!list_empty(&info->list))
 | 
			
		||||
		list_del(&info->list);
 | 
			
		||||
	strcpy(info->dev->pvid, "");
 | 
			
		||||
	label_destroy(info->label);
 | 
			
		||||
	dbg_free(info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
 | 
			
		||||
{
 | 
			
		||||
	if (vginfo->vgname)
 | 
			
		||||
		dbg_free(vginfo->vgname);
 | 
			
		||||
	dbg_free(vginfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _lvmcache_destroy_lockname(int present)
 | 
			
		||||
{
 | 
			
		||||
	/* Nothing to do */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvmcache_destroy(void)
 | 
			
		||||
{
 | 
			
		||||
	_has_scanned = 0;
 | 
			
		||||
 | 
			
		||||
	if (_vgid_hash) {
 | 
			
		||||
		hash_destroy(_vgid_hash);
 | 
			
		||||
		_vgid_hash = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_pvid_hash) {
 | 
			
		||||
		hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry);
 | 
			
		||||
		hash_destroy(_pvid_hash);
 | 
			
		||||
		_pvid_hash = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_vgname_hash) {
 | 
			
		||||
		hash_iter(_vgname_hash,
 | 
			
		||||
			  (iterate_fn) _lvmcache_destroy_vgnamelist);
 | 
			
		||||
		hash_destroy(_vgname_hash);
 | 
			
		||||
		_vgname_hash = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_lock_hash) {
 | 
			
		||||
		hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname);
 | 
			
		||||
		hash_destroy(_lock_hash);
 | 
			
		||||
		_lock_hash = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&_vginfos);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_CACHE_H
 | 
			
		||||
#define _LVM_CACHE_H
 | 
			
		||||
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
#define ORPHAN ""
 | 
			
		||||
 | 
			
		||||
#define CACHE_INVALID	0x00000001
 | 
			
		||||
#define CACHE_LOCKED	0x00000002
 | 
			
		||||
 | 
			
		||||
/* LVM specific per-volume info */
 | 
			
		||||
/* Eventual replacement for struct physical_volume perhaps? */
 | 
			
		||||
 | 
			
		||||
struct lvmcache_vginfo {
 | 
			
		||||
	struct list list;	/* Join these vginfos together */
 | 
			
		||||
	struct list infos;	/* List head for lvmcache_infos */
 | 
			
		||||
	char *vgname;		/* "" == orphan */
 | 
			
		||||
	char vgid[ID_LEN + 1];
 | 
			
		||||
	const struct format_type *fmt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lvmcache_info {
 | 
			
		||||
	struct list list;	/* Join VG members together */
 | 
			
		||||
	struct list mdas;	/* list head for metadata areas */
 | 
			
		||||
	struct list das;	/* list head for data areas */
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;	/* NULL == unknown */
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	const struct format_type *fmt;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	uint64_t device_size;	/* Bytes */
 | 
			
		||||
	uint32_t status;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int lvmcache_init(void);
 | 
			
		||||
void lvmcache_destroy(void);
 | 
			
		||||
 | 
			
		||||
/* Set full_scan to 1 to reread every filtered device label */
 | 
			
		||||
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
 | 
			
		||||
 | 
			
		||||
/* Add/delete a device */
 | 
			
		||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
 | 
			
		||||
				   struct device *dev,
 | 
			
		||||
				   const char *vgname, const char *vgid);
 | 
			
		||||
void lvmcache_del(struct lvmcache_info *info);
 | 
			
		||||
 | 
			
		||||
/* Update things */
 | 
			
		||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
 | 
			
		||||
int lvmcache_update_vg(struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
 | 
			
		||||
void lvmcache_unlock_vgname(const char *vgname);
 | 
			
		||||
 | 
			
		||||
/* Queries */
 | 
			
		||||
const struct format_type *fmt_from_vgname(const char *vgname);
 | 
			
		||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
 | 
			
		||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
 | 
			
		||||
struct lvmcache_info *info_from_pvid(const char *pvid);
 | 
			
		||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
 | 
			
		||||
int vgs_locked(void);
 | 
			
		||||
 | 
			
		||||
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
 | 
			
		||||
/* Set full_scan to 1 to reread every filtered device label */
 | 
			
		||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										15
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_ERRORS_H
 | 
			
		||||
#define _LVM_ERRORS_H
 | 
			
		||||
 | 
			
		||||
#define EINVALID_CMD_LINE	1
 | 
			
		||||
#define ENO_SUCH_CMD		3
 | 
			
		||||
#define ECMD_PROCESSED		4
 | 
			
		||||
#define ECMD_FAILED		5
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										521
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,521 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "filter-composite.h"
 | 
			
		||||
#include "filter-persistent.h"
 | 
			
		||||
#include "filter-regex.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "lvm-file.h"
 | 
			
		||||
#include "format-text.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBDL
 | 
			
		||||
#include "sharedlib.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef LVM1_INTERNAL
 | 
			
		||||
#include "format1.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#ifdef linux
 | 
			
		||||
#  include <malloc.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static FILE *_log;
 | 
			
		||||
 | 
			
		||||
static int _get_env_vars(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	const char *e;
 | 
			
		||||
 | 
			
		||||
	/* Set to "" to avoid using any system directory */
 | 
			
		||||
	if ((e = getenv("LVM_SYSTEM_DIR"))) {
 | 
			
		||||
		if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
 | 
			
		||||
				 "%s", e) < 0) {
 | 
			
		||||
			log_error("LVM_SYSTEM_DIR environment variable "
 | 
			
		||||
				  "is too long.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _init_logging(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	int append = 1;
 | 
			
		||||
	time_t t;
 | 
			
		||||
 | 
			
		||||
	const char *log_file;
 | 
			
		||||
 | 
			
		||||
	/* Syslog */
 | 
			
		||||
	cmd->default_settings.syslog =
 | 
			
		||||
	    find_config_int(cmd->cf->root, "log/syslog", '/', DEFAULT_SYSLOG);
 | 
			
		||||
	if (cmd->default_settings.syslog != 1)
 | 
			
		||||
		fin_syslog();
 | 
			
		||||
 | 
			
		||||
	if (cmd->default_settings.syslog > 1)
 | 
			
		||||
		init_syslog(cmd->default_settings.syslog);
 | 
			
		||||
 | 
			
		||||
	/* Debug level for log file output */
 | 
			
		||||
	cmd->default_settings.debug =
 | 
			
		||||
	    find_config_int(cmd->cf->root, "log/level", '/', DEFAULT_LOGLEVEL);
 | 
			
		||||
	init_debug(cmd->default_settings.debug);
 | 
			
		||||
 | 
			
		||||
	/* Verbose level for tty output */
 | 
			
		||||
	cmd->default_settings.verbose =
 | 
			
		||||
	    find_config_int(cmd->cf->root, "log/verbose", '/', DEFAULT_VERBOSE);
 | 
			
		||||
	init_verbose(cmd->default_settings.verbose);
 | 
			
		||||
 | 
			
		||||
	/* Log message formatting */
 | 
			
		||||
	init_indent(find_config_int(cmd->cf->root, "log/indent", '/',
 | 
			
		||||
				    DEFAULT_INDENT));
 | 
			
		||||
 | 
			
		||||
	cmd->default_settings.msg_prefix = find_config_str(cmd->cf->root,
 | 
			
		||||
							   "log/prefix", '/',
 | 
			
		||||
							   DEFAULT_MSG_PREFIX);
 | 
			
		||||
	init_msg_prefix(cmd->default_settings.msg_prefix);
 | 
			
		||||
 | 
			
		||||
	cmd->default_settings.cmd_name = find_config_int(cmd->cf->root,
 | 
			
		||||
							 "log/command_names",
 | 
			
		||||
							 '/', DEFAULT_CMD_NAME);
 | 
			
		||||
	init_cmd_name(cmd->default_settings.cmd_name);
 | 
			
		||||
 | 
			
		||||
	/* Test mode */
 | 
			
		||||
	cmd->default_settings.test =
 | 
			
		||||
	    find_config_int(cmd->cf->root, "global/test", '/', 0);
 | 
			
		||||
 | 
			
		||||
	/* Settings for logging to file */
 | 
			
		||||
	if (find_config_int(cmd->cf->root, "log/overwrite", '/',
 | 
			
		||||
			    DEFAULT_OVERWRITE))
 | 
			
		||||
		append = 0;
 | 
			
		||||
 | 
			
		||||
	log_file = find_config_str(cmd->cf->root, "log/file", '/', 0);
 | 
			
		||||
	if (log_file)
 | 
			
		||||
		init_log_file(log_file, append);
 | 
			
		||||
 | 
			
		||||
	log_file = find_config_str(cmd->cf->root, "log/activate_file", '/', 0);
 | 
			
		||||
	if (log_file)
 | 
			
		||||
		init_log_direct(log_file, append);
 | 
			
		||||
 | 
			
		||||
	init_log_while_suspended(find_config_int(cmd->cf->root,
 | 
			
		||||
						 "log/activation", '/', 0));
 | 
			
		||||
 | 
			
		||||
	t = time(NULL);
 | 
			
		||||
	log_verbose("Logging initialised at %s", ctime(&t));
 | 
			
		||||
 | 
			
		||||
	/* Tell device-mapper about our logging */
 | 
			
		||||
#ifdef DEVMAPPER_SUPPORT
 | 
			
		||||
	dm_log_init(print_log);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _process_config(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	mode_t old_umask;
 | 
			
		||||
 | 
			
		||||
	/* umask */
 | 
			
		||||
	cmd->default_settings.umask = find_config_int(cmd->cf->root,
 | 
			
		||||
						      "global/umask", '/',
 | 
			
		||||
						      DEFAULT_UMASK);
 | 
			
		||||
 | 
			
		||||
	if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
 | 
			
		||||
	    (mode_t) cmd->default_settings.umask)
 | 
			
		||||
		log_verbose("Set umask to %04o", cmd->default_settings.umask);
 | 
			
		||||
 | 
			
		||||
	/* dev dir */
 | 
			
		||||
	if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
 | 
			
		||||
			 find_config_str(cmd->cf->root, "devices/dir",
 | 
			
		||||
					 '/', DEFAULT_DEV_DIR)) < 0) {
 | 
			
		||||
		log_error("Device directory given in config file too long");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
#ifdef DEVMAPPER_SUPPORT
 | 
			
		||||
	dm_set_dev_dir(cmd->dev_dir);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* proc dir */
 | 
			
		||||
	if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
 | 
			
		||||
			 find_config_str(cmd->cf->root, "global/proc",
 | 
			
		||||
					 '/', DEFAULT_PROC_DIR)) < 0) {
 | 
			
		||||
		log_error("Device directory given in config file too long");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* activation? */
 | 
			
		||||
	cmd->default_settings.activation = find_config_int(cmd->cf->root,
 | 
			
		||||
							   "global/activation",
 | 
			
		||||
							   '/',
 | 
			
		||||
							   DEFAULT_ACTIVATION);
 | 
			
		||||
	set_activation(cmd->default_settings.activation);
 | 
			
		||||
 | 
			
		||||
	cmd->default_settings.suffix = find_config_int(cmd->cf->root,
 | 
			
		||||
						       "global/suffix",
 | 
			
		||||
						       '/', DEFAULT_SUFFIX);
 | 
			
		||||
 | 
			
		||||
	if (!(cmd->default_settings.unit_factor =
 | 
			
		||||
	      units_to_bytes(find_config_str(cmd->cf->root,
 | 
			
		||||
					     "global/units",
 | 
			
		||||
					     '/',
 | 
			
		||||
					     DEFAULT_UNITS),
 | 
			
		||||
			     &cmd->default_settings.unit_type))) {
 | 
			
		||||
		log_error("Invalid units specification");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find and read config file */
 | 
			
		||||
static int _init_config(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct stat info;
 | 
			
		||||
	char config_file[PATH_MAX] = "";
 | 
			
		||||
 | 
			
		||||
	if (!(cmd->cf = create_config_tree())) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* No config file if LVM_SYSTEM_DIR is empty */
 | 
			
		||||
	if (!*cmd->sys_dir)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(config_file, sizeof(config_file),
 | 
			
		||||
			 "%s/lvm.conf", cmd->sys_dir) < 0) {
 | 
			
		||||
		log_error("LVM_SYSTEM_DIR was too long");
 | 
			
		||||
		destroy_config_tree(cmd->cf);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Is there a config file? */
 | 
			
		||||
	if (stat(config_file, &info) == -1) {
 | 
			
		||||
		if (errno == ENOENT)
 | 
			
		||||
			return 1;
 | 
			
		||||
		log_sys_error("stat", config_file);
 | 
			
		||||
		destroy_config_tree(cmd->cf);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!read_config_file(cmd->cf, config_file)) {
 | 
			
		||||
		log_error("Failed to load config file %s", config_file);
 | 
			
		||||
		destroy_config_tree(cmd->cf);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_dev_cache(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
 | 
			
		||||
	if (!dev_cache_init()) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(cmd->cf->root, "devices/scan", '/'))) {
 | 
			
		||||
		if (!dev_cache_add_dir("/dev")) {
 | 
			
		||||
			log_error("Failed to add /dev to internal "
 | 
			
		||||
				  "device cache");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		log_verbose("device/scan not in config file: "
 | 
			
		||||
			    "Defaulting to /dev");
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (cv = cn->v; cv; cv = cv->next) {
 | 
			
		||||
		if (cv->type != CFG_STRING) {
 | 
			
		||||
			log_error("Invalid string in config file: "
 | 
			
		||||
				  "devices/scan");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!dev_cache_add_dir(cv->v.str)) {
 | 
			
		||||
			log_error("Failed to add %s to internal device cache",
 | 
			
		||||
				  cv->v.str);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
	struct dev_filter *f1, *f2, *f3;
 | 
			
		||||
 | 
			
		||||
	cn = find_config_node(cmd->cf->root, "devices/types", '/');
 | 
			
		||||
 | 
			
		||||
	if (!(f2 = lvm_type_filter_create(cmd->proc_dir, cn)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/'))) {
 | 
			
		||||
		log_debug("devices/filter not found in config file: no regex "
 | 
			
		||||
			  "filter installed");
 | 
			
		||||
		return f2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(f1 = regex_filter_create(cn->v))) {
 | 
			
		||||
		log_error("Failed to create regex device filter");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(f3 = composite_filter_create(2, f1, f2))) {
 | 
			
		||||
		log_error("Failed to create composite device filter");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return f3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_filters(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	const char *dev_cache;
 | 
			
		||||
	struct dev_filter *f3, *f4;
 | 
			
		||||
	struct stat st;
 | 
			
		||||
	char cache_file[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	cmd->dump_filter = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(f3 = _init_filter_components(cmd)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(cache_file, sizeof(cache_file),
 | 
			
		||||
			 "%s/.cache", cmd->sys_dir) < 0) {
 | 
			
		||||
		log_error("Persistent cache filename too long ('%s/.cache').",
 | 
			
		||||
			  cmd->sys_dir);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_cache =
 | 
			
		||||
	    find_config_str(cmd->cf->root, "devices/cache", '/', cache_file);
 | 
			
		||||
	if (!(f4 = persistent_filter_create(f3, dev_cache))) {
 | 
			
		||||
		log_error("Failed to create persistent device filter");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Should we ever dump persistent filter state? */
 | 
			
		||||
	if (find_config_int(cmd->cf->root, "devices/write_cache_state", '/', 1))
 | 
			
		||||
		cmd->dump_filter = 1;
 | 
			
		||||
 | 
			
		||||
	if (!*cmd->sys_dir)
 | 
			
		||||
		cmd->dump_filter = 0;
 | 
			
		||||
 | 
			
		||||
	if (!stat(dev_cache, &st) &&
 | 
			
		||||
	    (st.st_mtime > config_file_timestamp(cmd->cf)) &&
 | 
			
		||||
	    !persistent_filter_load(f4))
 | 
			
		||||
		log_verbose("Failed to load existing device cache from %s",
 | 
			
		||||
			    dev_cache);
 | 
			
		||||
 | 
			
		||||
	cmd->filter = f4;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_formats(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	const char *format;
 | 
			
		||||
 | 
			
		||||
	struct format_type *fmt;
 | 
			
		||||
	struct list *fmth;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBDL
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	label_init();
 | 
			
		||||
 | 
			
		||||
#ifdef LVM1_INTERNAL
 | 
			
		||||
	if (!(fmt = init_lvm1_format(cmd)))
 | 
			
		||||
		return 0;
 | 
			
		||||
	fmt->library = NULL;
 | 
			
		||||
	list_add(&cmd->formats, &fmt->list);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBDL
 | 
			
		||||
	/* Load any formats in shared libs */
 | 
			
		||||
	if ((cn = find_config_node(cmd->cf->root, "global/format_libraries",
 | 
			
		||||
				   '/'))) {
 | 
			
		||||
 | 
			
		||||
		struct config_value *cv;
 | 
			
		||||
		struct format_type *(*init_format_fn) (struct cmd_context *);
 | 
			
		||||
		void *lib;
 | 
			
		||||
 | 
			
		||||
		for (cv = cn->v; cv; cv = cv->next) {
 | 
			
		||||
			if (cv->type != CFG_STRING) {
 | 
			
		||||
				log_error("Invalid string in config file: "
 | 
			
		||||
					  "global/format_libraries");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			if (!(lib = load_shared_library(cmd->cf, cv->v.str,
 | 
			
		||||
							"format"))) {
 | 
			
		||||
				stack;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!(init_format_fn = dlsym(lib, "init_format"))) {
 | 
			
		||||
				log_error("Shared library %s does not contain "
 | 
			
		||||
					  "format functions", cv->v.str);
 | 
			
		||||
				dlclose(lib);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!(fmt = init_format_fn(cmd)))
 | 
			
		||||
				return 0;
 | 
			
		||||
			fmt->library = lib;
 | 
			
		||||
			list_add(&cmd->formats, &fmt->list);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (!(fmt = create_text_format(cmd)))
 | 
			
		||||
		return 0;
 | 
			
		||||
	fmt->library = NULL;
 | 
			
		||||
	list_add(&cmd->formats, &fmt->list);
 | 
			
		||||
 | 
			
		||||
	cmd->fmt_backup = fmt;
 | 
			
		||||
 | 
			
		||||
	format = find_config_str(cmd->cf->root, "global/format", '/',
 | 
			
		||||
				 DEFAULT_FORMAT);
 | 
			
		||||
 | 
			
		||||
	list_iterate(fmth, &cmd->formats) {
 | 
			
		||||
		fmt = list_item(fmth, struct format_type);
 | 
			
		||||
		if (!strcasecmp(fmt->name, format) ||
 | 
			
		||||
		    (fmt->alias && !strcasecmp(fmt->alias, format))) {
 | 
			
		||||
			cmd->default_settings.fmt = fmt;
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_error("_init_formats: Default format (%s) not found", format);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Entry point */
 | 
			
		||||
struct cmd_context *create_toolcontext(struct arg *the_args)
 | 
			
		||||
{
 | 
			
		||||
	struct cmd_context *cmd;
 | 
			
		||||
 | 
			
		||||
#ifdef M_MMAP_MAX
 | 
			
		||||
	mallopt(M_MMAP_MAX, 0);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (!setlocale(LC_ALL, ""))
 | 
			
		||||
		log_error("setlocale failed");
 | 
			
		||||
 | 
			
		||||
	init_syslog(DEFAULT_LOG_FACILITY);
 | 
			
		||||
 | 
			
		||||
	if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
 | 
			
		||||
		log_error("Failed to allocate command context");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(cmd, 0, sizeof(*cmd));
 | 
			
		||||
	cmd->args = the_args;
 | 
			
		||||
	list_init(&cmd->formats);
 | 
			
		||||
 | 
			
		||||
	strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
 | 
			
		||||
 | 
			
		||||
	if (!_get_env_vars(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	/* Create system directory if it doesn't already exist */
 | 
			
		||||
	if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (!_init_config(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	_init_logging(cmd);
 | 
			
		||||
 | 
			
		||||
	if (!_process_config(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (!_init_dev_cache(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (!_init_filters(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (!(cmd->mem = pool_create(4 * 1024))) {
 | 
			
		||||
		log_error("Command memory pool creation failed");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memlock_init(cmd);
 | 
			
		||||
 | 
			
		||||
	if (!_init_formats(cmd))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	cmd->current_settings = cmd->default_settings;
 | 
			
		||||
 | 
			
		||||
	return cmd;
 | 
			
		||||
 | 
			
		||||
      error:
 | 
			
		||||
	dbg_free(cmd);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy_formats(struct list *formats)
 | 
			
		||||
{
 | 
			
		||||
	struct list *fmtl, *tmp;
 | 
			
		||||
	struct format_type *fmt;
 | 
			
		||||
	void *lib;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(fmtl, tmp, formats) {
 | 
			
		||||
		fmt = list_item(fmtl, struct format_type);
 | 
			
		||||
		list_del(&fmt->list);
 | 
			
		||||
		lib = fmt->library;
 | 
			
		||||
		fmt->ops->destroy(fmt);
 | 
			
		||||
#ifdef HAVE_LIBDL
 | 
			
		||||
		if (lib)
 | 
			
		||||
			dlclose(lib);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_toolcontext(struct cmd_context *cmd)
 | 
			
		||||
{
 | 
			
		||||
	if (cmd->dump_filter)
 | 
			
		||||
		persistent_filter_dump(cmd->filter);
 | 
			
		||||
 | 
			
		||||
	activation_exit();
 | 
			
		||||
	lvmcache_destroy();
 | 
			
		||||
	label_exit();
 | 
			
		||||
	_destroy_formats(&cmd->formats);
 | 
			
		||||
	cmd->filter->destroy(cmd->filter);
 | 
			
		||||
	pool_destroy(cmd->mem);
 | 
			
		||||
	dev_cache_exit();
 | 
			
		||||
	destroy_config_tree(cmd->cf);
 | 
			
		||||
	dbg_free(cmd);
 | 
			
		||||
 | 
			
		||||
	release_log_memory();
 | 
			
		||||
	dump_memory();
 | 
			
		||||
	fin_log();
 | 
			
		||||
	fin_syslog();
 | 
			
		||||
 | 
			
		||||
	if (_log)
 | 
			
		||||
		fclose(_log);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_TOOLCONTEXT_H
 | 
			
		||||
#define _LVM_TOOLCONTEXT_H
 | 
			
		||||
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Config options that can be changed while commands are processed
 | 
			
		||||
 */
 | 
			
		||||
struct config_info {
 | 
			
		||||
	int debug;
 | 
			
		||||
	int verbose;
 | 
			
		||||
	int test;
 | 
			
		||||
	int syslog;
 | 
			
		||||
	int activation;
 | 
			
		||||
	int suffix;
 | 
			
		||||
	uint64_t unit_factor;
 | 
			
		||||
	char unit_type;
 | 
			
		||||
	const char *msg_prefix;
 | 
			
		||||
	int cmd_name;		/* Show command name? */
 | 
			
		||||
 | 
			
		||||
	int archive;		/* should we archive ? */
 | 
			
		||||
	int backup;		/* should we backup ? */
 | 
			
		||||
 | 
			
		||||
	struct format_type *fmt;
 | 
			
		||||
 | 
			
		||||
	mode_t umask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* FIXME Split into tool & library contexts */
 | 
			
		||||
/* command-instance-related variables needed by library */
 | 
			
		||||
struct cmd_context {
 | 
			
		||||
	/* format handler allocates all objects from here */
 | 
			
		||||
	struct pool *mem;
 | 
			
		||||
 | 
			
		||||
	const struct format_type *fmt;	/* Current format to use by default */
 | 
			
		||||
	struct format_type *fmt_backup;	/* Format to use for backups */
 | 
			
		||||
 | 
			
		||||
	struct list formats;	/* Available formats */
 | 
			
		||||
 | 
			
		||||
	char *cmd_line;
 | 
			
		||||
	struct command *command;
 | 
			
		||||
	struct arg *args;
 | 
			
		||||
	char **argv;
 | 
			
		||||
 | 
			
		||||
	struct dev_filter *filter;
 | 
			
		||||
	int dump_filter;	/* Dump filter when exiting? */
 | 
			
		||||
 | 
			
		||||
	struct config_tree *cf;
 | 
			
		||||
	struct config_info default_settings;
 | 
			
		||||
	struct config_info current_settings;
 | 
			
		||||
 | 
			
		||||
	char sys_dir[PATH_MAX];
 | 
			
		||||
	char dev_dir[PATH_MAX];
 | 
			
		||||
	char proc_dir[PATH_MAX];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cmd_context *create_toolcontext(struct arg *the_args);
 | 
			
		||||
void destroy_toolcontext(struct cmd_context *cmd);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -4,51 +4,52 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "crc.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
        TOK_INT,
 | 
			
		||||
        TOK_FLOAT,
 | 
			
		||||
        TOK_STRING,
 | 
			
		||||
        TOK_EQ,
 | 
			
		||||
        TOK_SECTION_B,
 | 
			
		||||
        TOK_SECTION_E,
 | 
			
		||||
        TOK_ARRAY_B,
 | 
			
		||||
        TOK_ARRAY_E,
 | 
			
		||||
        TOK_IDENTIFIER,
 | 
			
		||||
	TOK_INT,
 | 
			
		||||
	TOK_FLOAT,
 | 
			
		||||
	TOK_STRING,
 | 
			
		||||
	TOK_EQ,
 | 
			
		||||
	TOK_SECTION_B,
 | 
			
		||||
	TOK_SECTION_E,
 | 
			
		||||
	TOK_ARRAY_B,
 | 
			
		||||
	TOK_ARRAY_E,
 | 
			
		||||
	TOK_IDENTIFIER,
 | 
			
		||||
	TOK_COMMA,
 | 
			
		||||
	TOK_EOF
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct parser {
 | 
			
		||||
        const char *fb, *fe;    /* file limits */
 | 
			
		||||
	char *fb, *fe;		/* file limits */
 | 
			
		||||
 | 
			
		||||
        int t;                  /* token limits and type */
 | 
			
		||||
        const char *tb, *te;
 | 
			
		||||
	int t;			/* token limits and type */
 | 
			
		||||
	char *tb, *te;
 | 
			
		||||
 | 
			
		||||
        int fd;                 /* descriptor for file being parsed */
 | 
			
		||||
	int fd;			/* descriptor for file being parsed */
 | 
			
		||||
	int line;		/* line number we are on */
 | 
			
		||||
 | 
			
		||||
        struct pool *mem;
 | 
			
		||||
	struct pool *mem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cs {
 | 
			
		||||
        struct config_file cf;
 | 
			
		||||
        struct pool *mem;
 | 
			
		||||
	struct config_tree cf;
 | 
			
		||||
	struct pool *mem;
 | 
			
		||||
	time_t timestamp;
 | 
			
		||||
	char *filename;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void _get_token(struct parser *p);
 | 
			
		||||
static void _get_token(struct parser *p, int tok_prev);
 | 
			
		||||
static void _eat_space(struct parser *p);
 | 
			
		||||
static struct config_node *_file(struct parser *p);
 | 
			
		||||
static struct config_node *_section(struct parser *p);
 | 
			
		||||
@@ -68,7 +69,6 @@ static char *_dup_tok(struct parser *p);
 | 
			
		||||
   } \
 | 
			
		||||
} while(0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int _tok_match(const char *str, const char *b, const char *e)
 | 
			
		||||
{
 | 
			
		||||
	while (*str && (b != e)) {
 | 
			
		||||
@@ -79,85 +79,239 @@ static int _tok_match(const char *str, const char *b, const char *e)
 | 
			
		||||
	return !(*str || (b != e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * public interface
 | 
			
		||||
 */
 | 
			
		||||
struct config_file *create_config_file(void)
 | 
			
		||||
struct config_tree *create_config_tree(void)
 | 
			
		||||
{
 | 
			
		||||
        struct cs *c;
 | 
			
		||||
        struct pool *mem = pool_create(10 * 1024);
 | 
			
		||||
	struct cs *c;
 | 
			
		||||
	struct pool *mem = pool_create(10 * 1024);
 | 
			
		||||
 | 
			
		||||
        if (!mem) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        if (!(c = pool_alloc(mem, sizeof(*c)))) {
 | 
			
		||||
                stack;
 | 
			
		||||
                pool_destroy(mem);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	if (!(c = pool_alloc(mem, sizeof(*c)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		pool_destroy(mem);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        c->mem = mem;
 | 
			
		||||
	c->cf.root = (struct config_node *)NULL;
 | 
			
		||||
        return &c->cf;
 | 
			
		||||
	c->mem = mem;
 | 
			
		||||
	c->cf.root = (struct config_node *) NULL;
 | 
			
		||||
	c->timestamp = 0;
 | 
			
		||||
	c->filename = NULL;
 | 
			
		||||
	return &c->cf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_config_file(struct config_file *cf)
 | 
			
		||||
void destroy_config_tree(struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
        pool_destroy(((struct cs *) cf)->mem);
 | 
			
		||||
	pool_destroy(((struct cs *) cf)->mem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int read_config(struct config_file *cf, const char *file)
 | 
			
		||||
int read_config_fd(struct config_tree *cf, struct device *dev,
 | 
			
		||||
		   off_t offset, size_t size, off_t offset2, size_t size2,
 | 
			
		||||
		   checksum_fn_t checksum_fn, uint32_t checksum)
 | 
			
		||||
{
 | 
			
		||||
	struct cs *c = (struct cs *) cf;
 | 
			
		||||
        struct parser *p;
 | 
			
		||||
        struct stat info;
 | 
			
		||||
        int r = 1, fd;
 | 
			
		||||
	struct parser *p;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	int use_mmap = 1;
 | 
			
		||||
	off_t mmap_offset = 0;
 | 
			
		||||
 | 
			
		||||
        if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	p->mem = c->mem;
 | 
			
		||||
 | 
			
		||||
        /* memory map the file */
 | 
			
		||||
        if (stat(file, &info) || S_ISDIR(info.st_mode)) {
 | 
			
		||||
                log_sys_error("stat", file);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	/* Only use mmap with regular files */
 | 
			
		||||
	if (!(dev->flags & DEV_REGULAR) || size2)
 | 
			
		||||
		use_mmap = 0;
 | 
			
		||||
 | 
			
		||||
        if ((fd = open(file, O_RDONLY)) < 0) {
 | 
			
		||||
                log_sys_error("open", file);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	if (use_mmap) {
 | 
			
		||||
		mmap_offset = offset % getpagesize();
 | 
			
		||||
		/* memory map the file */
 | 
			
		||||
		p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
 | 
			
		||||
			     MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
 | 
			
		||||
		if (p->fb == (caddr_t) (-1)) {
 | 
			
		||||
			log_sys_error("mmap", dev_name(dev));
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		p->fb = p->fb + mmap_offset;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(p->fb = dbg_malloc(size + size2))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
 | 
			
		||||
			log_error("Read from %s failed", dev_name(dev));
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		if (size2) {
 | 
			
		||||
			if (!dev_read(dev, (uint64_t) offset2, size2,
 | 
			
		||||
				      p->fb + size)) {
 | 
			
		||||
				log_error("Circular read from %s failed",
 | 
			
		||||
					  dev_name(dev));
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 | 
			
		||||
        if (p->fb == MAP_FAILED) {
 | 
			
		||||
                log_sys_error("mmap", file);
 | 
			
		||||
                close(fd);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
        p->fe = p->fb + info.st_size;
 | 
			
		||||
	if (checksum_fn && checksum !=
 | 
			
		||||
	    (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
 | 
			
		||||
			 p->fb + size, size2))) {
 | 
			
		||||
		log_error("%s: Checksum error", dev_name(dev));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        /* parse */
 | 
			
		||||
        p->tb = p->te = p->fb;
 | 
			
		||||
	p->fe = p->fb + size + size2;
 | 
			
		||||
 | 
			
		||||
	/* parse */
 | 
			
		||||
	p->tb = p->te = p->fb;
 | 
			
		||||
	p->line = 1;
 | 
			
		||||
	_get_token(p);
 | 
			
		||||
        if (!(cf->root = _file(p))) {
 | 
			
		||||
                stack;
 | 
			
		||||
                r = 0;
 | 
			
		||||
        }
 | 
			
		||||
	_get_token(p, TOK_SECTION_E);
 | 
			
		||||
	if (!(cf->root = _file(p))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        /* unmap the file */
 | 
			
		||||
        if (munmap((char *) p->fb, info.st_size)) {
 | 
			
		||||
                log_sys_error("munmap", file);
 | 
			
		||||
                r = 0;
 | 
			
		||||
        }
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
        close(fd);
 | 
			
		||||
        return r;
 | 
			
		||||
      out:
 | 
			
		||||
	if (!use_mmap)
 | 
			
		||||
		dbg_free(p->fb);
 | 
			
		||||
	else {
 | 
			
		||||
		/* unmap the file */
 | 
			
		||||
		if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
 | 
			
		||||
			log_sys_error("munmap", dev_name(dev));
 | 
			
		||||
			r = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int read_config_file(struct config_tree *cf, const char *file)
 | 
			
		||||
{
 | 
			
		||||
	struct cs *c = (struct cs *) cf;
 | 
			
		||||
	struct stat info;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	if (stat(file, &info)) {
 | 
			
		||||
		log_sys_error("stat", file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!S_ISREG(info.st_mode)) {
 | 
			
		||||
		log_error("%s is not a regular file", file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info.st_size == 0) {
 | 
			
		||||
		log_verbose("%s is empty", file);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dev = dev_create_file(file, NULL, NULL))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_config_fd(cf, dev, 0, (size_t) info.st_size, 0, 0,
 | 
			
		||||
			   (checksum_fn_t) NULL, 0);
 | 
			
		||||
 | 
			
		||||
	dev_close(dev);
 | 
			
		||||
 | 
			
		||||
	c->timestamp = info.st_mtime;
 | 
			
		||||
	c->filename = pool_strdup(c->mem, file);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t config_file_timestamp(struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	struct cs *c = (struct cs *) cf;
 | 
			
		||||
 | 
			
		||||
	return c->timestamp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if config file reloaded
 | 
			
		||||
 */
 | 
			
		||||
int reload_config_file(struct config_tree **cf)
 | 
			
		||||
{
 | 
			
		||||
	struct config_tree *new_cf;
 | 
			
		||||
	struct cs *c = (struct cs *) *cf;
 | 
			
		||||
	struct cs *new_cs;
 | 
			
		||||
	struct stat info;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!c->filename)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (stat(c->filename, &info) == -1) {
 | 
			
		||||
		if (errno == ENOENT)
 | 
			
		||||
			return 1;
 | 
			
		||||
		log_sys_error("stat", c->filename);
 | 
			
		||||
		log_error("Failed to reload configuration file");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!S_ISREG(info.st_mode)) {
 | 
			
		||||
		log_error("Configuration file %s is not a regular file",
 | 
			
		||||
			  c->filename);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Unchanged? */
 | 
			
		||||
	if (c->timestamp == info.st_mtime)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	log_verbose("Detected config file change: Reloading %s", c->filename);
 | 
			
		||||
 | 
			
		||||
	if (info.st_size == 0) {
 | 
			
		||||
		log_verbose("Config file reload: %s is empty", c->filename);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(new_cf = create_config_tree())) {
 | 
			
		||||
		log_error("Allocation of new config_tree failed");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_config_fd(new_cf, dev, 0, (size_t) info.st_size,
 | 
			
		||||
			   0, 0, (checksum_fn_t) NULL, 0);
 | 
			
		||||
 | 
			
		||||
	dev_close(dev);
 | 
			
		||||
 | 
			
		||||
	if (r) {
 | 
			
		||||
		new_cs = (struct cs *) new_cf;
 | 
			
		||||
		new_cs->filename = pool_strdup(new_cs->mem, c->filename);
 | 
			
		||||
		new_cs->timestamp = info.st_mtime;
 | 
			
		||||
		destroy_config_tree(*cf);
 | 
			
		||||
		*cf = new_cf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _write_value(FILE *fp, struct config_value *v)
 | 
			
		||||
@@ -174,24 +328,32 @@ static void _write_value(FILE *fp, struct config_value *v)
 | 
			
		||||
	case CFG_INT:
 | 
			
		||||
		fprintf(fp, "%d", v->v.i);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CFG_EMPTY_ARRAY:
 | 
			
		||||
		fprintf(fp, "[]");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("_write_value: Unknown value type: %d", v->type);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _write_config(struct config_node *n, FILE *fp, int level)
 | 
			
		||||
{
 | 
			
		||||
        char space[MAX_INDENT + 1];
 | 
			
		||||
        int l = (level < MAX_INDENT) ? level : MAX_INDENT;
 | 
			
		||||
        int i;
 | 
			
		||||
	char space[MAX_INDENT + 1];
 | 
			
		||||
	int l = (level < MAX_INDENT) ? level : MAX_INDENT;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < l; i++)
 | 
			
		||||
                space[i] = ' ';
 | 
			
		||||
        space[i] = '\0';
 | 
			
		||||
	for (i = 0; i < l; i++)
 | 
			
		||||
		space[i] = '\t';
 | 
			
		||||
	space[i] = '\0';
 | 
			
		||||
 | 
			
		||||
        while (n) {
 | 
			
		||||
                fprintf(fp, "%s%s", space, n->key);
 | 
			
		||||
	while (n) {
 | 
			
		||||
		fprintf(fp, "%s%s", space, n->key);
 | 
			
		||||
		if (!n->v) {
 | 
			
		||||
			/* it's a sub section */
 | 
			
		||||
			fprintf(fp, " {\n");
 | 
			
		||||
@@ -214,26 +376,26 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
 | 
			
		||||
				_write_value(fp, v);
 | 
			
		||||
		}
 | 
			
		||||
		fprintf(fp, "\n");
 | 
			
		||||
                n = n->sib;
 | 
			
		||||
        }
 | 
			
		||||
		n = n->sib;
 | 
			
		||||
	}
 | 
			
		||||
	/* FIXME: add error checking */
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int write_config(struct config_file *cf, const char *file)
 | 
			
		||||
int write_config_file(struct config_tree *cf, const char *file)
 | 
			
		||||
{
 | 
			
		||||
	int r = 1;
 | 
			
		||||
        FILE *fp = fopen(file, "w");
 | 
			
		||||
        if (!fp) {
 | 
			
		||||
                log_sys_error("open", file);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
	FILE *fp = fopen(file, "w");
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		log_sys_error("open", file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        if (!_write_config(cf->root, fp, 0)) {
 | 
			
		||||
	if (!_write_config(cf->root, fp, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		r = 0;
 | 
			
		||||
	}
 | 
			
		||||
        fclose(fp);
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -260,7 +422,7 @@ static struct config_node *_file(struct parser *p)
 | 
			
		||||
 | 
			
		||||
static struct config_node *_section(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
        /* IDENTIFIER '{' VALUE* '}' */
 | 
			
		||||
	/* IDENTIFIER '{' VALUE* '}' */
 | 
			
		||||
	struct config_node *root, *n, *l = NULL;
 | 
			
		||||
	if (!(root = _create_node(p))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -272,7 +434,7 @@ static struct config_node *_section(struct parser *p)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        match (TOK_IDENTIFIER);
 | 
			
		||||
	match(TOK_IDENTIFIER);
 | 
			
		||||
 | 
			
		||||
	if (p->t == TOK_SECTION_B) {
 | 
			
		||||
		match(TOK_SECTION_B);
 | 
			
		||||
@@ -297,17 +459,17 @@ static struct config_node *_section(struct parser *p)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return root;
 | 
			
		||||
	return root;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_value *_value(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
        /* '[' TYPE* ']' | TYPE */
 | 
			
		||||
	struct config_value *h = 0, *l, *ll = 0;
 | 
			
		||||
        if (p->t == TOK_ARRAY_B) {
 | 
			
		||||
                match (TOK_ARRAY_B);
 | 
			
		||||
                while (p->t != TOK_ARRAY_E) {
 | 
			
		||||
                        if (!(l = _type(p))) {
 | 
			
		||||
	/* '[' TYPE* ']' | TYPE */
 | 
			
		||||
	struct config_value *h = NULL, *l, *ll = NULL;
 | 
			
		||||
	if (p->t == TOK_ARRAY_B) {
 | 
			
		||||
		match(TOK_ARRAY_B);
 | 
			
		||||
		while (p->t != TOK_ARRAY_E) {
 | 
			
		||||
			if (!(l = _type(p))) {
 | 
			
		||||
				stack;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
@@ -321,48 +483,61 @@ static struct config_value *_value(struct parser *p)
 | 
			
		||||
			if (p->t == TOK_COMMA)
 | 
			
		||||
				match(TOK_COMMA);
 | 
			
		||||
		}
 | 
			
		||||
                match(TOK_ARRAY_E);
 | 
			
		||||
        } else
 | 
			
		||||
		match(TOK_ARRAY_E);
 | 
			
		||||
		/*
 | 
			
		||||
		 * Special case for an empty array.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!h) {
 | 
			
		||||
			if (!(h = _create_value(p)))
 | 
			
		||||
				return NULL;
 | 
			
		||||
 | 
			
		||||
			h->type = CFG_EMPTY_ARRAY;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		h = _type(p);
 | 
			
		||||
 | 
			
		||||
        return h;
 | 
			
		||||
	return h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_value *_type(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
        /* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
 | 
			
		||||
	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
 | 
			
		||||
	struct config_value *v = _create_value(p);
 | 
			
		||||
 | 
			
		||||
        switch (p->t) {
 | 
			
		||||
        case TOK_INT:
 | 
			
		||||
	if (!v)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	switch (p->t) {
 | 
			
		||||
	case TOK_INT:
 | 
			
		||||
		v->type = CFG_INT;
 | 
			
		||||
		v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
 | 
			
		||||
                match(TOK_INT);
 | 
			
		||||
                break;
 | 
			
		||||
		v->v.i = strtol(p->tb, NULL, 0);	/* FIXME: check error */
 | 
			
		||||
		match(TOK_INT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
        case TOK_FLOAT:
 | 
			
		||||
	case TOK_FLOAT:
 | 
			
		||||
		v->type = CFG_FLOAT;
 | 
			
		||||
		v->v.r = strtod(p->tb, 0); /* FIXME: check error */
 | 
			
		||||
                match(TOK_FLOAT);
 | 
			
		||||
                break;
 | 
			
		||||
		v->v.r = strtod(p->tb, NULL);	/* FIXME: check error */
 | 
			
		||||
		match(TOK_FLOAT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
        case TOK_STRING:
 | 
			
		||||
	case TOK_STRING:
 | 
			
		||||
		v->type = CFG_STRING;
 | 
			
		||||
 | 
			
		||||
		p->tb++, p->te--; /* strip "'s */
 | 
			
		||||
		p->tb++, p->te--;	/* strip "'s */
 | 
			
		||||
		if (!(v->v.str = _dup_tok(p))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		p->te++;
 | 
			
		||||
                match(TOK_STRING);
 | 
			
		||||
                break;
 | 
			
		||||
		match(TOK_STRING);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Parse error at line %d: expected a value", p->line);
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return v;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _match_aux(struct parser *p, int t)
 | 
			
		||||
@@ -370,115 +545,146 @@ static int _match_aux(struct parser *p, int t)
 | 
			
		||||
	if (p->t != t)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_get_token(p);
 | 
			
		||||
	_get_token(p, t);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * tokeniser
 | 
			
		||||
 */
 | 
			
		||||
static void _get_token(struct parser *p)
 | 
			
		||||
static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
{
 | 
			
		||||
        p->tb = p->te;
 | 
			
		||||
        _eat_space(p);
 | 
			
		||||
        if (p->tb == p->fe) {
 | 
			
		||||
	int values_allowed = 0;
 | 
			
		||||
 | 
			
		||||
	p->tb = p->te;
 | 
			
		||||
	_eat_space(p);
 | 
			
		||||
	if (p->tb == p->fe || !*p->tb) {
 | 
			
		||||
		p->t = TOK_EOF;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        p->t = TOK_INT;         /* fudge so the fall through for
 | 
			
		||||
                                   floats works */
 | 
			
		||||
        switch (*p->te) {
 | 
			
		||||
        case '{':
 | 
			
		||||
                p->t = TOK_SECTION_B;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
	/* Should next token be interpreted as value instead of identifier? */
 | 
			
		||||
	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
 | 
			
		||||
	    tok_prev == TOK_COMMA)
 | 
			
		||||
		values_allowed = 1;
 | 
			
		||||
 | 
			
		||||
        case '}':
 | 
			
		||||
                p->t = TOK_SECTION_E;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        case '[':
 | 
			
		||||
                p->t = TOK_ARRAY_B;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        case ']':
 | 
			
		||||
                p->t = TOK_ARRAY_E;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        case ',':
 | 
			
		||||
                p->t = TOK_COMMA;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        case '=':
 | 
			
		||||
                p->t = TOK_EQ;
 | 
			
		||||
                p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        case '"':
 | 
			
		||||
                p->t = TOK_STRING;
 | 
			
		||||
	p->t = TOK_INT;		/* fudge so the fall through for
 | 
			
		||||
				   floats works */
 | 
			
		||||
	switch (*p->te) {
 | 
			
		||||
	case '{':
 | 
			
		||||
		p->t = TOK_SECTION_B;
 | 
			
		||||
		p->te++;
 | 
			
		||||
                while ((p->te != p->fe) && (*p->te != '"')) {
 | 
			
		||||
                        if ((*p->te == '\\') && (p->te + 1 != p->fe))
 | 
			
		||||
                                p->te++;
 | 
			
		||||
                        p->te++;
 | 
			
		||||
                }
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
                if (p->te != p->fe)
 | 
			
		||||
                        p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
	case '}':
 | 
			
		||||
		p->t = TOK_SECTION_E;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
        case '.':
 | 
			
		||||
                p->t = TOK_FLOAT;
 | 
			
		||||
        case '0': case '1': case '2': case '3': case '4':
 | 
			
		||||
        case '5': case '6': case '7': case '8': case '9':
 | 
			
		||||
                p->te++;
 | 
			
		||||
                while (p->te != p->fe) {
 | 
			
		||||
                        if (*p->te == '.') {
 | 
			
		||||
                                if (p->t == TOK_FLOAT)
 | 
			
		||||
                                        break;
 | 
			
		||||
                                p->t = TOK_FLOAT;
 | 
			
		||||
                        } else if (!isdigit((int) *p->te))
 | 
			
		||||
                                break;
 | 
			
		||||
                        p->te++;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
	case '[':
 | 
			
		||||
		p->t = TOK_ARRAY_B;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
                p->t = TOK_IDENTIFIER;
 | 
			
		||||
                while ((p->te != p->fe) && !isspace(*p->te) &&
 | 
			
		||||
		      (*p->te != '#') && (*p->te != '='))
 | 
			
		||||
                        p->te++;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
	case ']':
 | 
			
		||||
		p->t = TOK_ARRAY_E;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ',':
 | 
			
		||||
		p->t = TOK_COMMA;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '=':
 | 
			
		||||
		p->t = TOK_EQ;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '"':
 | 
			
		||||
		p->t = TOK_STRING;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
 | 
			
		||||
			if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
 | 
			
		||||
			    *(p->te + 1))
 | 
			
		||||
				p->te++;
 | 
			
		||||
			p->te++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((p->te != p->fe) && (*p->te))
 | 
			
		||||
			p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '\'':
 | 
			
		||||
		p->t = TOK_STRING;
 | 
			
		||||
		p->te++;
 | 
			
		||||
		while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
 | 
			
		||||
			p->te++;
 | 
			
		||||
 | 
			
		||||
		if ((p->te != p->fe) && (*p->te))
 | 
			
		||||
			p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '.':
 | 
			
		||||
		p->t = TOK_FLOAT;
 | 
			
		||||
	case '0':
 | 
			
		||||
	case '1':
 | 
			
		||||
	case '2':
 | 
			
		||||
	case '3':
 | 
			
		||||
	case '4':
 | 
			
		||||
	case '5':
 | 
			
		||||
	case '6':
 | 
			
		||||
	case '7':
 | 
			
		||||
	case '8':
 | 
			
		||||
	case '9':
 | 
			
		||||
	case '+':
 | 
			
		||||
	case '-':
 | 
			
		||||
		if (values_allowed) {
 | 
			
		||||
			p->te++;
 | 
			
		||||
			while ((p->te != p->fe) && (*p->te)) {
 | 
			
		||||
				if (*p->te == '.') {
 | 
			
		||||
					if (p->t == TOK_FLOAT)
 | 
			
		||||
						break;
 | 
			
		||||
					p->t = TOK_FLOAT;
 | 
			
		||||
				} else if (!isdigit((int) *p->te))
 | 
			
		||||
					break;
 | 
			
		||||
				p->te++;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		p->t = TOK_IDENTIFIER;
 | 
			
		||||
		while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
 | 
			
		||||
		       (*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
 | 
			
		||||
		       (*p->te != '}'))
 | 
			
		||||
			p->te++;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _eat_space(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
        while (p->tb != p->fe) {
 | 
			
		||||
                if (*p->te == '#') {
 | 
			
		||||
                        while ((p->te != p->fe) && (*p->te != '\n'))
 | 
			
		||||
                                p->te++;
 | 
			
		||||
	while ((p->tb != p->fe) && (*p->tb)) {
 | 
			
		||||
		if (*p->te == '#') {
 | 
			
		||||
			while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
 | 
			
		||||
				p->te++;
 | 
			
		||||
			p->line++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		else if (isspace(*p->te)) {
 | 
			
		||||
                        while ((p->te != p->fe) && isspace(*p->te)) {
 | 
			
		||||
			while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
 | 
			
		||||
				if (*p->te == '\n')
 | 
			
		||||
					p->line++;
 | 
			
		||||
                                p->te++;
 | 
			
		||||
				p->te++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
                else
 | 
			
		||||
                        return;
 | 
			
		||||
		else
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
                p->tb = p->te;
 | 
			
		||||
        }
 | 
			
		||||
		p->tb = p->te;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -500,7 +706,7 @@ static struct config_node *_create_node(struct parser *p)
 | 
			
		||||
 | 
			
		||||
static char *_dup_tok(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
	int len = p->te - p->tb;
 | 
			
		||||
	size_t len = p->te - p->tb;
 | 
			
		||||
	char *str = pool_alloc(p->mem, len + 1);
 | 
			
		||||
	if (!str) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -515,7 +721,7 @@ static char *_dup_tok(struct parser *p)
 | 
			
		||||
 * utility functions
 | 
			
		||||
 */
 | 
			
		||||
struct config_node *find_config_node(struct config_node *cn,
 | 
			
		||||
				     const char *path, char sep)
 | 
			
		||||
				     const char *path, const int sep)
 | 
			
		||||
{
 | 
			
		||||
	const char *e;
 | 
			
		||||
 | 
			
		||||
@@ -525,8 +731,7 @@ struct config_node *find_config_node(struct config_node *cn,
 | 
			
		||||
			path++;
 | 
			
		||||
 | 
			
		||||
		/* find the end of this segment */
 | 
			
		||||
		for (e = path; *e && (*e != sep); e++)
 | 
			
		||||
			;
 | 
			
		||||
		for (e = path; *e && (*e != sep); e++) ;
 | 
			
		||||
 | 
			
		||||
		/* hunt for the node */
 | 
			
		||||
		while (cn) {
 | 
			
		||||
@@ -547,25 +752,25 @@ struct config_node *find_config_node(struct config_node *cn,
 | 
			
		||||
	return cn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
find_config_str(struct config_node *cn,
 | 
			
		||||
		const char *path, char sep, const char *fail)
 | 
			
		||||
const char *find_config_str(struct config_node *cn,
 | 
			
		||||
			    const char *path, const int sep, const char *fail)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n = find_config_node(cn, path, sep);
 | 
			
		||||
 | 
			
		||||
	if (n && n->v->type == CFG_STRING) {
 | 
			
		||||
		log_very_verbose("Setting %s to %s", path, n->v->v.str);
 | 
			
		||||
		if (*n->v->v.str)
 | 
			
		||||
			log_very_verbose("Setting %s to %s", path, n->v->v.str);
 | 
			
		||||
		return n->v->v.str;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fail)
 | 
			
		||||
		log_very_verbose("%s not found in config: defaulting to %s",
 | 
			
		||||
			  path, fail);
 | 
			
		||||
				 path, fail);
 | 
			
		||||
	return fail;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int find_config_int(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, int fail)
 | 
			
		||||
		    const int sep, int fail)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n = find_config_node(cn, path, sep);
 | 
			
		||||
 | 
			
		||||
@@ -574,13 +779,13 @@ int find_config_int(struct config_node *cn, const char *path,
 | 
			
		||||
		return n->v->v.i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s not found in config: defaulting to %d", 
 | 
			
		||||
	log_very_verbose("%s not found in config: defaulting to %d",
 | 
			
		||||
			 path, fail);
 | 
			
		||||
	return fail;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float find_config_float(struct config_node *cn, const char *path,
 | 
			
		||||
			char sep, float fail)
 | 
			
		||||
			const int sep, float fail)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n = find_config_node(cn, path, sep);
 | 
			
		||||
 | 
			
		||||
@@ -590,7 +795,7 @@ float find_config_float(struct config_node *cn, const char *path,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("%s not found in config: defaulting to %f",
 | 
			
		||||
		  path, fail);
 | 
			
		||||
			 path, fail);
 | 
			
		||||
 | 
			
		||||
	return fail;
 | 
			
		||||
 | 
			
		||||
@@ -609,8 +814,9 @@ static int _str_in_array(const char *str, const char *values[])
 | 
			
		||||
 | 
			
		||||
static int _str_to_bool(const char *str, int fail)
 | 
			
		||||
{
 | 
			
		||||
	static const char *_true_values[] = {"y", "yes", "on", "true", NULL};
 | 
			
		||||
	static const char *_false_values[] = {"n", "no", "off", "false", NULL};
 | 
			
		||||
	static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
 | 
			
		||||
	static const char *_false_values[] =
 | 
			
		||||
	    { "n", "no", "off", "false", NULL };
 | 
			
		||||
 | 
			
		||||
	if (_str_in_array(str, _true_values))
 | 
			
		||||
		return 1;
 | 
			
		||||
@@ -622,7 +828,7 @@ static int _str_to_bool(const char *str, int fail)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int find_config_bool(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, int fail)
 | 
			
		||||
		     const int sep, int fail)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n = find_config_node(cn, path, sep);
 | 
			
		||||
	struct config_value *v;
 | 
			
		||||
@@ -644,7 +850,7 @@ int find_config_bool(struct config_node *cn, const char *path,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_config_uint32(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, uint32_t *result)
 | 
			
		||||
		      const int sep, uint32_t *result)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n;
 | 
			
		||||
 | 
			
		||||
@@ -658,7 +864,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_config_uint64(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, uint64_t *result)
 | 
			
		||||
		      const int sep, uint64_t *result)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n;
 | 
			
		||||
 | 
			
		||||
@@ -672,3 +878,16 @@ int get_config_uint64(struct config_node *cn, const char *path,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_config_str(struct config_node *cn, const char *path,
 | 
			
		||||
		   const int sep, char **result)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n;
 | 
			
		||||
 | 
			
		||||
	n = find_config_node(cn, path, sep);
 | 
			
		||||
 | 
			
		||||
	if (!n || !n->v || n->v->type != CFG_STRING)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	*result = n->v->v.str;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,66 +7,75 @@
 | 
			
		||||
#ifndef _LVM_CONFIG_H
 | 
			
		||||
#define _LVM_CONFIG_H
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include "device.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
        CFG_STRING,
 | 
			
		||||
        CFG_FLOAT,
 | 
			
		||||
        CFG_INT,
 | 
			
		||||
	CFG_STRING,
 | 
			
		||||
	CFG_FLOAT,
 | 
			
		||||
	CFG_INT,
 | 
			
		||||
	CFG_EMPTY_ARRAY
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_value {
 | 
			
		||||
        int type;
 | 
			
		||||
        union {
 | 
			
		||||
                int i;
 | 
			
		||||
                float r;
 | 
			
		||||
                char *str;
 | 
			
		||||
        } v;
 | 
			
		||||
        struct config_value *next; /* for arrays */
 | 
			
		||||
	int type;
 | 
			
		||||
	union {
 | 
			
		||||
		int i;
 | 
			
		||||
		float r;
 | 
			
		||||
		char *str;
 | 
			
		||||
	} v;
 | 
			
		||||
	struct config_value *next;	/* for arrays */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_node {
 | 
			
		||||
        char *key;
 | 
			
		||||
        struct config_node *sib, *child;
 | 
			
		||||
        struct config_value *v;
 | 
			
		||||
	char *key;
 | 
			
		||||
	struct config_node *sib, *child;
 | 
			
		||||
	struct config_value *v;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_file {
 | 
			
		||||
        struct config_node *root;
 | 
			
		||||
struct config_tree {
 | 
			
		||||
	struct config_node *root;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_file *create_config_file(void);
 | 
			
		||||
void destroy_config_file(struct config_file *cf);
 | 
			
		||||
struct config_tree *create_config_tree(void);
 | 
			
		||||
void destroy_config_tree(struct config_tree *cf);
 | 
			
		||||
 | 
			
		||||
int read_config(struct config_file *cf, const char *file);
 | 
			
		||||
int write_config(struct config_file *cf, const char *file);
 | 
			
		||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
 | 
			
		||||
 | 
			
		||||
int read_config_fd(struct config_tree *cf, struct device *dev,
 | 
			
		||||
		   off_t offset, size_t size, off_t offset2, size_t size2,
 | 
			
		||||
		   checksum_fn_t checksum_fn, uint32_t checksum);
 | 
			
		||||
 | 
			
		||||
int read_config_file(struct config_tree *cf, const char *file);
 | 
			
		||||
int write_config_file(struct config_tree *cf, const char *file);
 | 
			
		||||
int reload_config_file(struct config_tree **cf);
 | 
			
		||||
time_t config_file_timestamp(struct config_tree *cf);
 | 
			
		||||
 | 
			
		||||
struct config_node *find_config_node(struct config_node *cn,
 | 
			
		||||
				     const char *path, char seperator);
 | 
			
		||||
				     const char *path, const int separator);
 | 
			
		||||
 | 
			
		||||
const char *find_config_str(struct config_node *cn,
 | 
			
		||||
			    const char *path, char sep, const char *fail);
 | 
			
		||||
			    const char *path, const int sep, const char *fail);
 | 
			
		||||
 | 
			
		||||
int find_config_int(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, int fail);
 | 
			
		||||
		    const int sep, int fail);
 | 
			
		||||
 | 
			
		||||
float find_config_float(struct config_node *cn, const char *path,
 | 
			
		||||
			char sep, float fail);
 | 
			
		||||
			const int sep, float fail);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Understands (0, ~0), (y, n), (yes, no), (on,
 | 
			
		||||
 * off), (true, false).
 | 
			
		||||
 */
 | 
			
		||||
int find_config_bool(struct config_node *cn, const char *path,
 | 
			
		||||
		    char sep, int fail);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		     const int sep, int fail);
 | 
			
		||||
 | 
			
		||||
int get_config_uint32(struct config_node *cn, const char *path,
 | 
			
		||||
		      char sep, uint32_t *result);
 | 
			
		||||
		      const int sep, uint32_t *result);
 | 
			
		||||
 | 
			
		||||
int get_config_uint64(struct config_node *cn, const char *path,
 | 
			
		||||
		      char sep, uint64_t *result);
 | 
			
		||||
		      const int sep, uint64_t *result);
 | 
			
		||||
 | 
			
		||||
int get_config_str(struct config_node *cn, const char *path,
 | 
			
		||||
		   const int sep, char **result);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										91
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the GPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_DEFAULTS_H
 | 
			
		||||
#define _LVM_DEFAULTS_H
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_ARCHIVE_ENABLED 1
 | 
			
		||||
#define DEFAULT_BACKUP_ENABLED 1
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_ARCHIVE_SUBDIR "archive"
 | 
			
		||||
#define DEFAULT_BACKUP_SUBDIR "backup"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_ARCHIVE_DAYS 30
 | 
			
		||||
#define DEFAULT_ARCHIVE_NUMBER 10
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_SYS_DIR "/etc/lvm"
 | 
			
		||||
#define DEFAULT_DEV_DIR "/dev"
 | 
			
		||||
#define DEFAULT_PROC_DIR "/proc"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
 | 
			
		||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_UMASK 0077
 | 
			
		||||
 | 
			
		||||
#ifdef LVM1_SUPPORT
 | 
			
		||||
#  define DEFAULT_FORMAT "lvm1"
 | 
			
		||||
#else
 | 
			
		||||
#  define DEFAULT_FORMAT "lvm2"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_STRIPESIZE 64	/* KB */
 | 
			
		||||
#define DEFAULT_PVMETADATASIZE 255
 | 
			
		||||
#define DEFAULT_PVMETADATACOPIES 1
 | 
			
		||||
#define DEFAULT_LABELSECTOR UINT64_C(1)
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_MSG_PREFIX "  "
 | 
			
		||||
#define DEFAULT_CMD_NAME 0
 | 
			
		||||
#define DEFAULT_OVERWRITE 0
 | 
			
		||||
 | 
			
		||||
#ifndef DEFAULT_LOG_FACILITY
 | 
			
		||||
#  define DEFAULT_LOG_FACILITY LOG_USER
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_SYSLOG 1
 | 
			
		||||
#define DEFAULT_VERBOSE 0
 | 
			
		||||
#define DEFAULT_LOGLEVEL 0
 | 
			
		||||
#define DEFAULT_INDENT 1
 | 
			
		||||
#define DEFAULT_UNITS "h"
 | 
			
		||||
#define DEFAULT_SUFFIX 1
 | 
			
		||||
 | 
			
		||||
#ifdef DEVMAPPER_SUPPORT
 | 
			
		||||
#  define DEFAULT_ACTIVATION 1
 | 
			
		||||
#  define DEFAULT_RESERVED_MEMORY 8192
 | 
			
		||||
#  define DEFAULT_RESERVED_STACK 256
 | 
			
		||||
#  define DEFAULT_PROCESS_PRIORITY -18
 | 
			
		||||
#else
 | 
			
		||||
#  define DEFAULT_ACTIVATION 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
 | 
			
		||||
#define DEFAULT_MIRROR_REGION_SIZE 512	/* KB */
 | 
			
		||||
#define DEFAULT_INTERVAL 15
 | 
			
		||||
 | 
			
		||||
#ifdef READLINE_SUPPORT
 | 
			
		||||
#  define DEFAULT_MAX_HISTORY 100
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_REP_ALIGNED 1
 | 
			
		||||
#define DEFAULT_REP_BUFFERED 1
 | 
			
		||||
#define DEFAULT_REP_HEADINGS 1
 | 
			
		||||
#define DEFAULT_REP_SEPARATOR " "
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,move_percent"
 | 
			
		||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
 | 
			
		||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
 | 
			
		||||
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,move_percent,lv_uuid"
 | 
			
		||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
 | 
			
		||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
 | 
			
		||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_LVS_SORT "vg_name,lv_name"
 | 
			
		||||
#define DEFAULT_VGS_SORT "vg_name"
 | 
			
		||||
#define DEFAULT_PVS_SORT "pv_name"
 | 
			
		||||
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
 | 
			
		||||
 | 
			
		||||
#endif				/* _LVM_DEFAULTS_H */
 | 
			
		||||
@@ -4,18 +4,16 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "bitset.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/* FIXME: calculate this. */
 | 
			
		||||
#define INT_SHIFT 5
 | 
			
		||||
 | 
			
		||||
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
 | 
			
		||||
{
 | 
			
		||||
	int n = (num_bits / BITS_PER_INT) + 2;
 | 
			
		||||
	int size = sizeof(int) * n;
 | 
			
		||||
	unsigned n = (num_bits / BITS_PER_INT) + 2;
 | 
			
		||||
	size_t size = sizeof(int) * n;
 | 
			
		||||
	unsigned *bs = pool_zalloc(mem, size);
 | 
			
		||||
 | 
			
		||||
	if (!bs)
 | 
			
		||||
@@ -33,7 +31,7 @@ void bitset_destroy(bitset_t bs)
 | 
			
		||||
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
 | 
			
		||||
	for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
 | 
			
		||||
		out[i] = in1[i] | in2[i];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -58,7 +56,7 @@ int bit_get_next(bitset_t bs, int last_bit)
 | 
			
		||||
 | 
			
		||||
	last_bit++;		/* otherwise we'll return the same bit again */
 | 
			
		||||
 | 
			
		||||
	while(last_bit < bs[0]) {
 | 
			
		||||
	while (last_bit < bs[0]) {
 | 
			
		||||
		word = last_bit >> INT_SHIFT;
 | 
			
		||||
		test = bs[word + 1];
 | 
			
		||||
		bit = last_bit & (BITS_PER_INT - 1);
 | 
			
		||||
@@ -66,8 +64,8 @@ int bit_get_next(bitset_t bs, int last_bit)
 | 
			
		||||
		if ((bit = _test_word(test, bit)) >= 0)
 | 
			
		||||
			return (word * BITS_PER_INT) + bit;
 | 
			
		||||
 | 
			
		||||
		last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) + 
 | 
			
		||||
			BITS_PER_INT;
 | 
			
		||||
		last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
 | 
			
		||||
		    BITS_PER_INT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,22 +7,19 @@
 | 
			
		||||
#ifndef _LVM_BITSET_H
 | 
			
		||||
#define _LVM_BITSET_H
 | 
			
		||||
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef uint32_t *bitset_t;
 | 
			
		||||
 | 
			
		||||
bitset_t bitset_create(struct pool *mem, unsigned num_bits);
 | 
			
		||||
void bitset_destroy(bitset_t bs);
 | 
			
		||||
 | 
			
		||||
void bit_union(bitset_t out, bitset_t in1, bitset_t in2);
 | 
			
		||||
int bit_get_first(bitset_t bs);
 | 
			
		||||
int bit_get_next(bitset_t bs, int last_bit);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define BITS_PER_INT (sizeof(int) * CHAR_BIT)
 | 
			
		||||
 | 
			
		||||
#define bit(bs, i) \
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "btree.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
struct node {
 | 
			
		||||
	uint32_t key;
 | 
			
		||||
@@ -40,14 +40,13 @@ static uint32_t _shuffle(uint32_t k)
 | 
			
		||||
#if 1
 | 
			
		||||
	return ((k & 0xff) << 24 |
 | 
			
		||||
		(k & 0xff00) << 8 |
 | 
			
		||||
		(k & 0xff0000) >> 8 |
 | 
			
		||||
		(k & 0xff000000) >> 24);
 | 
			
		||||
		(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
 | 
			
		||||
#else
 | 
			
		||||
	return k;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct node **_lookup(struct node **c, uint32_t key, struct node **p)
 | 
			
		||||
static struct node **_lookup(struct node **c, uint32_t key, struct node **p)
 | 
			
		||||
{
 | 
			
		||||
	*p = NULL;
 | 
			
		||||
	while (*c) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#ifndef _LVM_BTREE_H
 | 
			
		||||
#define _LVM_BTREE_H
 | 
			
		||||
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
 | 
			
		||||
struct btree;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,8 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
struct hash_node {
 | 
			
		||||
	struct hash_node *next;
 | 
			
		||||
@@ -23,22 +21,30 @@ struct hash_table {
 | 
			
		||||
 | 
			
		||||
/* Permutation of the Integers 0 through 255 */
 | 
			
		||||
static unsigned char _nums[] = {
 | 
			
		||||
	1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
 | 
			
		||||
	87,197,177,107,234,169, 56, 68, 30,  7,173, 73,188, 40, 36, 65,
 | 
			
		||||
	49,213,104,190, 57,211,148,223, 48,115, 15,  2, 67,186,210, 28,
 | 
			
		||||
	12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144,
 | 
			
		||||
	176,161,141, 86, 60, 66,128, 83,156,241, 79, 46,168,198, 41,254,
 | 
			
		||||
	178, 85,253,237,250,154,133, 88, 35,206, 95,116,252,192, 54,221,
 | 
			
		||||
	102,218,255,240, 82,106,158,201, 61,  3, 89,  9, 42,155,159, 93,
 | 
			
		||||
	166, 80, 50, 34,175,195,100, 99, 26,150, 16,145,  4, 33,  8,189,
 | 
			
		||||
	121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194,
 | 
			
		||||
	193,239,101,242,  5,171,126, 11, 74, 59,137,228,108,191,232,139,
 | 
			
		||||
	6, 24, 81, 20,127, 17, 91, 92,251,151,225,207, 21, 98,113,112,
 | 
			
		||||
	84,226, 18,214,199,187, 13, 32, 94,220,224,212,247,204,196, 43,
 | 
			
		||||
	249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
 | 
			
		||||
	230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109,
 | 
			
		||||
	44, 38, 31,149,135,  0,216, 52, 63, 23, 37, 69, 39,117,146,184,
 | 
			
		||||
	163,200,222,235,248,243,219, 10,152,131,123,229,203, 76,120,209
 | 
			
		||||
	1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
 | 
			
		||||
	87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
 | 
			
		||||
	49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
 | 
			
		||||
	12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
 | 
			
		||||
	144,
 | 
			
		||||
	176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
 | 
			
		||||
	178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
 | 
			
		||||
	221,
 | 
			
		||||
	102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
 | 
			
		||||
	166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
 | 
			
		||||
	121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
 | 
			
		||||
	194,
 | 
			
		||||
	193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
 | 
			
		||||
	139,
 | 
			
		||||
	6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
 | 
			
		||||
	84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
 | 
			
		||||
	43,
 | 
			
		||||
	249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
 | 
			
		||||
	71,
 | 
			
		||||
	230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
 | 
			
		||||
	109,
 | 
			
		||||
	44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
 | 
			
		||||
	163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
 | 
			
		||||
	209
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct hash_node *_create_node(const char *str)
 | 
			
		||||
@@ -55,7 +61,7 @@ static struct hash_node *_create_node(const char *str)
 | 
			
		||||
 | 
			
		||||
static unsigned _hash(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long int h = 0, g;
 | 
			
		||||
	unsigned long h = 0, g;
 | 
			
		||||
	while (*str) {
 | 
			
		||||
		h <<= 4;
 | 
			
		||||
		h += _nums[(int) *str++];
 | 
			
		||||
@@ -83,7 +89,7 @@ struct hash_table *hash_create(unsigned size_hint)
 | 
			
		||||
 | 
			
		||||
	/* round size hint up to a power of two */
 | 
			
		||||
	while (new_size < size_hint)
 | 
			
		||||
		new_size  = new_size << 1;
 | 
			
		||||
		new_size = new_size << 1;
 | 
			
		||||
 | 
			
		||||
	hc->num_slots = new_size;
 | 
			
		||||
	len = sizeof(*(hc->slots)) * new_size;
 | 
			
		||||
@@ -94,7 +100,7 @@ struct hash_table *hash_create(unsigned size_hint)
 | 
			
		||||
	memset(hc->slots, 0, len);
 | 
			
		||||
	return hc;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	dbg_free(hc->slots);
 | 
			
		||||
	dbg_free(hc);
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -124,8 +130,8 @@ static inline struct hash_node **_find(struct hash_table *t, const char *key)
 | 
			
		||||
	unsigned h = _hash(key) & (t->num_slots - 1);
 | 
			
		||||
	struct hash_node **c;
 | 
			
		||||
 | 
			
		||||
	for(c = &t->slots[h]; *c; c = &((*c)->next))
 | 
			
		||||
		if(!strcmp(key, (*c)->key))
 | 
			
		||||
	for (c = &t->slots[h]; *c; c = &((*c)->next))
 | 
			
		||||
		if (!strcmp(key, (*c)->key))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	return c;
 | 
			
		||||
@@ -141,7 +147,7 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct hash_node **c = _find(t, key);
 | 
			
		||||
 | 
			
		||||
	if(*c)
 | 
			
		||||
	if (*c)
 | 
			
		||||
		(*c)->data = data;
 | 
			
		||||
	else {
 | 
			
		||||
		struct hash_node *n = _create_node(key);
 | 
			
		||||
@@ -175,7 +181,7 @@ unsigned hash_get_num_entries(struct hash_table *t)
 | 
			
		||||
	return t->num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hash_iterate(struct hash_table *t, iterate_fn f)
 | 
			
		||||
void hash_iter(struct hash_table *t, iterate_fn f)
 | 
			
		||||
{
 | 
			
		||||
	struct hash_node *c;
 | 
			
		||||
	int i;
 | 
			
		||||
@@ -202,7 +208,7 @@ void *hash_get_data(struct hash_table *t, struct hash_node *n)
 | 
			
		||||
	return n->data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct hash_node *_next_slot(struct hash_table *t, unsigned int s)
 | 
			
		||||
static struct hash_node *_next_slot(struct hash_table *t, unsigned s)
 | 
			
		||||
{
 | 
			
		||||
	struct hash_node *c = NULL;
 | 
			
		||||
	int i;
 | 
			
		||||
@@ -220,7 +226,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
 | 
			
		||||
 | 
			
		||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int h = _hash(n->key) & (t->num_slots - 1);
 | 
			
		||||
	unsigned h = _hash(n->key) & (t->num_slots - 1);
 | 
			
		||||
	return n->next ? n->next : _next_slot(t, h + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,23 +10,27 @@
 | 
			
		||||
struct hash_table;
 | 
			
		||||
struct hash_node;
 | 
			
		||||
 | 
			
		||||
typedef void (*iterate_fn)(void *data);
 | 
			
		||||
typedef void (*iterate_fn) (void *data);
 | 
			
		||||
 | 
			
		||||
struct hash_table *hash_create(unsigned size_hint);
 | 
			
		||||
void hash_destroy(struct hash_table *t);
 | 
			
		||||
void hash_wipe(struct hash_table *t);
 | 
			
		||||
 | 
			
		||||
void *hash_lookup(struct hash_table *t, const char *key);
 | 
			
		||||
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
 | 
			
		||||
int hash_insert(struct hash_table *t, const char *key, void *data);
 | 
			
		||||
void hash_remove(struct hash_table *t, const char *key);
 | 
			
		||||
 | 
			
		||||
unsigned hash_get_num_entries(struct hash_table *t);
 | 
			
		||||
void hash_iterate(struct hash_table *t, iterate_fn f);
 | 
			
		||||
void hash_iter(struct hash_table *t, iterate_fn f);
 | 
			
		||||
 | 
			
		||||
char *hash_get_key(struct hash_table *t, struct hash_node *n);
 | 
			
		||||
void *hash_get_data(struct hash_table *t, struct hash_node *n);
 | 
			
		||||
struct hash_node *hash_get_first(struct hash_table *t);
 | 
			
		||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#define hash_iterate(v, h) \
 | 
			
		||||
	for (v = hash_get_first(h); v; \
 | 
			
		||||
	     v = hash_get_next(h, v))
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,15 @@ struct list {
 | 
			
		||||
	struct list *n, *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void list_init(struct list *head) {
 | 
			
		||||
#define LIST_INIT(name)	struct list name = { &(name), &(name) }
 | 
			
		||||
 | 
			
		||||
static inline void list_init(struct list *head)
 | 
			
		||||
{
 | 
			
		||||
	head->n = head->p = head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void list_add(struct list *head, struct list *elem) {
 | 
			
		||||
static inline void list_add(struct list *head, struct list *elem)
 | 
			
		||||
{
 | 
			
		||||
	assert(head->n);
 | 
			
		||||
 | 
			
		||||
	elem->n = head;
 | 
			
		||||
@@ -27,7 +31,8 @@ static inline void list_add(struct list *head, struct list *elem) {
 | 
			
		||||
	head->p = elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void list_add_h(struct list *head, struct list *elem) {
 | 
			
		||||
static inline void list_add_h(struct list *head, struct list *elem)
 | 
			
		||||
{
 | 
			
		||||
	assert(head->n);
 | 
			
		||||
 | 
			
		||||
	elem->n = head->n;
 | 
			
		||||
@@ -37,27 +42,43 @@ static inline void list_add_h(struct list *head, struct list *elem) {
 | 
			
		||||
	head->n = elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void list_del(struct list *elem) {
 | 
			
		||||
static inline void list_del(struct list *elem)
 | 
			
		||||
{
 | 
			
		||||
	elem->n->p = elem->p;
 | 
			
		||||
	elem->p->n = elem->n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int list_empty(struct list *head) {
 | 
			
		||||
static inline int list_empty(struct list *head)
 | 
			
		||||
{
 | 
			
		||||
	return head->n == head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int list_end(struct list *head, struct list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return elem->n == head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct list *list_next(struct list *head, struct list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return (list_end(head, elem) ? NULL : elem->n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define list_iterate(v, head) \
 | 
			
		||||
	for (v = (head)->n; v != head; v = v->n)
 | 
			
		||||
 | 
			
		||||
#define list_uniterate(v, head, start) \
 | 
			
		||||
	for (v = (start)->p; v != head; v = v->p)
 | 
			
		||||
 | 
			
		||||
#define list_iterate_safe(v, t, head) \
 | 
			
		||||
	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
 | 
			
		||||
 | 
			
		||||
static inline int list_size(struct list *head) {
 | 
			
		||||
	int s = 0;
 | 
			
		||||
	struct list *v;
 | 
			
		||||
static inline unsigned int list_size(const struct list *head)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int s = 0;
 | 
			
		||||
	const struct list *v;
 | 
			
		||||
 | 
			
		||||
	list_iterate(v, head)
 | 
			
		||||
		s++;
 | 
			
		||||
	    s++;
 | 
			
		||||
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
@@ -65,8 +86,14 @@ static inline int list_size(struct list *head) {
 | 
			
		||||
#define list_item(v, t) \
 | 
			
		||||
    ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
 | 
			
		||||
 | 
			
		||||
/* Given a known element in a known structure, locate the struct list */
 | 
			
		||||
#define list_head(v, t, e) \
 | 
			
		||||
    (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->list)
 | 
			
		||||
#define list_struct_base(v, t, h) \
 | 
			
		||||
    ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
 | 
			
		||||
 | 
			
		||||
/* Given a known element in a known structure, locate another */
 | 
			
		||||
#define struct_field(v, t, e, f) \
 | 
			
		||||
    (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
 | 
			
		||||
 | 
			
		||||
/* Given a known element in a known structure, locate the list head */
 | 
			
		||||
#define list_head(v, t, e) struct_field(v, t, e, list)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,12 @@
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
/* Define some portable printing types */
 | 
			
		||||
#define PRIsize_t "Zu"
 | 
			
		||||
 | 
			
		||||
struct str_list {
 | 
			
		||||
	struct list list;
 | 
			
		||||
	char *str;
 | 
			
		||||
	const char *str;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -4,27 +4,18 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "btree.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <linux/kdev_t.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME: really need to seperate names from the devices since
 | 
			
		||||
 * multiple names can point to the same device.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct dev_iter {
 | 
			
		||||
	struct btree_iter *current;
 | 
			
		||||
@@ -46,42 +37,168 @@ static struct {
 | 
			
		||||
 | 
			
		||||
} _cache;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define _alloc(x) pool_alloc(_cache.mem, (x))
 | 
			
		||||
#define _free(x) pool_free(_cache.mem, (x))
 | 
			
		||||
 | 
			
		||||
static int _insert(const char *path, int rec);
 | 
			
		||||
 | 
			
		||||
static struct device *_create_dev(dev_t d)
 | 
			
		||||
struct device *dev_create_file(const char *filename, struct device *dev,
 | 
			
		||||
			       struct str_list *alias)
 | 
			
		||||
{
 | 
			
		||||
	int allocate = !dev;
 | 
			
		||||
 | 
			
		||||
	if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
 | 
			
		||||
		log_error("struct device allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
 | 
			
		||||
		log_error("struct str_list allocation failed");
 | 
			
		||||
		dbg_free(dev);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(alias->str = dbg_strdup(filename))) {
 | 
			
		||||
		log_error("filename strdup failed");
 | 
			
		||||
		if (allocate) {
 | 
			
		||||
			dbg_free(dev);
 | 
			
		||||
			dbg_free(alias);
 | 
			
		||||
		}
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	dev->flags = DEV_REGULAR;
 | 
			
		||||
	if (allocate)
 | 
			
		||||
		dev->flags |= DEV_ALLOCED;
 | 
			
		||||
	list_init(&dev->aliases);
 | 
			
		||||
	list_add(&dev->aliases, &alias->list);
 | 
			
		||||
	dev->end = UINT64_C(0);
 | 
			
		||||
	dev->dev = 0;
 | 
			
		||||
	dev->fd = -1;
 | 
			
		||||
	dev->open_count = 0;
 | 
			
		||||
	memset(dev->pvid, 0, sizeof(dev->pvid));
 | 
			
		||||
	list_init(&dev->open_list);
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct device *_dev_create(dev_t d)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
 | 
			
		||||
	if (!(dev = _alloc(sizeof(*dev)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		log_error("struct device allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->flags = 0;
 | 
			
		||||
	list_init(&dev->aliases);
 | 
			
		||||
	dev->dev = d;
 | 
			
		||||
	dev->fd = -1;
 | 
			
		||||
	dev->open_count = 0;
 | 
			
		||||
	dev->end = UINT64_C(0);
 | 
			
		||||
	memset(dev->pvid, 0, sizeof(dev->pvid));
 | 
			
		||||
	list_init(&dev->open_list);
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return 1 if we prefer path1 else return 0 */
 | 
			
		||||
static int _compare_paths(const char *path0, const char *path1)
 | 
			
		||||
{
 | 
			
		||||
	int slash0 = 0, slash1 = 0;
 | 
			
		||||
	const char *p;
 | 
			
		||||
	char p0[PATH_MAX], p1[PATH_MAX];
 | 
			
		||||
	char *s0, *s1;
 | 
			
		||||
	struct stat stat0, stat1;
 | 
			
		||||
 | 
			
		||||
	/* Return the path with fewer slashes */
 | 
			
		||||
	for (p = path0; p++; p = (const char *) strchr(p, '/'))
 | 
			
		||||
		slash0++;
 | 
			
		||||
 | 
			
		||||
	for (p = path1; p++; p = (const char *) strchr(p, '/'))
 | 
			
		||||
		slash1++;
 | 
			
		||||
 | 
			
		||||
	if (slash0 < slash1)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (slash1 < slash0)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	strncpy(p0, path0, PATH_MAX);
 | 
			
		||||
	strncpy(p1, path1, PATH_MAX);
 | 
			
		||||
	s0 = &p0[0] + 1;
 | 
			
		||||
	s1 = &p1[0] + 1;
 | 
			
		||||
 | 
			
		||||
	/* We prefer symlinks - they exist for a reason!
 | 
			
		||||
	 * So we prefer a shorter path before the first symlink in the name.
 | 
			
		||||
	 * FIXME Configuration option to invert this? */
 | 
			
		||||
	while (s0) {
 | 
			
		||||
		s0 = strchr(s0, '/');
 | 
			
		||||
		s1 = strchr(s1, '/');
 | 
			
		||||
		if (s0) {
 | 
			
		||||
			*s0 = '\0';
 | 
			
		||||
			*s1 = '\0';
 | 
			
		||||
		}
 | 
			
		||||
		if (lstat(p0, &stat0)) {
 | 
			
		||||
			log_sys_error("lstat", p0);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		if (lstat(p1, &stat1)) {
 | 
			
		||||
			log_sys_error("lstat", p1);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
 | 
			
		||||
			return 0;
 | 
			
		||||
		if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
 | 
			
		||||
			return 1;
 | 
			
		||||
		if (s0) {
 | 
			
		||||
			*s0++ = '/';
 | 
			
		||||
			*s1++ = '/';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* ASCII comparison */
 | 
			
		||||
	if (strcmp(path0, path1) < 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
	else
 | 
			
		||||
		return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _add_alias(struct device *dev, const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct str_list *sl = _alloc(sizeof(*sl));
 | 
			
		||||
	struct list *ah;
 | 
			
		||||
	const char *oldpath;
 | 
			
		||||
	int prefer_old = 1;
 | 
			
		||||
 | 
			
		||||
	if (!sl) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Is name already there? */
 | 
			
		||||
	list_iterate(ah, &dev->aliases) {
 | 
			
		||||
		if (!strcmp(list_item(ah, struct str_list)->str, path)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(sl->str = pool_strdup(_cache.mem, path))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add(&dev->aliases, &sl->list);
 | 
			
		||||
	if (!list_empty(&dev->aliases)) {
 | 
			
		||||
		oldpath = list_item(dev->aliases.n, struct str_list)->str;
 | 
			
		||||
		prefer_old = _compare_paths(path, oldpath);
 | 
			
		||||
		log_debug("%s: Aliased to %s in device cache%s",
 | 
			
		||||
			  path, oldpath, prefer_old ? "" : " (preferred name)");
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		log_debug("%s: Added to device cache", path);
 | 
			
		||||
 | 
			
		||||
	if (prefer_old)
 | 
			
		||||
		list_add(&dev->aliases, &sl->list);
 | 
			
		||||
	else
 | 
			
		||||
		list_add_h(&dev->aliases, &sl->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -94,14 +211,15 @@ static int _insert_dev(const char *path, dev_t d)
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
 | 
			
		||||
	/* is this device already registered ? */
 | 
			
		||||
	if (!(dev = (struct device *) btree_lookup(_cache.devices, d))) {
 | 
			
		||||
	if (!(dev = (struct device *) btree_lookup(_cache.devices,
 | 
			
		||||
						   (uint32_t) d))) {
 | 
			
		||||
		/* create new device */
 | 
			
		||||
		if (!(dev = _create_dev(d))) {
 | 
			
		||||
		if (!(dev = _dev_create(d))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(btree_insert(_cache.devices, d, dev))) {
 | 
			
		||||
		if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
 | 
			
		||||
			log_err("Couldn't insert device into binary tree.");
 | 
			
		||||
			_free(dev);
 | 
			
		||||
			return 0;
 | 
			
		||||
@@ -123,7 +241,7 @@ static int _insert_dev(const char *path, dev_t d)
 | 
			
		||||
 | 
			
		||||
static char *_join(const char *dir, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int len = strlen(dir) + strlen(name) + 2;
 | 
			
		||||
	size_t len = strlen(dir) + strlen(name) + 2;
 | 
			
		||||
	char *r = dbg_malloc(len);
 | 
			
		||||
	if (r)
 | 
			
		||||
		snprintf(r, len, "%s/%s", dir, name);
 | 
			
		||||
@@ -194,7 +312,7 @@ static int _insert(const char *path, int rec)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (S_ISDIR(info.st_mode)) { /* add a directory */
 | 
			
		||||
	if (S_ISDIR(info.st_mode)) {	/* add a directory */
 | 
			
		||||
		if (rec)
 | 
			
		||||
			r = _insert_dir(path);
 | 
			
		||||
 | 
			
		||||
@@ -230,6 +348,21 @@ static void _full_scan(void)
 | 
			
		||||
	_cache.has_scanned = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_cache_has_scanned(void)
 | 
			
		||||
{
 | 
			
		||||
	return _cache.has_scanned;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dev_cache_scan(int do_scan)
 | 
			
		||||
{
 | 
			
		||||
	if (!do_scan)
 | 
			
		||||
		_cache.has_scanned = 1;
 | 
			
		||||
	else {
 | 
			
		||||
		_cache.has_scanned = 0;
 | 
			
		||||
		_full_scan();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_cache_init(void)
 | 
			
		||||
{
 | 
			
		||||
	_cache.names = NULL;
 | 
			
		||||
@@ -255,12 +388,12 @@ int dev_cache_init(void)
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	dev_cache_exit();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _check_closed(struct device *dev)
 | 
			
		||||
static void _check_closed(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->fd >= 0)
 | 
			
		||||
		log_err("Device '%s' has been left open.", dev_name(dev));
 | 
			
		||||
@@ -268,7 +401,7 @@ void _check_closed(struct device *dev)
 | 
			
		||||
 | 
			
		||||
static inline void _check_for_open_devices(void)
 | 
			
		||||
{
 | 
			
		||||
	hash_iterate(_cache.names, (iterate_fn)_check_closed);
 | 
			
		||||
	hash_iter(_cache.names, (iterate_fn) _check_closed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dev_cache_exit(void)
 | 
			
		||||
@@ -296,8 +429,10 @@ int dev_cache_add_dir(const char *path)
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1)))
 | 
			
		||||
	if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
 | 
			
		||||
		log_error("dir_list allocation failed");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	strcpy(dl->dir, path);
 | 
			
		||||
	list_add(&_cache.dirs, &dl->list);
 | 
			
		||||
@@ -306,20 +441,31 @@ int dev_cache_add_dir(const char *path)
 | 
			
		||||
 | 
			
		||||
/* Check cached device name is still valid before returning it */
 | 
			
		||||
/* This should be a rare occurrence */
 | 
			
		||||
/* set quiet if the cache is expected to be out-of-date */
 | 
			
		||||
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
 | 
			
		||||
const char *dev_name_confirmed(struct device *dev)
 | 
			
		||||
const char *dev_name_confirmed(struct device *dev, int quiet)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	char *name;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	while ((r = stat(name = list_item(dev->aliases.n, 
 | 
			
		||||
					   struct str_list)->str, &buf)) || 
 | 
			
		||||
	while ((r = stat(name = list_item(dev->aliases.n,
 | 
			
		||||
					  struct str_list)->str, &buf)) ||
 | 
			
		||||
	       (buf.st_rdev != dev->dev)) {
 | 
			
		||||
		if (r < 0)
 | 
			
		||||
			log_sys_error("stat", name);
 | 
			
		||||
		log_error("Path %s no longer valid for device(%d,%d)",
 | 
			
		||||
			  name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev));
 | 
			
		||||
		if (r < 0) {
 | 
			
		||||
			if (quiet)
 | 
			
		||||
				log_sys_debug("stat", name);
 | 
			
		||||
			else
 | 
			
		||||
				log_sys_error("stat", name);
 | 
			
		||||
		}
 | 
			
		||||
		if (quiet)
 | 
			
		||||
			log_debug("Path %s no longer valid for device(%d,%d)",
 | 
			
		||||
			  	  name, (int) MAJOR(dev->dev),
 | 
			
		||||
				  (int) MINOR(dev->dev));
 | 
			
		||||
		else
 | 
			
		||||
			log_error("Path %s no longer valid for device(%d,%d)",
 | 
			
		||||
				  name, (int) MAJOR(dev->dev),
 | 
			
		||||
				  (int) MINOR(dev->dev));
 | 
			
		||||
 | 
			
		||||
		/* Remove the incorrect hash entry */
 | 
			
		||||
		hash_remove(_cache.names, name);
 | 
			
		||||
@@ -342,7 +488,6 @@ const char *dev_name_confirmed(struct device *dev)
 | 
			
		||||
	return dev_name(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
@@ -366,8 +511,10 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_iter *di = dbg_malloc(sizeof(*di));
 | 
			
		||||
 | 
			
		||||
	if (!di)
 | 
			
		||||
	if (!di) {
 | 
			
		||||
		log_error("dev_iter allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_full_scan();
 | 
			
		||||
	di->current = btree_first(_cache.devices);
 | 
			
		||||
@@ -399,4 +546,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#ifndef _LVM_DEV_CACHE_H
 | 
			
		||||
#define _LVM_DEV_CACHE_H
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
 | 
			
		||||
@@ -15,22 +14,24 @@
 | 
			
		||||
 * predicate for devices.
 | 
			
		||||
 */
 | 
			
		||||
struct dev_filter {
 | 
			
		||||
	int (*passes_filter)(struct dev_filter *f, struct device *dev);
 | 
			
		||||
	void (*destroy)(struct dev_filter *f);
 | 
			
		||||
	int (*passes_filter) (struct dev_filter * f, struct device * dev);
 | 
			
		||||
	void (*destroy) (struct dev_filter * f);
 | 
			
		||||
	void *private;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The global device cache.
 | 
			
		||||
 */
 | 
			
		||||
int dev_cache_init(void);
 | 
			
		||||
void dev_cache_exit(void);
 | 
			
		||||
 | 
			
		||||
/* Trigger(1) or avoid(0) a scan */
 | 
			
		||||
void dev_cache_scan(int do_scan);
 | 
			
		||||
int dev_cache_has_scanned(void);
 | 
			
		||||
 | 
			
		||||
int dev_cache_add_dir(const char *path);
 | 
			
		||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Object for iterating through the cache.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -4,21 +4,206 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "device.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <linux/fs.h> // UGH!!! for BLKSSZGET
 | 
			
		||||
 | 
			
		||||
#ifdef linux
 | 
			
		||||
#  define u64 uint64_t		/* Missing without __KERNEL__ */
 | 
			
		||||
#  undef WNOHANG		/* Avoid redefinition */
 | 
			
		||||
#  undef WUNTRACED		/* Avoid redefinition */
 | 
			
		||||
#  include <linux/fs.h>		/* For block ioctl definitions */
 | 
			
		||||
#  define BLKSIZE_SHIFT SECTOR_SHIFT
 | 
			
		||||
#else
 | 
			
		||||
#  include <sys/disk.h>
 | 
			
		||||
#  define BLKBSZGET DKIOCGETBLOCKSIZE
 | 
			
		||||
#  define BLKSSZGET DKIOCGETBLOCKSIZE
 | 
			
		||||
#  define BLKGETSIZE64 DKIOCGETBLOCKCOUNT
 | 
			
		||||
#  define BLKFLSBUF DKIOCSYNCHRONIZECACHE
 | 
			
		||||
#  define BLKSIZE_SHIFT 0
 | 
			
		||||
#  ifndef O_DIRECT
 | 
			
		||||
#    define O_DIRECT	0
 | 
			
		||||
#  endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* FIXME Use _llseek for 64-bit
 | 
			
		||||
_syscall5(int,  _llseek,  uint,  fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
 | 
			
		||||
 if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) { 
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static LIST_INIT(_open_devices);
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------
 | 
			
		||||
 * The standard io loop that keeps submitting an io until it's
 | 
			
		||||
 * all gone.
 | 
			
		||||
 *---------------------------------------------------------------*/
 | 
			
		||||
static int _io(struct device_area *where, void *buffer, int should_write)
 | 
			
		||||
{
 | 
			
		||||
	int fd = dev_fd(where->dev);
 | 
			
		||||
	ssize_t n = 0;
 | 
			
		||||
	size_t total = 0;
 | 
			
		||||
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		log_error("Attempt to read an unopened device (%s).",
 | 
			
		||||
			  dev_name(where->dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Skip all writes in test mode.
 | 
			
		||||
	 */
 | 
			
		||||
	if (should_write && test_mode())
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (where->size > SSIZE_MAX) {
 | 
			
		||||
		log_error("Read size too large: %" PRIu64, where->size);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) {
 | 
			
		||||
		log_sys_error("lseek", dev_name(where->dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (total < (size_t) where->size) {
 | 
			
		||||
		do
 | 
			
		||||
			n = should_write ?
 | 
			
		||||
			    write(fd, buffer, (size_t) where->size - total) :
 | 
			
		||||
			    read(fd, buffer, (size_t) where->size - total);
 | 
			
		||||
		while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
 | 
			
		||||
 | 
			
		||||
		if (n <= 0)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		total += n;
 | 
			
		||||
		buffer += n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (total == (size_t) where->size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------
 | 
			
		||||
 * LVM2 uses O_DIRECT when performing metadata io, which requires
 | 
			
		||||
 * block size aligned accesses.  If any io is not aligned we have
 | 
			
		||||
 * to perform the io via a bounce buffer, obviously this is quite
 | 
			
		||||
 * inefficient.
 | 
			
		||||
 *---------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Get the sector size from an _open_ device.
 | 
			
		||||
 */
 | 
			
		||||
static int _get_block_size(struct device *dev, unsigned int *size)
 | 
			
		||||
{
 | 
			
		||||
	int s;
 | 
			
		||||
 | 
			
		||||
	if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) {
 | 
			
		||||
		log_sys_error("ioctl BLKBSZGET", dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*size = (unsigned int) s;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Widens a region to be an aligned region.
 | 
			
		||||
 */
 | 
			
		||||
static void _widen_region(unsigned int block_size, struct device_area *region,
 | 
			
		||||
			  struct device_area *result)
 | 
			
		||||
{
 | 
			
		||||
	uint64_t mask = block_size - 1, delta;
 | 
			
		||||
	memcpy(result, region, sizeof(*result));
 | 
			
		||||
 | 
			
		||||
	/* adjust the start */
 | 
			
		||||
	delta = result->start & mask;
 | 
			
		||||
	if (delta) {
 | 
			
		||||
		result->start -= delta;
 | 
			
		||||
		result->size += delta;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* adjust the end */
 | 
			
		||||
	delta = (result->start + result->size) & mask;
 | 
			
		||||
	if (delta)
 | 
			
		||||
		result->size += block_size - delta;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _aligned_io(struct device_area *where, void *buffer,
 | 
			
		||||
		       int should_write)
 | 
			
		||||
{
 | 
			
		||||
	void *bounce;
 | 
			
		||||
	unsigned int block_size = 0;
 | 
			
		||||
	uintptr_t mask;
 | 
			
		||||
	struct device_area widened;
 | 
			
		||||
 | 
			
		||||
	if (!(where->dev->flags & DEV_REGULAR) &&
 | 
			
		||||
	    !_get_block_size(where->dev, &block_size)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!block_size)
 | 
			
		||||
		block_size = SECTOR_SIZE * 2;
 | 
			
		||||
 | 
			
		||||
	_widen_region(block_size, where, &widened);
 | 
			
		||||
 | 
			
		||||
	/* Do we need to use a bounce buffer? */
 | 
			
		||||
	mask = block_size - 1;
 | 
			
		||||
	if (!memcmp(where, &widened, sizeof(widened)) &&
 | 
			
		||||
	    !((uintptr_t) buffer & mask))
 | 
			
		||||
		return _io(where, buffer, should_write);
 | 
			
		||||
 | 
			
		||||
	/* Allocate a bounce buffer with an extra block */
 | 
			
		||||
	if (!(bounce = alloca((size_t) widened.size + block_size))) {
 | 
			
		||||
		log_error("Bounce buffer alloca failed");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Realign start of bounce buffer (using the extra sector)
 | 
			
		||||
	 */
 | 
			
		||||
	if (((uintptr_t) bounce) & mask)
 | 
			
		||||
		bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask);
 | 
			
		||||
 | 
			
		||||
	/* channel the io through the bounce buffer */
 | 
			
		||||
	if (!_io(&widened, bounce, 0)) {
 | 
			
		||||
		if (!should_write) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		/* FIXME pre-extend the file */
 | 
			
		||||
		memset(bounce, '\n', widened.size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (should_write) {
 | 
			
		||||
		memcpy(bounce + (where->start - widened.start), buffer,
 | 
			
		||||
		       (size_t) where->size);
 | 
			
		||||
 | 
			
		||||
		/* ... then we write */
 | 
			
		||||
		return _io(&widened, bounce, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(buffer, bounce + (where->start - widened.start),
 | 
			
		||||
	       (size_t) where->size);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------
 | 
			
		||||
 * Public functions
 | 
			
		||||
 *---------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
int dev_get_size(struct device *dev, uint64_t *size)
 | 
			
		||||
{
 | 
			
		||||
	int fd;
 | 
			
		||||
	long s;
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Getting size of %s", name);
 | 
			
		||||
@@ -27,15 +212,14 @@ int dev_get_size(struct device *dev, uint64_t *size)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: add 64 bit ioctl */
 | 
			
		||||
	if (ioctl(fd, BLKGETSIZE, &s) < 0) {
 | 
			
		||||
		log_sys_error("ioctl BLKGETSIZE", name);
 | 
			
		||||
	if (ioctl(fd, BLKGETSIZE64, size) < 0) {
 | 
			
		||||
		log_sys_error("ioctl BLKGETSIZE64", name);
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*size >>= BLKSIZE_SHIFT;	/* Convert to sectors */
 | 
			
		||||
	close(fd);
 | 
			
		||||
	*size = (uint64_t) s;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -62,40 +246,106 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_open(struct device *dev, int flags)
 | 
			
		||||
void dev_flush(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (fsync(dev->fd) >= 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	sync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	const char *name = dev_name_confirmed(dev);
 | 
			
		||||
	const char *name;
 | 
			
		||||
 | 
			
		||||
	if (!name) {
 | 
			
		||||
	if (dev->fd >= 0) {
 | 
			
		||||
		dev->open_count++;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (memlock())
 | 
			
		||||
		log_error("WARNING: dev_open(%s) called while suspended",
 | 
			
		||||
			  dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	if (dev->flags & DEV_REGULAR)
 | 
			
		||||
		name = dev_name(dev);
 | 
			
		||||
	else if (!(name = dev_name_confirmed(dev, quiet))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dev->fd >= 0) {
 | 
			
		||||
		log_error("Device '%s' has already been opened", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) {
 | 
			
		||||
	if (!(dev->flags & DEV_REGULAR) &&
 | 
			
		||||
	    ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) {
 | 
			
		||||
		log_error("%s: stat failed: Has device name changed?", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((dev->fd = open(name, flags)) < 0) {
 | 
			
		||||
	if (direct)
 | 
			
		||||
		flags |= O_DIRECT;
 | 
			
		||||
 | 
			
		||||
	if ((dev->fd = open(name, flags, 0777)) < 0) {
 | 
			
		||||
		log_sys_error("open", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) {
 | 
			
		||||
	dev->open_count = 1;
 | 
			
		||||
	dev->flags &= ~DEV_ACCESSED_W;
 | 
			
		||||
 | 
			
		||||
	if (!(dev->flags & DEV_REGULAR) &&
 | 
			
		||||
	    ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
 | 
			
		||||
		log_error("%s: fstat failed: Has device name changed?", name);
 | 
			
		||||
		dev_close(dev);
 | 
			
		||||
		dev->fd = -1;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
#if !O_DIRECT
 | 
			
		||||
	if (!(dev->flags & DEV_REGULAR))
 | 
			
		||||
		dev_flush(dev);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if ((flags & O_CREAT) && !(flags & O_TRUNC)) {
 | 
			
		||||
		dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add(&_open_devices, &dev->open_list);
 | 
			
		||||
	log_debug("Opened %s", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_open_quiet(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME Open O_RDONLY if vg read lock? */
 | 
			
		||||
	return dev_open_flags(dev, O_RDWR, 1, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_open(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME Open O_RDONLY if vg read lock? */
 | 
			
		||||
	return dev_open_flags(dev, O_RDWR, 1, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _close(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (close(dev->fd))
 | 
			
		||||
		log_sys_error("close", dev_name(dev));
 | 
			
		||||
	dev->fd = -1;
 | 
			
		||||
	list_del(&dev->open_list);
 | 
			
		||||
 | 
			
		||||
	log_debug("Closed %s", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	if (dev->flags & DEV_ALLOCED) {
 | 
			
		||||
		dbg_free((void *) list_item(dev->aliases.n, struct str_list)->
 | 
			
		||||
			 str);
 | 
			
		||||
		dbg_free(dev->aliases.n);
 | 
			
		||||
		dbg_free(dev);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_close(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->fd < 0) {
 | 
			
		||||
@@ -103,133 +353,115 @@ int dev_close(struct device *dev)
 | 
			
		||||
			  "which is not open.", dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
#if !O_DIRECT
 | 
			
		||||
	if (dev->flags & DEV_ACCESSED_W)
 | 
			
		||||
		dev_flush(dev);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (close(dev->fd))
 | 
			
		||||
		log_sys_error("close", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	dev->fd = -1;
 | 
			
		||||
	/* FIXME lookup device in cache to get vgname and see if it's locked? */
 | 
			
		||||
	if (--dev->open_count < 1 && !vgs_locked())
 | 
			
		||||
		_close(dev);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  FIXME: factor common code out.
 | 
			
		||||
void dev_close_all(void)
 | 
			
		||||
{
 | 
			
		||||
	struct list *doh, *doht;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(doh, doht, &_open_devices) {
 | 
			
		||||
		dev = list_struct_base(doh, struct device, open_list);
 | 
			
		||||
		if (dev->open_count < 1)
 | 
			
		||||
			_close(dev);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	struct device_area where;
 | 
			
		||||
 | 
			
		||||
	if (!dev->open_count)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	where.dev = dev;
 | 
			
		||||
	where.start = offset;
 | 
			
		||||
	where.size = len;
 | 
			
		||||
 | 
			
		||||
	return _aligned_io(&where, buffer, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
 | 
			
		||||
 *       But fails if concurrent processes writing
 | 
			
		||||
 */
 | 
			
		||||
int _read(int fd, void *buf, size_t count)
 | 
			
		||||
 | 
			
		||||
/* FIXME pre-extend the file */
 | 
			
		||||
int dev_append(struct device *dev, size_t len, void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	size_t n = 0;
 | 
			
		||||
	int tot = 0;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	while (tot < count) {
 | 
			
		||||
		do
 | 
			
		||||
			n = read(fd, buf, count - tot);
 | 
			
		||||
		while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
 | 
			
		||||
	if (!dev->open_count)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
		if (n <= 0)
 | 
			
		||||
			return tot ? tot : n;
 | 
			
		||||
	r = dev_write(dev, dev->end, len, buffer);
 | 
			
		||||
	dev->end += (uint64_t) len;
 | 
			
		||||
 | 
			
		||||
		tot += n;
 | 
			
		||||
		buf += n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tot;
 | 
			
		||||
#if !O_DIRECT
 | 
			
		||||
	dev_flush(dev);
 | 
			
		||||
#endif
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t dev_read(struct device *dev, uint64_t offset,
 | 
			
		||||
		 int64_t len, void *buffer)
 | 
			
		||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
	int fd = dev->fd;
 | 
			
		||||
	struct device_area where;
 | 
			
		||||
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		log_err("Attempt to read an unopened device (%s).", name);
 | 
			
		||||
	if (!dev->open_count)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lseek(fd, offset, SEEK_SET) < 0) {
 | 
			
		||||
		log_sys_error("lseek", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	where.dev = dev;
 | 
			
		||||
	where.start = offset;
 | 
			
		||||
	where.size = len;
 | 
			
		||||
 | 
			
		||||
	return _read(fd, buffer, len);
 | 
			
		||||
	dev->flags |= DEV_ACCESSED_W;
 | 
			
		||||
 | 
			
		||||
	return _aligned_io(&where, buffer, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _write(int fd, const void *buf, size_t count)
 | 
			
		||||
int dev_zero(struct device *dev, uint64_t offset, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	size_t n = 0;
 | 
			
		||||
	int tot = 0;
 | 
			
		||||
 | 
			
		||||
	/* Skip all writes */
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
		return count;
 | 
			
		||||
 | 
			
		||||
	while (tot < count) {
 | 
			
		||||
		do
 | 
			
		||||
			n = write(fd, buf, count - tot);
 | 
			
		||||
		while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
 | 
			
		||||
 | 
			
		||||
		if (n <= 0)
 | 
			
		||||
			return tot ? tot : n;
 | 
			
		||||
 | 
			
		||||
		tot += n;
 | 
			
		||||
		buf += n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t dev_write(struct device *dev, uint64_t offset,
 | 
			
		||||
		  int64_t len, void *buffer)
 | 
			
		||||
{
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
	int fd = dev->fd;
 | 
			
		||||
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		log_error("Attempt to write to unopened device %s", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lseek(fd, offset, SEEK_SET) < 0) {
 | 
			
		||||
		log_sys_error("lseek", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return _write(fd, buffer, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len)
 | 
			
		||||
{
 | 
			
		||||
	int64_t r, s;
 | 
			
		||||
	size_t s;
 | 
			
		||||
	char buffer[4096];
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
	int fd = dev->fd;
 | 
			
		||||
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		log_error("Attempt to zero part of an unopened device %s",
 | 
			
		||||
			  name);
 | 
			
		||||
	if (!dev_open(dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lseek(fd, offset, SEEK_SET) < 0) {
 | 
			
		||||
		log_sys_error("lseek", name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
 | 
			
		||||
		log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t,
 | 
			
		||||
			  dev_name(dev), offset, len);
 | 
			
		||||
	else
 | 
			
		||||
		log_debug("Wiping %s at sector %" PRIu64 " length %" PRIsize_t
 | 
			
		||||
			  " sectors", dev_name(dev), offset >> SECTOR_SHIFT,
 | 
			
		||||
			  len >> SECTOR_SHIFT);
 | 
			
		||||
 | 
			
		||||
	memset(buffer, 0, sizeof(buffer));
 | 
			
		||||
	while (1) {
 | 
			
		||||
		s = len > sizeof(buffer) ? sizeof(buffer) : len;
 | 
			
		||||
		r = _write(fd, buffer, s);
 | 
			
		||||
 | 
			
		||||
		if (r <= 0)
 | 
			
		||||
		if (!dev_write(dev, offset, s, buffer))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		len -= r;
 | 
			
		||||
		if (!len) {
 | 
			
		||||
			r = 1;
 | 
			
		||||
		len -= s;
 | 
			
		||||
		if (!len)
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->flags |= DEV_ACCESSED_W;
 | 
			
		||||
 | 
			
		||||
	if (!dev_close(dev))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: Always display error */
 | 
			
		||||
	return (len == 0);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,16 +17,19 @@
 | 
			
		||||
 * MA 02111-1307, USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#if 0
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <linux/fs.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
#include <linux/genhd.h>
 | 
			
		||||
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
@@ -34,13 +37,6 @@
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
 | 
			
		||||
#include <linux/fs.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
#include <linux/genhd.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
int _get_partition_type(struct dev_filter *filter, struct device *d);
 | 
			
		||||
 | 
			
		||||
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
 | 
			
		||||
 
 | 
			
		||||
@@ -7,19 +7,29 @@
 | 
			
		||||
#ifndef _LVM_DEVICE_H
 | 
			
		||||
#define _LVM_DEVICE_H
 | 
			
		||||
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#define DEV_ACCESSED_W		0x00000001	/* Device written to? */
 | 
			
		||||
#define DEV_REGULAR		0x00000002	/* Regular file? */
 | 
			
		||||
#define DEV_ALLOCED		0x00000004	/* dbg_malloc used */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * All devices in LVM will be represented by one of these.
 | 
			
		||||
 * pointer comparisons are valid.
 | 
			
		||||
 */
 | 
			
		||||
struct device {
 | 
			
		||||
	struct list aliases; /* struct str_list from lvm-types.h */
 | 
			
		||||
	struct list aliases;	/* struct str_list from lvm-types.h */
 | 
			
		||||
	dev_t dev;
 | 
			
		||||
 | 
			
		||||
	/* private */
 | 
			
		||||
	int fd;
 | 
			
		||||
	int open_count;
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	uint64_t end;
 | 
			
		||||
	struct list open_list;
 | 
			
		||||
 | 
			
		||||
	char pvid[ID_LEN + 1];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct device_list {
 | 
			
		||||
@@ -27,32 +37,57 @@ struct device_list {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct device_area {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	uint64_t start;		/* Bytes */
 | 
			
		||||
	uint64_t size;		/* Bytes */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * All io should use these routines.
 | 
			
		||||
 */
 | 
			
		||||
int dev_get_size(struct device *dev, uint64_t *size);
 | 
			
		||||
int dev_get_sectsize(struct device *dev, uint32_t *size);
 | 
			
		||||
 | 
			
		||||
int dev_open(struct device *dev, int flags);
 | 
			
		||||
/* Use quiet version if device number could change e.g. when opening LV */
 | 
			
		||||
int dev_open(struct device *dev);
 | 
			
		||||
int dev_open_quiet(struct device *dev);
 | 
			
		||||
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
 | 
			
		||||
int dev_close(struct device *dev);
 | 
			
		||||
void dev_close_all(void);
 | 
			
		||||
 | 
			
		||||
int64_t dev_read(struct device *dev,
 | 
			
		||||
		 uint64_t offset, int64_t len, void *buffer);
 | 
			
		||||
int64_t dev_write(struct device *dev,
 | 
			
		||||
		  uint64_t offset, int64_t len, void *buffer);
 | 
			
		||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
 | 
			
		||||
static inline int dev_fd(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return dev->fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
 | 
			
		||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
 | 
			
		||||
int dev_append(struct device *dev, size_t len, void *buffer);
 | 
			
		||||
int dev_zero(struct device *dev, uint64_t offset, size_t len);
 | 
			
		||||
void dev_flush(struct device *dev);
 | 
			
		||||
 | 
			
		||||
static inline const char *dev_name(struct device *dev) {
 | 
			
		||||
	return list_item(dev->aliases.n, struct str_list)->str;
 | 
			
		||||
struct device *dev_create_file(const char *filename, struct device *dev,
 | 
			
		||||
			       struct str_list *alias);
 | 
			
		||||
 | 
			
		||||
static inline const char *dev_name(const struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
 | 
			
		||||
	    "unknown device";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return a valid device name from the alias list; NULL otherwise */
 | 
			
		||||
const char *dev_name_confirmed(struct device *dev);
 | 
			
		||||
const char *dev_name_confirmed(struct device *dev, int quiet);
 | 
			
		||||
 | 
			
		||||
static inline int is_lvm_partition(const char *name) {
 | 
			
		||||
/* FIXME Check partition type if appropriate */
 | 
			
		||||
 | 
			
		||||
#define is_lvm_partition(a) 1
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
static inline int is_lvm_partition(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,47 +18,206 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
 | 
			
		||||
#define SIZE_BUF 128
 | 
			
		||||
 | 
			
		||||
char *display_size(unsigned long long size, size_len_t sl)
 | 
			
		||||
static struct {
 | 
			
		||||
	alloc_policy_t alloc;
 | 
			
		||||
	const char *str;
 | 
			
		||||
} _policies[] = {
 | 
			
		||||
	{
 | 
			
		||||
	ALLOC_NEXT_FREE, "next free"}, {
 | 
			
		||||
	ALLOC_CONTIGUOUS, "contiguous"}, {
 | 
			
		||||
	ALLOC_DEFAULT, "next free (default)"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	segment_type_t segtype;
 | 
			
		||||
	const char *str;
 | 
			
		||||
} _segtypes[] = {
 | 
			
		||||
	{
 | 
			
		||||
	SEG_STRIPED, "striped"}, {
 | 
			
		||||
	SEG_MIRRORED, "mirror"}, {
 | 
			
		||||
	SEG_SNAPSHOT, "snapshot"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
 | 
			
		||||
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
 | 
			
		||||
 | 
			
		||||
uint64_t units_to_bytes(const char *units, char *unit_type)
 | 
			
		||||
{
 | 
			
		||||
	char *ptr = NULL;
 | 
			
		||||
	uint64_t v;
 | 
			
		||||
 | 
			
		||||
	if (isdigit(*units)) {
 | 
			
		||||
		v = (uint64_t) strtod(units, &ptr);
 | 
			
		||||
		if (ptr == units)
 | 
			
		||||
			return 0;
 | 
			
		||||
		units = ptr;
 | 
			
		||||
	} else
 | 
			
		||||
		v = 1;
 | 
			
		||||
 | 
			
		||||
	if (v == 1)
 | 
			
		||||
		*unit_type = *units;
 | 
			
		||||
	else
 | 
			
		||||
		*unit_type = 'U';
 | 
			
		||||
 | 
			
		||||
	switch (*units) {
 | 
			
		||||
	case 'h':
 | 
			
		||||
	case 'H':
 | 
			
		||||
		v = UINT64_C(1);
 | 
			
		||||
		*unit_type = *units;
 | 
			
		||||
		break;
 | 
			
		||||
	case 's':
 | 
			
		||||
		v *= SECTOR_SIZE;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'b':
 | 
			
		||||
	case 'B':
 | 
			
		||||
		v *= UINT64_C(1);
 | 
			
		||||
		break;
 | 
			
		||||
#define KILO UINT64_C(1024)
 | 
			
		||||
	case 'k':
 | 
			
		||||
		v *= KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'm':
 | 
			
		||||
		v *= KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'g':
 | 
			
		||||
		v *= KILO * KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 't':
 | 
			
		||||
		v *= KILO * KILO * KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
#undef KILO
 | 
			
		||||
#define KILO UINT64_C(1000)
 | 
			
		||||
	case 'K':
 | 
			
		||||
		v *= KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'M':
 | 
			
		||||
		v *= KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'G':
 | 
			
		||||
		v *= KILO * KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
	case 'T':
 | 
			
		||||
		v *= KILO * KILO * KILO * KILO;
 | 
			
		||||
		break;
 | 
			
		||||
#undef KILO
 | 
			
		||||
	default:
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*(units + 1))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *get_alloc_string(alloc_policy_t alloc)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _num_policies; i++)
 | 
			
		||||
		if (_policies[i].alloc == alloc)
 | 
			
		||||
			return _policies[i].str;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *get_segtype_string(segment_type_t segtype)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _num_segtypes; i++)
 | 
			
		||||
		if (_segtypes[i].segtype == segtype)
 | 
			
		||||
			return _segtypes[i].str;
 | 
			
		||||
 | 
			
		||||
	return "unknown";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
alloc_policy_t get_alloc_from_string(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _num_policies; i++)
 | 
			
		||||
		if (!strcmp(_policies[i].str, str))
 | 
			
		||||
			return _policies[i].alloc;
 | 
			
		||||
 | 
			
		||||
	log_error("Unrecognised allocation policy - using default");
 | 
			
		||||
	return ALLOC_DEFAULT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
segment_type_t get_segtype_from_string(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _num_segtypes; i++)
 | 
			
		||||
		if (!strcmp(_segtypes[i].str, str))
 | 
			
		||||
			return _segtypes[i].segtype;
 | 
			
		||||
 | 
			
		||||
	log_error("Unrecognised segment type - using default (striped)");
 | 
			
		||||
	return SEG_STRIPED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
 | 
			
		||||
{
 | 
			
		||||
	int s;
 | 
			
		||||
	ulong byte = 1024 * 1024 * 1024;
 | 
			
		||||
	int suffix = 1;
 | 
			
		||||
	uint64_t byte = UINT64_C(0);
 | 
			
		||||
	uint64_t units = UINT64_C(1024);
 | 
			
		||||
	char *size_buf = NULL;
 | 
			
		||||
	char *size_str[][2] = {
 | 
			
		||||
		{"Terabyte", "TB"},
 | 
			
		||||
		{"Gigabyte", "GB"},
 | 
			
		||||
		{"Megabyte", "MB"},
 | 
			
		||||
		{"Kilobyte", "KB"},
 | 
			
		||||
		{"", ""}
 | 
			
		||||
	const char *size_str[][3] = {
 | 
			
		||||
		{" Terabyte", " TB", "T"},
 | 
			
		||||
		{" Gigabyte", " GB", "G"},
 | 
			
		||||
		{" Megabyte", " MB", "M"},
 | 
			
		||||
		{" Kilobyte", " KB", "K"},
 | 
			
		||||
		{"", "", ""},
 | 
			
		||||
		{" Byte    ", " B ", "B"},
 | 
			
		||||
		{" Units   ", " Un", "U"},
 | 
			
		||||
		{" Sectors ", " Se", "S"},
 | 
			
		||||
		{"         ", "   ", " "},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (!(size_buf = dbg_malloc(SIZE_BUF))) {
 | 
			
		||||
	if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
 | 
			
		||||
		log_error("no memory for size display buffer");
 | 
			
		||||
		return NULL;
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (size == 0LL)
 | 
			
		||||
		sprintf(size_buf, "0");
 | 
			
		||||
	else {
 | 
			
		||||
	suffix = cmd->current_settings.suffix;
 | 
			
		||||
 | 
			
		||||
	for (s = 0; s < 8; s++)
 | 
			
		||||
		if (toupper((int) cmd->current_settings.unit_type) ==
 | 
			
		||||
		    *size_str[s][2])
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	if (size == UINT64_C(0)) {
 | 
			
		||||
		sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
 | 
			
		||||
		return size_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (s < 8) {
 | 
			
		||||
		byte = cmd->current_settings.unit_factor;
 | 
			
		||||
		size *= UINT64_C(1024);
 | 
			
		||||
	} else {
 | 
			
		||||
		suffix = 1;
 | 
			
		||||
		if (cmd->current_settings.unit_type == 'H')
 | 
			
		||||
			units = UINT64_C(1000);
 | 
			
		||||
		else
 | 
			
		||||
			units = UINT64_C(1024);
 | 
			
		||||
		byte = units * units * units;
 | 
			
		||||
		s = 0;
 | 
			
		||||
		while (size_str[s] && size < byte)
 | 
			
		||||
			s++, byte /= 1024;
 | 
			
		||||
		snprintf(size_buf, SIZE_BUF - 1,
 | 
			
		||||
			 "%.2f %s", (float) size / byte, size_str[s][sl]);
 | 
			
		||||
			s++, byte /= units;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Caller to deallocate */
 | 
			
		||||
	snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
 | 
			
		||||
		 suffix ? size_str[s][sl] : "");
 | 
			
		||||
 | 
			
		||||
	return size_buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -74,26 +233,28 @@ void pvdisplay_colons(struct physical_volume *pv)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu64 ":%u:%u:%u:%s",
 | 
			
		||||
	log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu32 ":%u:%u:%u:%s",
 | 
			
		||||
		  dev_name(pv->dev), pv->vg_name, pv->size,
 | 
			
		||||
		  /* FIXME pv->pv_number, Derive or remove? */
 | 
			
		||||
		  pv->status,	/* FIXME Support old or new format here? */
 | 
			
		||||
		  pv->status & ALLOCATABLE_PV,  /* FIXME remove? */
 | 
			
		||||
		  pv->status & ALLOCATABLE_PV,	/* FIXME remove? */
 | 
			
		||||
		  /* FIXME pv->lv_cur, Remove? */
 | 
			
		||||
		  pv->pe_size / 2,
 | 
			
		||||
		  pv->pe_count,
 | 
			
		||||
		  pv->pe_count - pv->pe_allocated,
 | 
			
		||||
		  pv->pe_allocated, *uuid ? uuid : "none");
 | 
			
		||||
		  pv->pe_count - pv->pe_alloc_count,
 | 
			
		||||
		  pv->pe_alloc_count, *uuid ? uuid : "none");
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pvdisplay_full(struct physical_volume *pv)
 | 
			
		||||
/* FIXME Include label fields */
 | 
			
		||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
 | 
			
		||||
		    void *handle)
 | 
			
		||||
{
 | 
			
		||||
	char uuid[64];
 | 
			
		||||
	char *size, *size1;	/*, *size2; */
 | 
			
		||||
	const char *size;
 | 
			
		||||
 | 
			
		||||
	uint64_t pe_free;
 | 
			
		||||
	uint32_t pe_free;
 | 
			
		||||
 | 
			
		||||
	if (!pv)
 | 
			
		||||
		return;
 | 
			
		||||
@@ -108,64 +269,66 @@ void pvdisplay_full(struct physical_volume *pv)
 | 
			
		||||
	log_print("VG Name               %s%s", pv->vg_name,
 | 
			
		||||
		  pv->status & EXPORTED_VG ? " (exported)" : "");
 | 
			
		||||
 | 
			
		||||
	size = display_size(pv->size / 2, SIZE_SHORT);
 | 
			
		||||
	size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
 | 
			
		||||
	if (pv->pe_size && pv->pe_count) {
 | 
			
		||||
		size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
 | 
			
		||||
				     / 2, SIZE_SHORT);
 | 
			
		||||
 | 
			
		||||
/******** FIXME display LVM on-disk data size
 | 
			
		||||
		size2 = display_size(pv->size / 2, SIZE_SHORT);
 | 
			
		||||
********/
 | 
			
		||||
 | 
			
		||||
		log_print("PV Size               %s" " / not usable %s",	/*  [LVM: %s]", */
 | 
			
		||||
			  size, size1);	/* , size2);    */
 | 
			
		||||
			  size, display_size(cmd,
 | 
			
		||||
					     (pv->size -
 | 
			
		||||
					      pv->pe_count * pv->pe_size) / 2,
 | 
			
		||||
					     SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
		dbg_free(size1);
 | 
			
		||||
		/* dbg_free(size2); */
 | 
			
		||||
	} else
 | 
			
		||||
		log_print("PV Size               %s", size);
 | 
			
		||||
	dbg_free(size);
 | 
			
		||||
 | 
			
		||||
/*********FIXME Anything use this?
 | 
			
		||||
	log_print("PV#                   %u", pv->pv_number);
 | 
			
		||||
**********/
 | 
			
		||||
	/* PV number not part of LVM2 design
 | 
			
		||||
	   log_print("PV#                   %u", pv->pv_number);
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	pe_free = pv->pe_count - pv->pe_allocated;
 | 
			
		||||
	pe_free = pv->pe_count - pv->pe_alloc_count;
 | 
			
		||||
	if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
 | 
			
		||||
		log_print("Allocatable           yes %s",
 | 
			
		||||
			  (!pe_free && pv->pe_count) ? "(but full)" : "");
 | 
			
		||||
	else
 | 
			
		||||
		log_print("Allocatable           NO");
 | 
			
		||||
 | 
			
		||||
/*********FIXME
 | 
			
		||||
	log_print("Cur LV                %u", pv->lv_cur);
 | 
			
		||||
*********/
 | 
			
		||||
	log_print("PE Size (KByte)       %" PRIu64, pv->pe_size / 2);
 | 
			
		||||
	/* LV count is no longer available when displaying PV
 | 
			
		||||
	   log_print("Cur LV                %u", vg->lv_count);
 | 
			
		||||
	 */
 | 
			
		||||
	log_print("PE Size (KByte)       %" PRIu32, pv->pe_size / 2);
 | 
			
		||||
	log_print("Total PE              %u", pv->pe_count);
 | 
			
		||||
	log_print("Free PE               %" PRIu64, pe_free);
 | 
			
		||||
	log_print("Allocated PE          %u", pv->pe_allocated);
 | 
			
		||||
 | 
			
		||||
#ifdef LVM_FUTURE
 | 
			
		||||
	printf("Stale PE              %u", pv->pe_stale);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	log_print("Free PE               %" PRIu32, pe_free);
 | 
			
		||||
	log_print("Allocated PE          %u", pv->pe_alloc_count);
 | 
			
		||||
	log_print("PV UUID               %s", *uuid ? uuid : "none");
 | 
			
		||||
	log_print(" ");
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
 | 
			
		||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
		    struct physical_volume *pv, void *handle)
 | 
			
		||||
{
 | 
			
		||||
	char uuid[64];
 | 
			
		||||
 | 
			
		||||
	if (!pv)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_print("PV Name               %s     ", dev_name(pv->dev));
 | 
			
		||||
	/* FIXME  pv->pv_number); */
 | 
			
		||||
	log_print("PV UUID               %s", *uuid ? uuid : "none");
 | 
			
		||||
	log_print("PV Status             %sallocatable",
 | 
			
		||||
		  (pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
 | 
			
		||||
	log_print("Total PE / Free PE    %u / %u",
 | 
			
		||||
		  pv->pe_count, pv->pe_count - pv->pe_allocated);
 | 
			
		||||
		  pv->pe_count, pv->pe_count - pv->pe_alloc_count);
 | 
			
		||||
 | 
			
		||||
	log_print(" ");
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -174,7 +337,7 @@ int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
 | 
			
		||||
void lvdisplay_colons(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int inkernel;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	inkernel = lv_info(lv, &info) && info.exists;
 | 
			
		||||
 | 
			
		||||
	log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
 | 
			
		||||
@@ -182,25 +345,29 @@ void lvdisplay_colons(struct logical_volume *lv)
 | 
			
		||||
		  lv->vg->name,
 | 
			
		||||
		  lv->name,
 | 
			
		||||
		  lv->vg->name,
 | 
			
		||||
		  (lv->status & (LVM_READ | LVM_WRITE)) >> 8,
 | 
			
		||||
		  inkernel ? 1 : 0,
 | 
			
		||||
		  (lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
 | 
			
		||||
		  /* FIXME lv->lv_number,  */
 | 
			
		||||
		  inkernel ? info.open_count : 0, lv->size, lv->le_count,
 | 
			
		||||
		  /* FIXME Add num allocated to struct! lv->lv_allocated_le, */
 | 
			
		||||
		  ((lv->status & ALLOC_STRICT) +
 | 
			
		||||
		   (lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
 | 
			
		||||
		  inkernel ? info.major : -1,
 | 
			
		||||
		  inkernel ? info.minor : -1
 | 
			
		||||
	    );
 | 
			
		||||
		  (lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
 | 
			
		||||
		  inkernel ? info.major : -1, inkernel ? info.minor : -1);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvdisplay_full(struct logical_volume *lv)
 | 
			
		||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
		   void *handle)
 | 
			
		||||
{
 | 
			
		||||
	char *size;
 | 
			
		||||
	uint32_t alloc;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
	int inkernel;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	int inkernel, snap_active;
 | 
			
		||||
	char uuid[64];
 | 
			
		||||
	struct snapshot *snap = NULL;
 | 
			
		||||
	struct list *slh, *snaplist;
 | 
			
		||||
	float snap_percent;	/* fused, fsize; */
 | 
			
		||||
 | 
			
		||||
	if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inkernel = lv_info(lv, &info) && info.exists;
 | 
			
		||||
 | 
			
		||||
@@ -210,59 +377,43 @@ int lvdisplay_full(struct logical_volume *lv)
 | 
			
		||||
		  lv->vg->name, lv->name);
 | 
			
		||||
	log_print("VG Name                %s", lv->vg->name);
 | 
			
		||||
 | 
			
		||||
	log_print("LV UUID                %s", uuid);
 | 
			
		||||
 | 
			
		||||
	log_print("LV Write Access        %s",
 | 
			
		||||
		  (lv->status & LVM_WRITE) ? "read/write" : "read only");
 | 
			
		||||
 | 
			
		||||
/******* FIXME Snapshot
 | 
			
		||||
    if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
 | 
			
		||||
	if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
 | 
			
		||||
	    ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
 | 
			
		||||
	    goto lv_show_end;
 | 
			
		||||
	}
 | 
			
		||||
	printf("LV snapshot status     ");
 | 
			
		||||
	if (vg_check_active(vg_name) == TRUE) {
 | 
			
		||||
	    vg_t *vg_core;
 | 
			
		||||
	    if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
 | 
			
		||||
		lv_t *lv_ptr =
 | 
			
		||||
		    vg_core->
 | 
			
		||||
		    lv[lv_get_index_by_name(vg_core, lv->lv_name)];
 | 
			
		||||
		if (lv_ptr->lv_access & LV_SNAPSHOT) {
 | 
			
		||||
		    if (lv_ptr->lv_status & LV_ACTIVE)
 | 
			
		||||
			printf("active ");
 | 
			
		||||
		    else
 | 
			
		||||
			printf("INACTIVE ");
 | 
			
		||||
	if (lv_is_origin(lv)) {
 | 
			
		||||
		log_print("LV snapshot status     source of");
 | 
			
		||||
 | 
			
		||||
		snaplist = find_snapshots(lv);
 | 
			
		||||
		list_iterate(slh, snaplist) {
 | 
			
		||||
			snap = list_item(slh, struct snapshot_list)->snapshot;
 | 
			
		||||
			snap_active = lv_snapshot_percent(snap->cow,
 | 
			
		||||
							  &snap_percent);
 | 
			
		||||
			if (!snap_active || snap_percent < 0 ||
 | 
			
		||||
			    snap_percent >= 100)
 | 
			
		||||
				snap_active = 0;
 | 
			
		||||
			log_print("                       %s%s/%s [%s]",
 | 
			
		||||
				  lv->vg->cmd->dev_dir, lv->vg->name,
 | 
			
		||||
				  snap->cow->name,
 | 
			
		||||
				  (snap_active > 0) ? "active" : "INACTIVE");
 | 
			
		||||
		}
 | 
			
		||||
		if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
 | 
			
		||||
		    printf("source of\n");
 | 
			
		||||
		    while (lv_ptr->lv_snapshot_next != NULL) {
 | 
			
		||||
			lv_ptr = lv_ptr->lv_snapshot_next;
 | 
			
		||||
			printf("                       %s [%s]\n",
 | 
			
		||||
			       lv_ptr->lv_name,
 | 
			
		||||
			       (lv_ptr->
 | 
			
		||||
				lv_status & LV_ACTIVE) ? "active" :
 | 
			
		||||
			       "INACTIVE");
 | 
			
		||||
		    }
 | 
			
		||||
		    vg_free(vg_core, TRUE);
 | 
			
		||||
		} else {
 | 
			
		||||
		    printf("destination for %s\n",
 | 
			
		||||
			   lv_ptr->lv_snapshot_org->lv_name);
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	} else {
 | 
			
		||||
	    printf("INACTIVE ");
 | 
			
		||||
	    if (lv->lv_access & LV_SNAPSHOT_ORG)
 | 
			
		||||
		printf("original\n");
 | 
			
		||||
	    else
 | 
			
		||||
		printf("snapshot\n");
 | 
			
		||||
		snap = NULL;
 | 
			
		||||
	} else if ((snap = find_cow(lv))) {
 | 
			
		||||
		snap_active = lv_snapshot_percent(lv, &snap_percent);
 | 
			
		||||
		if (!snap_active || snap_percent < 0 || snap_percent >= 100)
 | 
			
		||||
			snap_active = 0;
 | 
			
		||||
		log_print("LV snapshot status     %s destination for %s%s/%s",
 | 
			
		||||
			  (snap_active > 0) ? "active" : "INACTIVE",
 | 
			
		||||
			  lv->vg->cmd->dev_dir, lv->vg->name,
 | 
			
		||||
			  snap->origin->name);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
***********/
 | 
			
		||||
 | 
			
		||||
	if (inkernel && info.suspended)
 | 
			
		||||
		log_print("LV Status              suspended");
 | 
			
		||||
	else
 | 
			
		||||
		log_print("LV Status              %savailable",
 | 
			
		||||
		  	  inkernel ? "" : "NOT ");
 | 
			
		||||
			  inkernel ? "" : "NOT ");
 | 
			
		||||
 | 
			
		||||
/********* FIXME lv_number
 | 
			
		||||
    log_print("LV #                   %u", lv->lv_number + 1);
 | 
			
		||||
@@ -271,100 +422,60 @@ int lvdisplay_full(struct logical_volume *lv)
 | 
			
		||||
	if (inkernel)
 | 
			
		||||
		log_print("# open                 %u", info.open_count);
 | 
			
		||||
 | 
			
		||||
/********
 | 
			
		||||
#ifdef LVM_FUTURE
 | 
			
		||||
    printf("Mirror copies          %u\n", lv->lv_mirror_copies);
 | 
			
		||||
    printf("Consistency recovery   ");
 | 
			
		||||
    if (lv->lv_recovery | LV_BADBLOCK_ON)
 | 
			
		||||
	printf("bad blocks\n");
 | 
			
		||||
    else
 | 
			
		||||
	printf("none\n");
 | 
			
		||||
    printf("Schedule               %u\n", lv->lv_schedule);
 | 
			
		||||
#endif
 | 
			
		||||
********/
 | 
			
		||||
	log_print("LV Size                %s",
 | 
			
		||||
		  display_size(cmd,
 | 
			
		||||
			       snap ? snap->origin->size / 2 : lv->size / 2,
 | 
			
		||||
			       SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
	size = display_size(lv->size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("LV Size                %s", size);
 | 
			
		||||
	dbg_free(size);
 | 
			
		||||
 | 
			
		||||
	log_print("Current LE             %u", lv->le_count);
 | 
			
		||||
	log_print("Current LE             %u",
 | 
			
		||||
		  snap ? snap->origin->le_count : lv->le_count);
 | 
			
		||||
 | 
			
		||||
/********** FIXME allocation
 | 
			
		||||
    log_print("Allocated LE           %u", lv->allocated_le);
 | 
			
		||||
**********/
 | 
			
		||||
 | 
			
		||||
/********** FIXME Snapshot
 | 
			
		||||
    if (lv->lv_access & LV_SNAPSHOT) {
 | 
			
		||||
	printf("snapshot chunk size    %s\n",
 | 
			
		||||
	       (dummy = lvm_show_size(lv->lv_chunk_size / 2, SHORT)));
 | 
			
		||||
	dbg_free(dummy);
 | 
			
		||||
	dummy = NULL;
 | 
			
		||||
	if (lv->lv_remap_end > 0) {
 | 
			
		||||
	    lv_remap_ptr = lv->lv_remap_ptr;
 | 
			
		||||
	    if (lv_remap_ptr > lv->lv_remap_end)
 | 
			
		||||
		lv_remap_ptr = lv->lv_remap_end;
 | 
			
		||||
	    dummy = lvm_show_size(lv_remap_ptr *
 | 
			
		||||
				  lv->lv_chunk_size / 2, SHORT);
 | 
			
		||||
	    dummy1 = lvm_show_size(lv->lv_remap_end *
 | 
			
		||||
				   lv->lv_chunk_size / 2, SHORT);
 | 
			
		||||
	    printf("Allocated to snapshot  %.2f%% [%s/%s]\n",
 | 
			
		||||
		   (float) lv_remap_ptr * 100 / lv->lv_remap_end,
 | 
			
		||||
		   dummy, dummy1);
 | 
			
		||||
	    dbg_free(dummy);
 | 
			
		||||
	    dbg_free(dummy1);
 | 
			
		||||
	    dummy =
 | 
			
		||||
		lvm_show_size((vg->
 | 
			
		||||
			       lv[lv_get_index_by_number
 | 
			
		||||
				  (vg,
 | 
			
		||||
				   lv->lv_number)]->lv_size -
 | 
			
		||||
			       lv->lv_remap_end * lv->lv_chunk_size) / 2,
 | 
			
		||||
			      SHORT);
 | 
			
		||||
	    printf("Allocated to COW-table %s\n", dummy);
 | 
			
		||||
	    dbg_free(dummy);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
******************/
 | 
			
		||||
 | 
			
		||||
	log_print("Segments               %u", list_size(&lv->segments));
 | 
			
		||||
 | 
			
		||||
/********* FIXME Stripes & stripesize for each segment
 | 
			
		||||
	log_print("Stripe size (KByte)    %u", lv->stripesize / 2);
 | 
			
		||||
***********/
 | 
			
		||||
 | 
			
		||||
/**************
 | 
			
		||||
#ifdef LVM_FUTURE
 | 
			
		||||
    printf("Bad block             ");
 | 
			
		||||
    if (lv->lv_badblock == LV_BADBLOCK_ON)
 | 
			
		||||
	printf("on\n");
 | 
			
		||||
    else
 | 
			
		||||
	printf("off\n");
 | 
			
		||||
#endif
 | 
			
		||||
***************/
 | 
			
		||||
	if (snap) {
 | 
			
		||||
		if (snap_percent == -1)
 | 
			
		||||
			snap_percent = 100;
 | 
			
		||||
 | 
			
		||||
	/* FIXME next free == ALLOC_SIMPLE */
 | 
			
		||||
	alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS);
 | 
			
		||||
	log_print("Allocation             %s%s%s%s",
 | 
			
		||||
		  !(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
 | 
			
		||||
		  "", (alloc == ALLOC_STRICT) ? "strict" : "",
 | 
			
		||||
		  (alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
 | 
			
		||||
		  (alloc ==
 | 
			
		||||
		   (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
 | 
			
		||||
		  "");
 | 
			
		||||
		log_print("Snapshot chunk size    %s",
 | 
			
		||||
			  display_size(cmd, (uint64_t) snap->chunk_size / 2,
 | 
			
		||||
				       SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	size = display_size(lv->size / 2, SIZE_SHORT);
 | 
			
		||||
	sscanf(size, "%f", &fsize);
 | 
			
		||||
	fused = fsize * snap_percent / 100;
 | 
			
		||||
*/
 | 
			
		||||
		log_print("Allocated to snapshot  %.2f%% ",	/* [%.2f/%s]", */
 | 
			
		||||
			  snap_percent);	/*, fused, size); */
 | 
			
		||||
		/* dbg_free(size); */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/********** FIXME Snapshot
 | 
			
		||||
	size = ???
 | 
			
		||||
	log_print("Allocated to COW-table %s", size);
 | 
			
		||||
	dbg_free(size);
 | 
			
		||||
    }
 | 
			
		||||
******************/
 | 
			
		||||
 | 
			
		||||
	log_print("Allocation             %s", get_alloc_string(lv->alloc));
 | 
			
		||||
	log_print("Read ahead sectors     %u", lv->read_ahead);
 | 
			
		||||
 | 
			
		||||
/****************
 | 
			
		||||
#ifdef LVM_FUTURE
 | 
			
		||||
    printf("IO Timeout (seconds)   ");
 | 
			
		||||
    if (lv->lv_io_timeout == 0)
 | 
			
		||||
	printf("default\n\n");
 | 
			
		||||
    else
 | 
			
		||||
	printf("%lu\n\n", lv->lv_io_timeout);
 | 
			
		||||
#endif
 | 
			
		||||
*************/
 | 
			
		||||
	if (lv->status & FIXED_MINOR) {
 | 
			
		||||
		if (lv->major >= 0)
 | 
			
		||||
			log_print("Persistent major       %d", lv->major);
 | 
			
		||||
		log_print("Persistent minor       %d", lv->minor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (inkernel)
 | 
			
		||||
    		log_print("Block device           %d:%d", info.major,
 | 
			
		||||
		log_print("Block device           %d:%d", info.major,
 | 
			
		||||
			  info.minor);
 | 
			
		||||
 | 
			
		||||
	log_print(" ");
 | 
			
		||||
@@ -372,53 +483,86 @@ int lvdisplay_full(struct logical_volume *lv)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
 | 
			
		||||
static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t len = seg->len / seg->stripes;
 | 
			
		||||
	switch (seg->area[s].type) {
 | 
			
		||||
	case AREA_PV:
 | 
			
		||||
		log_print("%sPhysical volume\t%s", pre,
 | 
			
		||||
			  seg->area[s].u.pv.pv ?
 | 
			
		||||
			  dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
 | 
			
		||||
 | 
			
		||||
	log_print("%sphysical volume\t%s", pre,
 | 
			
		||||
		  seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing");
 | 
			
		||||
		if (seg->area[s].u.pv.pv)
 | 
			
		||||
			log_print("%sPhysical extents\t%d to %d", pre,
 | 
			
		||||
				  seg->area[s].u.pv.pe,
 | 
			
		||||
				  seg->area[s].u.pv.pe + seg->area_len - 1);
 | 
			
		||||
		break;
 | 
			
		||||
	case AREA_LV:
 | 
			
		||||
		log_print("%sLogical volume\t%s", pre,
 | 
			
		||||
			  seg->area[s].u.lv.lv ?
 | 
			
		||||
			  seg->area[s].u.lv.lv->name : "Missing");
 | 
			
		||||
 | 
			
		||||
	if (seg->area[s].pv)
 | 
			
		||||
		log_print("%sphysical extents\t%d to %d", pre,
 | 
			
		||||
			   seg->area[s].pe, seg->area[s].pe + len - 1);
 | 
			
		||||
		if (seg->area[s].u.lv.lv)
 | 
			
		||||
			log_print("%sLogical extents\t%d to %d", pre,
 | 
			
		||||
				  seg->area[s].u.lv.le,
 | 
			
		||||
				  seg->area[s].u.lv.le + seg->area_len - 1);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvdisplay_segments(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int s;
 | 
			
		||||
	uint32_t s;
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	log_print("--- Segments ---");
 | 
			
		||||
 | 
			
		||||
	list_iterate (segh, &lv->segments) {
 | 
			
		||||
		seg = list_item(segh, struct stripe_segment);
 | 
			
		||||
	list_iterate(segh, &lv->segments) {
 | 
			
		||||
		seg = list_item(segh, struct lv_segment);
 | 
			
		||||
 | 
			
		||||
		log_print("logical extent %d to %d:",
 | 
			
		||||
		log_print("Logical extent %u to %u:",
 | 
			
		||||
			  seg->le, seg->le + seg->len - 1);
 | 
			
		||||
 | 
			
		||||
		if (seg->stripes == 1)
 | 
			
		||||
			_display_stripe(seg, 0, "  ");
 | 
			
		||||
		if (seg->type == SEG_STRIPED && seg->area_count == 1)
 | 
			
		||||
			log_print("  Type\t\tlinear");
 | 
			
		||||
		else
 | 
			
		||||
			log_print("  Type\t\t%s",
 | 
			
		||||
				  get_segtype_string(seg->type));
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			log_print("  stripes\t\t%d", seg->stripes);
 | 
			
		||||
			log_print("  stripe size\t\t%d", seg->stripe_size);
 | 
			
		||||
		switch (seg->type) {
 | 
			
		||||
		case SEG_STRIPED:
 | 
			
		||||
			if (seg->area_count == 1)
 | 
			
		||||
				_display_stripe(seg, 0, "  ");
 | 
			
		||||
			else {
 | 
			
		||||
				log_print("  Stripes\t\t%u", seg->area_count);
 | 
			
		||||
				log_print("  Stripe size\t\t%u KB",
 | 
			
		||||
					  seg->stripe_size / 2);
 | 
			
		||||
 | 
			
		||||
			for (s = 0; s < seg->stripes; s++) {
 | 
			
		||||
				log_print("  stripe %d:", s);
 | 
			
		||||
				_display_stripe(seg, s, "    ");
 | 
			
		||||
				for (s = 0; s < seg->area_count; s++) {
 | 
			
		||||
					log_print("  Stripe %d:", s);
 | 
			
		||||
					_display_stripe(seg, s, "    ");
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			log_print(" ");
 | 
			
		||||
			break;
 | 
			
		||||
		case SEG_SNAPSHOT:
 | 
			
		||||
			break;
 | 
			
		||||
		case SEG_MIRRORED:
 | 
			
		||||
			log_print("  Mirrors\t\t%u", seg->area_count);
 | 
			
		||||
			log_print("  Mirror size\t\t%u", seg->area_len);
 | 
			
		||||
			log_print("  Mirror original:");
 | 
			
		||||
			_display_stripe(seg, 0, "    ");
 | 
			
		||||
			log_print("  Mirror destination:");
 | 
			
		||||
			_display_stripe(seg, 1, "    ");
 | 
			
		||||
			log_print(" ");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		log_print(" ");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_print(" ");
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void vgdisplay_extents(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	return;
 | 
			
		||||
@@ -427,12 +571,23 @@ void vgdisplay_extents(struct volume_group *vg)
 | 
			
		||||
void vgdisplay_full(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t access;
 | 
			
		||||
	char *s1;
 | 
			
		||||
	uint32_t active_pvs;
 | 
			
		||||
	char uuid[64];
 | 
			
		||||
 | 
			
		||||
	if (vg->status & PARTIAL_VG)
 | 
			
		||||
		active_pvs = list_size(&vg->pvs);
 | 
			
		||||
	else
 | 
			
		||||
		active_pvs = vg->pv_count;
 | 
			
		||||
 | 
			
		||||
	log_print("--- Volume group ---");
 | 
			
		||||
	log_print("VG Name               %s", vg->name);
 | 
			
		||||
	log_print("System ID             %s", vg->system_id);
 | 
			
		||||
	log_print("Format                %s", vg->fid->fmt->name);
 | 
			
		||||
	if (vg->fid->fmt->features & FMT_MDAS) {
 | 
			
		||||
		log_print("Metadata Areas        %d",
 | 
			
		||||
			  list_size(&vg->fid->metadata_areas));
 | 
			
		||||
		log_print("Metadata Sequence No  %d", vg->seqno);
 | 
			
		||||
	}
 | 
			
		||||
	access = vg->status & (LVM_READ | LVM_WRITE);
 | 
			
		||||
	log_print("VG Access             %s%s%s%s",
 | 
			
		||||
		  access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
 | 
			
		||||
@@ -442,9 +597,9 @@ void vgdisplay_full(struct volume_group *vg)
 | 
			
		||||
	log_print("VG Status             %s%sresizable",
 | 
			
		||||
		  vg->status & EXPORTED_VG ? "exported/" : "",
 | 
			
		||||
		  vg->status & RESIZEABLE_VG ? "" : "NOT ");
 | 
			
		||||
/******* FIXME vg number
 | 
			
		||||
	log_print ("VG #                  %u\n", vg->vg_number);
 | 
			
		||||
********/
 | 
			
		||||
	/* vg number not part of LVM2 design
 | 
			
		||||
	   log_print ("VG #                  %u\n", vg->vg_number);
 | 
			
		||||
	 */
 | 
			
		||||
	if (vg->status & CLUSTERED) {
 | 
			
		||||
		log_print("Clustered             yes");
 | 
			
		||||
		log_print("Shared                %s",
 | 
			
		||||
@@ -452,9 +607,7 @@ void vgdisplay_full(struct volume_group *vg)
 | 
			
		||||
	}
 | 
			
		||||
	log_print("MAX LV                %u", vg->max_lv);
 | 
			
		||||
	log_print("Cur LV                %u", vg->lv_count);
 | 
			
		||||
/****** FIXME Open LVs
 | 
			
		||||
      log_print ( "Open LV               %u", vg->lv_open);
 | 
			
		||||
*******/
 | 
			
		||||
	log_print("Open LV               %u", lvs_in_vg_opened(vg));
 | 
			
		||||
/****** FIXME Max LV Size
 | 
			
		||||
      log_print ( "MAX LV Size           %s",
 | 
			
		||||
               ( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
 | 
			
		||||
@@ -462,30 +615,36 @@ void vgdisplay_full(struct volume_group *vg)
 | 
			
		||||
*********/
 | 
			
		||||
	log_print("Max PV                %u", vg->max_pv);
 | 
			
		||||
	log_print("Cur PV                %u", vg->pv_count);
 | 
			
		||||
/******* FIXME act PVs
 | 
			
		||||
      log_print ( "Act PV                %u", vg->pv_act);
 | 
			
		||||
*********/
 | 
			
		||||
	log_print("Act PV                %u", active_pvs);
 | 
			
		||||
 | 
			
		||||
	s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("VG Size               %s", s1);
 | 
			
		||||
	dbg_free(s1);
 | 
			
		||||
	log_print("VG Size               %s",
 | 
			
		||||
		  display_size(vg->cmd,
 | 
			
		||||
			       (uint64_t) vg->extent_count * (vg->extent_size /
 | 
			
		||||
							      2), SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
	s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("PE Size               %s", s1);
 | 
			
		||||
	dbg_free(s1);
 | 
			
		||||
	log_print("PE Size               %s",
 | 
			
		||||
		  display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
 | 
			
		||||
			       SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
	log_print("Total PE              %u", vg->extent_count);
 | 
			
		||||
 | 
			
		||||
	s1 =
 | 
			
		||||
	    display_size((vg->extent_count - vg->free_count) *
 | 
			
		||||
			 vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("Alloc PE / Size       %u / %s",
 | 
			
		||||
		  vg->extent_count - vg->free_count, s1);
 | 
			
		||||
	dbg_free(s1);
 | 
			
		||||
		  vg->extent_count - vg->free_count, display_size(vg->cmd,
 | 
			
		||||
								  ((uint64_t)
 | 
			
		||||
								   vg->
 | 
			
		||||
								   extent_count
 | 
			
		||||
								   -
 | 
			
		||||
								   vg->
 | 
			
		||||
								   free_count) *
 | 
			
		||||
								  (vg->
 | 
			
		||||
								   extent_size /
 | 
			
		||||
								   2),
 | 
			
		||||
								  SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
	s1 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("Free  PE / Size       %u / %s", vg->free_count, s1);
 | 
			
		||||
	dbg_free(s1);
 | 
			
		||||
	log_print("Free  PE / Size       %u / %s", vg->free_count,
 | 
			
		||||
		  display_size(vg->cmd,
 | 
			
		||||
			       (uint64_t) vg->free_count * (vg->extent_size /
 | 
			
		||||
							    2), SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
	if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -505,17 +664,17 @@ void vgdisplay_colons(struct volume_group *vg)
 | 
			
		||||
 | 
			
		||||
void vgdisplay_short(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	char *s1, *s2, *s3;
 | 
			
		||||
	s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	s2 =
 | 
			
		||||
	    display_size((vg->extent_count - vg->free_count) * vg->extent_size /
 | 
			
		||||
			 2, SIZE_SHORT);
 | 
			
		||||
	s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
 | 
			
		||||
	log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
 | 
			
		||||
/********* FIXME if "open" print "/used" else print "/idle"???  ******/
 | 
			
		||||
		  s1, s2, s3);
 | 
			
		||||
	dbg_free(s1);
 | 
			
		||||
	dbg_free(s2);
 | 
			
		||||
	dbg_free(s3);
 | 
			
		||||
		  display_size(vg->cmd, (uint64_t) vg->extent_count *
 | 
			
		||||
			       vg->extent_size / 2, SIZE_SHORT),
 | 
			
		||||
		  display_size(vg->cmd,
 | 
			
		||||
			       ((uint64_t) vg->extent_count -
 | 
			
		||||
				vg->free_count) * vg->extent_size / 2,
 | 
			
		||||
			       SIZE_SHORT), display_size(vg->cmd,
 | 
			
		||||
							 (uint64_t) vg->
 | 
			
		||||
							 free_count *
 | 
			
		||||
							 vg->extent_size / 2,
 | 
			
		||||
							 SIZE_SHORT));
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,23 +25,40 @@
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef	enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
 | 
			
		||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
 | 
			
		||||
 | 
			
		||||
uint64_t units_to_bytes(const char *units, char *unit_type);
 | 
			
		||||
 | 
			
		||||
/* Specify size in KB */
 | 
			
		||||
char *display_size(unsigned long long size, size_len_t sl);
 | 
			
		||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
 | 
			
		||||
char *display_uuid(char *uuidstr);
 | 
			
		||||
 | 
			
		||||
void pvdisplay_colons(struct physical_volume *pv);
 | 
			
		||||
void pvdisplay_full(struct physical_volume *pv);
 | 
			
		||||
int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv);
 | 
			
		||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
 | 
			
		||||
		    void *handle);
 | 
			
		||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
		    struct physical_volume *pv, void *handle);
 | 
			
		||||
 | 
			
		||||
void lvdisplay_colons(struct logical_volume *lv);
 | 
			
		||||
int lvdisplay_segments(struct logical_volume *lv);
 | 
			
		||||
int lvdisplay_full(struct logical_volume *lv);
 | 
			
		||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
		   void *handle);
 | 
			
		||||
 | 
			
		||||
void vgdisplay_extents(struct volume_group *vg);
 | 
			
		||||
void vgdisplay_full(struct volume_group *vg);
 | 
			
		||||
void vgdisplay_colons(struct volume_group *vg);
 | 
			
		||||
void vgdisplay_short(struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Allocation policy display conversion routines.
 | 
			
		||||
 */
 | 
			
		||||
const char *get_alloc_string(alloc_policy_t alloc);
 | 
			
		||||
alloc_policy_t get_alloc_from_string(const char *str);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Segment type display conversion routines.
 | 
			
		||||
 */
 | 
			
		||||
segment_type_t get_segtype_from_string(const char *str);
 | 
			
		||||
const char *get_segtype_string(segment_type_t segtype);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,8 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "filter-composite.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +19,8 @@ static int _and_p(struct dev_filter *f, struct device *dev)
 | 
			
		||||
		filters++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("Using %s", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +37,6 @@ static void _destroy(struct dev_filter *f)
 | 
			
		||||
	dbg_free(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct dev_filter *composite_filter_create(int n, ...)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,12 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "filter-persistent.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
@@ -34,8 +32,12 @@ static int _init_hash(struct pfilter *pf)
 | 
			
		||||
	if (pf->devices)
 | 
			
		||||
		hash_destroy(pf->devices);
 | 
			
		||||
 | 
			
		||||
	pf->devices = hash_create(128);
 | 
			
		||||
	return pf->devices ? 1 : 0;
 | 
			
		||||
	if (!(pf->devices = hash_create(128))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int persistent_filter_wipe(struct dev_filter *f)
 | 
			
		||||
@@ -43,10 +45,13 @@ int persistent_filter_wipe(struct dev_filter *f)
 | 
			
		||||
	struct pfilter *pf = (struct pfilter *) f->private;
 | 
			
		||||
 | 
			
		||||
	hash_wipe(pf->devices);
 | 
			
		||||
	/* Trigger complete device scan */
 | 
			
		||||
	dev_cache_scan(1);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_array(struct pfilter *pf, struct config_file *cf,
 | 
			
		||||
static int _read_array(struct pfilter *pf, struct config_tree *cf,
 | 
			
		||||
		       const char *path, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
@@ -54,7 +59,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(cf->root, path, '/'))) {
 | 
			
		||||
		log_very_verbose("Couldn't find %s array in '%s'",
 | 
			
		||||
			 path, pf->file);
 | 
			
		||||
				 path, pf->file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -65,13 +70,15 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
 | 
			
		||||
	for (cv = cn->v; cv; cv = cv->next) {
 | 
			
		||||
		if (cv->type != CFG_STRING) {
 | 
			
		||||
			log_verbose("Devices array contains a value "
 | 
			
		||||
				 "which is not a string ... ignoring");
 | 
			
		||||
				    "which is not a string ... ignoring");
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!hash_insert(pf->devices, cv->v.str, data))
 | 
			
		||||
			log_verbose("Couldn't add '%s' to filter ... ignoring",
 | 
			
		||||
				 cv->v.str);
 | 
			
		||||
				    cv->v.str);
 | 
			
		||||
		/* Populate dev_cache ourselves */
 | 
			
		||||
		dev_cache_get(cv->v.str, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -81,28 +88,35 @@ int persistent_filter_load(struct dev_filter *f)
 | 
			
		||||
	struct pfilter *pf = (struct pfilter *) f->private;
 | 
			
		||||
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct config_file *cf;
 | 
			
		||||
	struct config_tree *cf;
 | 
			
		||||
 | 
			
		||||
	if (!(cf = create_config_file())) {
 | 
			
		||||
	if (!(cf = create_config_tree())) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!read_config(cf, pf->file)) {
 | 
			
		||||
	if (!read_config_file(cf, pf->file)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_read_array(pf, cf, "persistent_filter_cache/valid_devices",
 | 
			
		||||
		    PF_GOOD_DEVICE);
 | 
			
		||||
	_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
 | 
			
		||||
		    PF_BAD_DEVICE);
 | 
			
		||||
	/* We don't gain anything by holding invalid devices */
 | 
			
		||||
	/* _read_array(pf, cf, "persistent_filter_cache/invalid_devices",
 | 
			
		||||
	   PF_BAD_DEVICE); */
 | 
			
		||||
 | 
			
		||||
	if (hash_get_num_entries(pf->devices))
 | 
			
		||||
	/* Did we find anything? */
 | 
			
		||||
	if (hash_get_num_entries(pf->devices)) {
 | 
			
		||||
		/* We populated dev_cache ourselves */
 | 
			
		||||
		dev_cache_scan(0);
 | 
			
		||||
		r = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	destroy_config_file(cf);
 | 
			
		||||
	log_very_verbose("Loaded persistent filter cache from %s", pf->file);
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	destroy_config_tree(cf);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -147,11 +161,18 @@ int persistent_filter_dump(struct dev_filter *f)
 | 
			
		||||
				 "- not writing to %s", pf->file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!dev_cache_has_scanned()) {
 | 
			
		||||
		log_very_verbose("Device cache incomplete - not writing "
 | 
			
		||||
				 "to %s", pf->file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Dumping persistent device cache to %s", pf->file);
 | 
			
		||||
 | 
			
		||||
	fp = fopen(pf->file, "w");
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		log_sys_error("fopen", pf->file);
 | 
			
		||||
		if (errno != EROFS)
 | 
			
		||||
			log_sys_error("fopen", pf->file);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -159,7 +180,8 @@ int persistent_filter_dump(struct dev_filter *f)
 | 
			
		||||
	fprintf(fp, "persistent_filter_cache {\n");
 | 
			
		||||
 | 
			
		||||
	_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
 | 
			
		||||
	_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE);
 | 
			
		||||
	/* We don't gain anything by remembering invalid devices */
 | 
			
		||||
	/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
 | 
			
		||||
 | 
			
		||||
	fprintf(fp, "}\n");
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
@@ -175,7 +197,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
 | 
			
		||||
 | 
			
		||||
	if (!l) {
 | 
			
		||||
		l = pf->real->passes_filter(pf->real, dev) ?
 | 
			
		||||
			PF_GOOD_DEVICE : PF_BAD_DEVICE;
 | 
			
		||||
		    PF_GOOD_DEVICE : PF_BAD_DEVICE;
 | 
			
		||||
 | 
			
		||||
		list_iterate(ah, &dev->aliases) {
 | 
			
		||||
			sl = list_item(ah, struct str_list);
 | 
			
		||||
@@ -183,7 +205,11 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return l == PF_GOOD_DEVICE;
 | 
			
		||||
	if (l == PF_BAD_DEVICE) {
 | 
			
		||||
		log_debug("%s: Skipping (cached)", dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else
 | 
			
		||||
		return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct dev_filter *f)
 | 
			
		||||
@@ -232,7 +258,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
 | 
			
		||||
 | 
			
		||||
	return f;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	dbg_free(pf->file);
 | 
			
		||||
	if (pf->devices)
 | 
			
		||||
		hash_destroy(pf->devices);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "filter-regex.h"
 | 
			
		||||
#include "matcher.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
#include "bitset.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
 | 
			
		||||
struct rfilter {
 | 
			
		||||
@@ -19,7 +19,7 @@ struct rfilter {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int _extract_pattern(struct pool *mem, const char *pat,
 | 
			
		||||
			    char **regex, bitset_t accept, int index)
 | 
			
		||||
			    char **regex, bitset_t accept, int ix)
 | 
			
		||||
{
 | 
			
		||||
	char sep, *r, *ptr;
 | 
			
		||||
 | 
			
		||||
@@ -28,11 +28,11 @@ static int _extract_pattern(struct pool *mem, const char *pat,
 | 
			
		||||
	 */
 | 
			
		||||
	switch (*pat) {
 | 
			
		||||
	case 'a':
 | 
			
		||||
		bit_set(accept, index);
 | 
			
		||||
		bit_set(accept, ix);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 'r':
 | 
			
		||||
		bit_clear(accept, index);
 | 
			
		||||
		bit_clear(accept, ix);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
@@ -80,7 +80,7 @@ static int _extract_pattern(struct pool *mem, const char *pat,
 | 
			
		||||
	}
 | 
			
		||||
	*ptr = '\0';
 | 
			
		||||
 | 
			
		||||
	regex[index] = r;
 | 
			
		||||
	regex[ix] = r;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +89,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
 | 
			
		||||
	struct pool *scratch;
 | 
			
		||||
	struct config_value *v;
 | 
			
		||||
	char **regex;
 | 
			
		||||
	int count = 0, i, r = 0;
 | 
			
		||||
	unsigned count = 0;
 | 
			
		||||
	int i, r = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(scratch = pool_create(1024))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -128,8 +129,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
 | 
			
		||||
	 * the matcher gives.
 | 
			
		||||
	 */
 | 
			
		||||
	for (v = val, i = count - 1; v; v = v->next, i--)
 | 
			
		||||
		if (!_extract_pattern(scratch, v->v.str,
 | 
			
		||||
				      regex, rf->accept, i)) {
 | 
			
		||||
		if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
 | 
			
		||||
			log_info("invalid filter pattern");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
@@ -137,12 +137,12 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
 | 
			
		||||
	/*
 | 
			
		||||
	 * build the matcher.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(rf->engine = matcher_create(rf->mem,
 | 
			
		||||
					  (const char **) regex, count)))
 | 
			
		||||
	if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
 | 
			
		||||
					  count)))
 | 
			
		||||
		stack;
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
      out:
 | 
			
		||||
	pool_destroy(scratch);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
@@ -162,6 +162,8 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
 | 
			
		||||
			if (bit(rf->accept, m)) {
 | 
			
		||||
 | 
			
		||||
				if (!first) {
 | 
			
		||||
					log_debug("%s: New preferred name",
 | 
			
		||||
						  sl->str);
 | 
			
		||||
					list_del(&sl->list);
 | 
			
		||||
					list_add_h(&dev->aliases, &sl->list);
 | 
			
		||||
				}
 | 
			
		||||
@@ -221,8 +223,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
 | 
			
		||||
	f->private = rf;
 | 
			
		||||
	return f;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,32 +18,34 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <linux/kdev_t.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#define NUMBER_OF_MAJORS 256
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	char *name;
 | 
			
		||||
	int max_partitions;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const int max_partitions;
 | 
			
		||||
} device_info_t;
 | 
			
		||||
 | 
			
		||||
static int _md_major = -1;
 | 
			
		||||
 | 
			
		||||
static device_info_t device_info[] = {
 | 
			
		||||
int md_major(void)
 | 
			
		||||
{
 | 
			
		||||
	return _md_major;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This list can be supplemented with devices/types in the config file */
 | 
			
		||||
static const device_info_t device_info[] = {
 | 
			
		||||
	{"ide", 16},		/* IDE disk */
 | 
			
		||||
	{"sd", 16},		/* SCSI disk */
 | 
			
		||||
	{"md", 16},		/* Multiple Disk driver (SoftRAID) */
 | 
			
		||||
@@ -58,78 +60,59 @@ static device_info_t device_info[] = {
 | 
			
		||||
	{NULL, 0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int *scan_proc_dev(const char *proc);
 | 
			
		||||
 | 
			
		||||
static int passes_lvm_type_device_filter(struct dev_filter *f,
 | 
			
		||||
					 struct device *dev)
 | 
			
		||||
static int _passes_lvm_type_device_filter(struct dev_filter *f,
 | 
			
		||||
					  struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int fd;
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
 | 
			
		||||
	/* Is this a recognised device type? */
 | 
			
		||||
	if (!(((int *) f->private)[MAJOR(dev->dev)]))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Check it's accessible */
 | 
			
		||||
        if ((fd = open(name, O_RDONLY)) < 0) {
 | 
			
		||||
                log_debug("Unable to open %s: %s", name, strerror(errno));
 | 
			
		||||
	if (!(((int *) f->private)[MAJOR(dev->dev)])) {
 | 
			
		||||
		log_debug("%s: Skipping: Unrecognised LVM device type %"
 | 
			
		||||
			  PRIu64, name, (uint64_t) MAJOR(dev->dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        close(fd);
 | 
			
		||||
	/* Check it's accessible */
 | 
			
		||||
	if ((fd = open(name, O_RDONLY)) < 0) {
 | 
			
		||||
		log_debug("%s: Skipping: open failed: %s", name,
 | 
			
		||||
			  strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dev_filter *lvm_type_filter_create(const char *proc)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_filter *f;
 | 
			
		||||
 | 
			
		||||
	if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
 | 
			
		||||
		log_error("LVM type filter allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f->passes_filter = passes_lvm_type_device_filter;
 | 
			
		||||
	f->destroy = lvm_type_filter_destroy;
 | 
			
		||||
 | 
			
		||||
	if (!(f->private = scan_proc_dev(proc)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int md_major(void)
 | 
			
		||||
{
 | 
			
		||||
	return _md_major;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvm_type_filter_destroy(struct dev_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(f->private);
 | 
			
		||||
	dbg_free(f);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int *scan_proc_dev(const char *proc)
 | 
			
		||||
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
 | 
			
		||||
{
 | 
			
		||||
	char line[80];
 | 
			
		||||
	char proc_devices[PATH_MAX];
 | 
			
		||||
	FILE *pd = NULL;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	int i, j = 0;
 | 
			
		||||
	int line_maj = 0;
 | 
			
		||||
	int blocksection = 0;
 | 
			
		||||
	int dev_len = 0;
 | 
			
		||||
 | 
			
		||||
	size_t dev_len = 0;
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
	int *max_partitions_by_major;
 | 
			
		||||
	char *name;
 | 
			
		||||
 | 
			
		||||
	if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
 | 
			
		||||
	if (!(max_partitions_by_major =
 | 
			
		||||
	      dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
 | 
			
		||||
		log_error("Filter failed to allocate max_partitions_by_major");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(proc_devices, sizeof(proc_devices), 
 | 
			
		||||
	if (!*proc) {
 | 
			
		||||
		log_verbose("No proc filesystem found: using all block device "
 | 
			
		||||
			    "types");
 | 
			
		||||
		for (i = 0; i < NUMBER_OF_MAJORS; i++)
 | 
			
		||||
			max_partitions_by_major[i] = 1;
 | 
			
		||||
		return max_partitions_by_major;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(proc_devices, sizeof(proc_devices),
 | 
			
		||||
			 "%s/devices", proc) < 0) {
 | 
			
		||||
		log_error("Failed to create /proc/devices string");
 | 
			
		||||
		return NULL;
 | 
			
		||||
@@ -140,7 +123,7 @@ static int *scan_proc_dev(const char *proc)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
 | 
			
		||||
	memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
 | 
			
		||||
	while (fgets(line, 80, pd) != NULL) {
 | 
			
		||||
		i = 0;
 | 
			
		||||
		while (line[i] == ' ' && line[i] != '\0')
 | 
			
		||||
@@ -168,16 +151,48 @@ static int *scan_proc_dev(const char *proc)
 | 
			
		||||
			_md_major = line_maj;
 | 
			
		||||
 | 
			
		||||
		/* Go through the valid device names and if there is a
 | 
			
		||||
   			match store max number of partitions */
 | 
			
		||||
		   match store max number of partitions */
 | 
			
		||||
		for (j = 0; device_info[j].name != NULL; j++) {
 | 
			
		||||
 | 
			
		||||
			dev_len = strlen(device_info[j].name);
 | 
			
		||||
			if (dev_len <= strlen(line + i)
 | 
			
		||||
			    && !strncmp(device_info[j].name, line + i, dev_len)
 | 
			
		||||
			    && (line_maj < NUMBER_OF_MAJORS)) {
 | 
			
		||||
			if (dev_len <= strlen(line + i) &&
 | 
			
		||||
			    !strncmp(device_info[j].name, line + i, dev_len) &&
 | 
			
		||||
			    (line_maj < NUMBER_OF_MAJORS)) {
 | 
			
		||||
				max_partitions_by_major[line_maj] =
 | 
			
		||||
				    device_info[j].max_partitions;
 | 
			
		||||
				ret++;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (max_partitions_by_major[line_maj] || !cn)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Check devices/types for local variations */
 | 
			
		||||
		for (cv = cn->v; cv; cv = cv->next) {
 | 
			
		||||
			if (cv->type != CFG_STRING) {
 | 
			
		||||
				log_error("Expecting string in devices/types "
 | 
			
		||||
					  "in config file");
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			dev_len = strlen(cv->v.str);
 | 
			
		||||
			name = cv->v.str;
 | 
			
		||||
			cv = cv->next;
 | 
			
		||||
			if (!cv || cv->type != CFG_INT) {
 | 
			
		||||
				log_error("Max partition count missing for %s "
 | 
			
		||||
					  "in devices/types in config file",
 | 
			
		||||
					  name);
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			if (!cv->v.i) {
 | 
			
		||||
				log_error("Zero partition count invalid for "
 | 
			
		||||
					  "%s in devices/types in config file",
 | 
			
		||||
					  name);
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			if (dev_len <= strlen(line + i) &&
 | 
			
		||||
			    !strncmp(name, line + i, dev_len) &&
 | 
			
		||||
			    (line_maj < NUMBER_OF_MAJORS)) {
 | 
			
		||||
				max_partitions_by_major[line_maj] = cv->v.i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -185,3 +200,31 @@ static int *scan_proc_dev(const char *proc)
 | 
			
		||||
	fclose(pd);
 | 
			
		||||
	return max_partitions_by_major;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dev_filter *lvm_type_filter_create(const char *proc,
 | 
			
		||||
					  struct config_node *cn)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_filter *f;
 | 
			
		||||
 | 
			
		||||
	if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
 | 
			
		||||
		log_error("LVM type filter allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f->passes_filter = _passes_lvm_type_device_filter;
 | 
			
		||||
	f->destroy = lvm_type_filter_destroy;
 | 
			
		||||
 | 
			
		||||
	if (!(f->private = _scan_proc_dev(proc, cn))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvm_type_filter_destroy(struct dev_filter *f)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(f->private);
 | 
			
		||||
	dbg_free(f);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,23 @@
 | 
			
		||||
#ifndef _LVM_FILTER_H
 | 
			
		||||
#define _LVM_FILTER_H
 | 
			
		||||
 | 
			
		||||
struct dev_filter *lvm_type_filter_create();
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#ifdef linux
 | 
			
		||||
#  include <linux/kdev_t.h>
 | 
			
		||||
#else
 | 
			
		||||
#  define MAJOR(x) major((x))
 | 
			
		||||
#  define MINOR(x) minor((x))
 | 
			
		||||
#  define MKDEV(x,y) makedev((x),(y))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct dev_filter *lvm_type_filter_create(const char *proc,
 | 
			
		||||
					  struct config_node *cn);
 | 
			
		||||
 | 
			
		||||
void lvm_type_filter_destroy(struct dev_filter *f);
 | 
			
		||||
 | 
			
		||||
int md_major(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								lib/format1/.export.sym
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								lib/format1/.export.sym
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
Base { 
 | 
			
		||||
	global:
 | 
			
		||||
		init_format;
 | 
			
		||||
	local:
 | 
			
		||||
		*;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								lib/format1/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/format1/Makefile.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
#
 | 
			
		||||
# This file is released under the LGPL.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
VPATH = @srcdir@
 | 
			
		||||
 | 
			
		||||
SOURCES=\
 | 
			
		||||
	disk-rep.c \
 | 
			
		||||
	format1.c \
 | 
			
		||||
	import-export.c \
 | 
			
		||||
	import-extents.c \
 | 
			
		||||
	layout.c \
 | 
			
		||||
	lvm1-label.c \
 | 
			
		||||
	vg_number.c
 | 
			
		||||
 | 
			
		||||
TARGETS=liblvm2format1.so
 | 
			
		||||
 | 
			
		||||
include ../../make.tmpl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
install: libformat1.so
 | 
			
		||||
	$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
 | 
			
		||||
		$(libdir)/liblvm2format1.so.$(LIB_VERSION)
 | 
			
		||||
	$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
 | 
			
		||||
 | 
			
		||||
.PHONY: install
 | 
			
		||||
 | 
			
		||||
@@ -4,18 +4,14 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "vgcache.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <linux/kdev_t.h>
 | 
			
		||||
 | 
			
		||||
#define fail do {stack; return 0;} while(0)
 | 
			
		||||
#define xx16(v) disk->v = xlate16(disk->v)
 | 
			
		||||
@@ -96,7 +92,7 @@ static void _xlate_vgd(struct vg_disk *disk)
 | 
			
		||||
	xx32(pvg_total);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _xlate_extents(struct pe_disk *extents, int count)
 | 
			
		||||
static void _xlate_extents(struct pe_disk *extents, uint32_t count)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
@@ -116,12 +112,12 @@ static int _munge_formats(struct pv_disk *pvd)
 | 
			
		||||
	switch (pvd->version) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		pvd->pe_start = ((pvd->pe_on_disk.base +
 | 
			
		||||
				  pvd->pe_on_disk.size) / SECTOR_SIZE);
 | 
			
		||||
				  pvd->pe_on_disk.size) >> SECTOR_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 2:
 | 
			
		||||
		pvd->version = 1;
 | 
			
		||||
		pe_start = pvd->pe_start * SECTOR_SIZE;
 | 
			
		||||
		pe_start = pvd->pe_start << SECTOR_SHIFT;
 | 
			
		||||
		pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
@@ -132,10 +128,10 @@ static int _munge_formats(struct pv_disk *pvd)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int read_pvd(struct device *dev, struct pv_disk *pvd)
 | 
			
		||||
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
 | 
			
		||||
{
 | 
			
		||||
	if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
 | 
			
		||||
		log_very_verbose("Failed to read PV data from %s", 
 | 
			
		||||
	if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
 | 
			
		||||
		log_very_verbose("Failed to read PV data from %s",
 | 
			
		||||
				 dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -143,23 +139,23 @@ int read_pvd(struct device *dev, struct pv_disk *pvd)
 | 
			
		||||
	_xlate_pvd(pvd);
 | 
			
		||||
 | 
			
		||||
	if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
 | 
			
		||||
		log_very_verbose("%s does not have a valid PV identifier",
 | 
			
		||||
		log_very_verbose("%s does not have a valid LVM1 PV identifier",
 | 
			
		||||
				 dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_munge_formats(pvd)) {
 | 
			
		||||
		log_very_verbose("Unknown metadata version %d found on %s",
 | 
			
		||||
				 pvd->version, dev_name(dev));
 | 
			
		||||
		log_very_verbose("format1: Unknown metadata version %d "
 | 
			
		||||
				 "found on %s", pvd->version, dev_name(dev));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
 | 
			
		||||
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
 | 
			
		||||
{
 | 
			
		||||
	if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
 | 
			
		||||
	if (!dev_read(dev, pos, sizeof(*disk), disk))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_lvd(disk);
 | 
			
		||||
@@ -170,8 +166,8 @@ static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
 | 
			
		||||
static int _read_vgd(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	struct vg_disk *vgd = &data->vgd;
 | 
			
		||||
	ulong pos = data->pvd.vg_on_disk.base;
 | 
			
		||||
	if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
 | 
			
		||||
	uint64_t pos = data->pvd.vg_on_disk.base;
 | 
			
		||||
	if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_vgd(vgd);
 | 
			
		||||
@@ -184,12 +180,11 @@ static int _read_uuids(struct disk_list *data)
 | 
			
		||||
	int num_read = 0;
 | 
			
		||||
	struct uuid_list *ul;
 | 
			
		||||
	char buffer[NAME_LEN];
 | 
			
		||||
	ulong pos = data->pvd.pv_uuidlist_on_disk.base;
 | 
			
		||||
	ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
 | 
			
		||||
	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
 | 
			
		||||
	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
 | 
			
		||||
 | 
			
		||||
	while (pos < end && num_read < data->vgd.pv_cur) {
 | 
			
		||||
		if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
 | 
			
		||||
		    sizeof(buffer))
 | 
			
		||||
		if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
 | 
			
		||||
			fail;
 | 
			
		||||
 | 
			
		||||
		if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
 | 
			
		||||
@@ -214,8 +209,8 @@ static inline int _check_lvd(struct lv_disk *lvd)
 | 
			
		||||
 | 
			
		||||
static int _read_lvs(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	int i, read = 0;
 | 
			
		||||
	ulong pos;
 | 
			
		||||
	unsigned int i, read = 0;
 | 
			
		||||
	uint64_t pos;
 | 
			
		||||
	struct lvd_list *ll;
 | 
			
		||||
	struct vg_disk *vgd = &data->vgd;
 | 
			
		||||
 | 
			
		||||
@@ -243,12 +238,12 @@ static int _read_extents(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
 | 
			
		||||
	struct pe_disk *extents = pool_alloc(data->mem, len);
 | 
			
		||||
	ulong pos = data->pvd.pe_on_disk.base;
 | 
			
		||||
	uint64_t pos = data->pvd.pe_on_disk.base;
 | 
			
		||||
 | 
			
		||||
	if (!extents)
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	if (dev_read(data->dev, pos, len, extents) != len)
 | 
			
		||||
	if (!dev_read(data->dev, pos, len, extents))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_extents(extents, data->pvd.pe_total);
 | 
			
		||||
@@ -260,110 +255,122 @@ static int _read_extents(struct disk_list *data)
 | 
			
		||||
/* 
 | 
			
		||||
 * If exported, remove "PV_EXP" from end of VG name 
 | 
			
		||||
 */
 | 
			
		||||
static void _munge_exported_vg(struct disk_list *data)
 | 
			
		||||
void munge_exported_vg(struct pv_disk *pvd)
 | 
			
		||||
{
 | 
			
		||||
	int l, s;
 | 
			
		||||
	int l;
 | 
			
		||||
	size_t s;
 | 
			
		||||
 | 
			
		||||
	/* Return if PV not in a VG or VG not exported */
 | 
			
		||||
	if ((!*data->pvd.vg_name) ||
 | 
			
		||||
	    !(data->vgd.vg_status & VG_EXPORTED))
 | 
			
		||||
	/* Return if PV not in a VG */
 | 
			
		||||
	if ((!*pvd->vg_name))
 | 
			
		||||
		return;
 | 
			
		||||
	/* FIXME also check vgd->status & VG_EXPORTED? */
 | 
			
		||||
 | 
			
		||||
	l = strlen(data->pvd.vg_name);
 | 
			
		||||
	l = strlen(pvd->vg_name);
 | 
			
		||||
	s = sizeof(EXPORTED_TAG);
 | 
			
		||||
	if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
 | 
			
		||||
		     data->pvd.vg_name[l - s + 1] = '\0';
 | 
			
		||||
	if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s))
 | 
			
		||||
		pvd->vg_name[l - s + 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	data->pvd.pv_status |= VG_EXPORTED;
 | 
			
		||||
	pvd->pv_status |= VG_EXPORTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
 | 
			
		||||
static struct disk_list *__read_disk(const struct format_type *fmt,
 | 
			
		||||
				     struct device *dev, struct pool *mem,
 | 
			
		||||
				     const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	struct disk_list *data = pool_alloc(mem, sizeof(*data));
 | 
			
		||||
	struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
 | 
			
		||||
	const char *name = dev_name(dev);
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
 | 
			
		||||
	if (!data) {
 | 
			
		||||
	if (!dl) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data->dev = dev;
 | 
			
		||||
	data->mem = mem;
 | 
			
		||||
	list_init(&data->uuids);
 | 
			
		||||
	list_init(&data->lvds);
 | 
			
		||||
	dl->dev = dev;
 | 
			
		||||
	dl->mem = mem;
 | 
			
		||||
	list_init(&dl->uuids);
 | 
			
		||||
	list_init(&dl->lvds);
 | 
			
		||||
 | 
			
		||||
	if (!read_pvd(dev, &data->pvd)) {
 | 
			
		||||
	if (!_read_pvd(dev, &dl->pvd)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If VG is exported, set VG name back to the real name */
 | 
			
		||||
	munge_exported_vg(&dl->pvd);
 | 
			
		||||
 | 
			
		||||
	if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
 | 
			
		||||
				  dl->pvd.vg_name, NULL)))
 | 
			
		||||
		stack;
 | 
			
		||||
	else {
 | 
			
		||||
		info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
 | 
			
		||||
		list_init(&info->mdas);
 | 
			
		||||
		info->status &= ~CACHE_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * is it an orphan ?
 | 
			
		||||
	 */
 | 
			
		||||
	if (!*data->pvd.vg_name) {
 | 
			
		||||
		log_very_verbose("%s is not a member of any VG", name);
 | 
			
		||||
	if (!*dl->pvd.vg_name) {
 | 
			
		||||
		log_very_verbose("%s is not a member of any format1 VG", name);
 | 
			
		||||
 | 
			
		||||
		/* Update VG cache */
 | 
			
		||||
		vgcache_add(data->pvd.vg_name, dev);
 | 
			
		||||
		/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
 | 
			
		||||
 | 
			
		||||
		return (vg_name) ? NULL : data;
 | 
			
		||||
		return (vg_name) ? NULL : dl;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_vgd(data)) {
 | 
			
		||||
	if (!_read_vgd(dl)) {
 | 
			
		||||
		log_error("Failed to read VG data from PV (%s)", name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If VG is exported, set VG name back to the real name */
 | 
			
		||||
	_munge_exported_vg(data);
 | 
			
		||||
 | 
			
		||||
	/* Update VG cache with what we found */
 | 
			
		||||
	vgcache_add(data->pvd.vg_name, dev);
 | 
			
		||||
	/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
 | 
			
		||||
 | 
			
		||||
	if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
 | 
			
		||||
	if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
 | 
			
		||||
		log_very_verbose("%s is not a member of the VG %s",
 | 
			
		||||
				 name, vg_name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_uuids(data)) {
 | 
			
		||||
	if (!_read_uuids(dl)) {
 | 
			
		||||
		log_error("Failed to read PV uuid list from %s", name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_lvs(data)) {
 | 
			
		||||
	if (!_read_lvs(dl)) {
 | 
			
		||||
		log_error("Failed to read LV's from %s", name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_extents(data)) {
 | 
			
		||||
	if (!_read_extents(dl)) {
 | 
			
		||||
		log_error("Failed to read extents from %s", name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Found %s in %sVG %s", name, 
 | 
			
		||||
			 (data->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
 | 
			
		||||
			 data->pvd.vg_name);
 | 
			
		||||
	log_very_verbose("Found %s in %sVG %s", name,
 | 
			
		||||
			 (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
 | 
			
		||||
			 dl->pvd.vg_name);
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
	return dl;
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	pool_free(data->mem, data);
 | 
			
		||||
	pool_free(dl->mem, dl);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
 | 
			
		||||
			    const char *vg_name)
 | 
			
		||||
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
 | 
			
		||||
			    struct pool *mem, const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	struct disk_list *r;
 | 
			
		||||
 | 
			
		||||
	if (!dev_open(dev, O_RDONLY)) {
 | 
			
		||||
	if (!dev_open(dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = __read_disk(dev, mem, vg_name);
 | 
			
		||||
	r = __read_disk(fmt, dev, mem, vg_name);
 | 
			
		||||
 | 
			
		||||
	if (!dev_close(dev))
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -378,16 +385,16 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
 | 
			
		||||
 | 
			
		||||
	list_iterate(pvdh, head) {
 | 
			
		||||
		pvd = &list_item(pvdh, struct disk_list)->pvd;
 | 
			
		||||
		if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid, 
 | 
			
		||||
		if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
 | 
			
		||||
			     sizeof(pvd->pv_uuid))) {
 | 
			
		||||
			if (MAJOR(data->dev->dev) != md_major()) {
 | 
			
		||||
				log_very_verbose("Ignoring duplicate PV %s on "
 | 
			
		||||
						 "%s", pvd->pv_uuid, 
 | 
			
		||||
						 "%s", pvd->pv_uuid,
 | 
			
		||||
						 dev_name(data->dev));
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			log_very_verbose("Duplicate PV %s - using md %s", 
 | 
			
		||||
				  	 pvd->pv_uuid, dev_name(data->dev));
 | 
			
		||||
			log_very_verbose("Duplicate PV %s - using md %s",
 | 
			
		||||
					 pvd->pv_uuid, dev_name(data->dev));
 | 
			
		||||
			list_del(pvdh);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
@@ -400,20 +407,22 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
 | 
			
		||||
 * We keep track of the first object allocated form the pool
 | 
			
		||||
 * so we can free off all the memory if something goes wrong.
 | 
			
		||||
 */
 | 
			
		||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
 | 
			
		||||
		   struct pool *mem, struct list *head)
 | 
			
		||||
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
 | 
			
		||||
		   struct dev_filter *filter, struct pool *mem,
 | 
			
		||||
		   struct list *head)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_iter *iter;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	struct disk_list *data = NULL;
 | 
			
		||||
 | 
			
		||||
	struct list *pvdh, *pvdh2;
 | 
			
		||||
	struct list *vgih;
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
 | 
			
		||||
	/* Fast path if we already saw this VG and cached the list of PVs */
 | 
			
		||||
	if ((pvdh = vgcache_find(vg_name))) {
 | 
			
		||||
		list_iterate(pvdh2, pvdh) {
 | 
			
		||||
			dev = list_item(pvdh2, struct pvdev_list)->dev;
 | 
			
		||||
			if (!(data = read_disk(dev, mem, vg_name)))
 | 
			
		||||
	if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
 | 
			
		||||
	    vginfo->infos.n) {
 | 
			
		||||
		list_iterate(vgih, &vginfo->infos) {
 | 
			
		||||
			dev = list_item(vgih, struct lvmcache_info)->dev;
 | 
			
		||||
			if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
 | 
			
		||||
				break;
 | 
			
		||||
			_add_pv_to_list(head, data);
 | 
			
		||||
		}
 | 
			
		||||
@@ -424,9 +433,9 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
 | 
			
		||||
		     list_size(head) == data->vgd.pv_cur))
 | 
			
		||||
			return 1;
 | 
			
		||||
 | 
			
		||||
		/* Something changed. Remove the hints. */
 | 
			
		||||
		/* Failed */
 | 
			
		||||
		list_init(head);
 | 
			
		||||
		vgcache_del(vg_name);
 | 
			
		||||
		/* vgcache_del(vg_name); */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(iter = dev_iter_create(filter))) {
 | 
			
		||||
@@ -436,7 +445,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
 | 
			
		||||
 | 
			
		||||
	/* Otherwise do a complete scan */
 | 
			
		||||
	for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
 | 
			
		||||
		if ((data = read_disk(dev, mem, vg_name))) {
 | 
			
		||||
		if ((data = read_disk(fmt, dev, mem, vg_name))) {
 | 
			
		||||
			_add_pv_to_list(head, data);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -451,10 +460,10 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
 | 
			
		||||
static int _write_vgd(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	struct vg_disk *vgd = &data->vgd;
 | 
			
		||||
	ulong pos = data->pvd.vg_on_disk.base;
 | 
			
		||||
	uint64_t pos = data->pvd.vg_on_disk.base;
 | 
			
		||||
 | 
			
		||||
	_xlate_vgd(vgd);
 | 
			
		||||
	if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
 | 
			
		||||
	if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_vgd(vgd);
 | 
			
		||||
@@ -466,8 +475,8 @@ static int _write_uuids(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	struct uuid_list *ul;
 | 
			
		||||
	struct list *uh;
 | 
			
		||||
	ulong pos = data->pvd.pv_uuidlist_on_disk.base;
 | 
			
		||||
	ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
 | 
			
		||||
	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
 | 
			
		||||
	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
 | 
			
		||||
 | 
			
		||||
	list_iterate(uh, &data->uuids) {
 | 
			
		||||
		if (pos >= end) {
 | 
			
		||||
@@ -477,7 +486,7 @@ static int _write_uuids(struct disk_list *data)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ul = list_item(uh, struct uuid_list);
 | 
			
		||||
		if (dev_write(data->dev, pos, NAME_LEN, ul->uuid) != NAME_LEN)
 | 
			
		||||
		if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
 | 
			
		||||
			fail;
 | 
			
		||||
 | 
			
		||||
		pos += NAME_LEN;
 | 
			
		||||
@@ -486,10 +495,10 @@ static int _write_uuids(struct disk_list *data)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
 | 
			
		||||
static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
 | 
			
		||||
{
 | 
			
		||||
	_xlate_lvd(disk);
 | 
			
		||||
	if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
 | 
			
		||||
	if (!dev_write(dev, pos, sizeof(*disk), disk))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_lvd(disk);
 | 
			
		||||
@@ -500,7 +509,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
 | 
			
		||||
static int _write_lvs(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	ulong pos;
 | 
			
		||||
	uint64_t pos, offset;
 | 
			
		||||
 | 
			
		||||
	pos = data->pvd.lv_on_disk.base;
 | 
			
		||||
 | 
			
		||||
@@ -513,10 +522,14 @@ static int _write_lvs(struct disk_list *data)
 | 
			
		||||
	list_iterate(lvh, &data->lvds) {
 | 
			
		||||
		struct lvd_list *ll = list_item(lvh, struct lvd_list);
 | 
			
		||||
 | 
			
		||||
		if (!_write_lvd(data->dev, pos, &ll->lvd))
 | 
			
		||||
			fail;
 | 
			
		||||
		offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
 | 
			
		||||
		if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
 | 
			
		||||
			log_error("lv_number %d too large", ll->lvd.lv_number);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pos += sizeof(struct lv_disk);
 | 
			
		||||
		if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
 | 
			
		||||
			fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -526,10 +539,10 @@ static int _write_extents(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
 | 
			
		||||
	struct pe_disk *extents = data->extents;
 | 
			
		||||
	ulong pos = data->pvd.pe_on_disk.base;
 | 
			
		||||
	uint64_t pos = data->pvd.pe_on_disk.base;
 | 
			
		||||
 | 
			
		||||
	_xlate_extents(extents, data->pvd.pe_total);
 | 
			
		||||
	if (dev_write(data->dev, pos, len, extents) != len)
 | 
			
		||||
	if (!dev_write(data->dev, pos, len, extents))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_xlate_extents(extents, data->pvd.pe_total);
 | 
			
		||||
@@ -540,19 +553,19 @@ static int _write_extents(struct disk_list *data)
 | 
			
		||||
static int _write_pvd(struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	char *buf;
 | 
			
		||||
	ulong pos = data->pvd.pv_on_disk.base;
 | 
			
		||||
	ulong size = data->pvd.pv_on_disk.size;
 | 
			
		||||
	uint64_t pos = data->pvd.pv_on_disk.base;
 | 
			
		||||
	size_t size = data->pvd.pv_on_disk.size;
 | 
			
		||||
 | 
			
		||||
	if(size < sizeof(struct pv_disk)) {
 | 
			
		||||
	if (size < sizeof(struct pv_disk)) {
 | 
			
		||||
		log_error("Invalid PV structure size.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	/* Make sure that the gap between the PV structure and
 | 
			
		||||
	/* Make sure that the gap between the PV structure and
 | 
			
		||||
	   the next one is zeroed in order to make non LVM tools
 | 
			
		||||
	   happy (idea from AED) */
 | 
			
		||||
	buf = dbg_malloc(size);
 | 
			
		||||
	if(!buf) {
 | 
			
		||||
	if (!buf) {
 | 
			
		||||
		log_err("Couldn't allocate temporary PV buffer.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -560,8 +573,8 @@ static int _write_pvd(struct disk_list *data)
 | 
			
		||||
	memset(buf, 0, size);
 | 
			
		||||
	memcpy(buf, &data->pvd, sizeof(struct pv_disk));
 | 
			
		||||
 | 
			
		||||
	_xlate_pvd((struct pv_disk *)buf);
 | 
			
		||||
	if (dev_write(data->dev, pos, size, buf) != size) {
 | 
			
		||||
	_xlate_pvd((struct pv_disk *) buf);
 | 
			
		||||
	if (!dev_write(data->dev, pos, size, buf)) {
 | 
			
		||||
		dbg_free(buf);
 | 
			
		||||
		fail;
 | 
			
		||||
	}
 | 
			
		||||
@@ -573,7 +586,8 @@ static int _write_pvd(struct disk_list *data)
 | 
			
		||||
/*
 | 
			
		||||
 * assumes the device has been opened.
 | 
			
		||||
 */
 | 
			
		||||
static int __write_all_pvd(struct disk_list *data)
 | 
			
		||||
static int __write_all_pvd(const struct format_type *fmt,
 | 
			
		||||
			   struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	const char *pv_name = dev_name(data->dev);
 | 
			
		||||
 | 
			
		||||
@@ -582,13 +596,19 @@ static int __write_all_pvd(struct disk_list *data)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!test_mode())
 | 
			
		||||
		vgcache_add(data->pvd.vg_name, data->dev);
 | 
			
		||||
	/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
 | 
			
		||||
	/*
 | 
			
		||||
	 * Stop here for orphan pv's.
 | 
			
		||||
	 */
 | 
			
		||||
	if (data->pvd.vg_name[0] == '\0')
 | 
			
		||||
	if (data->pvd.vg_name[0] == '\0') {
 | 
			
		||||
		/* if (!test_mode())
 | 
			
		||||
		   vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* if (!test_mode())
 | 
			
		||||
	   vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
 | 
			
		||||
	   fmt); */
 | 
			
		||||
 | 
			
		||||
	if (!_write_vgd(data)) {
 | 
			
		||||
		log_error("Failed to write VG data to %s", pv_name);
 | 
			
		||||
@@ -616,16 +636,16 @@ static int __write_all_pvd(struct disk_list *data)
 | 
			
		||||
/*
 | 
			
		||||
 * opens the device and hands to the above fn.
 | 
			
		||||
 */
 | 
			
		||||
static int _write_all_pvd(struct disk_list *data)
 | 
			
		||||
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!dev_open(data->dev, O_WRONLY)) {
 | 
			
		||||
	if (!dev_open(data->dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = __write_all_pvd(data);
 | 
			
		||||
	r = __write_all_pvd(fmt, data);
 | 
			
		||||
 | 
			
		||||
	if (!dev_close(data->dev))
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -638,17 +658,17 @@ static int _write_all_pvd(struct disk_list *data)
 | 
			
		||||
 * little sanity checking, so make sure correct
 | 
			
		||||
 * data is passed to here.
 | 
			
		||||
 */
 | 
			
		||||
int write_disks(struct list *pvs)
 | 
			
		||||
int write_disks(const struct format_type *fmt, struct list *pvs)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvh;
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
 | 
			
		||||
	list_iterate(pvh, pvs) {
 | 
			
		||||
		dl = list_item(pvh, struct disk_list);
 | 
			
		||||
		if (!(_write_all_pvd(dl)))
 | 
			
		||||
		if (!(_write_all_pvd(fmt, dl)))
 | 
			
		||||
			fail;
 | 
			
		||||
 | 
			
		||||
		log_very_verbose("Successfully wrote data to %s", 
 | 
			
		||||
		log_very_verbose("Successfully wrote data to %s",
 | 
			
		||||
				 dev_name(dl->dev));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,20 +11,17 @@
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SECTOR_SIZE 512
 | 
			
		||||
 | 
			
		||||
#define MAX_PV 256
 | 
			
		||||
#define MAX_LV 256
 | 
			
		||||
#define MAX_VG 99
 | 
			
		||||
 | 
			
		||||
#define MIN_PE_SIZE	(8192L / SECTOR_SIZE)     /* 8 KB in sectors */
 | 
			
		||||
#define MAX_PE_SIZE	(16L * 1024L * 1024L / SECTOR_SIZE * 1024)
 | 
			
		||||
#define PE_SIZE_PV_SIZE_REL 5   /* PV size must be at least 5 times PE size */
 | 
			
		||||
#define	MAX_LE_TOTAL	65534   /* 2^16 - 2 */
 | 
			
		||||
#define MAX_PV_SIZE	((uint32_t) -1)	/* 2TB in sectors - 1 */
 | 
			
		||||
#define MIN_PE_SIZE	(8192L >> SECTOR_SHIFT)	/* 8 KB in sectors */
 | 
			
		||||
#define MAX_PE_SIZE	(16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
 | 
			
		||||
#define PE_SIZE_PV_SIZE_REL 5	/* PV size must be at least 5 times PE size */
 | 
			
		||||
#define	MAX_LE_TOTAL	65534	/* 2^16 - 2 */
 | 
			
		||||
#define	MAX_PE_TOTAL	((uint32_t) -2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define UNMAPPED_EXTENT 0
 | 
			
		||||
 | 
			
		||||
/* volume group */
 | 
			
		||||
@@ -40,6 +37,7 @@
 | 
			
		||||
/* logical volume */
 | 
			
		||||
#define	LV_ACTIVE            0x01	/* lv_status */
 | 
			
		||||
#define	LV_SPINDOWN          0x02	/*     "     */
 | 
			
		||||
#define LV_PERSISTENT_MINOR  0x04	/*     "     */
 | 
			
		||||
 | 
			
		||||
#define	LV_READ              0x01	/* lv_access */
 | 
			
		||||
#define	LV_WRITE             0x02	/*     "     */
 | 
			
		||||
@@ -58,86 +56,84 @@
 | 
			
		||||
#define EXPORTED_TAG "PV_EXP"	/* Identifier for exported PV */
 | 
			
		||||
#define IMPORTED_TAG "PV_IMP"	/* Identifier for imported PV */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct data_area {
 | 
			
		||||
	uint32_t base;
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
};
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct pv_disk {
 | 
			
		||||
        uint8_t id[2];
 | 
			
		||||
        uint16_t version;               /* lvm version */
 | 
			
		||||
        struct data_area pv_on_disk;
 | 
			
		||||
        struct data_area vg_on_disk;
 | 
			
		||||
        struct data_area pv_uuidlist_on_disk;
 | 
			
		||||
        struct data_area lv_on_disk;
 | 
			
		||||
        struct data_area pe_on_disk;
 | 
			
		||||
        uint8_t pv_uuid[NAME_LEN];
 | 
			
		||||
        uint8_t vg_name[NAME_LEN];
 | 
			
		||||
        uint8_t system_id[NAME_LEN];    /* for vgexport/vgimport */
 | 
			
		||||
        uint32_t pv_major;
 | 
			
		||||
        uint32_t pv_number;
 | 
			
		||||
        uint32_t pv_status;
 | 
			
		||||
        uint32_t pv_allocatable;
 | 
			
		||||
        uint32_t pv_size;
 | 
			
		||||
        uint32_t lv_cur;
 | 
			
		||||
        uint32_t pe_size;
 | 
			
		||||
        uint32_t pe_total;
 | 
			
		||||
        uint32_t pe_allocated;
 | 
			
		||||
	uint8_t id[2];
 | 
			
		||||
	uint16_t version;	/* lvm version */
 | 
			
		||||
	struct data_area pv_on_disk;
 | 
			
		||||
	struct data_area vg_on_disk;
 | 
			
		||||
	struct data_area pv_uuidlist_on_disk;
 | 
			
		||||
	struct data_area lv_on_disk;
 | 
			
		||||
	struct data_area pe_on_disk;
 | 
			
		||||
	uint8_t pv_uuid[NAME_LEN];
 | 
			
		||||
	uint8_t vg_name[NAME_LEN];
 | 
			
		||||
	uint8_t system_id[NAME_LEN];	/* for vgexport/vgimport */
 | 
			
		||||
	uint32_t pv_major;
 | 
			
		||||
	uint32_t pv_number;
 | 
			
		||||
	uint32_t pv_status;
 | 
			
		||||
	uint32_t pv_allocatable;
 | 
			
		||||
	uint32_t pv_size;
 | 
			
		||||
	uint32_t lv_cur;
 | 
			
		||||
	uint32_t pe_size;
 | 
			
		||||
	uint32_t pe_total;
 | 
			
		||||
	uint32_t pe_allocated;
 | 
			
		||||
 | 
			
		||||
	/* only present on version == 2 pv's */
 | 
			
		||||
	uint32_t pe_start;
 | 
			
		||||
};
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct lv_disk {
 | 
			
		||||
        uint8_t lv_name[NAME_LEN];
 | 
			
		||||
        uint8_t vg_name[NAME_LEN];
 | 
			
		||||
        uint32_t lv_access;
 | 
			
		||||
        uint32_t lv_status;
 | 
			
		||||
        uint32_t lv_open;
 | 
			
		||||
        uint32_t lv_dev;
 | 
			
		||||
        uint32_t lv_number;
 | 
			
		||||
        uint32_t lv_mirror_copies; /* for future use */
 | 
			
		||||
        uint32_t lv_recovery;      /*       "        */
 | 
			
		||||
        uint32_t lv_schedule;      /*       "        */
 | 
			
		||||
        uint32_t lv_size;
 | 
			
		||||
        uint32_t lv_snapshot_minor; /* minor number of original */
 | 
			
		||||
        uint16_t lv_chunk_size;     /* chunk size of snapshot */
 | 
			
		||||
        uint16_t dummy;
 | 
			
		||||
        uint32_t lv_allocated_le;
 | 
			
		||||
        uint32_t lv_stripes;
 | 
			
		||||
        uint32_t lv_stripesize;
 | 
			
		||||
        uint32_t lv_badblock;   /* for future use */
 | 
			
		||||
        uint32_t lv_allocation;
 | 
			
		||||
        uint32_t lv_io_timeout; /* for future use */
 | 
			
		||||
        uint32_t lv_read_ahead;
 | 
			
		||||
};
 | 
			
		||||
	uint8_t lv_name[NAME_LEN];
 | 
			
		||||
	uint8_t vg_name[NAME_LEN];
 | 
			
		||||
	uint32_t lv_access;
 | 
			
		||||
	uint32_t lv_status;
 | 
			
		||||
	uint32_t lv_open;
 | 
			
		||||
	uint32_t lv_dev;
 | 
			
		||||
	uint32_t lv_number;
 | 
			
		||||
	uint32_t lv_mirror_copies;	/* for future use */
 | 
			
		||||
	uint32_t lv_recovery;	/*       "        */
 | 
			
		||||
	uint32_t lv_schedule;	/*       "        */
 | 
			
		||||
	uint32_t lv_size;
 | 
			
		||||
	uint32_t lv_snapshot_minor;	/* minor number of original */
 | 
			
		||||
	uint16_t lv_chunk_size;	/* chunk size of snapshot */
 | 
			
		||||
	uint16_t dummy;
 | 
			
		||||
	uint32_t lv_allocated_le;
 | 
			
		||||
	uint32_t lv_stripes;
 | 
			
		||||
	uint32_t lv_stripesize;
 | 
			
		||||
	uint32_t lv_badblock;	/* for future use */
 | 
			
		||||
	uint32_t lv_allocation;
 | 
			
		||||
	uint32_t lv_io_timeout;	/* for future use */
 | 
			
		||||
	uint32_t lv_read_ahead;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct vg_disk {
 | 
			
		||||
        uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
 | 
			
		||||
        uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
 | 
			
		||||
        uint32_t vg_number;     /* volume group number */
 | 
			
		||||
        uint32_t vg_access;     /* read/write */
 | 
			
		||||
        uint32_t vg_status;     /* active or not */
 | 
			
		||||
        uint32_t lv_max;	/* maximum logical volumes */
 | 
			
		||||
        uint32_t lv_cur;	/* current logical volumes */
 | 
			
		||||
        uint32_t lv_open;	/* open logical volumes */
 | 
			
		||||
        uint32_t pv_max;	/* maximum physical volumes */
 | 
			
		||||
        uint32_t pv_cur;	/* current physical volumes FU */
 | 
			
		||||
        uint32_t pv_act;	/* active physical volumes */
 | 
			
		||||
        uint32_t dummy;
 | 
			
		||||
        uint32_t vgda;          /* volume group descriptor arrays FU */
 | 
			
		||||
        uint32_t pe_size;	/* physical extent size in sectors */
 | 
			
		||||
        uint32_t pe_total;	/* total of physical extents */
 | 
			
		||||
        uint32_t pe_allocated;  /* allocated physical extents */
 | 
			
		||||
        uint32_t pvg_total;     /* physical volume groups FU */
 | 
			
		||||
};
 | 
			
		||||
	uint8_t vg_uuid[ID_LEN];	/* volume group UUID */
 | 
			
		||||
	uint8_t vg_name_dummy[NAME_LEN - ID_LEN];	/* rest of v1 VG name */
 | 
			
		||||
	uint32_t vg_number;	/* volume group number */
 | 
			
		||||
	uint32_t vg_access;	/* read/write */
 | 
			
		||||
	uint32_t vg_status;	/* active or not */
 | 
			
		||||
	uint32_t lv_max;	/* maximum logical volumes */
 | 
			
		||||
	uint32_t lv_cur;	/* current logical volumes */
 | 
			
		||||
	uint32_t lv_open;	/* open logical volumes */
 | 
			
		||||
	uint32_t pv_max;	/* maximum physical volumes */
 | 
			
		||||
	uint32_t pv_cur;	/* current physical volumes FU */
 | 
			
		||||
	uint32_t pv_act;	/* active physical volumes */
 | 
			
		||||
	uint32_t dummy;
 | 
			
		||||
	uint32_t vgda;		/* volume group descriptor arrays FU */
 | 
			
		||||
	uint32_t pe_size;	/* physical extent size in sectors */
 | 
			
		||||
	uint32_t pe_total;	/* total of physical extents */
 | 
			
		||||
	uint32_t pe_allocated;	/* allocated physical extents */
 | 
			
		||||
	uint32_t pvg_total;	/* physical volume groups FU */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct pe_disk {
 | 
			
		||||
	uint16_t lv_num;
 | 
			
		||||
	uint16_t le_num;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct uuid_list {
 | 
			
		||||
	struct list list;
 | 
			
		||||
@@ -161,39 +157,35 @@ struct disk_list {
 | 
			
		||||
	struct pe_disk *extents;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Layout constants.
 | 
			
		||||
 */
 | 
			
		||||
#define METADATA_ALIGN 4096UL
 | 
			
		||||
#define	PE_ALIGN (65536UL / SECTOR_SIZE)
 | 
			
		||||
 | 
			
		||||
#define	METADATA_BASE 0UL
 | 
			
		||||
#define	PV_SIZE 1024UL
 | 
			
		||||
#define	VG_SIZE 4096UL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Functions to calculate layout info.
 | 
			
		||||
 */
 | 
			
		||||
int calculate_layout(struct disk_list *dl);
 | 
			
		||||
int calculate_extent_count(struct physical_volume *pv);
 | 
			
		||||
 | 
			
		||||
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
 | 
			
		||||
			   uint32_t max_extent_count);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Low level io routines which read/write
 | 
			
		||||
 * disk_lists.
 | 
			
		||||
 */
 | 
			
		||||
int read_pvd(struct device *dev, struct pv_disk *pvd);
 | 
			
		||||
 | 
			
		||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
 | 
			
		||||
			    const char *vg_name);
 | 
			
		||||
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
 | 
			
		||||
			    struct pool *mem, const char *vg_name);
 | 
			
		||||
 | 
			
		||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
 | 
			
		||||
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
 | 
			
		||||
		   struct dev_filter *filter,
 | 
			
		||||
		   struct pool *mem, struct list *results);
 | 
			
		||||
 | 
			
		||||
int write_disks(struct list *pvds);
 | 
			
		||||
 | 
			
		||||
int write_disks(const struct format_type *fmt, struct list *pvds);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Functions to translate to between disk and in
 | 
			
		||||
@@ -206,40 +198,38 @@ int export_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	      struct pv_disk *pvd, struct physical_volume *pv);
 | 
			
		||||
 | 
			
		||||
int import_vg(struct pool *mem,
 | 
			
		||||
	      struct volume_group *vg, struct disk_list *dl,
 | 
			
		||||
	      int partial);
 | 
			
		||||
	      struct volume_group *vg, struct disk_list *dl, int partial);
 | 
			
		||||
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
int import_lv(struct pool *mem, struct logical_volume *lv,
 | 
			
		||||
	      struct lv_disk *lvd);
 | 
			
		||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
 | 
			
		||||
	       struct logical_volume *lv, const char *dev_dir);
 | 
			
		||||
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
 | 
			
		||||
 | 
			
		||||
int import_extents(struct pool *mem, struct volume_group *vg, 
 | 
			
		||||
int import_extents(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
		   struct list *pvds);
 | 
			
		||||
int export_extents(struct disk_list *dl, int lv_num,
 | 
			
		||||
		   struct logical_volume *lv,
 | 
			
		||||
		   struct physical_volume *pv);
 | 
			
		||||
int export_extents(struct disk_list *dl, uint32_t lv_num,
 | 
			
		||||
		   struct logical_volume *lv, struct physical_volume *pv);
 | 
			
		||||
 | 
			
		||||
int import_pvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
int import_pvs(const struct format_type *fmt, struct pool *mem,
 | 
			
		||||
	       struct volume_group *vg,
 | 
			
		||||
	       struct list *pvds, struct list *results, int *count);
 | 
			
		||||
 | 
			
		||||
int import_lvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	       struct list *pvds);
 | 
			
		||||
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
 | 
			
		||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
 | 
			
		||||
	       struct physical_volume *pv, const char *dev_dir);
 | 
			
		||||
 | 
			
		||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
		     struct list *pvds);
 | 
			
		||||
 | 
			
		||||
int export_uuids(struct disk_list *dl, struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
void export_numbers(struct list *pvds, struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
void export_pv_act(struct list *pvds);
 | 
			
		||||
void munge_exported_vg(struct pv_disk *pvd);
 | 
			
		||||
 | 
			
		||||
/* blech */
 | 
			
		||||
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
 | 
			
		||||
		       int *result);
 | 
			
		||||
int export_vg_number(struct list *pvds, const char *vg_name,
 | 
			
		||||
		     struct dev_filter *filter);
 | 
			
		||||
 | 
			
		||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
 | 
			
		||||
		       const char *candidate_vg, int *result);
 | 
			
		||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
 | 
			
		||||
		     const char *vg_name, struct dev_filter *filter);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,17 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "limits.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "lvm1-label.h"
 | 
			
		||||
#include "format1.h"
 | 
			
		||||
 | 
			
		||||
/* VG consistency checks */
 | 
			
		||||
static int _check_vgs(struct list *pvs, int *partial)
 | 
			
		||||
@@ -19,8 +23,9 @@ static int _check_vgs(struct list *pvs, int *partial)
 | 
			
		||||
	struct disk_list *dl = NULL;
 | 
			
		||||
	struct disk_list *first = NULL;
 | 
			
		||||
 | 
			
		||||
	int pv_count = 0;
 | 
			
		||||
	int exported = -1;
 | 
			
		||||
	uint32_t pv_count = 0;
 | 
			
		||||
	uint32_t exported = 0;
 | 
			
		||||
	int first_time = 1;
 | 
			
		||||
 | 
			
		||||
	*partial = 0;
 | 
			
		||||
 | 
			
		||||
@@ -28,12 +33,13 @@ static int _check_vgs(struct list *pvs, int *partial)
 | 
			
		||||
	 * If there are exported and unexported PVs, ignore exported ones.
 | 
			
		||||
	 * This means an active VG won't be affected if disks are inserted
 | 
			
		||||
	 * bearing an exported VG with the same name.
 | 
			
		||||
	 */ 
 | 
			
		||||
	 */
 | 
			
		||||
	list_iterate(pvh, pvs) {
 | 
			
		||||
		dl = list_item(pvh, struct disk_list);
 | 
			
		||||
 | 
			
		||||
		if (exported < 0) {
 | 
			
		||||
		if (first_time) {
 | 
			
		||||
			exported = dl->pvd.pv_status & VG_EXPORTED;
 | 
			
		||||
			first_time = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -48,7 +54,6 @@ static int _check_vgs(struct list *pvs, int *partial)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Remove any PVs with VG structs that differ from the first */
 | 
			
		||||
	list_iterate_safe(pvh, t, pvs) {
 | 
			
		||||
		dl = list_item(pvh, struct disk_list);
 | 
			
		||||
@@ -81,8 +86,10 @@ static int _check_vgs(struct list *pvs, int *partial)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
 | 
			
		||||
static struct volume_group *_build_vg(struct format_instance *fid,
 | 
			
		||||
				      struct list *pvs)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = fid->fmt->cmd->mem;
 | 
			
		||||
	struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	int partial;
 | 
			
		||||
@@ -95,8 +102,12 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
 | 
			
		||||
 | 
			
		||||
	memset(vg, 0, sizeof(*vg));
 | 
			
		||||
 | 
			
		||||
	vg->cmd = fid->fmt->cmd;
 | 
			
		||||
	vg->fid = fid;
 | 
			
		||||
	vg->seqno = 0;
 | 
			
		||||
	list_init(&vg->pvs);
 | 
			
		||||
	list_init(&vg->lvs);
 | 
			
		||||
	list_init(&vg->snapshots);
 | 
			
		||||
 | 
			
		||||
	if (!_check_vgs(pvs, &partial))
 | 
			
		||||
		goto bad;
 | 
			
		||||
@@ -106,7 +117,7 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
 | 
			
		||||
	if (!import_vg(mem, vg, dl, partial))
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	if (!import_pvs(mem, vg, pvs, &vg->pvs, &vg->pv_count))
 | 
			
		||||
	if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	if (!import_lvs(mem, vg, pvs))
 | 
			
		||||
@@ -115,16 +126,20 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
 | 
			
		||||
	if (!import_extents(mem, vg, pvs))
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	if (!import_snapshots(mem, vg, pvs))
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	return vg;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	stack;
 | 
			
		||||
	pool_free(mem, vg);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct volume_group *_vg_read(struct format_instance *fi,
 | 
			
		||||
				     const char *vg_name)
 | 
			
		||||
static struct volume_group *_vg_read(struct format_instance *fid,
 | 
			
		||||
				     const char *vg_name,
 | 
			
		||||
				     struct metadata_area *mda)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = pool_create(1024 * 10);
 | 
			
		||||
	struct list pvs;
 | 
			
		||||
@@ -136,22 +151,21 @@ static struct volume_group *_vg_read(struct format_instance *fi,
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        /* Strip dev_dir if present */
 | 
			
		||||
	vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
 | 
			
		||||
	/* Strip dev_dir if present */
 | 
			
		||||
	vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
 | 
			
		||||
 | 
			
		||||
	if (!read_pvs_in_vg(vg_name, fi->cmd->filter, mem, &pvs)) {
 | 
			
		||||
	if (!read_pvs_in_vg
 | 
			
		||||
	    (fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
 | 
			
		||||
	if (!(vg = _build_vg(fid, &pvs))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vg->cmd = fi->cmd;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return vg;
 | 
			
		||||
}
 | 
			
		||||
@@ -176,8 +190,7 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	if (!export_pv(mem, vg, &dl->pvd, pv) ||
 | 
			
		||||
	    !export_vg(&dl->vgd, vg) ||
 | 
			
		||||
	    !export_uuids(dl, vg) ||
 | 
			
		||||
	    !export_lvs(dl, vg, pv, dev_dir) ||
 | 
			
		||||
	    !calculate_layout(dl)) {
 | 
			
		||||
	    !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		pool_free(mem, dl);
 | 
			
		||||
		return NULL;
 | 
			
		||||
@@ -186,7 +199,8 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	return dl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _flatten_vg(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
static int _flatten_vg(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
		       struct volume_group *vg,
 | 
			
		||||
		       struct list *pvds, const char *dev_dir,
 | 
			
		||||
		       struct dev_filter *filter)
 | 
			
		||||
{
 | 
			
		||||
@@ -208,7 +222,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	export_numbers(pvds, vg);
 | 
			
		||||
	export_pv_act(pvds);
 | 
			
		||||
 | 
			
		||||
	if (!export_vg_number(pvds, vg->name, filter)) {
 | 
			
		||||
	if (!export_vg_number(fid, pvds, vg->name, filter)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -216,7 +230,8 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
 | 
			
		||||
		     struct metadata_area *mda)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = pool_create(1024 * 10);
 | 
			
		||||
	struct list pvds;
 | 
			
		||||
@@ -227,204 +242,163 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vg->status & PARTIAL_VG) {
 | 
			
		||||
		log_error("Cannot change metadata for partial volume group %s",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&pvds);
 | 
			
		||||
 | 
			
		||||
	r = (_flatten_vg(mem, vg, &pvds, fi->cmd->dev_dir, fi->cmd->filter) &&
 | 
			
		||||
	     write_disks(&pvds));
 | 
			
		||||
	r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
 | 
			
		||||
			 fid->fmt->cmd->filter) &&
 | 
			
		||||
	     write_disks(fid->fmt, &pvds));
 | 
			
		||||
 | 
			
		||||
	lvmcache_update_vg(vg);
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct physical_volume *_pv_read(struct format_instance *fi,
 | 
			
		||||
					const char *name)
 | 
			
		||||
static int _pv_read(const struct format_type *fmt, const char *pv_name,
 | 
			
		||||
		    struct physical_volume *pv, struct list *mdas)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = pool_create(1024);
 | 
			
		||||
	struct physical_volume *pv = NULL;
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
        log_very_verbose("Reading physical volume data %s from disk", name);
 | 
			
		||||
	log_very_verbose("Reading physical volume data %s from disk", pv_name);
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dev = dev_cache_get(name, fi->cmd->filter))) {
 | 
			
		||||
	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dl = read_disk(dev, mem, NULL))) {
 | 
			
		||||
	if (!(dl = read_disk(fmt, dev, mem, NULL))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pv = pool_alloc(fi->cmd->mem, sizeof(*pv)))) {
 | 
			
		||||
	if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!import_pv(fi->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		pool_free(fi->cmd->mem, pv);
 | 
			
		||||
		pv = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pv->fmt = fmt;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return pv;
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct list *_get_pvs(struct format_instance *fi)
 | 
			
		||||
static int _pv_setup(const struct format_type *fmt,
 | 
			
		||||
		     uint64_t pe_start, uint32_t extent_count,
 | 
			
		||||
		     uint32_t extent_size,
 | 
			
		||||
		     int pvmetadatacopies,
 | 
			
		||||
		     uint64_t pvmetadatasize, struct list *mdas,
 | 
			
		||||
		     struct physical_volume *pv, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = pool_create(1024 * 10);
 | 
			
		||||
	struct list pvs, *results;
 | 
			
		||||
	uint32_t count;
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if (pv->size > MAX_PV_SIZE)
 | 
			
		||||
		pv->size--;
 | 
			
		||||
	if (pv->size > MAX_PV_SIZE) {
 | 
			
		||||
		log_error("Physical volumes cannot be bigger than %s",
 | 
			
		||||
			  display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
 | 
			
		||||
				       SIZE_SHORT));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(results = pool_alloc(fi->cmd->mem, sizeof(*results)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		pool_destroy(mem);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	/* Nothing more to do if extent size isn't provided */
 | 
			
		||||
	if (!extent_size)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	list_init(&pvs);
 | 
			
		||||
	list_init(results);
 | 
			
		||||
 | 
			
		||||
	if (!read_pvs_in_vg(NULL, fi->cmd->filter, mem, &pvs)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!import_pvs(fi->cmd->mem, NULL, &pvs, results, &count)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return results;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	pool_free(fi->cmd->mem, results);
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _find_vg_name(struct list *names, const char *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *nh;
 | 
			
		||||
	struct name_list *nl;
 | 
			
		||||
 | 
			
		||||
	list_iterate(nh, names) {
 | 
			
		||||
		nl = list_item(nh, struct name_list);
 | 
			
		||||
		if (!strcmp(nl->name, vg))
 | 
			
		||||
			return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct list *_get_vgs(struct format_instance *fi)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvh;
 | 
			
		||||
	struct list *pvs, *names = pool_alloc(fi->cmd->mem, sizeof(*names));
 | 
			
		||||
	struct name_list *nl;
 | 
			
		||||
 | 
			
		||||
	if (!names) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(names);
 | 
			
		||||
 | 
			
		||||
	if (!(pvs = _get_pvs(fi))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_iterate(pvh, pvs) {
 | 
			
		||||
		struct pv_list *pvl = list_item(pvh, struct pv_list);
 | 
			
		||||
 | 
			
		||||
		if (!(*pvl->pv->vg_name) ||
 | 
			
		||||
	 	     _find_vg_name(names, pvl->pv->vg_name))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(nl->name = pool_strdup(fi->cmd->mem,
 | 
			
		||||
					     pvl->pv->vg_name))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list_add(names, &nl->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (list_empty(names))
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	return names;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	pool_free(fi->cmd->mem, names);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
 | 
			
		||||
		     struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * This works out pe_start and pe_count.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!calculate_extent_count(pv)) {
 | 
			
		||||
	if (!calculate_extent_count(pv, extent_size, extent_count)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Retain existing extent locations exactly */
 | 
			
		||||
	/* FIXME Relax this so a non-overlapping existing pe_start can also 
 | 
			
		||||
	 * be used in place of the calculated one */
 | 
			
		||||
	if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
 | 
			
		||||
	    (extent_count && (extent_count != pv->pe_count))) {
 | 
			
		||||
		log_error("Metadata would overwrite physical extents");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
 | 
			
		||||
static uint32_t _find_free_lvnum(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int lvnum_used[MAX_LV];
 | 
			
		||||
	uint32_t i = 0;
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	struct lv_list *lvl;
 | 
			
		||||
 | 
			
		||||
	memset(&lvnum_used, 0, sizeof(lvnum_used));
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &lv->vg->lvs) {
 | 
			
		||||
		lvl = list_item(lvh, struct lv_list);
 | 
			
		||||
		lvnum_used[lvnum_from_lvid(&lvl->lv->lvid)] = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (lvnum_used[i])
 | 
			
		||||
		i++;
 | 
			
		||||
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	uint64_t max_size = UINT_MAX;
 | 
			
		||||
 | 
			
		||||
	if (!*lv->lvid.s)
 | 
			
		||||
		lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
 | 
			
		||||
 | 
			
		||||
	if (lv->le_count > MAX_LE_TOTAL) {
 | 
			
		||||
		log_error("logical volumes cannot contain more than "
 | 
			
		||||
			  "%d extents.", MAX_LE_TOTAL);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (lv->size > max_size) {
 | 
			
		||||
		log_error("logical volumes cannot be larger than %s",
 | 
			
		||||
			  display_size(fid->fmt->cmd, max_size / 2,
 | 
			
		||||
				       SIZE_SHORT));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
 | 
			
		||||
static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
 | 
			
		||||
		     struct list *mdas, int64_t sector)
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem;
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	struct list pvs;
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
 | 
			
		||||
	if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
 | 
			
		||||
				  pv->vg_name, NULL))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	label = info->label;
 | 
			
		||||
	info->device_size = pv->size << SECTOR_SHIFT;
 | 
			
		||||
	info->fmt = fmt;
 | 
			
		||||
 | 
			
		||||
	list_init(&info->mdas);
 | 
			
		||||
 | 
			
		||||
	list_init(&pvs);
 | 
			
		||||
 | 
			
		||||
	if (*pv->vg_name || pv->pe_allocated ) {
 | 
			
		||||
		log_error("Assertion failed: can't _pv_write non-orphan PV "
 | 
			
		||||
			  "(in VG %s)", pv->vg_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ensure any residual PE structure is gone */
 | 
			
		||||
	pv->pe_size = pv->pe_count = pv->pe_start = 0;
 | 
			
		||||
	pv->pe_size = pv->pe_count = 0;
 | 
			
		||||
	pv->pe_start = PE_ALIGN;
 | 
			
		||||
 | 
			
		||||
	if (!(mem = pool_create(1024))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -447,9 +421,10 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
 | 
			
		||||
	   dev_write in order to make other disk tools happy */
 | 
			
		||||
	dl->pvd.pv_on_disk.base = METADATA_BASE;
 | 
			
		||||
	dl->pvd.pv_on_disk.size = PV_SIZE;
 | 
			
		||||
	dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
 | 
			
		||||
 | 
			
		||||
	list_add(&pvs, &dl->list);
 | 
			
		||||
	if (!write_disks(&pvs)) {
 | 
			
		||||
	if (!write_disks(fmt, &pvs)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
@@ -457,37 +432,37 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _vg_setup(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	/* just check max_pv and max_lv */
 | 
			
		||||
	if (vg->max_lv >= MAX_LV)
 | 
			
		||||
		vg->max_lv = MAX_LV - 1;
 | 
			
		||||
 | 
			
		||||
        if (vg->max_pv >= MAX_PV)
 | 
			
		||||
	if (vg->max_pv >= MAX_PV)
 | 
			
		||||
		vg->max_pv = MAX_PV - 1;
 | 
			
		||||
 | 
			
		||||
	if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
 | 
			
		||||
		char *dummy, *dummy2;
 | 
			
		||||
 | 
			
		||||
		log_error("Extent size must be between %s and %s",
 | 
			
		||||
			(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
 | 
			
		||||
			(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
 | 
			
		||||
			  display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
 | 
			
		||||
				       / 2,
 | 
			
		||||
				       SIZE_SHORT), display_size(fid->fmt->cmd,
 | 
			
		||||
								 (uint64_t)
 | 
			
		||||
								 MAX_PE_SIZE
 | 
			
		||||
								 / 2,
 | 
			
		||||
								 SIZE_SHORT));
 | 
			
		||||
 | 
			
		||||
		dbg_free(dummy);
 | 
			
		||||
		dbg_free(dummy2);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vg->extent_size % MIN_PE_SIZE) {
 | 
			
		||||
		char *dummy;
 | 
			
		||||
		log_error("Extent size must be multiple of %s",
 | 
			
		||||
			(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
 | 
			
		||||
		dbg_free(dummy);
 | 
			
		||||
			  display_size(fid->fmt->cmd,
 | 
			
		||||
				       (uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -500,37 +475,91 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _destroy(struct format_instance *fi)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(fi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct format_handler _format1_ops = {
 | 
			
		||||
	get_vgs: _get_vgs,
 | 
			
		||||
	get_pvs: _get_pvs,
 | 
			
		||||
	pv_read: _pv_read,
 | 
			
		||||
	pv_setup: _pv_setup,
 | 
			
		||||
	pv_write: _pv_write,
 | 
			
		||||
	lv_setup: _lv_setup,
 | 
			
		||||
	vg_read: _vg_read,
 | 
			
		||||
	vg_setup: _vg_setup,
 | 
			
		||||
	vg_write: _vg_write,
 | 
			
		||||
	destroy: _destroy,
 | 
			
		||||
static struct metadata_area_ops _metadata_format1_ops = {
 | 
			
		||||
	vg_read:_vg_read,
 | 
			
		||||
	vg_write:_vg_write,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd)
 | 
			
		||||
static struct format_instance *_create_instance(const struct format_type *fmt,
 | 
			
		||||
						const char *vgname,
 | 
			
		||||
						void *private)
 | 
			
		||||
{
 | 
			
		||||
	struct format_instance *fi = dbg_malloc(sizeof(*fi));
 | 
			
		||||
	struct format_instance *fid;
 | 
			
		||||
	struct metadata_area *mda;
 | 
			
		||||
 | 
			
		||||
	if (!fi) {
 | 
			
		||||
	if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fi->cmd = cmd;
 | 
			
		||||
	fi->ops = &_format1_ops;
 | 
			
		||||
	fi->private = NULL;
 | 
			
		||||
	fid->fmt = fmt;
 | 
			
		||||
	list_init(&fid->metadata_areas);
 | 
			
		||||
 | 
			
		||||
	return fi;
 | 
			
		||||
	/* Define a NULL metadata area */
 | 
			
		||||
	if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		pool_free(fmt->cmd->mem, fid);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mda->ops = &_metadata_format1_ops;
 | 
			
		||||
	mda->metadata_locn = NULL;
 | 
			
		||||
	list_add(&fid->metadata_areas, &mda->list);
 | 
			
		||||
 | 
			
		||||
	return fid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy_instance(struct format_instance *fid)
 | 
			
		||||
{
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(const struct format_type *fmt)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free((void *) fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct format_handler _format1_ops = {
 | 
			
		||||
	pv_read:_pv_read,
 | 
			
		||||
	pv_setup:_pv_setup,
 | 
			
		||||
	pv_write:_pv_write,
 | 
			
		||||
	lv_setup:_lv_setup,
 | 
			
		||||
	vg_setup:_vg_setup,
 | 
			
		||||
	create_instance:_create_instance,
 | 
			
		||||
	destroy_instance:_destroy_instance,
 | 
			
		||||
	destroy:_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef LVM1_INTERNAL
 | 
			
		||||
struct format_type *init_lvm1_format(struct cmd_context *cmd)
 | 
			
		||||
#else				/* Shared */
 | 
			
		||||
struct format_type *init_format(struct cmd_context *cmd);
 | 
			
		||||
struct format_type *init_format(struct cmd_context *cmd)
 | 
			
		||||
#endif
 | 
			
		||||
{
 | 
			
		||||
	struct format_type *fmt = dbg_malloc(sizeof(*fmt));
 | 
			
		||||
 | 
			
		||||
	if (!fmt) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt->cmd = cmd;
 | 
			
		||||
	fmt->ops = &_format1_ops;
 | 
			
		||||
	fmt->name = FMT_LVM1_NAME;
 | 
			
		||||
	fmt->alias = NULL;
 | 
			
		||||
	fmt->features = 0;
 | 
			
		||||
	fmt->private = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
 | 
			
		||||
		log_error("Couldn't create lvm1 label handler.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
 | 
			
		||||
		log_error("Couldn't register lvm1 label handler.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,10 @@
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd);
 | 
			
		||||
#define FMT_LVM1_NAME "lvm1"
 | 
			
		||||
 | 
			
		||||
#ifdef LVM1_INTERNAL
 | 
			
		||||
struct format_type *init_lvm1_format(struct cmd_context *cmd);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,13 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
@@ -52,15 +52,15 @@ int import_pv(struct pool *mem, struct device *dev,
 | 
			
		||||
 | 
			
		||||
	/* Store system_id from first PV if PV belongs to a VG */
 | 
			
		||||
	if (vg && !*vg->system_id)
 | 
			
		||||
	    strncpy(vg->system_id, pvd->system_id, NAME_LEN);
 | 
			
		||||
		strncpy(vg->system_id, pvd->system_id, NAME_LEN);
 | 
			
		||||
 | 
			
		||||
	if (vg &&
 | 
			
		||||
	    strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
 | 
			
		||||
		log_very_verbose("System ID %s on %s differs from %s for "
 | 
			
		||||
				 "volume group", pvd->system_id, 
 | 
			
		||||
				 "volume group", pvd->system_id,
 | 
			
		||||
				 dev_name(pv->dev), vg->system_id);
 | 
			
		||||
	
 | 
			
		||||
	/* 
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If exported, we still need to flag in pv->status too because
 | 
			
		||||
	 * we don't always have a struct volume_group when we need this.
 | 
			
		||||
	 */
 | 
			
		||||
@@ -74,12 +74,12 @@ int import_pv(struct pool *mem, struct device *dev,
 | 
			
		||||
	pv->pe_size = pvd->pe_size;
 | 
			
		||||
	pv->pe_start = pvd->pe_start;
 | 
			
		||||
	pv->pe_count = pvd->pe_total;
 | 
			
		||||
	pv->pe_allocated = pvd->pe_allocated;
 | 
			
		||||
	pv->pe_alloc_count = pvd->pe_allocated;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _system_id(char *s, const char *prefix)
 | 
			
		||||
static int _system_id(char *s, const char *prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct utsname uts;
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +88,7 @@ int _system_id(char *s, const char *prefix)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(s, NAME_LEN, "%s%s%lu", 
 | 
			
		||||
	if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
 | 
			
		||||
			 prefix, uts.nodename, time(NULL)) < 0) {
 | 
			
		||||
		log_error("Generated system_id too long");
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -119,14 +119,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
		strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
 | 
			
		||||
 | 
			
		||||
	/* Preserve existing system_id if it exists */
 | 
			
		||||
	if (vg && *vg->system_id) 
 | 
			
		||||
	if (vg && *vg->system_id)
 | 
			
		||||
		strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id));
 | 
			
		||||
 | 
			
		||||
	/* Is VG already exported or being exported? */
 | 
			
		||||
	if (vg && (vg->status & EXPORTED_VG)) {
 | 
			
		||||
		/* Does system_id need setting? */
 | 
			
		||||
		if (!*vg->system_id || 
 | 
			
		||||
		    strncmp(vg->system_id, EXPORTED_TAG, 
 | 
			
		||||
		if (!*vg->system_id ||
 | 
			
		||||
		    strncmp(vg->system_id, EXPORTED_TAG,
 | 
			
		||||
			    sizeof(EXPORTED_TAG) - 1)) {
 | 
			
		||||
			if (!_system_id(pvd->system_id, EXPORTED_TAG)) {
 | 
			
		||||
				stack;
 | 
			
		||||
@@ -159,7 +159,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* Update internal system_id if we changed it */
 | 
			
		||||
	if (vg && 
 | 
			
		||||
	if (vg &&
 | 
			
		||||
	    (!*vg->system_id ||
 | 
			
		||||
	     strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
 | 
			
		||||
		strncpy(vg->system_id, pvd->system_id, NAME_LEN);
 | 
			
		||||
@@ -171,17 +171,19 @@ int export_pv(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
 | 
			
		||||
	pvd->pv_size = pv->size;
 | 
			
		||||
	pvd->lv_cur = 0;	/* this is set when exporting the lv list */
 | 
			
		||||
	pvd->pe_size = pv->pe_size;
 | 
			
		||||
	if (vg)
 | 
			
		||||
		pvd->pe_size = vg->extent_size;
 | 
			
		||||
	else
 | 
			
		||||
		pvd->pe_size = pv->pe_size;
 | 
			
		||||
	pvd->pe_total = pv->pe_count;
 | 
			
		||||
	pvd->pe_allocated = pv->pe_allocated;
 | 
			
		||||
	pvd->pe_allocated = pv->pe_alloc_count;
 | 
			
		||||
	pvd->pe_start = pv->pe_start;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int import_vg(struct pool *mem,
 | 
			
		||||
	      struct volume_group *vg, struct disk_list *dl,
 | 
			
		||||
	      int partial)
 | 
			
		||||
	      struct volume_group *vg, struct disk_list *dl, int partial)
 | 
			
		||||
{
 | 
			
		||||
	struct vg_disk *vgd = &dl->vgd;
 | 
			
		||||
	memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
 | 
			
		||||
@@ -271,56 +273,58 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg)
 | 
			
		||||
 | 
			
		||||
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
 | 
			
		||||
{
 | 
			
		||||
	memset(&lv->id, 0, sizeof(lv->id));
 | 
			
		||||
        if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
 | 
			
		||||
	lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
 | 
			
		||||
 | 
			
		||||
	if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->status |= VISIBLE_LV;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_status & LV_SPINDOWN)
 | 
			
		||||
		lv->status |= SPINDOWN_LV;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_status & LV_PERSISTENT_MINOR) {
 | 
			
		||||
		lv->status |= FIXED_MINOR;
 | 
			
		||||
		lv->minor = MINOR(lvd->lv_dev);
 | 
			
		||||
		lv->major = MAJOR(lvd->lv_dev);
 | 
			
		||||
	} else {
 | 
			
		||||
		lv->major = -1;
 | 
			
		||||
		lv->minor = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_access & LV_READ)
 | 
			
		||||
		lv->status |= LVM_READ;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_access & LV_WRITE)
 | 
			
		||||
		lv->status |= LVM_WRITE;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_access & LV_SNAPSHOT)
 | 
			
		||||
		lv->status |= SNAPSHOT;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_access & LV_SNAPSHOT_ORG)
 | 
			
		||||
		lv->status |= SNAPSHOT_ORG;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_badblock)
 | 
			
		||||
		lv->status |= BADBLOCK_ON;
 | 
			
		||||
 | 
			
		||||
	if (lvd->lv_allocation & LV_STRICT)
 | 
			
		||||
		lv->status |= ALLOC_STRICT;
 | 
			
		||||
 | 
			
		||||
	/* Drop the unused LV_STRICT here */
 | 
			
		||||
	if (lvd->lv_allocation & LV_CONTIGUOUS)
 | 
			
		||||
		lv->status |= ALLOC_CONTIGUOUS;
 | 
			
		||||
		lv->alloc = ALLOC_CONTIGUOUS;
 | 
			
		||||
	else
 | 
			
		||||
		lv->status |= ALLOC_SIMPLE;
 | 
			
		||||
		lv->alloc = ALLOC_NEXT_FREE;
 | 
			
		||||
 | 
			
		||||
	lv->read_ahead = lvd->lv_read_ahead;
 | 
			
		||||
        lv->size = lvd->lv_size;
 | 
			
		||||
        lv->le_count = lvd->lv_allocated_le;
 | 
			
		||||
	lv->size = lvd->lv_size;
 | 
			
		||||
	lv->le_count = lvd->lv_allocated_le;
 | 
			
		||||
 | 
			
		||||
	list_init(&lv->segments);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
 | 
			
		||||
	       struct logical_volume *lv, const char *dev_dir)
 | 
			
		||||
static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
 | 
			
		||||
		       struct logical_volume *lv, const char *dev_dir)
 | 
			
		||||
{
 | 
			
		||||
	memset(lvd, 0, sizeof(*lvd));
 | 
			
		||||
	snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
 | 
			
		||||
		 dev_dir, vg->name, lv->name);
 | 
			
		||||
 | 
			
		||||
	/* FIXME: Add 'if' test */
 | 
			
		||||
	_check_vg_name(vg->name);
 | 
			
		||||
	strcpy(lvd->vg_name, vg->name);
 | 
			
		||||
 | 
			
		||||
	if (lv->status & LVM_READ)
 | 
			
		||||
@@ -329,55 +333,60 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
 | 
			
		||||
	if (lv->status & LVM_WRITE)
 | 
			
		||||
		lvd->lv_access |= LV_WRITE;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & SNAPSHOT)
 | 
			
		||||
		lvd->lv_access |= LV_SNAPSHOT;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & SNAPSHOT_ORG)
 | 
			
		||||
		lvd->lv_access |= LV_SNAPSHOT_ORG;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & SPINDOWN_LV)
 | 
			
		||||
		lvd->lv_status |= LV_SPINDOWN;
 | 
			
		||||
 | 
			
		||||
	lvd->lv_read_ahead = lv->read_ahead;
 | 
			
		||||
	lvd->lv_stripes = list_item(lv->segments.n,
 | 
			
		||||
				    struct stripe_segment)->stripes;
 | 
			
		||||
	lvd->lv_stripesize = list_item(lv->segments.n,
 | 
			
		||||
				    struct stripe_segment)->stripe_size;
 | 
			
		||||
	if (lv->status & FIXED_MINOR) {
 | 
			
		||||
		lvd->lv_status |= LV_PERSISTENT_MINOR;
 | 
			
		||||
		lvd->lv_dev = MKDEV(lv->major, lv->minor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        lvd->lv_size = lv->size;
 | 
			
		||||
        lvd->lv_allocated_le = lv->le_count;
 | 
			
		||||
	lvd->lv_read_ahead = lv->read_ahead;
 | 
			
		||||
	lvd->lv_stripes =
 | 
			
		||||
	    list_item(lv->segments.n, struct lv_segment)->area_count;
 | 
			
		||||
	lvd->lv_stripesize =
 | 
			
		||||
	    list_item(lv->segments.n, struct lv_segment)->stripe_size;
 | 
			
		||||
 | 
			
		||||
	lvd->lv_size = lv->size;
 | 
			
		||||
	lvd->lv_allocated_le = lv->le_count;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & BADBLOCK_ON)
 | 
			
		||||
		lvd->lv_badblock = LV_BADBLOCK_ON;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & ALLOC_STRICT)
 | 
			
		||||
		lvd->lv_allocation |= LV_STRICT;
 | 
			
		||||
 | 
			
		||||
	if (lv->status & ALLOC_CONTIGUOUS)
 | 
			
		||||
	if (lv->alloc == ALLOC_CONTIGUOUS)
 | 
			
		||||
		lvd->lv_allocation |= LV_CONTIGUOUS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int export_extents(struct disk_list *dl, int lv_num,
 | 
			
		||||
		   struct logical_volume *lv,
 | 
			
		||||
		   struct physical_volume *pv)
 | 
			
		||||
int export_extents(struct disk_list *dl, uint32_t lv_num,
 | 
			
		||||
		   struct logical_volume *lv, struct physical_volume *pv)
 | 
			
		||||
{
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
	struct pe_disk *ped;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	uint32_t pe, s;
 | 
			
		||||
 | 
			
		||||
	list_iterate (segh, &lv->segments) {
 | 
			
		||||
		seg = list_item(segh, struct stripe_segment);
 | 
			
		||||
	list_iterate(segh, &lv->segments) {
 | 
			
		||||
		seg = list_item(segh, struct lv_segment);
 | 
			
		||||
 | 
			
		||||
		for (s = 0; s < seg->stripes; s++) {
 | 
			
		||||
			if (seg->area[s].pv != pv)
 | 
			
		||||
				continue; /* not our pv */
 | 
			
		||||
		for (s = 0; s < seg->area_count; s++) {
 | 
			
		||||
			if (seg->type != SEG_STRIPED) {
 | 
			
		||||
				log_error("Non-striped segment type in LV %s: "
 | 
			
		||||
					  "unsupported by format1", lv->name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			if (seg->area[s].type != AREA_PV) {
 | 
			
		||||
				log_error("LV stripe found in LV %s: "
 | 
			
		||||
					  "unsupported by format1", lv->name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			if (seg->area[s].u.pv.pv != pv)
 | 
			
		||||
				continue;	/* not our pv */
 | 
			
		||||
 | 
			
		||||
			for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
 | 
			
		||||
				ped = &dl->extents[pe + seg->area[s].pe];
 | 
			
		||||
			for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
 | 
			
		||||
				ped = &dl->extents[pe + seg->area[s].u.pv.pe];
 | 
			
		||||
				ped->lv_num = lv_num;
 | 
			
		||||
				ped->le_num = (seg->le / seg->stripes) + pe +
 | 
			
		||||
					      s * (lv->le_count / seg->stripes);
 | 
			
		||||
				ped->le_num = (seg->le / seg->area_count) + pe +
 | 
			
		||||
				    s * (lv->le_count / seg->area_count);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -385,7 +394,8 @@ int export_extents(struct disk_list *dl, int lv_num,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int import_pvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
int import_pvs(const struct format_type *fmt, struct pool *mem,
 | 
			
		||||
	       struct volume_group *vg,
 | 
			
		||||
	       struct list *pvds, struct list *results, int *count)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvdh;
 | 
			
		||||
@@ -397,7 +407,7 @@ int import_pvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
 | 
			
		||||
		dl = list_item(pvdh, struct disk_list);
 | 
			
		||||
 | 
			
		||||
		if (!(pvl = pool_alloc(mem, sizeof(*pvl))) ||
 | 
			
		||||
		if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
 | 
			
		||||
		    !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
@@ -408,6 +418,7 @@ int import_pvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pvl->pv->fmt = fmt;
 | 
			
		||||
		list_add(results, &pvl->list);
 | 
			
		||||
		(*count)++;
 | 
			
		||||
	}
 | 
			
		||||
@@ -428,6 +439,7 @@ static struct logical_volume *_add_lv(struct pool *mem,
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	lv = ll->lv;
 | 
			
		||||
	lv->vg = vg;
 | 
			
		||||
 | 
			
		||||
	if (!import_lv(mem, lv, lvd)) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -435,14 +447,12 @@ static struct logical_volume *_add_lv(struct pool *mem,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add(&vg->lvs, &ll->list);
 | 
			
		||||
	lv->vg = vg;
 | 
			
		||||
	vg->lv_count++;
 | 
			
		||||
 | 
			
		||||
	return lv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int import_lvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	       struct list *pvds)
 | 
			
		||||
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
 | 
			
		||||
{
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	struct lvd_list *ll;
 | 
			
		||||
@@ -466,13 +476,27 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: tidy */
 | 
			
		||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
 | 
			
		||||
	       struct physical_volume *pv, const char *dev_dir)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct list *lvh, *sh;
 | 
			
		||||
	struct lv_list *ll;
 | 
			
		||||
	struct lvd_list *lvdl;
 | 
			
		||||
	int lv_num = 0, len;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	uint32_t lv_num;
 | 
			
		||||
	struct hash_table *lvd_hash;
 | 
			
		||||
 | 
			
		||||
	if (!_check_vg_name(vg->name)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(lvd_hash = hash_create(32))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * setup the pv's extents array
 | 
			
		||||
@@ -480,29 +504,142 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
 | 
			
		||||
	len = sizeof(struct pe_disk) * dl->pvd.pe_total;
 | 
			
		||||
	if (!(dl->extents = pool_alloc(dl->mem, len))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	memset(dl->extents, 0, len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		ll = list_item(lvh, struct lv_list);
 | 
			
		||||
		if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
 | 
			
		||||
		_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
 | 
			
		||||
 | 
			
		||||
		lv_num = lvnum_from_lvid(&ll->lv->lvid);
 | 
			
		||||
 | 
			
		||||
		lvdl->lvd.lv_number = lv_num;
 | 
			
		||||
 | 
			
		||||
		if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!export_extents(dl, lv_num + 1, ll->lv, pv)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list_add(&dl->lvds, &lvdl->list);
 | 
			
		||||
		dl->pvd.lv_cur++;
 | 
			
		||||
		lv_num++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Now we need to run through the snapshots, exporting
 | 
			
		||||
	 * the SNAPSHOT_ORG flags etc.
 | 
			
		||||
	 */
 | 
			
		||||
	list_iterate(sh, &vg->snapshots) {
 | 
			
		||||
		struct lv_disk *org, *cow;
 | 
			
		||||
		struct snapshot *s = list_item(sh,
 | 
			
		||||
					       struct snapshot_list)->snapshot;
 | 
			
		||||
 | 
			
		||||
		if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
 | 
			
		||||
			log_err("Couldn't find snapshot origin '%s'.",
 | 
			
		||||
				s->origin->name);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
 | 
			
		||||
			log_err("Couldn't find snapshot cow store '%s'.",
 | 
			
		||||
				s->cow->name);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		org->lv_access |= LV_SNAPSHOT_ORG;
 | 
			
		||||
		cow->lv_access |= LV_SNAPSHOT;
 | 
			
		||||
		cow->lv_snapshot_minor = org->lv_number;
 | 
			
		||||
		cow->lv_chunk_size = s->chunk_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	hash_destroy(lvd_hash);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME: More inefficient code.
 | 
			
		||||
 */
 | 
			
		||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
		     struct list *pvds)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lvs[MAX_LV];
 | 
			
		||||
	struct list *pvdh, *lvdh;
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	struct lv_disk *lvd;
 | 
			
		||||
	int lvnum;
 | 
			
		||||
	struct logical_volume *org, *cow;
 | 
			
		||||
 | 
			
		||||
	/* build an index of lv numbers */
 | 
			
		||||
	memset(lvs, 0, sizeof(lvs));
 | 
			
		||||
	list_iterate(pvdh, pvds) {
 | 
			
		||||
		dl = list_item(pvdh, struct disk_list);
 | 
			
		||||
 | 
			
		||||
		list_iterate(lvdh, &dl->lvds) {
 | 
			
		||||
			lvd = &(list_item(lvdh, struct lvd_list)->lvd);
 | 
			
		||||
 | 
			
		||||
			lvnum = lvd->lv_number;
 | 
			
		||||
 | 
			
		||||
			if (lvnum > MAX_LV) {
 | 
			
		||||
				log_err("Logical volume number "
 | 
			
		||||
					"out of bounds.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!lvs[lvnum] &&
 | 
			
		||||
			    !(lvs[lvnum] = find_lv(vg, lvd->lv_name))) {
 | 
			
		||||
				log_err("Couldn't find logical volume '%s'.",
 | 
			
		||||
					lvd->lv_name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Now iterate through yet again adding the snapshots.
 | 
			
		||||
	 */
 | 
			
		||||
	list_iterate(pvdh, pvds) {
 | 
			
		||||
		dl = list_item(pvdh, struct disk_list);
 | 
			
		||||
 | 
			
		||||
		list_iterate(lvdh, &dl->lvds) {
 | 
			
		||||
			lvd = &(list_item(lvdh, struct lvd_list)->lvd);
 | 
			
		||||
 | 
			
		||||
			if (!(lvd->lv_access & LV_SNAPSHOT))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			lvnum = lvd->lv_number;
 | 
			
		||||
			cow = lvs[lvnum];
 | 
			
		||||
			if (!(org = lvs[lvd->lv_snapshot_minor])) {
 | 
			
		||||
				log_err("Couldn't find origin logical volume "
 | 
			
		||||
					"for snapshot '%s'.", lvd->lv_name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* we may have already added this snapshot */
 | 
			
		||||
			if (lv_is_cow(cow))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* insert the snapshot */
 | 
			
		||||
			if (!vg_add_snapshot(org, cow, 1, NULL,
 | 
			
		||||
					     lvd->lv_chunk_size)) {
 | 
			
		||||
				log_err("Couldn't add snapshot.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -528,9 +665,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This calculates the nasty pv_number and
 | 
			
		||||
 * lv_number fields used by LVM1.  Very
 | 
			
		||||
 * inefficient code.
 | 
			
		||||
 * This calculates the nasty pv_number field
 | 
			
		||||
 * used by LVM1.
 | 
			
		||||
 */
 | 
			
		||||
void export_numbers(struct list *pvds, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
@@ -565,14 +701,14 @@ void export_pv_act(struct list *pvds)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int export_vg_number(struct list *pvds, const char *vg_name,
 | 
			
		||||
		     struct dev_filter *filter)
 | 
			
		||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
 | 
			
		||||
		     const char *vg_name, struct dev_filter *filter)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvdh;
 | 
			
		||||
	struct disk_list *dl;
 | 
			
		||||
	int vg_num;
 | 
			
		||||
 | 
			
		||||
	if (!get_free_vg_number(filter, vg_name, &vg_num)) {
 | 
			
		||||
	if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -584,4 +720,3 @@ int export_vg_number(struct list *pvds, const char *vg_name,
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,9 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
 | 
			
		||||
@@ -192,9 +191,9 @@ static int _check_maps_are_complete(struct hash_table *maps)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
 | 
			
		||||
static struct lv_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
 | 
			
		||||
{
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
 | 
			
		||||
 | 
			
		||||
	if (!(seg = pool_zalloc(mem, len))) {
 | 
			
		||||
@@ -208,26 +207,30 @@ static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
 | 
			
		||||
static int _read_linear(struct pool *mem, struct lv_map *lvm)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t le = 0;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	while (le < lvm->lv->le_count) {
 | 
			
		||||
		seg = _alloc_seg(mem, 1);
 | 
			
		||||
 | 
			
		||||
		seg->lv = lvm->lv;
 | 
			
		||||
		seg->type = SEG_STRIPED;
 | 
			
		||||
		seg->le = le;
 | 
			
		||||
		seg->len = 0;
 | 
			
		||||
		seg->area_len = 0;
 | 
			
		||||
		seg->stripe_size = 0;
 | 
			
		||||
		seg->stripes = 1;
 | 
			
		||||
		seg->area_count = 1;
 | 
			
		||||
 | 
			
		||||
		seg->area[0].pv = lvm->map[le].pv;
 | 
			
		||||
		seg->area[0].pe = lvm->map[le].pe;
 | 
			
		||||
		seg->area[0].type = AREA_PV;
 | 
			
		||||
		seg->area[0].u.pv.pv = lvm->map[le].pv;
 | 
			
		||||
		seg->area[0].u.pv.pe = lvm->map[le].pe;
 | 
			
		||||
 | 
			
		||||
		do
 | 
			
		||||
		do {
 | 
			
		||||
			seg->len++;
 | 
			
		||||
 | 
			
		||||
		while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
 | 
			
		||||
		       (lvm->map[le + seg->len].pe == seg->area[0].pe +
 | 
			
		||||
			seg->len));
 | 
			
		||||
			seg->area_len++;
 | 
			
		||||
		} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
 | 
			
		||||
			 (seg->area[0].u.pv.pv &&
 | 
			
		||||
			  lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
 | 
			
		||||
			  seg->len));
 | 
			
		||||
 | 
			
		||||
		le += seg->len;
 | 
			
		||||
 | 
			
		||||
@@ -237,7 +240,7 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
 | 
			
		||||
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
 | 
			
		||||
			 uint32_t base_le, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t le, st;
 | 
			
		||||
@@ -247,9 +250,11 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Is the next physical extent in every stripe adjacent to the last?
 | 
			
		||||
	 */
 | 
			
		||||
	for (st = 0; st < seg->stripes; st++)
 | 
			
		||||
		if ((lvm->map[le + st * len].pv != seg->area[st].pv) ||
 | 
			
		||||
	       	    (lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
 | 
			
		||||
	for (st = 0; st < seg->area_count; st++)
 | 
			
		||||
		if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
 | 
			
		||||
		    (seg->area[st].u.pv.pv &&
 | 
			
		||||
		     lvm->map[le + st * len].pe !=
 | 
			
		||||
		     seg->area[st].u.pv.pe + seg->len))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -258,7 +263,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
 | 
			
		||||
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t st, le = 0, len;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Work out overall striped length
 | 
			
		||||
@@ -266,8 +271,7 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
 | 
			
		||||
	if (lvm->lv->le_count % lvm->stripes) {
 | 
			
		||||
		log_error("Number of stripes (%u) incompatible "
 | 
			
		||||
			  "with logical extent count (%u) for %s",
 | 
			
		||||
			  lvm->stripes, lvm->lv->le_count,
 | 
			
		||||
			  lvm->lv->name);
 | 
			
		||||
			  lvm->stripes, lvm->lv->le_count, lvm->lv->name);
 | 
			
		||||
	}
 | 
			
		||||
	len = lvm->lv->le_count / lvm->stripes;
 | 
			
		||||
 | 
			
		||||
@@ -278,28 +282,32 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seg->lv = lvm->lv;
 | 
			
		||||
		seg->type = SEG_STRIPED;
 | 
			
		||||
		seg->stripe_size = lvm->stripe_size;
 | 
			
		||||
		seg->stripes = lvm->stripes;
 | 
			
		||||
		seg->le = seg->stripes * le;
 | 
			
		||||
		seg->area_count = lvm->stripes;
 | 
			
		||||
		seg->le = seg->area_count * le;
 | 
			
		||||
		seg->len = 1;
 | 
			
		||||
		seg->area_len = 1;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Set up start positions of each stripe in this segment
 | 
			
		||||
		 */
 | 
			
		||||
		for (st = 0; st < seg->stripes; st++) {
 | 
			
		||||
			seg->area[st].pv = lvm->map[le + st * len].pv;
 | 
			
		||||
			seg->area[st].pe = lvm->map[le + st * len].pe;
 | 
			
		||||
		for (st = 0; st < seg->area_count; st++) {
 | 
			
		||||
			seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
 | 
			
		||||
			seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* 
 | 
			
		||||
		 * Find how many blocks are contiguous in all stripes
 | 
			
		||||
		 * and so can form part of this segment
 | 
			
		||||
		 */
 | 
			
		||||
		while (_check_stripe(lvm, seg, le, len))
 | 
			
		||||
		while (_check_stripe(lvm, seg, le, len)) {
 | 
			
		||||
			seg->len++;
 | 
			
		||||
			seg->area_len++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		le += seg->len;
 | 
			
		||||
		seg->len *= seg->stripes;
 | 
			
		||||
		seg->len *= seg->area_count;
 | 
			
		||||
 | 
			
		||||
		list_add(&lvm->lv->segments, &seg->list);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,21 +4,19 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Only works with powers of 2.
 | 
			
		||||
 */
 | 
			
		||||
static inline ulong _round_up(ulong n, ulong size)
 | 
			
		||||
static inline uint32_t _round_up(uint32_t n, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
	size--;
 | 
			
		||||
	return (n + size) & ~size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline ulong _div_up(ulong n, ulong size)
 | 
			
		||||
static inline uint32_t _div_up(uint32_t n, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
	return _round_up(n, size) / size;
 | 
			
		||||
}
 | 
			
		||||
@@ -37,7 +35,7 @@ static uint32_t _next_base(struct data_area *area)
 | 
			
		||||
 */
 | 
			
		||||
static int _adjust_pe_on_disk(struct pv_disk *pvd)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t pe_start = pvd->pe_start * SECTOR_SIZE;
 | 
			
		||||
	uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -51,20 +49,20 @@ static void _calc_simple_layout(struct pv_disk *pvd)
 | 
			
		||||
	pvd->pv_on_disk.base = METADATA_BASE;
 | 
			
		||||
	pvd->pv_on_disk.size = PV_SIZE;
 | 
			
		||||
 | 
			
		||||
        pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
 | 
			
		||||
        pvd->vg_on_disk.size = VG_SIZE;
 | 
			
		||||
	pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
 | 
			
		||||
	pvd->vg_on_disk.size = VG_SIZE;
 | 
			
		||||
 | 
			
		||||
        pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
 | 
			
		||||
        pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
 | 
			
		||||
	pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
 | 
			
		||||
	pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
 | 
			
		||||
 | 
			
		||||
        pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
 | 
			
		||||
        pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
 | 
			
		||||
	pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
 | 
			
		||||
	pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
 | 
			
		||||
 | 
			
		||||
        pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
 | 
			
		||||
        pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
 | 
			
		||||
	pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
 | 
			
		||||
	pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _check_vg_limits(struct disk_list *dl)
 | 
			
		||||
static int _check_vg_limits(struct disk_list *dl)
 | 
			
		||||
{
 | 
			
		||||
	if (dl->vgd.lv_max > MAX_LV) {
 | 
			
		||||
		log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
 | 
			
		||||
@@ -103,49 +101,47 @@ int calculate_layout(struct disk_list *dl)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * It may seem strange to have a struct
 | 
			
		||||
 * physical_volume in here, but the number of
 | 
			
		||||
 * extents that can fit on a disk *is* metadata
 | 
			
		||||
 * format dependant.
 | 
			
		||||
 * The number of extents that can fit on a disk is metadata format dependant.
 | 
			
		||||
 */
 | 
			
		||||
int calculate_extent_count(struct physical_volume *pv)
 | 
			
		||||
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
 | 
			
		||||
			   uint32_t max_extent_count)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
 | 
			
		||||
	uint32_t end;
 | 
			
		||||
 | 
			
		||||
	if (!pvd) {
 | 
			
		||||
		stack;
 | 
			
		||||
		dbg_free(pvd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Guess how many extents will fit,
 | 
			
		||||
	 * bearing in mind that one is going to be
 | 
			
		||||
	 * knocked off at the start of the next
 | 
			
		||||
	 * loop.
 | 
			
		||||
	 * Guess how many extents will fit, bearing in mind that
 | 
			
		||||
	 * one is going to be knocked off at the start of the
 | 
			
		||||
	 * next loop.
 | 
			
		||||
	 */
 | 
			
		||||
	pvd->pe_total = (pv->size / pv->pe_size);
 | 
			
		||||
	if (max_extent_count)
 | 
			
		||||
		pvd->pe_total = max_extent_count + 1;
 | 
			
		||||
	else
 | 
			
		||||
		pvd->pe_total = (pv->size / extent_size);
 | 
			
		||||
 | 
			
		||||
	if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
 | 
			
		||||
		log_error("Insufficient space for extents on %s",
 | 
			
		||||
		log_error("Too few extents on %s.  Try smaller extent size.",
 | 
			
		||||
			  dev_name(pv->dev));
 | 
			
		||||
		dbg_free(pvd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		pvd->pe_total--;
 | 
			
		||||
		_calc_simple_layout(pvd);
 | 
			
		||||
		end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + \
 | 
			
		||||
			SECTOR_SIZE - 1) / SECTOR_SIZE);
 | 
			
		||||
		end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
 | 
			
		||||
			SECTOR_SIZE - 1) >> SECTOR_SHIFT);
 | 
			
		||||
 | 
			
		||||
		pvd->pe_start = _round_up(end, PE_ALIGN);
 | 
			
		||||
 | 
			
		||||
	} while((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size);
 | 
			
		||||
	} while ((pvd->pe_start + (pvd->pe_total * extent_size))
 | 
			
		||||
		 > pv->size);
 | 
			
		||||
 | 
			
		||||
	if (pvd->pe_total > MAX_PE_TOTAL) {
 | 
			
		||||
		log_error("Metadata extent limit (%u) exceeded for %s - "
 | 
			
		||||
@@ -157,6 +153,7 @@ int calculate_extent_count(struct physical_volume *pv)
 | 
			
		||||
 | 
			
		||||
	pv->pe_count = pvd->pe_total;
 | 
			
		||||
	pv->pe_start = pvd->pe_start;
 | 
			
		||||
	/* We can't set pe_size here without breaking LVM1 compatibility */
 | 
			
		||||
	dbg_free(pvd);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										107
									
								
								lib/format1/lvm1-label.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								lib/format1/lvm1-label.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "lvm1-label.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
static void _not_supported(const char *op)
 | 
			
		||||
{
 | 
			
		||||
	log_err("The '%s' operation is not supported for the lvm1 labeller.",
 | 
			
		||||
		op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_disk *pvd = (struct pv_disk *) buf;
 | 
			
		||||
	uint32_t version;
 | 
			
		||||
 | 
			
		||||
	/* LVM1 label must always be in first sector */
 | 
			
		||||
	if (sector)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	version = xlate16(pvd->version);
 | 
			
		||||
 | 
			
		||||
	if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
 | 
			
		||||
	    (version == 1 || version == 2))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _write(struct label *label, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	_not_supported("write");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read(struct labeller *l, struct device *dev, char *buf,
 | 
			
		||||
		 struct label **label)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_disk *pvd = (struct pv_disk *) buf;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
 | 
			
		||||
	munge_exported_vg(pvd);
 | 
			
		||||
	if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL)))
 | 
			
		||||
		return 0;
 | 
			
		||||
	*label = info->label;
 | 
			
		||||
 | 
			
		||||
	info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT;
 | 
			
		||||
	list_init(&info->mdas);
 | 
			
		||||
 | 
			
		||||
	info->status &= ~CACHE_INVALID;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _initialise_label(struct labeller *l, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	strcpy(label->type, "LVM1");
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy_label(struct labeller *l, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct labeller *l)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct label_ops _lvm1_ops = {
 | 
			
		||||
	can_handle:_can_handle,
 | 
			
		||||
	write:_write,
 | 
			
		||||
	read:_read,
 | 
			
		||||
	verify:_can_handle,
 | 
			
		||||
	initialise_label:_initialise_label,
 | 
			
		||||
	destroy_label:_destroy_label,
 | 
			
		||||
	destroy:_destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct labeller *lvm1_labeller_create(struct format_type *fmt)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
 | 
			
		||||
	if (!(l = dbg_malloc(sizeof(*l)))) {
 | 
			
		||||
		log_err("Couldn't allocate labeller object.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l->ops = &_lvm1_ops;
 | 
			
		||||
	l->private = (const void *) fmt;
 | 
			
		||||
 | 
			
		||||
	return l;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								lib/format1/lvm1-label.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/format1/lvm1-label.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_LVM1_LABEL_H
 | 
			
		||||
#define _LVM_LVM1_LABEL_H
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
struct labeller *lvm1_labeller_create(struct format_type *fmt);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,145 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lvm1_label.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
static void _not_supported(const char *op)
 | 
			
		||||
{
 | 
			
		||||
	log_err("The '%s' operation is not supported for the lvm1 labeller.",
 | 
			
		||||
		op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _can_handle(struct labeller *l, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_disk pvd;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
        if (!dev_open(dev, O_RDONLY)) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	r = read_pvd(dev, &pvd);
 | 
			
		||||
 | 
			
		||||
        if (!dev_close(dev))
 | 
			
		||||
                stack;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _write(struct labeller *l,
 | 
			
		||||
		  struct device *dev, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	_not_supported("write");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _remove(struct labeller *l, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	_not_supported("remove");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct label *_to_label(struct pv_disk *pvd)
 | 
			
		||||
{
 | 
			
		||||
	struct label *l;
 | 
			
		||||
	struct lvm_label_info *info;
 | 
			
		||||
 | 
			
		||||
	if (!(l = dbg_malloc(sizeof(*l)))) {
 | 
			
		||||
		log_err("Couldn't allocate label.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(info = (struct lvm_label_info *) dbg_strdup(pvd->vg_name))) {
 | 
			
		||||
		dbg_free(l);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(&l->id, &pvd->pv_uuid, sizeof(l->id));
 | 
			
		||||
	strcpy(l->volume_type, "lvm");
 | 
			
		||||
	l->version[0] = 1;
 | 
			
		||||
	l->version[0] = 0;
 | 
			
		||||
	l->version[0] = 0;
 | 
			
		||||
	l->extra_info = info;
 | 
			
		||||
 | 
			
		||||
	return l;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read(struct labeller *l, struct device *dev, struct label **label)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_disk pvd;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
        if (!dev_open(dev, O_RDONLY)) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	r = read_pvd(dev, &pvd);
 | 
			
		||||
 | 
			
		||||
        if (!dev_close(dev))
 | 
			
		||||
                stack;
 | 
			
		||||
 | 
			
		||||
	if (!r) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert the disk_list into a label structure.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(*label = _to_label(&pvd))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy_label(struct labeller *l, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(label->extra_info);
 | 
			
		||||
	dbg_free(label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct labeller *l)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct label_ops _lvm1_ops = {
 | 
			
		||||
	can_handle: _can_handle,
 | 
			
		||||
	write: _write,
 | 
			
		||||
	remove: _remove,
 | 
			
		||||
	read: _read,
 | 
			
		||||
	verify: _can_handle,
 | 
			
		||||
	destroy_label: _destroy_label,
 | 
			
		||||
	destroy: _destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct labeller *lvm1_labeller_create(void)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
 | 
			
		||||
	if (!(l = dbg_malloc(sizeof(*l)))) {
 | 
			
		||||
		log_err("Couldn't allocate labeller object.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l->ops = &_lvm1_ops;
 | 
			
		||||
	l->private = NULL;
 | 
			
		||||
 | 
			
		||||
	return l;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_LVM1_LABEL_H
 | 
			
		||||
#define _LVM_LVM1_LABEL_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is what the 'extra_info' field of the label will point to
 | 
			
		||||
 * if the label type is lvm1.
 | 
			
		||||
 */
 | 
			
		||||
struct lvm_label_info {
 | 
			
		||||
	char volume_group[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct labeller *lvm1_labeller_create(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "disk-rep.h"
 | 
			
		||||
 | 
			
		||||
@@ -15,8 +15,8 @@
 | 
			
		||||
 * Put in separate file so it wouldn't contaminate
 | 
			
		||||
 * other code.
 | 
			
		||||
 */
 | 
			
		||||
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
 | 
			
		||||
		       int *result)
 | 
			
		||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
 | 
			
		||||
		       const char *candidate_vg, int *result)
 | 
			
		||||
{
 | 
			
		||||
	struct list *pvh;
 | 
			
		||||
	struct list all_pvs;
 | 
			
		||||
@@ -31,7 +31,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!read_pvs_in_vg(NULL, filter, mem, &all_pvs)) {
 | 
			
		||||
	if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
@@ -40,8 +40,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
 | 
			
		||||
 | 
			
		||||
	list_iterate(pvh, &all_pvs) {
 | 
			
		||||
		dl = list_item(pvh, struct disk_list);
 | 
			
		||||
		if (!*dl->pvd.vg_name ||
 | 
			
		||||
		    !strcmp(dl->pvd.vg_name, candidate_vg))
 | 
			
		||||
		if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		numbers[dl->vgd.vg_number] = 1;
 | 
			
		||||
@@ -55,7 +54,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
      out:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,23 +4,25 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "format-text.h"
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "import-export.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "lvm-file.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#define SECS_PER_DAY 86400	/* 24*60*60 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The format instance is given a directory path upon creation.
 | 
			
		||||
@@ -34,119 +36,38 @@
 | 
			
		||||
 * Backup files that have expired will be removed.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct archive_c {
 | 
			
		||||
	uint32_t retain_days;
 | 
			
		||||
	uint32_t min_retains;
 | 
			
		||||
 | 
			
		||||
	char *dir;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * An ordered list of previous archives.  Each list
 | 
			
		||||
	 * entered against the vg name.  Most recent first.
 | 
			
		||||
	 */
 | 
			
		||||
	struct hash_table *vg_archives;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Scratch pool.  Contents of vg_archives come from here.
 | 
			
		||||
	 */
 | 
			
		||||
	struct pool *mem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A list of these is built up for each volume group.  Ordered
 | 
			
		||||
 * A list of these is built up for our volume group.  Ordered
 | 
			
		||||
 * with the least recent at the head.
 | 
			
		||||
 */
 | 
			
		||||
struct archive_file {
 | 
			
		||||
	struct list list;
 | 
			
		||||
 | 
			
		||||
	char *path;
 | 
			
		||||
	char *vg;
 | 
			
		||||
	int index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This format is write only.
 | 
			
		||||
 */
 | 
			
		||||
static void _unsupported(const char *cmd)
 | 
			
		||||
{
 | 
			
		||||
	log_err("The archive format doesn't support '%s'", cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct list *_get_vgs(struct format_instance *fi)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("get_vgs");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct list *_get_pvs(struct format_instance *fi)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("get_pvs");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct physical_volume *_pv_read(struct format_instance *fi,
 | 
			
		||||
					const char *pv_name)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("pv_read");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
 | 
			
		||||
	     struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("pv_setup");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("pv_write");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("vg_setup");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct volume_group *_vg_read(struct format_instance *fi,
 | 
			
		||||
				     const char *vg_name)
 | 
			
		||||
{
 | 
			
		||||
	_unsupported("vg_read");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct format_instance *fi)
 | 
			
		||||
{
 | 
			
		||||
	struct archive_c *bc = (struct archive_c *) fi->private;
 | 
			
		||||
	if (bc->vg_archives)
 | 
			
		||||
		hash_destroy(bc->vg_archives);
 | 
			
		||||
	pool_destroy(bc->mem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Extract vg name and version number from a filename.
 | 
			
		||||
 */
 | 
			
		||||
static int _split_vg(const char *filename, char *vg, size_t vg_size,
 | 
			
		||||
		     uint32_t *index)
 | 
			
		||||
		     uint32_t *ix)
 | 
			
		||||
{
 | 
			
		||||
	int len, vg_len;
 | 
			
		||||
	char *dot, *underscore;
 | 
			
		||||
	size_t len, vg_len;
 | 
			
		||||
	const char *dot, *underscore;
 | 
			
		||||
 | 
			
		||||
	len = strlen(filename);
 | 
			
		||||
	if (len < 7)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	dot = (char *) (filename + len - 3);
 | 
			
		||||
	dot = (filename + len - 3);
 | 
			
		||||
	if (strcmp(".vg", dot))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(underscore = rindex(filename, '_')))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(underscore + 1, "%u", index) != 1)
 | 
			
		||||
	if (sscanf(underscore + 1, "%u", ix) != 1)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	vg_len = underscore - filename;
 | 
			
		||||
@@ -162,7 +83,7 @@ static int _split_vg(const char *filename, char *vg, size_t vg_size,
 | 
			
		||||
static void _insert_file(struct list *head, struct archive_file *b)
 | 
			
		||||
{
 | 
			
		||||
	struct list *bh;
 | 
			
		||||
	struct archive_file *bf;
 | 
			
		||||
	struct archive_file *bf = NULL;
 | 
			
		||||
 | 
			
		||||
	if (list_empty(head)) {
 | 
			
		||||
		list_add(head, &b->list);
 | 
			
		||||
@@ -170,7 +91,7 @@ static void _insert_file(struct list *head, struct archive_file *b)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* index increases through list */
 | 
			
		||||
	list_iterate (bh, head) {
 | 
			
		||||
	list_iterate(bh, head) {
 | 
			
		||||
		bf = list_item(bh, struct archive_file);
 | 
			
		||||
 | 
			
		||||
		if (bf->index > b->index) {
 | 
			
		||||
@@ -182,50 +103,6 @@ static void _insert_file(struct list *head, struct archive_file *b)
 | 
			
		||||
	list_add_h(&bf->list, &b->list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _scan_vg(struct archive_c *bc, const char *file,
 | 
			
		||||
		    const char *vg_name, int index)
 | 
			
		||||
{
 | 
			
		||||
	struct archive_file *b;
 | 
			
		||||
	struct list *files;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Do we need to create a new list of archive files for
 | 
			
		||||
	 * this vg ?
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(files = hash_lookup(bc->vg_archives, vg_name))) {
 | 
			
		||||
		if (!(files = pool_alloc(bc->mem, sizeof(*files)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list_init(files);
 | 
			
		||||
		if (!hash_insert(bc->vg_archives, vg_name, files)) {
 | 
			
		||||
			log_err("Couldn't insert archive file "
 | 
			
		||||
				"into hash table.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Create a new archive file.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(b = pool_alloc(bc->mem, sizeof(*b)))) {
 | 
			
		||||
		log_err("Couldn't create new archive file.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b->index = index;
 | 
			
		||||
	b->path = (char *)file;
 | 
			
		||||
	b->vg = (char *)vg_name;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Insert it to the correct part of the list.
 | 
			
		||||
	 */
 | 
			
		||||
	_insert_file(files, b);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *_join(struct pool *mem, const char *dir, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	if (!pool_begin_object(mem, 32) ||
 | 
			
		||||
@@ -240,70 +117,130 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
 | 
			
		||||
	return pool_end_object(mem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _scan_dir(struct archive_c *bc)
 | 
			
		||||
/*
 | 
			
		||||
 * Returns a list of archive_files.
 | 
			
		||||
 */
 | 
			
		||||
static struct list *_scan_archive(struct pool *mem,
 | 
			
		||||
				  const char *vg, const char *dir)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0, i, count, index;
 | 
			
		||||
	int i, count, ix;
 | 
			
		||||
	char vg_name[64], *path;
 | 
			
		||||
	struct dirent **dirent;
 | 
			
		||||
	struct archive_file *af;
 | 
			
		||||
	struct list *results;
 | 
			
		||||
 | 
			
		||||
	if ((count = scandir(bc->dir, &dirent, NULL, alphasort)) < 0) {
 | 
			
		||||
	if (!(results = pool_alloc(mem, sizeof(*results)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(results);
 | 
			
		||||
 | 
			
		||||
	/* Sort fails beyond 5-digit indexes */
 | 
			
		||||
	if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
 | 
			
		||||
		log_err("Couldn't scan archive directory.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; i++) {
 | 
			
		||||
		if ((dirent[i]->d_name[0] == '.') ||
 | 
			
		||||
		    !_split_vg(dirent[i]->d_name, vg_name,
 | 
			
		||||
			       sizeof(vg_name), &index))
 | 
			
		||||
		/* ignore dot files */
 | 
			
		||||
		if (dirent[i]->d_name[0] == '.')
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(path = _join(bc->mem, bc->dir, dirent[i]->d_name))) {
 | 
			
		||||
		/* check the name is the correct format */
 | 
			
		||||
		if (!_split_vg(dirent[i]->d_name, vg_name, sizeof(vg_name),
 | 
			
		||||
			       &ix))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* is it the vg we're interested in ? */
 | 
			
		||||
		if (strcmp(vg, vg_name))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(path = _join(mem, dir, dirent[i]->d_name))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_scan_vg(bc, path, vg_name, index);
 | 
			
		||||
	}
 | 
			
		||||
	r = 1;
 | 
			
		||||
		/*
 | 
			
		||||
		 * Create a new archive_file.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!(af = pool_alloc(mem, sizeof(*af)))) {
 | 
			
		||||
			log_err("Couldn't create new archive file.");
 | 
			
		||||
			results = NULL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
		af->index = ix;
 | 
			
		||||
		af->path = path;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Insert it to the correct part of the list.
 | 
			
		||||
		 */
 | 
			
		||||
		_insert_file(results, af);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	for (i = 0; i < count; i++)
 | 
			
		||||
		free(dirent[i]);
 | 
			
		||||
	free(dirent);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
	return results;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _scan_archives(struct archive_c *bc)
 | 
			
		||||
static void _remove_expired(struct list *archives, uint32_t archives_size,
 | 
			
		||||
			    uint32_t retain_days, uint32_t min_archive)
 | 
			
		||||
{
 | 
			
		||||
	pool_empty(bc->mem);
 | 
			
		||||
	struct list *bh;
 | 
			
		||||
	struct archive_file *bf;
 | 
			
		||||
	struct stat sb;
 | 
			
		||||
	time_t retain_time;
 | 
			
		||||
 | 
			
		||||
	if (bc->vg_archives)
 | 
			
		||||
		hash_destroy(bc->vg_archives);
 | 
			
		||||
	/* Make sure there are enough archives to even bother looking for
 | 
			
		||||
	 * expired ones... */
 | 
			
		||||
	if (archives_size <= min_archive)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!(bc->vg_archives = hash_create(128))) {
 | 
			
		||||
		log_err("Couldn't create hash table for scanning archives.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	/* Convert retain_days into the time after which we must retain */
 | 
			
		||||
	retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
 | 
			
		||||
 | 
			
		||||
	/* Assume list is ordered oldest first (by index) */
 | 
			
		||||
	list_iterate(bh, archives) {
 | 
			
		||||
		bf = list_item(bh, struct archive_file);
 | 
			
		||||
 | 
			
		||||
		/* Get the mtime of the file and unlink if too old */
 | 
			
		||||
		if (stat(bf->path, &sb)) {
 | 
			
		||||
			log_sys_error("stat", bf->path);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (sb.st_mtime > retain_time)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		log_very_verbose("Expiring archive %s", bf->path);
 | 
			
		||||
		if (unlink(bf->path))
 | 
			
		||||
			log_sys_error("unlink", bf->path);
 | 
			
		||||
 | 
			
		||||
		/* Don't delete any more if we've reached the minimum */
 | 
			
		||||
		if (--archives_size <= min_archive)
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_scan_dir(bc)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
int archive_vg(struct volume_group *vg,
 | 
			
		||||
	       const char *dir, const char *desc,
 | 
			
		||||
	       uint32_t retain_days, uint32_t min_archive)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0, i, fd;
 | 
			
		||||
	unsigned int index = 0;
 | 
			
		||||
	struct archive_c *bc = (struct archive_c *) fi->private;
 | 
			
		||||
	int i, fd, renamed = 0;
 | 
			
		||||
	unsigned int ix = 0;
 | 
			
		||||
	struct archive_file *last;
 | 
			
		||||
	FILE *fp = NULL;
 | 
			
		||||
	char temp_file[PATH_MAX], archive_name[PATH_MAX];
 | 
			
		||||
	struct list *archives;
 | 
			
		||||
 | 
			
		||||
	if (!create_temp_name(bc->dir, temp_file, sizeof(temp_file), &fd)) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * Write the vg out to a temporary file.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!create_temp_name(dir, temp_file, sizeof(temp_file), &fd)) {
 | 
			
		||||
		log_err("Couldn't create temporary archive name.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -314,7 +251,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!text_vg_export(fp, vg)) {
 | 
			
		||||
	if (!text_vg_export_file(vg, desc, fp)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		fclose(fp);
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -325,97 +262,96 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
 | 
			
		||||
	/*
 | 
			
		||||
	 * Now we want to rename this file to <vg>_index.vg.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!_scan_archives(bc)) {
 | 
			
		||||
		log_err("Couldn't scan the archive directory (%s).", bc->dir);
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
 | 
			
		||||
		log_err("Couldn't scan the archive directory (%s).", dir);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((last = (struct archive_file *) hash_lookup(bc->vg_archives,
 | 
			
		||||
							vg->name))) {
 | 
			
		||||
		/* move to the last in the list */
 | 
			
		||||
		last = list_item(last->list.p, struct archive_file);
 | 
			
		||||
		index = last->index + 1;
 | 
			
		||||
	if (list_empty(archives))
 | 
			
		||||
		ix = 0;
 | 
			
		||||
	else {
 | 
			
		||||
		last = list_item(archives->p, struct archive_file);
 | 
			
		||||
		ix = last->index + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 10; i++) {
 | 
			
		||||
		if (lvm_snprintf(archive_name, sizeof(archive_name),
 | 
			
		||||
				 "%s/%s_%05d.vg",
 | 
			
		||||
				 bc->dir, vg->name, index) < 0) {
 | 
			
		||||
			log_err("archive file name too long.");
 | 
			
		||||
			goto out;
 | 
			
		||||
				 "%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
 | 
			
		||||
			log_error("Archive file name too long.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (lvm_rename(temp_file, archive_name)) {
 | 
			
		||||
			r = 1;
 | 
			
		||||
		if ((renamed = lvm_rename(temp_file, archive_name)))
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		index++;
 | 
			
		||||
		ix++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	return r;
 | 
			
		||||
	if (!renamed)
 | 
			
		||||
		log_error("Archive rename failed for %s", temp_file);
 | 
			
		||||
 | 
			
		||||
	_remove_expired(archives, list_size(archives) + renamed, retain_days,
 | 
			
		||||
			min_archive);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void archive_expire(struct format_instance *fi)
 | 
			
		||||
static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME: finish */
 | 
			
		||||
	struct volume_group *vg = NULL;
 | 
			
		||||
	struct format_instance *tf;
 | 
			
		||||
	time_t when;
 | 
			
		||||
	char *desc;
 | 
			
		||||
	void *context;
 | 
			
		||||
 | 
			
		||||
	log_print("path:\t\t%s", af->path);
 | 
			
		||||
 | 
			
		||||
	if (!(context = create_text_context(cmd, af->path, NULL)) ||
 | 
			
		||||
	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
 | 
			
		||||
							 context))) {
 | 
			
		||||
		log_error("Couldn't create text instance object.");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Read the archive file to ensure that it is valid, and
 | 
			
		||||
	 * retrieve the archive time and description.
 | 
			
		||||
	 */
 | 
			
		||||
	/* FIXME Use variation on _vg_read */
 | 
			
		||||
	if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
 | 
			
		||||
		log_print("Unable to read archive file.");
 | 
			
		||||
		tf->fmt->ops->destroy_instance(tf);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_print("description:\t%s", desc ? desc : "<No description>");
 | 
			
		||||
	log_print("time:\t\t%s", ctime(&when));
 | 
			
		||||
 | 
			
		||||
	pool_free(cmd->mem, vg);
 | 
			
		||||
	tf->fmt->ops->destroy_instance(tf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct format_handler _archive_handler = {
 | 
			
		||||
	get_vgs: _get_vgs,
 | 
			
		||||
	get_pvs: _get_pvs,
 | 
			
		||||
	pv_read: _pv_read,
 | 
			
		||||
	pv_setup: _pv_setup,
 | 
			
		||||
	pv_write: _pv_write,
 | 
			
		||||
	vg_setup: _vg_setup,
 | 
			
		||||
	vg_read: _vg_read,
 | 
			
		||||
	vg_write: _vg_write,
 | 
			
		||||
	destroy: _destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct format_instance *archive_format_create(struct cmd_context *cmd,
 | 
			
		||||
					     const char *dir,
 | 
			
		||||
					     uint32_t retain_days,
 | 
			
		||||
					     uint32_t min_retains)
 | 
			
		||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct format_instance *fi;
 | 
			
		||||
	struct archive_c *bc = NULL;
 | 
			
		||||
	struct pool *mem = cmd->mem;
 | 
			
		||||
	struct list *archives, *ah;
 | 
			
		||||
	struct archive_file *af;
 | 
			
		||||
 | 
			
		||||
	if (!(bc = pool_zalloc(mem, sizeof(*bc)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if (!(archives = _scan_archive(cmd->mem, vg, dir))) {
 | 
			
		||||
		log_err("Couldn't scan the archive directory (%s).", dir);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(bc->mem = pool_create(1024))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	if (list_empty(archives))
 | 
			
		||||
		log_print("No archives found.");
 | 
			
		||||
 | 
			
		||||
	list_iterate(ah, archives) {
 | 
			
		||||
		af = list_item(ah, struct archive_file);
 | 
			
		||||
 | 
			
		||||
		_display_archive(cmd, af);
 | 
			
		||||
		log_print(" ");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(bc->dir = pool_strdup(mem, dir))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
	pool_free(cmd->mem, archives);
 | 
			
		||||
 | 
			
		||||
	bc->retain_days = retain_days;
 | 
			
		||||
	bc->min_retains = min_retains;
 | 
			
		||||
 | 
			
		||||
	if (!(fi = pool_alloc(mem, sizeof(*fi)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fi->cmd = cmd;
 | 
			
		||||
	fi->ops = &_archive_handler;
 | 
			
		||||
	fi->private = bc;
 | 
			
		||||
 | 
			
		||||
	return fi;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	if (bc->mem)
 | 
			
		||||
		pool_destroy(bc->mem);
 | 
			
		||||
 | 
			
		||||
	pool_free(mem, bc);
 | 
			
		||||
	return NULL;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,46 +4,75 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "import-export.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct formatter;
 | 
			
		||||
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
 | 
			
		||||
				    const char *fmt, va_list ap);
 | 
			
		||||
typedef void (*nl_fn) (struct formatter * f);
 | 
			
		||||
/*
 | 
			
		||||
 * The first half of this file deals with
 | 
			
		||||
 * exporting the vg, ie. writing it to a file.
 | 
			
		||||
 */
 | 
			
		||||
struct formatter {
 | 
			
		||||
	struct pool *mem;	/* pv names allocated from here */
 | 
			
		||||
	struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
 | 
			
		||||
	struct hash_table *pv_names;	/* dev_name -> pv_name (eg, pv1) */
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		FILE *fp;	/* where we're writing to */
 | 
			
		||||
		struct {
 | 
			
		||||
			char *buf;
 | 
			
		||||
			uint32_t size;
 | 
			
		||||
			uint32_t used;
 | 
			
		||||
		} buf;
 | 
			
		||||
	} data;
 | 
			
		||||
 | 
			
		||||
	out_with_comment_fn out_with_comment;
 | 
			
		||||
	nl_fn nl;
 | 
			
		||||
 | 
			
		||||
	FILE *fp;		/* where we're writing to */
 | 
			
		||||
	int indent;		/* current level of indentation */
 | 
			
		||||
 | 
			
		||||
	int error;
 | 
			
		||||
	int header;		/* 1 => comments at start; 0 => end */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct utsname _utsname;
 | 
			
		||||
 | 
			
		||||
static void _init(void)
 | 
			
		||||
{
 | 
			
		||||
	static int _initialised = 0;
 | 
			
		||||
 | 
			
		||||
	if (_initialised)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (uname(&_utsname)) {
 | 
			
		||||
		log_error("uname failed: %s", strerror(errno));
 | 
			
		||||
		memset(&_utsname, 0, sizeof(_utsname));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_initialised = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Formatting functions.
 | 
			
		||||
 */
 | 
			
		||||
static void _out_size(struct formatter *f, uint64_t size,
 | 
			
		||||
		      const char *fmt, ...)
 | 
			
		||||
            __attribute__ (( format (printf, 3, 4) ));
 | 
			
		||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
 | 
			
		||||
    __attribute__ ((format(printf, 3, 4)));
 | 
			
		||||
 | 
			
		||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
            __attribute__ (( format (printf, 2, 3) ));
 | 
			
		||||
 | 
			
		||||
static void _out(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
            __attribute__ (( format (printf, 2, 3) ));
 | 
			
		||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
    __attribute__ ((format(printf, 2, 3)));
 | 
			
		||||
 | 
			
		||||
static int _out(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
    __attribute__ ((format(printf, 2, 3)));
 | 
			
		||||
 | 
			
		||||
#define MAX_INDENT 5
 | 
			
		||||
static void _inc_indent(struct formatter *f)
 | 
			
		||||
@@ -63,26 +92,39 @@ static void _dec_indent(struct formatter *f)
 | 
			
		||||
/*
 | 
			
		||||
 * Newline function for prettier layout.
 | 
			
		||||
 */
 | 
			
		||||
static void _nl(struct formatter *f)
 | 
			
		||||
static void _nl_file(struct formatter *f)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(f->fp, "\n");
 | 
			
		||||
	fprintf(f->data.fp, "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _nl_raw(struct formatter *f)
 | 
			
		||||
{
 | 
			
		||||
	if (f->data.buf.used >= f->data.buf.size - 1)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	*f->data.buf.buf = '\n';
 | 
			
		||||
	f->data.buf.buf += 1;
 | 
			
		||||
	f->data.buf.used += 1;
 | 
			
		||||
	*f->data.buf.buf = '\0';
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define COMMENT_TAB 6
 | 
			
		||||
static void _out_with_comment(struct formatter *f, const char *comment,
 | 
			
		||||
			      const char *fmt, va_list ap)
 | 
			
		||||
static int _out_with_comment_file(struct formatter *f, const char *comment,
 | 
			
		||||
				  const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	char white_space[MAX_INDENT + 1];
 | 
			
		||||
 | 
			
		||||
	if (ferror(f->fp))
 | 
			
		||||
		return;
 | 
			
		||||
	if (ferror(f->data.fp))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < f->indent; i++)
 | 
			
		||||
		white_space[i] = '\t';
 | 
			
		||||
	white_space[i] = '\0';
 | 
			
		||||
	fprintf(f->fp, white_space);
 | 
			
		||||
	i = vfprintf(f->fp, fmt, ap);
 | 
			
		||||
	fprintf(f->data.fp, white_space);
 | 
			
		||||
	i = vfprintf(f->data.fp, fmt, ap);
 | 
			
		||||
 | 
			
		||||
	if (comment) {
 | 
			
		||||
		/*
 | 
			
		||||
@@ -93,13 +135,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
 | 
			
		||||
		i++;
 | 
			
		||||
 | 
			
		||||
		do
 | 
			
		||||
			fputc('\t', f->fp);
 | 
			
		||||
			fputc('\t', f->data.fp);
 | 
			
		||||
 | 
			
		||||
		while (++i < COMMENT_TAB);
 | 
			
		||||
 | 
			
		||||
		fprintf(f->fp, comment);
 | 
			
		||||
		fprintf(f->data.fp, comment);
 | 
			
		||||
	}
 | 
			
		||||
	fputc('\n', f->fp);
 | 
			
		||||
	fputc('\n', f->data.fp);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _out_with_comment_raw(struct formatter *f, const char *comment,
 | 
			
		||||
				 const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
 | 
			
		||||
		      fmt, ap);
 | 
			
		||||
 | 
			
		||||
	if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	f->data.buf.buf += n;
 | 
			
		||||
	f->data.buf.used += n;
 | 
			
		||||
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -110,13 +173,13 @@ static void _out_with_comment(struct formatter *f, const char *comment,
 | 
			
		||||
 */
 | 
			
		||||
static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
 | 
			
		||||
{
 | 
			
		||||
	static char *_units[] = {
 | 
			
		||||
	static const char *_units[] = {
 | 
			
		||||
		"Kilobytes",
 | 
			
		||||
		"Megabytes",
 | 
			
		||||
		"Gigabytes",
 | 
			
		||||
		"Terrabytes",
 | 
			
		||||
		"Terabytes",
 | 
			
		||||
		NULL
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	double d = (double) sectors;
 | 
			
		||||
@@ -124,7 +187,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
 | 
			
		||||
	/* to convert to K */
 | 
			
		||||
	d /= 2.0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; (d > 1024.0)  && _units[i]; i++)
 | 
			
		||||
	for (i = 0; (d > 1024.0) && _units[i]; i++)
 | 
			
		||||
		d /= 1024.0;
 | 
			
		||||
 | 
			
		||||
	return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
 | 
			
		||||
@@ -134,53 +197,74 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
 | 
			
		||||
 * Appends a comment giving a size in more easily
 | 
			
		||||
 * readable form (eg, 4M instead of 8096).
 | 
			
		||||
 */
 | 
			
		||||
static void _out_size(struct formatter *f, uint64_t size,
 | 
			
		||||
		      const char *fmt, ...)
 | 
			
		||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[64];
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	_sectors_to_units(size, buffer, sizeof(buffer));
 | 
			
		||||
	if (!_sectors_to_units(size, buffer, sizeof(buffer)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	_out_with_comment(f, buffer, fmt, ap);
 | 
			
		||||
	r = f->out_with_comment(f, buffer, fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Appends a comment indicating that the line is
 | 
			
		||||
 * only a hint.
 | 
			
		||||
 */
 | 
			
		||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	_out_with_comment(f, "# Hint only", fmt, ap);
 | 
			
		||||
	r = f->out_with_comment(f, "# Hint only", fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The normal output function.
 | 
			
		||||
 */
 | 
			
		||||
static void _out(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
static int _out(struct formatter *f, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	_out_with_comment(f, NULL, fmt, ap);
 | 
			
		||||
	r = f->out_with_comment(f, NULL, fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_header(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
 | 
			
		||||
 | 
			
		||||
static int _print_header(struct formatter *f,
 | 
			
		||||
			 struct volume_group *vg, const char *desc)
 | 
			
		||||
{
 | 
			
		||||
	time_t t;
 | 
			
		||||
 | 
			
		||||
	t = time(NULL);
 | 
			
		||||
 | 
			
		||||
	_out(f,
 | 
			
		||||
	     "# This file was originally generated by the LVM2 library\n"
 | 
			
		||||
	     "# Generated: %s\n", ctime(&t));
 | 
			
		||||
	_outf(f, "# Generated by LVM2: %s", ctime(&t));
 | 
			
		||||
	_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
 | 
			
		||||
	_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
 | 
			
		||||
	_outf(f, "description = \"%s\"", desc);
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
	_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
 | 
			
		||||
	      _utsname.sysname, _utsname.nodename, _utsname.release,
 | 
			
		||||
	      _utsname.version, _utsname.machine);
 | 
			
		||||
	_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -193,19 +277,24 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_out(f, "id = \"%s\"", buffer);
 | 
			
		||||
	_outf(f, "id = \"%s\"", buffer);
 | 
			
		||||
 | 
			
		||||
	_outf(f, "seqno = %u", vg->seqno);
 | 
			
		||||
	if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_out(f, "status = %s", buffer);
 | 
			
		||||
	_outf(f, "status = %s", buffer);
 | 
			
		||||
	if (vg->system_id && *vg->system_id)
 | 
			
		||||
		_out(f, "system_id = \"%s\"", vg->system_id);
 | 
			
		||||
	_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size);
 | 
			
		||||
	_out(f, "max_lv = %u", vg->max_lv);
 | 
			
		||||
	_out(f, "max_pv = %u", vg->max_pv);
 | 
			
		||||
		_outf(f, "system_id = \"%s\"", vg->system_id);
 | 
			
		||||
	if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
 | 
			
		||||
		       vg->extent_size)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	_outf(f, "max_lv = %u", vg->max_lv);
 | 
			
		||||
	_outf(f, "max_pv = %u", vg->max_pv);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -214,12 +303,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
 * Get the pv%d name from the formatters hash
 | 
			
		||||
 * table.
 | 
			
		||||
 */
 | 
			
		||||
static inline const char *
 | 
			
		||||
_get_pv_name(struct formatter *f, struct physical_volume *pv)
 | 
			
		||||
static inline const char *_get_pv_name(struct formatter *f,
 | 
			
		||||
				       struct physical_volume *pv)
 | 
			
		||||
{
 | 
			
		||||
	return (pv) ? (const char *) 
 | 
			
		||||
		      hash_lookup(f->pv_names, dev_name(pv->dev)) :
 | 
			
		||||
		      "Missing";
 | 
			
		||||
	return (pv) ? (const char *)
 | 
			
		||||
	    hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_pvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
@@ -229,10 +317,10 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
	char buffer[256];
 | 
			
		||||
	const char *name;
 | 
			
		||||
 | 
			
		||||
	_out(f, "physical_volumes {");
 | 
			
		||||
	_outf(f, "physical_volumes {");
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	list_iterate (pvh, &vg->pvs) {
 | 
			
		||||
	list_iterate(pvh, &vg->pvs) {
 | 
			
		||||
 | 
			
		||||
		pv = list_item(pvh, struct pv_list)->pv;
 | 
			
		||||
 | 
			
		||||
@@ -241,8 +329,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_nl(f);
 | 
			
		||||
		_out(f, "%s {", name);
 | 
			
		||||
		f->nl(f);
 | 
			
		||||
		_outf(f, "%s {", name);
 | 
			
		||||
		_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
		if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
 | 
			
		||||
@@ -250,66 +338,109 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_out(f, "id = \"%s\"", buffer);
 | 
			
		||||
		_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
 | 
			
		||||
		_nl(f);
 | 
			
		||||
		_outf(f, "id = \"%s\"", buffer);
 | 
			
		||||
		if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		f->nl(f);
 | 
			
		||||
 | 
			
		||||
		if (!print_flags(pv->status, PV_FLAGS,
 | 
			
		||||
				 buffer, sizeof(buffer))) {
 | 
			
		||||
		if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_out(f, "status = %s", buffer);
 | 
			
		||||
		_out(f, "pe_start = %llu", pv->pe_start);
 | 
			
		||||
		_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
 | 
			
		||||
			  "pe_count = %u", pv->pe_count);
 | 
			
		||||
		_outf(f, "status = %s", buffer);
 | 
			
		||||
		_outf(f, "pe_start = %" PRIu64, pv->pe_start);
 | 
			
		||||
		if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
 | 
			
		||||
			       "pe_count = %u", pv->pe_count)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_dec_indent(f);
 | 
			
		||||
		_out(f, "}");
 | 
			
		||||
		_outf(f, "}");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_out(f, "}");
 | 
			
		||||
	_outf(f, "}");
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
 | 
			
		||||
			  int count, struct stripe_segment *seg)
 | 
			
		||||
			  int count, struct lv_segment *seg)
 | 
			
		||||
{
 | 
			
		||||
	int s;
 | 
			
		||||
	unsigned int s;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *type;
 | 
			
		||||
 | 
			
		||||
	_out(f, "segment%u {", count);
 | 
			
		||||
	_outf(f, "segment%u {", count);
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	_out(f, "start_extent = %u", seg->le);
 | 
			
		||||
	_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
 | 
			
		||||
	_out(f, "stripes = %u", seg->stripes);
 | 
			
		||||
	_outf(f, "start_extent = %u", seg->le);
 | 
			
		||||
	if (!_out_size(f, (uint64_t) seg->len * vg->extent_size,
 | 
			
		||||
		       "extent_count = %u", seg->len)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->stripes > 1)
 | 
			
		||||
		_out_size(f, seg->stripe_size,
 | 
			
		||||
			  "stripe_size = %u", seg->stripe_size);
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
	_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
 | 
			
		||||
 | 
			
		||||
	_nl(f);
 | 
			
		||||
	_out(f, "areas = [");
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
	switch (seg->type) {
 | 
			
		||||
	case SEG_SNAPSHOT:
 | 
			
		||||
		_outf(f, "chunk_size = %u", seg->chunk_size);
 | 
			
		||||
		_outf(f, "origin = \"%s\"", seg->origin->name);
 | 
			
		||||
		_outf(f, "cow_store = \"%s\"", seg->cow->name);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	for (s = 0; s < seg->stripes; s++) {
 | 
			
		||||
		if (!(name = _get_pv_name(f, seg->area[s].pv))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
	case SEG_MIRRORED:
 | 
			
		||||
	case SEG_STRIPED:
 | 
			
		||||
		type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe";
 | 
			
		||||
		_outf(f, "%s_count = %u%s", type, seg->area_count,
 | 
			
		||||
		      (seg->area_count == 1) ? "\t# linear" : "");
 | 
			
		||||
 | 
			
		||||
		if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE))
 | 
			
		||||
			_out_size(f, (uint64_t) seg->extents_moved,
 | 
			
		||||
				  "extents_moved = %u", seg->extents_moved);
 | 
			
		||||
 | 
			
		||||
		if ((seg->type == SEG_STRIPED) && (seg->area_count > 1))
 | 
			
		||||
			_out_size(f, (uint64_t) seg->stripe_size,
 | 
			
		||||
				  "stripe_size = %u", seg->stripe_size);
 | 
			
		||||
 | 
			
		||||
		f->nl(f);
 | 
			
		||||
 | 
			
		||||
		_outf(f, "%ss = [", type);
 | 
			
		||||
		_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
		for (s = 0; s < seg->area_count; s++) {
 | 
			
		||||
			switch (seg->area[s].type) {
 | 
			
		||||
			case AREA_PV:
 | 
			
		||||
				if (!(name = _get_pv_name(f, seg->
 | 
			
		||||
							  area[s].u.pv.pv))) {
 | 
			
		||||
					stack;
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				_outf(f, "\"%s\", %u%s", name,
 | 
			
		||||
				      seg->area[s].u.pv.pe,
 | 
			
		||||
				      (s == seg->area_count - 1) ? "" : ",");
 | 
			
		||||
				break;
 | 
			
		||||
			case AREA_LV:
 | 
			
		||||
				_outf(f, "\"%s\", %u%s",
 | 
			
		||||
				      seg->area[s].u.lv.lv->name,
 | 
			
		||||
				      seg->area[s].u.lv.le,
 | 
			
		||||
				      (s == seg->area_count - 1) ? "" : ",");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_out(f, "\"%s\", %u%s", name, seg->area[s].pe,
 | 
			
		||||
		     (s == seg->stripes - 1) ? "" : ",");
 | 
			
		||||
		_dec_indent(f);
 | 
			
		||||
		_outf(f, "]");
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_out(f, "]");
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_out(f, "}");
 | 
			
		||||
	_outf(f, "}");
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -319,44 +450,129 @@ static int _count_segments(struct logical_volume *lv)
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
 | 
			
		||||
	list_iterate (segh, &lv->segments)
 | 
			
		||||
		r++;
 | 
			
		||||
	list_iterate(segh, &lv->segments)
 | 
			
		||||
	    r++;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
 | 
			
		||||
			   unsigned int count)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[256];
 | 
			
		||||
	struct lv_segment seg;
 | 
			
		||||
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
 | 
			
		||||
	_outf(f, "snapshot%u {", count);
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_outf(f, "id = \"%s\"", buffer);
 | 
			
		||||
	if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
 | 
			
		||||
			 buffer, sizeof(buffer))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_outf(f, "status = %s", buffer);
 | 
			
		||||
	_outf(f, "segment_count = 1");
 | 
			
		||||
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
 | 
			
		||||
	seg.type = SEG_SNAPSHOT;
 | 
			
		||||
	seg.le = 0;
 | 
			
		||||
	seg.len = snap->origin->le_count;
 | 
			
		||||
	seg.origin = snap->origin;
 | 
			
		||||
	seg.cow = snap->cow;
 | 
			
		||||
	seg.chunk_size = snap->chunk_size;
 | 
			
		||||
 | 
			
		||||
	if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_outf(f, "}");
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *sh;
 | 
			
		||||
	struct snapshot *s;
 | 
			
		||||
	unsigned int count = 0;
 | 
			
		||||
 | 
			
		||||
	list_iterate(sh, &vg->snapshots) {
 | 
			
		||||
		s = list_item(sh, struct snapshot_list)->snapshot;
 | 
			
		||||
 | 
			
		||||
		if (!_print_snapshot(f, s, count++)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lvh, *segh;
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	char buffer[256];
 | 
			
		||||
	int seg_count;
 | 
			
		||||
 | 
			
		||||
	_out(f, "logical_volumes {");
 | 
			
		||||
	_nl(f);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Don't bother with an lv section if there are no lvs.
 | 
			
		||||
	 */
 | 
			
		||||
	if (list_empty(&vg->lvs))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	_outf(f, "logical_volumes {");
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	list_iterate (lvh, &vg->lvs) {
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
 | 
			
		||||
		_out(f, "%s {", lv->name);
 | 
			
		||||
		f->nl(f);
 | 
			
		||||
		_outf(f, "%s {", lv->name);
 | 
			
		||||
		_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
		if (!print_flags(lv->status, LV_FLAGS,
 | 
			
		||||
				 buffer, sizeof(buffer))) {
 | 
			
		||||
		/* FIXME: Write full lvid */
 | 
			
		||||
		if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_out(f, "status = %s", buffer);
 | 
			
		||||
		_out(f, "read_ahead = %u", lv->read_ahead);
 | 
			
		||||
		_out(f, "segment_count = %u", _count_segments(lv));
 | 
			
		||||
		_nl(f);
 | 
			
		||||
		_outf(f, "id = \"%s\"", buffer);
 | 
			
		||||
 | 
			
		||||
		if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_outf(f, "status = %s", buffer);
 | 
			
		||||
		if (lv->alloc != ALLOC_DEFAULT)
 | 
			
		||||
			_outf(f, "allocation_policy = \"%s\"",
 | 
			
		||||
			      get_alloc_string(lv->alloc));
 | 
			
		||||
		if (lv->read_ahead)
 | 
			
		||||
			_outf(f, "read_ahead = %u", lv->read_ahead);
 | 
			
		||||
		if (lv->major >= 0)
 | 
			
		||||
			_outf(f, "major = %d", lv->major);
 | 
			
		||||
		if (lv->minor >= 0)
 | 
			
		||||
			_outf(f, "minor = %d", lv->minor);
 | 
			
		||||
		_outf(f, "segment_count = %u", _count_segments(lv));
 | 
			
		||||
		f->nl(f);
 | 
			
		||||
 | 
			
		||||
		seg_count = 1;
 | 
			
		||||
		list_iterate (segh, &lv->segments) {
 | 
			
		||||
			seg = list_item(segh, struct stripe_segment);
 | 
			
		||||
		list_iterate(segh, &lv->segments) {
 | 
			
		||||
			seg = list_item(segh, struct lv_segment);
 | 
			
		||||
 | 
			
		||||
			if (!_print_segment(f, vg, seg_count++, seg)) {
 | 
			
		||||
				stack;
 | 
			
		||||
@@ -365,11 +581,16 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_dec_indent(f);
 | 
			
		||||
		_out(f, "}");
 | 
			
		||||
		_outf(f, "}");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_print_snapshots(f, vg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_out(f, "}");
 | 
			
		||||
	_outf(f, "}");
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -379,8 +600,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
 * 'pv2' etc.  This function builds a hash table
 | 
			
		||||
 * to enable a quick lookup from device -> name.
 | 
			
		||||
 */
 | 
			
		||||
static int _build_pv_names(struct formatter *f,
 | 
			
		||||
			   struct volume_group *vg)
 | 
			
		||||
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	struct list *pvh;
 | 
			
		||||
@@ -397,11 +617,11 @@ static int _build_pv_names(struct formatter *f,
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_iterate (pvh, &vg->pvs) {
 | 
			
		||||
	list_iterate(pvh, &vg->pvs) {
 | 
			
		||||
		pv = list_item(pvh, struct pv_list)->pv;
 | 
			
		||||
 | 
			
		||||
		if (lvm_snprintf(buffer, sizeof(buffer),
 | 
			
		||||
				 "pv%d", count++) < 0) {
 | 
			
		||||
		/* FIXME But skip if there's already an LV called pv%d ! */
 | 
			
		||||
		if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
@@ -419,7 +639,7 @@ static int _build_pv_names(struct formatter *f,
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
      bad:
 | 
			
		||||
	if (f->mem)
 | 
			
		||||
		pool_destroy(f->mem);
 | 
			
		||||
 | 
			
		||||
@@ -429,10 +649,62 @@ static int _build_pv_names(struct formatter *f,
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int text_vg_export(FILE *fp, struct volume_group *vg)
 | 
			
		||||
static int _text_vg_export(struct formatter *f,
 | 
			
		||||
			   struct volume_group *vg, const char *desc)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
	if (!_build_pv_names(f, vg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
#define fail do {stack; goto out;} while(0)
 | 
			
		||||
 | 
			
		||||
	if (f->header && !_print_header(f, vg, desc))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	if (!_out(f, "%s {", vg->name))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	if (!_print_vg(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
	if (!_print_pvs(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	f->nl(f);
 | 
			
		||||
	if (!_print_lvs(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	if (!_out(f, "}"))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	if (!f->header && !_print_header(f, vg, desc))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
#undef fail
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	if (f->mem)
 | 
			
		||||
		pool_destroy(f->mem);
 | 
			
		||||
 | 
			
		||||
	if (f->pv_names)
 | 
			
		||||
		hash_destroy(f->pv_names);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
 | 
			
		||||
{
 | 
			
		||||
	struct formatter *f;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	_init();
 | 
			
		||||
 | 
			
		||||
	if (!(f = dbg_malloc(sizeof(*f)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -440,48 +712,52 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(f, 0, sizeof(*f));
 | 
			
		||||
	f->fp = fp;
 | 
			
		||||
	f->data.fp = fp;
 | 
			
		||||
	f->indent = 0;
 | 
			
		||||
	f->header = 1;
 | 
			
		||||
	f->out_with_comment = &_out_with_comment_file;
 | 
			
		||||
	f->nl = &_nl_file;
 | 
			
		||||
 | 
			
		||||
	if (!_build_pv_names(f, vg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#define fail do {stack; goto out;} while(0)
 | 
			
		||||
 | 
			
		||||
	if (!_print_header(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_out(f, "%s {", vg->name);
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	if (!_print_vg(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_nl(f);
 | 
			
		||||
 | 
			
		||||
	if (!_print_pvs(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
	_nl(f);
 | 
			
		||||
 | 
			
		||||
	if (!_print_lvs(f, vg))
 | 
			
		||||
		fail;
 | 
			
		||||
 | 
			
		||||
#undef fail
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	_out(f, "}");
 | 
			
		||||
	r = !ferror(f->fp);
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	if (f->mem)
 | 
			
		||||
		pool_destroy(f->mem);
 | 
			
		||||
 | 
			
		||||
	if (f->pv_names)
 | 
			
		||||
		hash_destroy(f->pv_names);
 | 
			
		||||
 | 
			
		||||
	r = _text_vg_export(f, vg, desc);
 | 
			
		||||
	if (r)
 | 
			
		||||
		r = !ferror(f->data.fp);
 | 
			
		||||
	dbg_free(f);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Returns amount of buffer used incl. terminating NUL */
 | 
			
		||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
 | 
			
		||||
		       uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct formatter *f;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	_init();
 | 
			
		||||
 | 
			
		||||
	if (!(f = dbg_malloc(sizeof(*f)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(f, 0, sizeof(*f));
 | 
			
		||||
	f->data.buf.buf = buf;
 | 
			
		||||
	f->data.buf.size = size;
 | 
			
		||||
	f->indent = 0;
 | 
			
		||||
	f->header = 0;
 | 
			
		||||
	f->out_with_comment = &_out_with_comment_raw;
 | 
			
		||||
	f->nl = &_nl_raw;
 | 
			
		||||
 | 
			
		||||
	if (!_text_vg_export(f, vg, desc)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		r = 0;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = f->data.buf.used + 1;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	dbg_free(f);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#undef _outf
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "import-export.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
@@ -14,14 +14,15 @@
 | 
			
		||||
 * converted into arrays of strings.
 | 
			
		||||
 */
 | 
			
		||||
struct flag {
 | 
			
		||||
	int mask;
 | 
			
		||||
	char *description;
 | 
			
		||||
	const int mask;
 | 
			
		||||
	const char *description;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct flag _vg_flags[] = {
 | 
			
		||||
	{EXPORTED_VG, "EXPORTED"},
 | 
			
		||||
	{RESIZEABLE_VG, "RESIZEABLE"},
 | 
			
		||||
	{PARTIAL_VG, "PARTIAL"},
 | 
			
		||||
	{PVMOVE, "PVMOVE"},
 | 
			
		||||
	{LVM_READ, "READ"},
 | 
			
		||||
	{LVM_WRITE, "WRITE"},
 | 
			
		||||
	{CLUSTERED, "CLUSTERED"},
 | 
			
		||||
@@ -38,11 +39,10 @@ static struct flag _pv_flags[] = {
 | 
			
		||||
static struct flag _lv_flags[] = {
 | 
			
		||||
	{LVM_READ, "READ"},
 | 
			
		||||
	{LVM_WRITE, "WRITE"},
 | 
			
		||||
	{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
 | 
			
		||||
	{ALLOC_STRICT, "ALLOC_STRICT"},
 | 
			
		||||
	{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
 | 
			
		||||
	{SNAPSHOT, "SNASHOT"},
 | 
			
		||||
	{SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"},
 | 
			
		||||
	{FIXED_MINOR, "FIXED_MINOR"},
 | 
			
		||||
	{VISIBLE_LV, "VISIBLE"},
 | 
			
		||||
	{PVMOVE, "PVMOVE"},
 | 
			
		||||
	{LOCKED, "LOCKED"},
 | 
			
		||||
	{0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +65,7 @@ static struct flag *_get_flags(int type)
 | 
			
		||||
 | 
			
		||||
static int _emit(char **buffer, size_t *size, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	size_t n;
 | 
			
		||||
	int n;
 | 
			
		||||
	va_list ap;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
@@ -136,6 +136,9 @@ int read_flags(uint32_t *status, int type, struct config_value *cv)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cv->type == CFG_EMPTY_ARRAY)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	while (cv) {
 | 
			
		||||
		if (cv->type != CFG_STRING) {
 | 
			
		||||
			log_err("Status value is not a string.");
 | 
			
		||||
@@ -156,6 +159,7 @@ int read_flags(uint32_t *status, int type, struct config_value *cv)
 | 
			
		||||
		cv = cv->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	*status = s;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -9,29 +9,46 @@
 | 
			
		||||
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "uuid-map.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
 | 
			
		||||
#define FMT_TEXT_NAME "lvm2"
 | 
			
		||||
#define FMT_TEXT_ALIAS "text"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The archive format is used to maintain a set of metadata backup files
 | 
			
		||||
 * in an archive directory.
 | 
			
		||||
 * 'retain_days' is the minimum number of days that an archive file must 
 | 
			
		||||
 *               be held for.
 | 
			
		||||
 *
 | 
			
		||||
 * 'min_archives' is the minimum number of archives required to be kept
 | 
			
		||||
 *               for each volume group.
 | 
			
		||||
 * Archives a vg config.  'retain_days' is the minimum number of
 | 
			
		||||
 * days that an archive file must be held for.  'min_archives' is
 | 
			
		||||
 * the minimum number of archives required to be kept for each
 | 
			
		||||
 * volume group.
 | 
			
		||||
 */
 | 
			
		||||
struct format_instance *archive_format_create(struct cmd_context *cmd,
 | 
			
		||||
					     const char *dir,
 | 
			
		||||
					     uint32_t retain_days,
 | 
			
		||||
					     uint32_t min_archives);
 | 
			
		||||
int archive_vg(struct volume_group *vg,
 | 
			
		||||
	       const char *dir,
 | 
			
		||||
	       const char *desc, uint32_t retain_days, uint32_t min_archive);
 | 
			
		||||
 | 
			
		||||
void backup_expire(struct format_instance *fi);
 | 
			
		||||
/*
 | 
			
		||||
 * Displays a list of vg backups in a particular archive directory.
 | 
			
		||||
 */
 | 
			
		||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The text format can read and write a volume_group to a file.
 | 
			
		||||
 */
 | 
			
		||||
struct format_instance *text_format_create(struct cmd_context *cmd,
 | 
			
		||||
					   const char *file,
 | 
			
		||||
					   struct uuid_map *um);
 | 
			
		||||
struct format_type *create_text_format(struct cmd_context *cmd);
 | 
			
		||||
void *create_text_context(struct cmd_context *cmd, const char *path,
 | 
			
		||||
			  const char *desc);
 | 
			
		||||
 | 
			
		||||
struct labeller *text_labeller_create(const struct format_type *fmt);
 | 
			
		||||
 | 
			
		||||
int pvhdr_read(struct device *dev, char *buf);
 | 
			
		||||
 | 
			
		||||
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
 | 
			
		||||
	   uint64_t start, uint64_t size);
 | 
			
		||||
void del_das(struct list *das);
 | 
			
		||||
 | 
			
		||||
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
 | 
			
		||||
	    struct device *dev, uint64_t start, uint64_t size);
 | 
			
		||||
void del_mdas(struct list *mdas);
 | 
			
		||||
 | 
			
		||||
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
 | 
			
		||||
		    char *buf, uint32_t size);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -10,22 +10,55 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "uuid-map.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Constants to identify files this code can parse.
 | 
			
		||||
 */
 | 
			
		||||
#define CONTENTS_FIELD "contents"
 | 
			
		||||
#define CONTENTS_VALUE "Text Format Volume Group"
 | 
			
		||||
 | 
			
		||||
#define FORMAT_VERSION_FIELD "version"
 | 
			
		||||
#define FORMAT_VERSION_VALUE 1
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * VGs, PVs and LVs all have status bitsets, we gather together
 | 
			
		||||
 * common code for reading and writing them.
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
	VG_FLAGS,
 | 
			
		||||
	PV_FLAGS,
 | 
			
		||||
	LV_FLAGS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct text_vg_version_ops {
 | 
			
		||||
	int (*check_version) (struct config_tree * cf);
 | 
			
		||||
	struct volume_group *(*read_vg) (struct format_instance * fid,
 | 
			
		||||
					 struct config_tree * cf);
 | 
			
		||||
	void (*read_desc) (struct pool * mem, struct config_tree * cf,
 | 
			
		||||
			   time_t *when, char **desc);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct text_vg_version_ops *text_vg_vsn1_init(void);
 | 
			
		||||
 | 
			
		||||
int print_flags(uint32_t status, int type, char *buffer, size_t size);
 | 
			
		||||
int read_flags(uint32_t *status, int type, struct config_value *cv);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int text_vg_export(FILE *fp, struct volume_group *vg);
 | 
			
		||||
struct volume_group *text_vg_import(struct cmd_context *cmd, const char *file,
 | 
			
		||||
				    struct uuid_map *um);
 | 
			
		||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
 | 
			
		||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
 | 
			
		||||
		       uint32_t size);
 | 
			
		||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
 | 
			
		||||
					 const char *file,
 | 
			
		||||
					 time_t *when, char **desc);
 | 
			
		||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
 | 
			
		||||
				       const char *file,
 | 
			
		||||
				       struct device *dev,
 | 
			
		||||
				       off_t offset, uint32_t size,
 | 
			
		||||
				       off_t offset2, uint32_t size2,
 | 
			
		||||
				       checksum_fn_t checksum_fn,
 | 
			
		||||
				       uint32_t checksum,
 | 
			
		||||
				       time_t *when, char **desc);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -4,549 +4,79 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "import-export.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef int (*section_fn)(struct pool *mem,
 | 
			
		||||
			  struct volume_group *vg, struct config_node *pvn,
 | 
			
		||||
			  struct config_node *vgn, struct hash_table *pv_hash,
 | 
			
		||||
			  struct uuid_map *um);
 | 
			
		||||
 | 
			
		||||
#define _read_int32(root, path, result) \
 | 
			
		||||
	get_config_uint32(root, path, '/', result)
 | 
			
		||||
 | 
			
		||||
#define _read_int64(root, path, result) \
 | 
			
		||||
	get_config_uint64(root, path, '/', result)
 | 
			
		||||
 | 
			
		||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(cn, path, '/'))) {
 | 
			
		||||
		log_err("Couldn't find uuid.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cv = cn->v;
 | 
			
		||||
	if (!cv || !cv->v.str) {
 | 
			
		||||
		log_err("uuid must be a string.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!id_read_format(id, cv->v.str)) {
 | 
			
		||||
		log_err("Invalid uuid.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_pv(struct pool *mem,
 | 
			
		||||
		    struct volume_group *vg, struct config_node *pvn,
 | 
			
		||||
		    struct config_node *vgn,
 | 
			
		||||
		    struct hash_table *pv_hash,
 | 
			
		||||
		    struct uuid_map *um)
 | 
			
		||||
{
 | 
			
		||||
	struct physical_volume *pv;
 | 
			
		||||
	struct pv_list *pvl;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
 | 
			
		||||
	if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
 | 
			
		||||
	    !(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pv = pvl->pv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Add the pv to the pv hash for quick lookup when we read
 | 
			
		||||
	 * the lv segments.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!hash_insert(pv_hash, pvn->key, pv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pvn = pvn->child)) {
 | 
			
		||||
		log_err("Empty pv section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_id(&pv->id, pvn, "id")) {
 | 
			
		||||
		log_err("Couldn't read uuid for volume group.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Use the uuid map to convert the uuid into a device.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
 | 
			
		||||
		char buffer[64];
 | 
			
		||||
 | 
			
		||||
		if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
 | 
			
		||||
			log_err("Couldn't find device.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_err("Couldn't find device with uuid '%s'.", buffer);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(pvn, "status", '/'))) {
 | 
			
		||||
		log_err("Couldn't find status flags for physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
 | 
			
		||||
		log_err("Couldn't read status flags for physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
 | 
			
		||||
		log_err("Couldn't read extent size for volume group.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
 | 
			
		||||
		log_err("Couldn't find extent count (pe_count) for "
 | 
			
		||||
			"physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* adjust the volume group. */
 | 
			
		||||
	vg->extent_count += pv->pe_count;
 | 
			
		||||
	vg->free_count += pv->pe_count;
 | 
			
		||||
 | 
			
		||||
	pv->pe_size = vg->extent_size;
 | 
			
		||||
	pv->size = pv->pe_size * (uint64_t) pv->pe_count;
 | 
			
		||||
	pv->pe_allocated = 0;
 | 
			
		||||
 | 
			
		||||
	vg->pv_count++;
 | 
			
		||||
	list_add(&vg->pvs, &pvl->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _insert_segment(struct logical_volume *lv,
 | 
			
		||||
			    struct stripe_segment *seg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
	struct stripe_segment *comp;
 | 
			
		||||
 | 
			
		||||
	list_iterate (segh, &lv->segments) {
 | 
			
		||||
		comp = list_item(segh, struct stripe_segment);
 | 
			
		||||
 | 
			
		||||
		if (comp->le > seg->le) {
 | 
			
		||||
			list_add(&comp->list, &seg->list);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->le_count += seg->len;
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_segment(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
			 struct logical_volume *lv, struct config_node *sn,
 | 
			
		||||
			 struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	int s;
 | 
			
		||||
	uint32_t stripes;
 | 
			
		||||
	struct stripe_segment *seg;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
	const char *seg_name = sn->key;
 | 
			
		||||
 | 
			
		||||
	if (!(sn = sn->child)) {
 | 
			
		||||
		log_err("Empty segment section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(sn, "stripes", &stripes)) {
 | 
			
		||||
		log_err("Couldn't read 'stripes' for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(seg = pool_zalloc(mem, sizeof(*seg) +
 | 
			
		||||
				(sizeof(seg->area[0]) * stripes)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	seg->stripes = stripes;
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(sn, "start_extent", &seg->le)) {
 | 
			
		||||
		log_err("Couldn't read 'start_extent' for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(sn, "extent_count", &seg->len)) {
 | 
			
		||||
		log_err("Couldn't read 'extent_count' for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->stripes == 0) {
 | 
			
		||||
		log_err("Zero stripes is *not* allowed for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((seg->stripes != 1) &&
 | 
			
		||||
	    !_read_int32(sn, "stripe_size", &seg->stripe_size)) {
 | 
			
		||||
		log_err("Couldn't read 'stripe_size' for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(sn, "areas", '/'))) {
 | 
			
		||||
		log_err("Couldn't find 'areas' array for segment '%s'.",
 | 
			
		||||
			sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Read the stripes from the 'areas' array.
 | 
			
		||||
	 * FIXME: we could move this to a separate function.
 | 
			
		||||
	 */
 | 
			
		||||
	for (cv = cn->v, s = 0; cv && s < seg->stripes; s++, cv = cv->next) {
 | 
			
		||||
 | 
			
		||||
		/* first we read the pv */
 | 
			
		||||
		const char *bad = "Badly formed areas array for segment '%s'.";
 | 
			
		||||
		struct physical_volume *pv;
 | 
			
		||||
		uint32_t allocated;
 | 
			
		||||
 | 
			
		||||
		if (cv->type != CFG_STRING) {
 | 
			
		||||
			log_err(bad, sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
 | 
			
		||||
			log_err("Couldn't find physical volume '%s' for "
 | 
			
		||||
				"segment '%s'.",
 | 
			
		||||
				cn->v->v.str ? cn->v->v.str : "NULL",
 | 
			
		||||
				seg_name);
 | 
			
		||||
				return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seg->area[s].pv = pv;
 | 
			
		||||
 | 
			
		||||
		if (!(cv = cv->next)) {
 | 
			
		||||
			log_err(bad, sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cv->type != CFG_INT) {
 | 
			
		||||
			log_err(bad, sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seg->area[s].pe = cv->v.i;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Adjust the extent counts in the pv and vg.
 | 
			
		||||
		 */
 | 
			
		||||
		allocated = seg->len / seg->stripes;
 | 
			
		||||
		pv->pe_allocated += allocated;
 | 
			
		||||
		vg->free_count -= allocated;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check we read the correct number of stripes.
 | 
			
		||||
	 */
 | 
			
		||||
	if (cv || (s < seg->stripes)) {
 | 
			
		||||
		log_err("Incorrect number of stripes in 'area' array "
 | 
			
		||||
			"for segment '%s'.", seg_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Insert into correct part of segment list.
 | 
			
		||||
	 */
 | 
			
		||||
	_insert_segment(lv, seg);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_segments(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
			  struct logical_volume *lv, struct config_node *lvn,
 | 
			
		||||
			  struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *sn;
 | 
			
		||||
	int count = 0, seg_count;
 | 
			
		||||
 | 
			
		||||
	for (sn = lvn; sn; sn = sn->sib) {
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * All sub-sections are assumed to be segments.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!sn->v) {
 | 
			
		||||
			if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
 | 
			
		||||
				stack;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(lvn, "segment_count", &seg_count)) {
 | 
			
		||||
		log_err("Couldn't read segment count for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg_count != count) {
 | 
			
		||||
		log_err("segment_count and actual number of segments "
 | 
			
		||||
			"disagree.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check there are no gaps or overlaps in the lv.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!lv_check_segments(lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Merge segments in case someones been editing things by hand.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!lv_merge_segments(lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_lv(struct pool *mem,
 | 
			
		||||
		    struct volume_group *vg, struct config_node *lvn,
 | 
			
		||||
		    struct config_node *vgn, struct hash_table *pv_hash,
 | 
			
		||||
		    struct uuid_map *um)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lv_list *lvl;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
 | 
			
		||||
	if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
 | 
			
		||||
	    !(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv = lvl->lv;
 | 
			
		||||
 | 
			
		||||
	if (!(lv->name = pool_strdup(mem, lvn->key))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(lvn = lvn->child)) {
 | 
			
		||||
		log_err("Empty logical volume section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->vg = vg;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(lvn, "status", '/'))) {
 | 
			
		||||
		log_err("Couldn't find status flags for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
 | 
			
		||||
		log_err("Couldn't read status flags for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
 | 
			
		||||
		log_err("Couldn't read 'read_ahead' value for "
 | 
			
		||||
			"logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&lv->segments);
 | 
			
		||||
	if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
 | 
			
		||||
 | 
			
		||||
	vg->lv_count++;
 | 
			
		||||
	list_add(&vg->lvs, &lvl->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_sections(const char *section, section_fn fn,
 | 
			
		||||
			  struct pool *mem,
 | 
			
		||||
			  struct volume_group *vg, struct config_node *vgn,
 | 
			
		||||
			  struct hash_table *pv_hash,
 | 
			
		||||
			  struct uuid_map *um)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n;
 | 
			
		||||
 | 
			
		||||
	if (!(n = find_config_node(vgn, section, '/'))) {
 | 
			
		||||
		log_err("Couldn't find section '%s'.", section);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (n = n->child; n; n = n->sib) {
 | 
			
		||||
		if (!fn(mem, vg, n, vgn, pv_hash, um)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
 | 
			
		||||
				     struct uuid_map *um)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *vgn = cf->root, *cn;
 | 
			
		||||
	struct volume_group *vg;
 | 
			
		||||
	struct hash_table *pv_hash = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!vgn) {
 | 
			
		||||
		log_err("Couldn't find volume group.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vgn = cf->root)) {
 | 
			
		||||
		log_err("Couldn't find volume group in file.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg->name = pool_strdup(mem, vgn->key))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vgn = vgn->child;
 | 
			
		||||
	if (!_read_id(&vg->id, vgn, "id")) {
 | 
			
		||||
		log_err("Couldn't read uuid for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(vgn, "status", '/'))) {
 | 
			
		||||
		log_err("Couldn't find status flags for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
 | 
			
		||||
		log_err("Couldn't read status flags for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
 | 
			
		||||
		log_err("Couldn't read extent size for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 'extent_count' and 'free_count' get filled in
 | 
			
		||||
	 * implicitly when reading in the pv's and lv's.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
 | 
			
		||||
		log_err("Couldn't read 'max_lv' for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
 | 
			
		||||
		log_err("Couldn't read 'max_pv' for volume group %s.",
 | 
			
		||||
			vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The pv hash memoises the pv section names -> pv
 | 
			
		||||
	 * structures.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(pv_hash = hash_create(32))) {
 | 
			
		||||
		log_err("Couldn't create hash table.");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&vg->pvs);
 | 
			
		||||
	if (!_read_sections("physical_volumes", _read_pv, mem, vg,
 | 
			
		||||
			    vgn, pv_hash, um)) {
 | 
			
		||||
		log_err("Couldn't find all physical volumes for volume "
 | 
			
		||||
			"group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&vg->lvs);
 | 
			
		||||
	if (!_read_sections("logical_volumes", _read_lv, mem, vg,
 | 
			
		||||
			    vgn, pv_hash, um)) {
 | 
			
		||||
		log_err("Couldn't read all logical volumes for volume "
 | 
			
		||||
			"group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hash_destroy(pv_hash);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Finished.
 | 
			
		||||
	 */
 | 
			
		||||
	return vg;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	if (pv_hash)
 | 
			
		||||
		hash_destroy(pv_hash);
 | 
			
		||||
 | 
			
		||||
	pool_free(mem, vg);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct volume_group *text_vg_import(struct cmd_context *cmd,
 | 
			
		||||
				    const char *file,
 | 
			
		||||
				    struct uuid_map *um)
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
/* FIXME Use tidier inclusion method */
 | 
			
		||||
static struct text_vg_version_ops *(_text_vsn_list[2]);
 | 
			
		||||
 | 
			
		||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
 | 
			
		||||
				       const char *file,
 | 
			
		||||
				       struct device *dev,
 | 
			
		||||
				       off_t offset, uint32_t size,
 | 
			
		||||
				       off_t offset2, uint32_t size2,
 | 
			
		||||
				       checksum_fn_t checksum_fn,
 | 
			
		||||
				       uint32_t checksum,
 | 
			
		||||
				       time_t *when, char **desc)
 | 
			
		||||
{
 | 
			
		||||
	struct volume_group *vg = NULL;
 | 
			
		||||
	struct config_file *cf;
 | 
			
		||||
	struct config_tree *cf;
 | 
			
		||||
	struct text_vg_version_ops **vsn;
 | 
			
		||||
 | 
			
		||||
	if (!(cf = create_config_file())) {
 | 
			
		||||
	static int _initialised = 0;
 | 
			
		||||
 | 
			
		||||
	if (!_initialised) {
 | 
			
		||||
		_text_vsn_list[0] = text_vg_vsn1_init();
 | 
			
		||||
		_text_vsn_list[1] = NULL;
 | 
			
		||||
		_initialised = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*desc = NULL;
 | 
			
		||||
	*when = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(cf = create_config_tree())) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!read_config(cf, file)) {
 | 
			
		||||
		log_error("Couldn't read volume group file.");
 | 
			
		||||
	if ((!dev && !read_config_file(cf, file)) ||
 | 
			
		||||
	    (dev && !read_config_fd(cf, dev, offset, size,
 | 
			
		||||
				    offset2, size2, checksum_fn, checksum))) {
 | 
			
		||||
		log_error("Couldn't read volume group metadata.");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg = _read_vg(cmd->mem, cf, um))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
	/* 
 | 
			
		||||
	 * Find a set of version functions that can read this file
 | 
			
		||||
	 */
 | 
			
		||||
	for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
 | 
			
		||||
		if (!(*vsn)->check_version(cf))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(vg = (*vsn)->read_vg(fid, cf))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		(*vsn)->read_desc(fid->fmt->cmd->mem, cf, when, desc);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vg->cmd = cmd;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
	destroy_config_file(cf);
 | 
			
		||||
      out:
 | 
			
		||||
	destroy_config_tree(cf);
 | 
			
		||||
	return vg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
 | 
			
		||||
					 const char *file,
 | 
			
		||||
					 time_t *when, char **desc)
 | 
			
		||||
{
 | 
			
		||||
	return text_vg_import_fd(fid, file, NULL, 0, 0, 0, 0, NULL, 0,
 | 
			
		||||
				 when, desc);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										810
									
								
								lib/format_text/import_vsn1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										810
									
								
								lib/format_text/import_vsn1.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,810 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "import-export.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
 | 
			
		||||
			   struct volume_group * vg, struct config_node * pvn,
 | 
			
		||||
			   struct config_node * vgn,
 | 
			
		||||
			   struct hash_table * pv_hash);
 | 
			
		||||
 | 
			
		||||
#define _read_int32(root, path, result) \
 | 
			
		||||
	get_config_uint32(root, path, '/', result)
 | 
			
		||||
 | 
			
		||||
#define _read_uint32(root, path, result) \
 | 
			
		||||
	get_config_uint32(root, path, '/', result)
 | 
			
		||||
 | 
			
		||||
#define _read_int64(root, path, result) \
 | 
			
		||||
	get_config_uint64(root, path, '/', result)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Logs an attempt to read an invalid format file.
 | 
			
		||||
 */
 | 
			
		||||
static void _invalid_format(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	log_error("Can't process text format file - %s.", str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Checks that the config file contains vg metadata, and that it
 | 
			
		||||
 * we recognise the version number,
 | 
			
		||||
 */
 | 
			
		||||
static int _check_version(struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check the contents field.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
 | 
			
		||||
		_invalid_format("missing contents field");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cv = cn->v;
 | 
			
		||||
	if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
 | 
			
		||||
		_invalid_format("unrecognised contents field");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check the version number.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
 | 
			
		||||
		_invalid_format("missing version number");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cv = cn->v;
 | 
			
		||||
	if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
 | 
			
		||||
		_invalid_format("unrecognised version number");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(cn, path, '/'))) {
 | 
			
		||||
		log_error("Couldn't find uuid.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cv = cn->v;
 | 
			
		||||
	if (!cv || !cv->v.str) {
 | 
			
		||||
		log_error("uuid must be a string.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!id_read_format(id, cv->v.str)) {
 | 
			
		||||
		log_error("Invalid uuid.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_pv(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
		    struct volume_group *vg, struct config_node *pvn,
 | 
			
		||||
		    struct config_node *vgn, struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	struct physical_volume *pv;
 | 
			
		||||
	struct pv_list *pvl;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
 | 
			
		||||
	if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
 | 
			
		||||
	    !(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pv = pvl->pv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Add the pv to the pv hash for quick lookup when we read
 | 
			
		||||
	 * the lv segments.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!hash_insert(pv_hash, pvn->key, pv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pvn = pvn->child)) {
 | 
			
		||||
		log_error("Empty pv section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_id(&pv->id, pvn, "id")) {
 | 
			
		||||
		log_error("Couldn't read uuid for volume group.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Convert the uuid into a device.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
 | 
			
		||||
		char buffer[64];
 | 
			
		||||
 | 
			
		||||
		if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
 | 
			
		||||
			log_error("Couldn't find device.");
 | 
			
		||||
		else
 | 
			
		||||
			log_error("Couldn't find device with uuid '%s'.",
 | 
			
		||||
				  buffer);
 | 
			
		||||
 | 
			
		||||
		if (partial_mode())
 | 
			
		||||
			vg->status |= PARTIAL_VG;
 | 
			
		||||
		else
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(pvn, "status", '/'))) {
 | 
			
		||||
		log_error("Couldn't find status flags for physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
 | 
			
		||||
		log_error("Couldn't read status flags for physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
 | 
			
		||||
		log_error("Couldn't read extent size for volume group.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
 | 
			
		||||
		log_error("Couldn't find extent count (pe_count) for "
 | 
			
		||||
			  "physical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* adjust the volume group. */
 | 
			
		||||
	vg->extent_count += pv->pe_count;
 | 
			
		||||
	vg->free_count += pv->pe_count;
 | 
			
		||||
 | 
			
		||||
	pv->pe_size = vg->extent_size;
 | 
			
		||||
	pv->size = vg->extent_size * (uint64_t) pv->pe_count;
 | 
			
		||||
	pv->pe_alloc_count = 0;
 | 
			
		||||
	pv->fmt = fid->fmt;
 | 
			
		||||
 | 
			
		||||
	vg->pv_count++;
 | 
			
		||||
	list_add(&vg->pvs, &pvl->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
 | 
			
		||||
{
 | 
			
		||||
	struct list *segh;
 | 
			
		||||
	struct lv_segment *comp;
 | 
			
		||||
 | 
			
		||||
	list_iterate(segh, &lv->segments) {
 | 
			
		||||
		comp = list_item(segh, struct lv_segment);
 | 
			
		||||
 | 
			
		||||
		if (comp->le > seg->le) {
 | 
			
		||||
			list_add(&comp->list, &seg->list);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->le_count += seg->len;
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_segment(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
			 struct logical_volume *lv, struct config_node *sn,
 | 
			
		||||
			 struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int s;
 | 
			
		||||
	uint32_t area_count = 0;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
	struct config_value *cv;
 | 
			
		||||
	const char *seg_name = sn->key;
 | 
			
		||||
	uint32_t start_extent, extent_count;
 | 
			
		||||
	uint32_t chunk_size, extents_moved = 0u, seg_status = 0u;
 | 
			
		||||
	const char *org_name, *cow_name;
 | 
			
		||||
	struct logical_volume *org, *cow, *lv1;
 | 
			
		||||
	segment_type_t segtype;
 | 
			
		||||
 | 
			
		||||
	if (!(sn = sn->child)) {
 | 
			
		||||
		log_error("Empty segment section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(sn, "start_extent", &start_extent)) {
 | 
			
		||||
		log_error("Couldn't read 'start_extent' for segment '%s'.",
 | 
			
		||||
			  sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(sn, "extent_count", &extent_count)) {
 | 
			
		||||
		log_error("Couldn't read 'extent_count' for segment '%s'.",
 | 
			
		||||
			  sn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	segtype = SEG_STRIPED;	/* Default */
 | 
			
		||||
	if ((cn = find_config_node(sn, "type", '/'))) {
 | 
			
		||||
		cv = cn->v;
 | 
			
		||||
		if (!cv || !cv->v.str) {
 | 
			
		||||
			log_error("Segment type must be a string.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		segtype = get_segtype_from_string(cv->v.str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (segtype == SEG_STRIPED) {
 | 
			
		||||
		if (!_read_int32(sn, "stripe_count", &area_count)) {
 | 
			
		||||
			log_error("Couldn't read 'stripe_count' for "
 | 
			
		||||
				  "segment '%s'.", sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (segtype == SEG_MIRRORED) {
 | 
			
		||||
		if (!_read_int32(sn, "mirror_count", &area_count)) {
 | 
			
		||||
			log_error("Couldn't read 'mirror_count' for "
 | 
			
		||||
				  "segment '%s'.", sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (find_config_node(sn, "extents_moved", '/')) {
 | 
			
		||||
			if (_read_uint32(sn, "extents_moved", &extents_moved))
 | 
			
		||||
				seg_status |= PVMOVE;
 | 
			
		||||
			else {
 | 
			
		||||
				log_error("Couldn't read 'extents_moved' for "
 | 
			
		||||
					  "segment '%s'.", sn->key);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(seg = pool_zalloc(mem, sizeof(*seg) +
 | 
			
		||||
				(sizeof(seg->area[0]) * area_count)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	seg->le = start_extent;
 | 
			
		||||
	seg->len = extent_count;
 | 
			
		||||
	seg->area_len = extent_count;
 | 
			
		||||
	seg->type = segtype;
 | 
			
		||||
	seg->status = seg_status;
 | 
			
		||||
	seg->extents_moved = extents_moved;
 | 
			
		||||
 | 
			
		||||
	switch (segtype) {
 | 
			
		||||
	case SEG_SNAPSHOT:
 | 
			
		||||
		lv->status |= SNAPSHOT;
 | 
			
		||||
 | 
			
		||||
		if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
 | 
			
		||||
			log_error("Couldn't read chunk size for snapshot.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_suppress(1);
 | 
			
		||||
 | 
			
		||||
		if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
 | 
			
		||||
			log_suppress(0);
 | 
			
		||||
			log_error("Snapshot cow storage not specified.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
 | 
			
		||||
			log_suppress(0);
 | 
			
		||||
			log_error("Snapshot origin not specified.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_suppress(0);
 | 
			
		||||
 | 
			
		||||
		if (!(cow = find_lv(vg, cow_name))) {
 | 
			
		||||
			log_error("Unknown logical volume specified for "
 | 
			
		||||
				  "snapshot cow store.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(org = find_lv(vg, org_name))) {
 | 
			
		||||
			log_error("Unknown logical volume specified for "
 | 
			
		||||
				  "snapshot origin.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SEG_STRIPED:
 | 
			
		||||
		if ((area_count != 1) &&
 | 
			
		||||
		    !_read_int32(sn, "stripe_size", &seg->stripe_size)) {
 | 
			
		||||
			log_error("Couldn't read stripe_size for segment '%s'.",
 | 
			
		||||
				  sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(cn = find_config_node(sn, "stripes", '/'))) {
 | 
			
		||||
			log_error("Couldn't find stripes array for segment "
 | 
			
		||||
				  "'%s'.", sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seg->area_len /= area_count;
 | 
			
		||||
 | 
			
		||||
	case SEG_MIRRORED:
 | 
			
		||||
		seg->area_count = area_count;
 | 
			
		||||
 | 
			
		||||
		if (!seg->area_count) {
 | 
			
		||||
			log_error("Zero areas not allowed for segment '%s'",
 | 
			
		||||
				  sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((seg->type == SEG_MIRRORED) &&
 | 
			
		||||
		    !(cn = find_config_node(sn, "mirrors", '/'))) {
 | 
			
		||||
			log_error("Couldn't find mirrors array for segment "
 | 
			
		||||
				  "'%s'.", sn->key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (cv = cn->v, s = 0; cv && s < seg->area_count;
 | 
			
		||||
		     s++, cv = cv->next) {
 | 
			
		||||
 | 
			
		||||
			/* first we read the pv */
 | 
			
		||||
			const char *bad = "Badly formed areas array for "
 | 
			
		||||
			    "segment '%s'.";
 | 
			
		||||
			struct physical_volume *pv;
 | 
			
		||||
 | 
			
		||||
			if (cv->type != CFG_STRING) {
 | 
			
		||||
				log_error(bad, sn->key);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!cv->next) {
 | 
			
		||||
				log_error(bad, sn->key);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (cv->next->type != CFG_INT) {
 | 
			
		||||
				log_error(bad, sn->key);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* FIXME Cope if LV not yet read in */
 | 
			
		||||
			if ((pv = hash_lookup(pv_hash, cv->v.str))) {
 | 
			
		||||
				seg->area[s].type = AREA_PV;
 | 
			
		||||
				seg->area[s].u.pv.pv = pv;
 | 
			
		||||
				seg->area[s].u.pv.pe = cv->next->v.i;
 | 
			
		||||
				/*
 | 
			
		||||
				 * Adjust extent counts in the pv and vg.
 | 
			
		||||
				 */
 | 
			
		||||
				pv->pe_alloc_count += seg->area_len;
 | 
			
		||||
				vg->free_count -= seg->area_len;
 | 
			
		||||
 | 
			
		||||
			} else if ((lv1 = find_lv(vg, cv->v.str))) {
 | 
			
		||||
				seg->area[s].type = AREA_LV;
 | 
			
		||||
				seg->area[s].u.lv.lv = lv1;
 | 
			
		||||
				seg->area[s].u.lv.le = cv->next->v.i;
 | 
			
		||||
			} else {
 | 
			
		||||
				log_error("Couldn't find volume '%s' "
 | 
			
		||||
					  "for segment '%s'.",
 | 
			
		||||
					  cv->v.str ? cv->v.str : "NULL",
 | 
			
		||||
					  seg_name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			cv = cv->next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Check we read the correct number of stripes.
 | 
			
		||||
		 */
 | 
			
		||||
		if (cv || (s < seg->area_count)) {
 | 
			
		||||
			log_error("Incorrect number of areas in area array "
 | 
			
		||||
				  "for segment '%s'.", seg_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Insert into correct part of segment list.
 | 
			
		||||
	 */
 | 
			
		||||
	_insert_segment(lv, seg);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_segments(struct pool *mem, struct volume_group *vg,
 | 
			
		||||
			  struct logical_volume *lv, struct config_node *lvn,
 | 
			
		||||
			  struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *sn;
 | 
			
		||||
	int count = 0, seg_count;
 | 
			
		||||
 | 
			
		||||
	for (sn = lvn; sn; sn = sn->sib) {
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * All sub-sections are assumed to be segments.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!sn->v) {
 | 
			
		||||
			if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
 | 
			
		||||
				stack;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			count++;
 | 
			
		||||
		}
 | 
			
		||||
		/* FIXME Remove this restriction */
 | 
			
		||||
		if ((lv->status & SNAPSHOT) && count > 1) {
 | 
			
		||||
			log_error("Only one segment permitted for snapshot");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(lvn, "segment_count", &seg_count)) {
 | 
			
		||||
		log_error("Couldn't read segment count for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg_count != count) {
 | 
			
		||||
		log_error("segment_count and actual number of segments "
 | 
			
		||||
			  "disagree.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check there are no gaps or overlaps in the lv.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!lv_check_segments(lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Merge segments in case someones been editing things by hand.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!lv_merge_segments(lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_lvnames(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
			 struct volume_group *vg, struct config_node *lvn,
 | 
			
		||||
			 struct config_node *vgn, struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lv_list *lvl;
 | 
			
		||||
	struct config_node *cn;
 | 
			
		||||
 | 
			
		||||
	if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
 | 
			
		||||
	    !(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv = lvl->lv;
 | 
			
		||||
 | 
			
		||||
	if (!(lv->name = pool_strdup(mem, lvn->key))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(lvn = lvn->child)) {
 | 
			
		||||
		log_error("Empty logical volume section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(lvn, "status", '/'))) {
 | 
			
		||||
		log_error("Couldn't find status flags for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
 | 
			
		||||
		log_error("Couldn't read status flags for logical volume.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->alloc = ALLOC_DEFAULT;
 | 
			
		||||
	if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
 | 
			
		||||
		struct config_value *cv = cn->v;
 | 
			
		||||
		if (!cv || !cv->v.str) {
 | 
			
		||||
			log_error("allocation_policy must be a string.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lv->alloc = get_alloc_from_string(cv->v.str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* read_ahead defaults to 0 */
 | 
			
		||||
	if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
 | 
			
		||||
		lv->read_ahead = 0;
 | 
			
		||||
 | 
			
		||||
	list_init(&lv->segments);
 | 
			
		||||
 | 
			
		||||
	lv->vg = vg;
 | 
			
		||||
	vg->lv_count++;
 | 
			
		||||
	list_add(&vg->lvs, &lvl->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
			struct volume_group *vg, struct config_node *lvn,
 | 
			
		||||
			struct config_node *vgn, struct hash_table *pv_hash)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct lv_list *lvl;
 | 
			
		||||
 | 
			
		||||
	if (!(lvl = find_lv_in_vg(vg, lvn->key))) {
 | 
			
		||||
		log_error("Lost logical volume reference %s", lvn->key);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv = lvl->lv;
 | 
			
		||||
 | 
			
		||||
	if (!(lvn = lvn->child)) {
 | 
			
		||||
		log_error("Empty logical volume section.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: read full lvid */
 | 
			
		||||
	if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
 | 
			
		||||
		log_error("Couldn't read uuid for logical volume %s.",
 | 
			
		||||
			  lv->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
 | 
			
		||||
 | 
			
		||||
	if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
 | 
			
		||||
 | 
			
		||||
	/* Skip this for now for snapshots */
 | 
			
		||||
	if (!(lv->status & SNAPSHOT)) {
 | 
			
		||||
		lv->minor = -1;
 | 
			
		||||
		if ((lv->status & FIXED_MINOR) &&
 | 
			
		||||
		    !_read_int32(lvn, "minor", &lv->minor)) {
 | 
			
		||||
			log_error("Couldn't read minor number for logical "
 | 
			
		||||
				  "volume %s.", lv->name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		lv->major = -1;
 | 
			
		||||
		if ((lv->status & FIXED_MINOR) &&
 | 
			
		||||
		    !_read_int32(lvn, "major", &lv->major)) {
 | 
			
		||||
			log_error("Couldn't read major number for logical "
 | 
			
		||||
				  "volume %s.", lv->name);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		vg->lv_count--;
 | 
			
		||||
		list_del(&lvl->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read_sections(struct format_instance *fid,
 | 
			
		||||
			  const char *section, section_fn fn,
 | 
			
		||||
			  struct pool *mem,
 | 
			
		||||
			  struct volume_group *vg, struct config_node *vgn,
 | 
			
		||||
			  struct hash_table *pv_hash, int optional)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *n;
 | 
			
		||||
 | 
			
		||||
	if (!(n = find_config_node(vgn, section, '/'))) {
 | 
			
		||||
		if (!optional) {
 | 
			
		||||
			log_error("Couldn't find section '%s'.", section);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (n = n->child; n; n = n->sib) {
 | 
			
		||||
		if (!fn(fid, mem, vg, n, vgn, pv_hash)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct volume_group *_read_vg(struct format_instance *fid,
 | 
			
		||||
				     struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	struct config_node *vgn, *cn;
 | 
			
		||||
	struct volume_group *vg;
 | 
			
		||||
	struct hash_table *pv_hash = NULL;
 | 
			
		||||
	struct pool *mem = fid->fmt->cmd->mem;
 | 
			
		||||
 | 
			
		||||
	/* skip any top-level values */
 | 
			
		||||
	for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
 | 
			
		||||
 | 
			
		||||
	if (!vgn) {
 | 
			
		||||
		log_error("Couldn't find volume group in file.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	vg->cmd = fid->fmt->cmd;
 | 
			
		||||
 | 
			
		||||
	/* FIXME Determine format type from file contents */
 | 
			
		||||
	/* eg Set to instance of fmt1 here if reading a format1 backup? */
 | 
			
		||||
	vg->fid = fid;
 | 
			
		||||
 | 
			
		||||
	if (!(vg->name = pool_strdup(mem, vgn->key))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vgn = vgn->child;
 | 
			
		||||
 | 
			
		||||
	if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
 | 
			
		||||
		if (!cn->v->v.str) {
 | 
			
		||||
			log_error("system_id must be a string");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
		strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_id(&vg->id, vgn, "id")) {
 | 
			
		||||
		log_error("Couldn't read uuid for volume group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "seqno", &vg->seqno)) {
 | 
			
		||||
		log_error("Couldn't read 'seqno' for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = find_config_node(vgn, "status", '/'))) {
 | 
			
		||||
		log_error("Couldn't find status flags for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
 | 
			
		||||
		log_error("Couldn't read status flags for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
 | 
			
		||||
		log_error("Couldn't read extent size for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 'extent_count' and 'free_count' get filled in
 | 
			
		||||
	 * implicitly when reading in the pv's and lv's.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
 | 
			
		||||
		log_error("Couldn't read 'max_lv' for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
 | 
			
		||||
		log_error("Couldn't read 'max_pv' for volume group %s.",
 | 
			
		||||
			  vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The pv hash memoises the pv section names -> pv
 | 
			
		||||
	 * structures.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!(pv_hash = hash_create(32))) {
 | 
			
		||||
		log_error("Couldn't create hash table.");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&vg->pvs);
 | 
			
		||||
	if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
 | 
			
		||||
			    vgn, pv_hash, 0)) {
 | 
			
		||||
		log_error("Couldn't find all physical volumes for volume "
 | 
			
		||||
			  "group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&vg->lvs);
 | 
			
		||||
	list_init(&vg->snapshots);
 | 
			
		||||
 | 
			
		||||
	if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
 | 
			
		||||
			    vgn, pv_hash, 1)) {
 | 
			
		||||
		log_error("Couldn't read all logical volume names for volume "
 | 
			
		||||
			  "group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg,
 | 
			
		||||
			    vgn, pv_hash, 1)) {
 | 
			
		||||
		log_error("Couldn't read all logical volumes for "
 | 
			
		||||
			  "volume group %s.", vg->name);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hash_destroy(pv_hash);
 | 
			
		||||
 | 
			
		||||
	if (vg->status & PARTIAL_VG) {
 | 
			
		||||
		vg->status &= ~LVM_WRITE;
 | 
			
		||||
		vg->status |= LVM_READ;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Finished.
 | 
			
		||||
	 */
 | 
			
		||||
	return vg;
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	if (pv_hash)
 | 
			
		||||
		hash_destroy(pv_hash);
 | 
			
		||||
 | 
			
		||||
	pool_free(mem, vg);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _read_desc(struct pool *mem,
 | 
			
		||||
		       struct config_tree *cf, time_t *when, char **desc)
 | 
			
		||||
{
 | 
			
		||||
	const char *d;
 | 
			
		||||
	unsigned int u = 0u;
 | 
			
		||||
 | 
			
		||||
	log_suppress(1);
 | 
			
		||||
	d = find_config_str(cf->root, "description", '/', "");
 | 
			
		||||
	log_suppress(0);
 | 
			
		||||
	*desc = pool_strdup(mem, d);
 | 
			
		||||
 | 
			
		||||
	get_config_uint32(cf->root, "creation_time", '/', &u);
 | 
			
		||||
	*when = u;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct text_vg_version_ops _vsn1_ops = {
 | 
			
		||||
	check_version:_check_version,
 | 
			
		||||
	read_vg:_read_vg,
 | 
			
		||||
	read_desc:_read_desc
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct text_vg_version_ops *text_vg_vsn1_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return &_vsn1_ops;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										76
									
								
								lib/format_text/layout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								lib/format_text/layout.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_TEXT_LAYOUT_H
 | 
			
		||||
#define _LVM_TEXT_LAYOUT_H
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "lvm-types.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
 | 
			
		||||
/* On disk */
 | 
			
		||||
struct disk_locn {
 | 
			
		||||
	uint64_t offset;	/* Offset in bytes to start sector */
 | 
			
		||||
	uint64_t size;		/* Bytes */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* Data areas (holding PEs) */
 | 
			
		||||
struct data_area_list {
 | 
			
		||||
	struct list list;
 | 
			
		||||
	struct disk_locn disk_locn;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Fields with the suffix _xl should be xlate'd wherever they appear */
 | 
			
		||||
/* On disk */
 | 
			
		||||
struct pv_header {
 | 
			
		||||
	uint8_t pv_uuid[ID_LEN];
 | 
			
		||||
	uint64_t device_size_xl;	/* Bytes */
 | 
			
		||||
 | 
			
		||||
	/* NULL-terminated list of data areas followed by */
 | 
			
		||||
	/* NULL-terminated list of metadata area headers */
 | 
			
		||||
	struct disk_locn disk_areas_xl[0];	/* Two lists */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* On disk */
 | 
			
		||||
struct raw_locn {
 | 
			
		||||
	uint64_t offset;	/* Offset in bytes to start sector */
 | 
			
		||||
	uint64_t size;		/* Bytes */
 | 
			
		||||
	uint32_t checksum;
 | 
			
		||||
	uint32_t filler;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* On disk */
 | 
			
		||||
/* Structure size limited to one sector */
 | 
			
		||||
struct mda_header {
 | 
			
		||||
	uint32_t checksum_xl;	/* Checksum of rest of mda_header */
 | 
			
		||||
	uint8_t magic[16];	/* To aid scans for metadata */
 | 
			
		||||
	uint32_t version;
 | 
			
		||||
	uint64_t start;		/* Absolute start byte of mda_header */
 | 
			
		||||
	uint64_t size;		/* Size of metadata area */
 | 
			
		||||
 | 
			
		||||
	struct raw_locn raw_locns[0];	/* NULL-terminated list */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct mda_lists {
 | 
			
		||||
	struct list dirs;
 | 
			
		||||
	struct list raws;
 | 
			
		||||
	struct metadata_area_ops *file_ops;
 | 
			
		||||
	struct metadata_area_ops *raw_ops;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mda_context {
 | 
			
		||||
	struct device_area area;
 | 
			
		||||
	struct raw_locn rlocn;	/* Store inbetween write and commit */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* FIXME Convert this at runtime */
 | 
			
		||||
#define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
 | 
			
		||||
#define FMTT_VERSION 1
 | 
			
		||||
#define MDA_HEADER_SIZE 512
 | 
			
		||||
#define LVM2_LABEL "LVM2 001"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
# An example volume group
 | 
			
		||||
 | 
			
		||||
# YYYY-MM-DD HH:MM:SS
 | 
			
		||||
output_date = "2001-12-11 11:35:12"
 | 
			
		||||
 | 
			
		||||
sample_volume_group {
 | 
			
		||||
 | 
			
		||||
	id = "ksjdlfksjldskjlsk"
 | 
			
		||||
	status = ["ACTIVE"]
 | 
			
		||||
 | 
			
		||||
	extent_size = 8192	# 4 Megabytes
 | 
			
		||||
 | 
			
		||||
	max_lv = 99
 | 
			
		||||
        max_pv = 255
 | 
			
		||||
 | 
			
		||||
	physical_volumes {
 | 
			
		||||
 | 
			
		||||
		pv1 {
 | 
			
		||||
			id = "lksjdflksdlsk"
 | 
			
		||||
			device = "/dev/hda1"	# Hint only
 | 
			
		||||
 | 
			
		||||
			status = ["ALLOCATABLE"]
 | 
			
		||||
			pe_start = 8192
 | 
			
		||||
       		 	pe_count = 2048   	# 8 Gigabytes
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pv2 {
 | 
			
		||||
			id = "lksjdflksdlsk"
 | 
			
		||||
			device = "/dev/hda2"	# Hint only
 | 
			
		||||
 | 
			
		||||
			status = ["ALLOCATABLE"]
 | 
			
		||||
			pe_start = 8192
 | 
			
		||||
        		pe_count = 1024   	# 4 Gigabytes
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logical_volumes {
 | 
			
		||||
 | 
			
		||||
		music {
 | 
			
		||||
	        	status = ["ACTIVE"]
 | 
			
		||||
			read_ahead = 1024
 | 
			
		||||
 | 
			
		||||
			segment_count = 2
 | 
			
		||||
 | 
			
		||||
	        	segment1 {
 | 
			
		||||
				start_extent = 0
 | 
			
		||||
				extent_count = 1024	# 4 Gigabytes
 | 
			
		||||
				stripes = 1
 | 
			
		||||
		
 | 
			
		||||
				areas = [
 | 
			
		||||
					"pv1", 0
 | 
			
		||||
				]
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			segment2 {
 | 
			
		||||
				start_extent = 1024
 | 
			
		||||
				extent_count = 2048	# 8 Gigabytes
 | 
			
		||||
				stripes = 2
 | 
			
		||||
				stripe_size = 32	# 16 Kilobytes
 | 
			
		||||
 | 
			
		||||
				areas = [
 | 
			
		||||
					"pv1", 1024,
 | 
			
		||||
					"pv2", 0
 | 
			
		||||
				]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										280
									
								
								lib/format_text/text_label.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								lib/format_text/text_label.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "format-text.h"
 | 
			
		||||
#include "layout.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
 | 
			
		||||
{
 | 
			
		||||
	struct label_header *lh = (struct label_header *) buf;
 | 
			
		||||
 | 
			
		||||
	if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _write(struct label *label, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct label_header *lh = (struct label_header *) buf;
 | 
			
		||||
	struct pv_header *pvhdr;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
	struct disk_locn *pvh_dlocn_xl;
 | 
			
		||||
	struct list *mdash, *dash;
 | 
			
		||||
	struct metadata_area *mda;
 | 
			
		||||
	struct mda_context *mdac;
 | 
			
		||||
	struct data_area_list *da;
 | 
			
		||||
 | 
			
		||||
	/* FIXME Move to where label is created */
 | 
			
		||||
	strncpy(label->type, LVM2_LABEL, sizeof(label->type));
 | 
			
		||||
 | 
			
		||||
	strncpy(lh->type, label->type, sizeof(label->type));
 | 
			
		||||
 | 
			
		||||
	pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
 | 
			
		||||
	info = (struct lvmcache_info *) label->info;
 | 
			
		||||
	pvhdr->device_size_xl = xlate64(info->device_size);
 | 
			
		||||
	memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
 | 
			
		||||
 | 
			
		||||
	pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
 | 
			
		||||
 | 
			
		||||
	/* List of data areas (holding PEs) */
 | 
			
		||||
	list_iterate(dash, &info->das) {
 | 
			
		||||
		da = list_item(dash, struct data_area_list);
 | 
			
		||||
 | 
			
		||||
		pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
 | 
			
		||||
		pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
 | 
			
		||||
		pvh_dlocn_xl++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* NULL-termination */
 | 
			
		||||
	pvh_dlocn_xl->offset = xlate64(0);
 | 
			
		||||
	pvh_dlocn_xl->size = xlate64(0);
 | 
			
		||||
	pvh_dlocn_xl++;
 | 
			
		||||
 | 
			
		||||
	/* List of metadata area header locations */
 | 
			
		||||
	list_iterate(mdash, &info->mdas) {
 | 
			
		||||
		mda = list_item(mdash, struct metadata_area);
 | 
			
		||||
		mdac = (struct mda_context *) mda->metadata_locn;
 | 
			
		||||
 | 
			
		||||
		if (mdac->area.dev != info->dev)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		pvh_dlocn_xl->offset = xlate64(mdac->area.start);
 | 
			
		||||
		pvh_dlocn_xl->size = xlate64(mdac->area.size);
 | 
			
		||||
		pvh_dlocn_xl++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* NULL-termination */
 | 
			
		||||
	pvh_dlocn_xl->offset = xlate64(0);
 | 
			
		||||
	pvh_dlocn_xl->size = xlate64(0);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
 | 
			
		||||
	   uint64_t start, uint64_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct data_area_list *dal;
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		if (!(dal = dbg_malloc(sizeof(*dal)))) {
 | 
			
		||||
			log_error("struct data_area_list allocation failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(dal = pool_alloc(mem, sizeof(*dal)))) {
 | 
			
		||||
			log_error("struct data_area_list allocation failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dal->disk_locn.offset = start;
 | 
			
		||||
	dal->disk_locn.size = size;
 | 
			
		||||
 | 
			
		||||
	list_add(das, &dal->list);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void del_das(struct list *das)
 | 
			
		||||
{
 | 
			
		||||
	struct list *dah, *tmp;
 | 
			
		||||
	struct data_area_list *da;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(dah, tmp, das) {
 | 
			
		||||
		da = list_item(dah, struct data_area_list);
 | 
			
		||||
		list_del(&da->list);
 | 
			
		||||
		dbg_free(da);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
 | 
			
		||||
	    struct device *dev, uint64_t start, uint64_t size)
 | 
			
		||||
{
 | 
			
		||||
/* FIXME List size restricted by pv_header SECTOR_SIZE */
 | 
			
		||||
	struct metadata_area *mdal;
 | 
			
		||||
	struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
 | 
			
		||||
	struct mda_context *mdac;
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		if (!(mdal = dbg_malloc(sizeof(struct metadata_area)))) {
 | 
			
		||||
			log_error("struct mda_list allocation failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(mdac = dbg_malloc(sizeof(struct mda_context)))) {
 | 
			
		||||
			log_error("struct mda_context allocation failed");
 | 
			
		||||
			dbg_free(mdal);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(mdal = pool_alloc(mem, sizeof(struct metadata_area)))) {
 | 
			
		||||
			log_error("struct mda_list allocation failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(mdac = pool_alloc(mem, sizeof(struct mda_context)))) {
 | 
			
		||||
			log_error("struct mda_context allocation failed");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mdal->ops = mda_lists->raw_ops;
 | 
			
		||||
	mdal->metadata_locn = mdac;
 | 
			
		||||
 | 
			
		||||
	mdac->area.dev = dev;
 | 
			
		||||
	mdac->area.start = start;
 | 
			
		||||
	mdac->area.size = size;
 | 
			
		||||
	memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
 | 
			
		||||
 | 
			
		||||
	list_add(mdas, &mdal->list);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void del_mdas(struct list *mdas)
 | 
			
		||||
{
 | 
			
		||||
	struct list *mdah, *tmp;
 | 
			
		||||
	struct metadata_area *mda;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(mdah, tmp, mdas) {
 | 
			
		||||
		mda = list_item(mdah, struct metadata_area);
 | 
			
		||||
		dbg_free(mda->metadata_locn);
 | 
			
		||||
		list_del(&mda->list);
 | 
			
		||||
		dbg_free(mda);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _initialise_label(struct labeller *l, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	strncpy(label->type, LVM2_LABEL, sizeof(label->type));
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _read(struct labeller *l, struct device *dev, char *buf,
 | 
			
		||||
		 struct label **label)
 | 
			
		||||
{
 | 
			
		||||
	struct label_header *lh = (struct label_header *) buf;
 | 
			
		||||
	struct pv_header *pvhdr;
 | 
			
		||||
	struct lvmcache_info *info;
 | 
			
		||||
	struct disk_locn *dlocn_xl;
 | 
			
		||||
	uint64_t offset;
 | 
			
		||||
	struct list *mdah;
 | 
			
		||||
	struct metadata_area *mda;
 | 
			
		||||
	char vgnamebuf[NAME_LEN + 2];
 | 
			
		||||
	struct mda_context *mdac;
 | 
			
		||||
 | 
			
		||||
	pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
 | 
			
		||||
 | 
			
		||||
	if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
 | 
			
		||||
		return 0;
 | 
			
		||||
	*label = info->label;
 | 
			
		||||
 | 
			
		||||
	info->device_size = xlate64(pvhdr->device_size_xl);
 | 
			
		||||
 | 
			
		||||
	if (info->das.n)
 | 
			
		||||
		del_das(&info->das);
 | 
			
		||||
	list_init(&info->das);
 | 
			
		||||
 | 
			
		||||
	if (info->mdas.n)
 | 
			
		||||
		del_mdas(&info->mdas);
 | 
			
		||||
	list_init(&info->mdas);
 | 
			
		||||
 | 
			
		||||
	/* Data areas holding the PEs */
 | 
			
		||||
	dlocn_xl = pvhdr->disk_areas_xl;
 | 
			
		||||
	while ((offset = xlate64(dlocn_xl->offset))) {
 | 
			
		||||
		add_da(info->fmt, NULL, &info->das, offset,
 | 
			
		||||
		       xlate64(dlocn_xl->size));
 | 
			
		||||
		dlocn_xl++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Metadata area headers */
 | 
			
		||||
	dlocn_xl++;
 | 
			
		||||
	while ((offset = xlate64(dlocn_xl->offset))) {
 | 
			
		||||
		add_mda(info->fmt, NULL, &info->mdas, dev, offset,
 | 
			
		||||
			xlate64(dlocn_xl->size));
 | 
			
		||||
		dlocn_xl++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_iterate(mdah, &info->mdas) {
 | 
			
		||||
		mda = list_item(mdah, struct metadata_area);
 | 
			
		||||
		mdac = (struct mda_context *) mda->metadata_locn;
 | 
			
		||||
		if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
 | 
			
		||||
				    sizeof(vgnamebuf))) {
 | 
			
		||||
			lvmcache_update_vgname(info, vgnamebuf);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->status &= ~CACHE_INVALID;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy_label(struct labeller *l, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_info *info = (struct lvmcache_info *) label->info;
 | 
			
		||||
 | 
			
		||||
	if (info->mdas.n)
 | 
			
		||||
		del_mdas(&info->mdas);
 | 
			
		||||
	if (info->das.n)
 | 
			
		||||
		del_das(&info->das);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct labeller *l)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct label_ops _text_ops = {
 | 
			
		||||
	can_handle:_can_handle,
 | 
			
		||||
	write:_write,
 | 
			
		||||
	read:_read,
 | 
			
		||||
	verify:_can_handle,
 | 
			
		||||
	initialise_label:_initialise_label,
 | 
			
		||||
	destroy_label:_destroy_label,
 | 
			
		||||
	destroy:_destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct labeller *text_labeller_create(const struct format_type *fmt)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
 | 
			
		||||
	if (!(l = dbg_malloc(sizeof(*l)))) {
 | 
			
		||||
		log_err("Couldn't allocate labeller object.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l->ops = &_text_ops;
 | 
			
		||||
	l->private = (const void *) fmt;
 | 
			
		||||
 | 
			
		||||
	return l;
 | 
			
		||||
}
 | 
			
		||||
@@ -4,10 +4,18 @@
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "crc.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
/* FIXME Allow for larger labels?  Restricted to single sector currently */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Internal labeller struct.
 | 
			
		||||
@@ -21,7 +29,6 @@ struct labeller_i {
 | 
			
		||||
 | 
			
		||||
static struct list _labellers;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller_i *li;
 | 
			
		||||
@@ -45,7 +52,6 @@ static void _free_li(struct labeller_i *li)
 | 
			
		||||
	dbg_free(li);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int label_init(void)
 | 
			
		||||
{
 | 
			
		||||
	list_init(&_labellers);
 | 
			
		||||
@@ -60,6 +66,7 @@ void label_exit(void)
 | 
			
		||||
	for (c = _labellers.n; c != &_labellers; c = n) {
 | 
			
		||||
		n = c->n;
 | 
			
		||||
		li = list_item(c, struct labeller_i);
 | 
			
		||||
		li->l->ops->destroy(li->l);
 | 
			
		||||
		_free_li(li);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -82,7 +89,7 @@ struct labeller *label_get_handler(const char *name)
 | 
			
		||||
	struct list *lih;
 | 
			
		||||
	struct labeller_i *li;
 | 
			
		||||
 | 
			
		||||
	list_iterate (lih, &_labellers) {
 | 
			
		||||
	list_iterate(lih, &_labellers) {
 | 
			
		||||
		li = list_item(lih, struct labeller_i);
 | 
			
		||||
		if (!strcmp(li->name, name))
 | 
			
		||||
			return li->l;
 | 
			
		||||
@@ -91,64 +98,257 @@ struct labeller *label_get_handler(const char *name)
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct labeller *_find_labeller(struct device *dev)
 | 
			
		||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
 | 
			
		||||
				       uint64_t *label_sector)
 | 
			
		||||
{
 | 
			
		||||
	struct list *lih;
 | 
			
		||||
	struct labeller_i *li;
 | 
			
		||||
	struct labeller *r = NULL;
 | 
			
		||||
	struct label_header *lh;
 | 
			
		||||
	uint64_t sector;
 | 
			
		||||
	int found = 0;
 | 
			
		||||
	char readbuf[LABEL_SCAN_SIZE];
 | 
			
		||||
 | 
			
		||||
	list_iterate (lih, &_labellers) {
 | 
			
		||||
		li = list_item(lih, struct labeller_i);
 | 
			
		||||
		if (li->l->ops->can_handle(li->l, dev))
 | 
			
		||||
			return li->l;
 | 
			
		||||
	if (!dev_open(dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("No label on device '%s'.", dev_name(dev));
 | 
			
		||||
	return NULL;
 | 
			
		||||
	if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
 | 
			
		||||
		log_debug("%s: Failed to read label area", dev_name(dev));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Scan first few sectors for a valid label */
 | 
			
		||||
	for (sector = 0; sector < LABEL_SCAN_SECTORS;
 | 
			
		||||
	     sector += LABEL_SIZE >> SECTOR_SHIFT) {
 | 
			
		||||
		lh = (struct label_header *) (readbuf +
 | 
			
		||||
					      (sector << SECTOR_SHIFT));
 | 
			
		||||
 | 
			
		||||
		if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
 | 
			
		||||
			if (found) {
 | 
			
		||||
				log_error("Ignoring additional label on %s at "
 | 
			
		||||
					  "sector %" PRIu64, dev_name(dev),
 | 
			
		||||
					  sector);
 | 
			
		||||
			}
 | 
			
		||||
			if (xlate64(lh->sector_xl) != sector) {
 | 
			
		||||
				log_info("%s: Label for sector %" PRIu64
 | 
			
		||||
					 " found at sector %" PRIu64
 | 
			
		||||
					 " - ignoring", dev_name(dev),
 | 
			
		||||
					 xlate64(lh->sector_xl), sector);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
 | 
			
		||||
				     ((void *) &lh->offset_xl - (void *) lh)) !=
 | 
			
		||||
			    xlate32(lh->crc_xl)) {
 | 
			
		||||
				log_info("Label checksum incorrect on %s - "
 | 
			
		||||
					 "ignoring", dev_name(dev));
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (found)
 | 
			
		||||
				continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		list_iterate(lih, &_labellers) {
 | 
			
		||||
			li = list_item(lih, struct labeller_i);
 | 
			
		||||
			if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
 | 
			
		||||
				log_very_verbose("%s: %s label detected",
 | 
			
		||||
						 dev_name(dev), li->name);
 | 
			
		||||
				if (found) {
 | 
			
		||||
					log_error("Ignoring additional label "
 | 
			
		||||
						  "on %s at sector %" PRIu64,
 | 
			
		||||
						  dev_name(dev), sector);
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				r = li->l;
 | 
			
		||||
				memcpy(buf, lh, LABEL_SIZE);
 | 
			
		||||
				if (label_sector)
 | 
			
		||||
					*label_sector = sector;
 | 
			
		||||
				found = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!found)
 | 
			
		||||
		log_very_verbose("%s: No label detected", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	if (!dev_close(dev))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME Also wipe associated metadata area headers? */
 | 
			
		||||
int label_remove(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
	char buf[LABEL_SIZE];
 | 
			
		||||
	char readbuf[LABEL_SCAN_SIZE];
 | 
			
		||||
	int r = 1;
 | 
			
		||||
	uint64_t sector;
 | 
			
		||||
	int wipe;
 | 
			
		||||
	struct list *lih;
 | 
			
		||||
	struct labeller_i *li;
 | 
			
		||||
	struct label_header *lh;
 | 
			
		||||
 | 
			
		||||
	if (!(l = _find_labeller(dev))) {
 | 
			
		||||
	memset(buf, 0, LABEL_SIZE);
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
 | 
			
		||||
 | 
			
		||||
	if (!dev_open(dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return l->ops->remove(l, dev);
 | 
			
		||||
}
 | 
			
		||||
	/*
 | 
			
		||||
	 * We flush the device just in case someone is stupid
 | 
			
		||||
	 * enough to be trying to import an open pv into lvm.
 | 
			
		||||
	 */
 | 
			
		||||
	dev_flush(dev);
 | 
			
		||||
 | 
			
		||||
int label_read(struct device *dev, struct label **result)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct list *lih;
 | 
			
		||||
	struct labeller_i *li;
 | 
			
		||||
	if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
 | 
			
		||||
		log_debug("%s: Failed to read label area", dev_name(dev));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_iterate (lih, &_labellers) {
 | 
			
		||||
		li = list_item(lih, struct labeller_i);
 | 
			
		||||
		if ((r = li->l->ops->read(li->l, dev, result))) {
 | 
			
		||||
			(*result)->labeller = li->l;
 | 
			
		||||
			return r;
 | 
			
		||||
	/* Scan first few sectors for anything looking like a label */
 | 
			
		||||
	for (sector = 0; sector < LABEL_SCAN_SECTORS;
 | 
			
		||||
	     sector += LABEL_SIZE >> SECTOR_SHIFT) {
 | 
			
		||||
		lh = (struct label_header *) (readbuf +
 | 
			
		||||
					      (sector << SECTOR_SHIFT));
 | 
			
		||||
 | 
			
		||||
		wipe = 0;
 | 
			
		||||
 | 
			
		||||
		if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
 | 
			
		||||
			if (xlate64(lh->sector_xl) == sector)
 | 
			
		||||
				wipe = 1;
 | 
			
		||||
		} else {
 | 
			
		||||
			list_iterate(lih, &_labellers) {
 | 
			
		||||
				li = list_item(lih, struct labeller_i);
 | 
			
		||||
				if (li->l->ops->can_handle(li->l, (char *) lh,
 | 
			
		||||
							   sector)) {
 | 
			
		||||
					wipe = 1;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (wipe) {
 | 
			
		||||
			log_info("%s: Wiping label at sector %" PRIu64,
 | 
			
		||||
				 dev_name(dev), sector);
 | 
			
		||||
			if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
 | 
			
		||||
				       buf)) {
 | 
			
		||||
				log_error("Failed to remove label from %s at "
 | 
			
		||||
					  "sector %" PRIu64, dev_name(dev),
 | 
			
		||||
					  sector);
 | 
			
		||||
				r = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("No label on device '%s'.", dev_name(dev));
 | 
			
		||||
	return 0;
 | 
			
		||||
      out:
 | 
			
		||||
	if (!dev_close(dev))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME Avoid repeated re-reading if cache lock held */
 | 
			
		||||
int label_read(struct device *dev, struct label **result)
 | 
			
		||||
{
 | 
			
		||||
	char buf[LABEL_SIZE];
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
	uint64_t sector;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!(l = _find_labeller(dev, buf, §or))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
 | 
			
		||||
		(*result)->sector = sector;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Caller may need to use label_get_handler to create label struct! */
 | 
			
		||||
int label_write(struct device *dev, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	char buf[LABEL_SIZE];
 | 
			
		||||
	struct label_header *lh = (struct label_header *) buf;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
 | 
			
		||||
		log_error("Label sector %" PRIu64 " beyond range (%ld)",
 | 
			
		||||
			  label->sector, LABEL_SCAN_SECTORS);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(buf, 0, LABEL_SIZE);
 | 
			
		||||
 | 
			
		||||
	strncpy(lh->id, LABEL_ID, sizeof(lh->id));
 | 
			
		||||
	lh->sector_xl = xlate64(label->sector);
 | 
			
		||||
	lh->offset_xl = xlate32(sizeof(*lh));
 | 
			
		||||
 | 
			
		||||
	if (!label->labeller->ops->write(label, buf))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
 | 
			
		||||
				      ((void *) &lh->offset_xl - (void *) lh)));
 | 
			
		||||
 | 
			
		||||
	if (!dev_open(dev)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_info("%s: Writing label to sector %" PRIu64, dev_name(dev),
 | 
			
		||||
		 label->sector);
 | 
			
		||||
	if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
 | 
			
		||||
		log_debug("Failed to write label to %s", dev_name(dev));
 | 
			
		||||
		r = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dev_close(dev))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int label_verify(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct labeller *l;
 | 
			
		||||
	char buf[LABEL_SIZE];
 | 
			
		||||
	uint64_t sector;
 | 
			
		||||
 | 
			
		||||
	if (!(l = _find_labeller(dev))) {
 | 
			
		||||
	if (!(l = _find_labeller(dev, buf, §or))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return l->ops->verify(l, dev);
 | 
			
		||||
	return l->ops->verify(l, buf, sector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void label_destroy(struct label *lab)
 | 
			
		||||
void label_destroy(struct label *label)
 | 
			
		||||
{
 | 
			
		||||
	lab->labeller->ops->destroy_label(lab->labeller, lab);
 | 
			
		||||
	label->labeller->ops->destroy_label(label->labeller, label);
 | 
			
		||||
	dbg_free(label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct label *label_create(struct labeller *labeller)
 | 
			
		||||
{
 | 
			
		||||
	struct label *label;
 | 
			
		||||
 | 
			
		||||
	if (!(label = dbg_malloc(sizeof(*label)))) {
 | 
			
		||||
		log_error("label allocaction failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(label, 0, sizeof(*label));
 | 
			
		||||
 | 
			
		||||
	label->labeller = labeller;
 | 
			
		||||
 | 
			
		||||
	labeller->ops->initialise_label(labeller, label);
 | 
			
		||||
 | 
			
		||||
	return label;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,18 +7,30 @@
 | 
			
		||||
#ifndef _LVM_LABEL_H
 | 
			
		||||
#define _LVM_LABEL_H
 | 
			
		||||
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
 | 
			
		||||
#define LABEL_ID "LABELONE"
 | 
			
		||||
#define LABEL_SIZE SECTOR_SIZE	/* Think very carefully before changing this */
 | 
			
		||||
#define LABEL_SCAN_SECTORS 4L
 | 
			
		||||
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
 | 
			
		||||
 | 
			
		||||
/* On disk - 32 bytes */
 | 
			
		||||
struct label_header {
 | 
			
		||||
	uint8_t id[8];		/* LABELONE */
 | 
			
		||||
	uint64_t sector_xl;	/* Sector number of this label */
 | 
			
		||||
	uint32_t crc_xl;	/* From next field to end of sector */
 | 
			
		||||
	uint32_t offset_xl;	/* Offset from start of struct to contents */
 | 
			
		||||
	uint8_t type[8];	/* LVM2 001 */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* In core */
 | 
			
		||||
struct label {
 | 
			
		||||
	struct id id;
 | 
			
		||||
 | 
			
		||||
	char volume_type[32];
 | 
			
		||||
	uint32_t version[3];
 | 
			
		||||
 | 
			
		||||
	void *extra_info;
 | 
			
		||||
 | 
			
		||||
	char type[8];
 | 
			
		||||
	uint64_t sector;
 | 
			
		||||
	struct labeller *labeller;
 | 
			
		||||
	void *info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct labeller;
 | 
			
		||||
@@ -27,47 +39,45 @@ struct label_ops {
 | 
			
		||||
	/*
 | 
			
		||||
	 * Is the device labelled with this format ?
 | 
			
		||||
	 */
 | 
			
		||||
	int (*can_handle)(struct labeller *l, struct device *dev);
 | 
			
		||||
	int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Write a label to a volume.
 | 
			
		||||
	 */
 | 
			
		||||
	int (*write)(struct labeller *l,
 | 
			
		||||
		     struct device *dev, struct label *label);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Remove a label from a device.
 | 
			
		||||
	 */
 | 
			
		||||
	int (*remove)(struct labeller *l, struct device *dev);
 | 
			
		||||
	int (*write) (struct label * label, char *buf);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Read a label from a volume.
 | 
			
		||||
	 */
 | 
			
		||||
	int (*read)(struct labeller *l,
 | 
			
		||||
		    struct device *dev, struct label **label);
 | 
			
		||||
	int (*read) (struct labeller * l, struct device * dev,
 | 
			
		||||
		     char *buf, struct label ** label);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Additional consistency checks for the paranoid.
 | 
			
		||||
	 */
 | 
			
		||||
	int (*verify)(struct labeller *l, struct device *dev);
 | 
			
		||||
	int (*verify) (struct labeller * l, char *buf, uint64_t sector);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Populate label_type etc.
 | 
			
		||||
	 */
 | 
			
		||||
	int (*initialise_label) (struct labeller * l, struct label * label);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Destroy a previously read label.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*destroy_label)(struct labeller *l, struct label *label);
 | 
			
		||||
	void (*destroy_label) (struct labeller * l, struct label * label);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Destructor.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*destroy)(struct labeller *l);
 | 
			
		||||
	void (*destroy) (struct labeller * l);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct labeller {
 | 
			
		||||
	struct label_ops *ops;
 | 
			
		||||
	void *private;
 | 
			
		||||
	const void *private;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int label_init(void);
 | 
			
		||||
void label_exit(void);
 | 
			
		||||
 | 
			
		||||
@@ -77,14 +87,9 @@ struct labeller *label_get_handler(const char *name);
 | 
			
		||||
 | 
			
		||||
int label_remove(struct device *dev);
 | 
			
		||||
int label_read(struct device *dev, struct label **result);
 | 
			
		||||
int label_write(struct device *dev, struct label *label);
 | 
			
		||||
int label_verify(struct device *dev);
 | 
			
		||||
void label_destroy(struct label *lab);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We'll support two label types: the 'pretend the
 | 
			
		||||
 * LVM1 pv structure at the begining of the disk
 | 
			
		||||
 * is a label' hack, and pjc's 1 sector labels at
 | 
			
		||||
 * the front and back of the device.
 | 
			
		||||
 */
 | 
			
		||||
struct label *label_create(struct labeller *labeller);
 | 
			
		||||
void label_destroy(struct label *label);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,561 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2002 Sistina Software
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "device.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "pool.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "lvm2_label.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
/* Label Magic is "LnXl" - error: imagination failure */
 | 
			
		||||
#define LABEL_MAGIC 0x6c586e4c
 | 
			
		||||
 | 
			
		||||
/* Size of blocks that dev_get_size() returns the number of */
 | 
			
		||||
#define BLOCK_SIZE 512
 | 
			
		||||
 | 
			
		||||
/* This is just the "struct lvm2_label" with the data pointer removed */
 | 
			
		||||
struct label_ondisk
 | 
			
		||||
{
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t crc;
 | 
			
		||||
    uint64_t label1_loc;
 | 
			
		||||
    uint64_t label2_loc;
 | 
			
		||||
    uint16_t datalen;
 | 
			
		||||
    uint16_t pad;
 | 
			
		||||
 | 
			
		||||
    uint32_t version[3];
 | 
			
		||||
    char     disk_type[32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct filter_private
 | 
			
		||||
{
 | 
			
		||||
    void *mem;
 | 
			
		||||
    char disk_type[32];
 | 
			
		||||
    uint32_t version[3];
 | 
			
		||||
    int version_match;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Calculate CRC32 of a buffer */
 | 
			
		||||
static uint32_t crc32(uint32_t initial, const unsigned char *databuf, size_t datalen)
 | 
			
		||||
{
 | 
			
		||||
    static const u_int crctab[] = {
 | 
			
		||||
        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
 | 
			
		||||
        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
 | 
			
		||||
        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
 | 
			
		||||
        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
 | 
			
		||||
    };
 | 
			
		||||
    uint32_t idx, crc = initial;
 | 
			
		||||
 | 
			
		||||
    for (idx = 0; idx < datalen; idx++) {
 | 
			
		||||
        crc ^= *databuf++;
 | 
			
		||||
        crc = (crc >> 4) ^ crctab[crc & 0xf];
 | 
			
		||||
        crc = (crc >> 4) ^ crctab[crc & 0xf];
 | 
			
		||||
    }
 | 
			
		||||
    return crc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Calculate crc */
 | 
			
		||||
static uint32_t calc_crc(struct label_ondisk *label, char *data)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t crcval = 0xffffffff;
 | 
			
		||||
 | 
			
		||||
    crcval = crc32(crcval, (char *)&label->magic, sizeof(label->magic));
 | 
			
		||||
    crcval = crc32(crcval, (char *)&label->label1_loc, sizeof(label->label1_loc));
 | 
			
		||||
    crcval = crc32(crcval, (char *)&label->label2_loc, sizeof(label->label2_loc));
 | 
			
		||||
    crcval = crc32(crcval, (char *)&label->datalen, sizeof(label->datalen));
 | 
			
		||||
    crcval = crc32(crcval, (char *)&label->version, sizeof(label->version));
 | 
			
		||||
    crcval = crc32(crcval, (char *)label->disk_type, strlen(label->disk_type));
 | 
			
		||||
    crcval = crc32(crcval, (char *)data, label->datalen);
 | 
			
		||||
 | 
			
		||||
    return crcval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Calculate the locations we should find the labels in */
 | 
			
		||||
static inline void get_label_locations(uint64_t size, uint32_t sectsize, long *first, long *second)
 | 
			
		||||
{
 | 
			
		||||
    *first  = sectsize;
 | 
			
		||||
    *second = size*BLOCK_SIZE - sectsize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read a label off disk */
 | 
			
		||||
static int lvm2_label_read(struct labeller *l, struct device *dev, struct label **label)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint32_t sectsize;
 | 
			
		||||
    char     *block;
 | 
			
		||||
    struct   label_ondisk *ondisk;
 | 
			
		||||
    int      status;
 | 
			
		||||
    int      iter;
 | 
			
		||||
    long     offset[2];
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_size(dev, &size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_sectsize(dev, §size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_open(dev, O_RDONLY))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    block = dbg_malloc(sectsize);
 | 
			
		||||
    if (!block)
 | 
			
		||||
    {
 | 
			
		||||
	stack;
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
    ondisk = (struct label_ondisk *)block;
 | 
			
		||||
    get_label_locations(size, sectsize, &offset[0], &offset[1]);
 | 
			
		||||
 | 
			
		||||
    /* If the first label is bad then use the second */
 | 
			
		||||
    for (iter = 0; iter <= 1; iter++)
 | 
			
		||||
    {
 | 
			
		||||
	status = dev_read(dev, offset[iter], sectsize, block);
 | 
			
		||||
	if (status)
 | 
			
		||||
	{
 | 
			
		||||
	    struct label *incore;
 | 
			
		||||
	    int i;
 | 
			
		||||
	    int found_nul;
 | 
			
		||||
 | 
			
		||||
	    /* If the MAGIC doesn't match there's no point in
 | 
			
		||||
	       carrying on */
 | 
			
		||||
	    if (xlate32(ondisk->magic) != LABEL_MAGIC)
 | 
			
		||||
		continue;
 | 
			
		||||
 | 
			
		||||
	    /* Look for a NUL in the disk_type string so we don't
 | 
			
		||||
	       SEGV is something has gone horribly wrong */
 | 
			
		||||
	    found_nul = 0;
 | 
			
		||||
	    for (i=0; i<sizeof(ondisk->disk_type); i++)
 | 
			
		||||
		if (ondisk->disk_type[i] == '\0')
 | 
			
		||||
		    found_nul = 1;
 | 
			
		||||
 | 
			
		||||
	    if (!found_nul)
 | 
			
		||||
		continue;
 | 
			
		||||
 | 
			
		||||
	    incore = dbg_malloc(sizeof(struct label));
 | 
			
		||||
	    if (incore == NULL)
 | 
			
		||||
	    {
 | 
			
		||||
		return 0;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
            /* Copy and convert endianness */
 | 
			
		||||
	    strncpy(incore->volume_type, ondisk->disk_type, sizeof(incore->volume_type));
 | 
			
		||||
	    incore->version[0] = xlate32(ondisk->version[0]);
 | 
			
		||||
	    incore->version[1] = xlate32(ondisk->version[1]);
 | 
			
		||||
	    incore->version[2] = xlate32(ondisk->version[2]);
 | 
			
		||||
	    incore->extra_len  = xlate16(ondisk->datalen);
 | 
			
		||||
	    incore->extra_info = block + sizeof(struct label_ondisk);
 | 
			
		||||
 | 
			
		||||
	    /* Make sure datalen is a sensible size too */
 | 
			
		||||
	    if (incore->extra_len > sectsize)
 | 
			
		||||
		continue;
 | 
			
		||||
 | 
			
		||||
	    /* Check Crc */
 | 
			
		||||
	    if (xlate32(ondisk->crc) != calc_crc(ondisk, incore->extra_info))
 | 
			
		||||
	    {
 | 
			
		||||
		log_error("Crc %d on device %s does not match. got %x, expected %x",
 | 
			
		||||
			  iter, dev_name(dev), xlate32(ondisk->crc), calc_crc(ondisk, incore->extra_info));
 | 
			
		||||
		continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    /* Check label locations match our view of the device */
 | 
			
		||||
	    if (xlate64(ondisk->label1_loc) != offset[0])
 | 
			
		||||
		log_error("Label 1 location is wrong in label %d - check block size of the device\n",
 | 
			
		||||
			  iter);
 | 
			
		||||
	    if (xlate64(ondisk->label2_loc) != offset[1])
 | 
			
		||||
		log_error("Label 2 location is wrong in label %d - the size of the device must have changed\n",
 | 
			
		||||
			  iter);
 | 
			
		||||
 | 
			
		||||
	    /* Copy to user's data area */
 | 
			
		||||
	    *label = incore;
 | 
			
		||||
	    incore->extra_info = dbg_malloc(incore->extra_len);
 | 
			
		||||
	    if (!incore->extra_info)
 | 
			
		||||
	    {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	    }
 | 
			
		||||
	    memcpy(incore->extra_info, block + sizeof(struct label_ondisk), incore->extra_len);
 | 
			
		||||
 | 
			
		||||
	    dbg_free(block);
 | 
			
		||||
	    dev_close(dev);
 | 
			
		||||
	    return 1;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dbg_free(block);
 | 
			
		||||
    dev_close(dev);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write a label to a device */
 | 
			
		||||
static int lvm2_label_write(struct labeller *l, struct device *dev, struct label *label)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint32_t sectsize;
 | 
			
		||||
    char     *block;
 | 
			
		||||
    struct label_ondisk *ondisk;
 | 
			
		||||
    int       status1, status2;
 | 
			
		||||
    long      offset[2];
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_size(dev, &size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_sectsize(dev, §size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    /* Can the metata fit in the remaining space ? */
 | 
			
		||||
    if (label->extra_len > sectsize - sizeof(struct label_ondisk))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
 | 
			
		||||
    if (!block)
 | 
			
		||||
    {
 | 
			
		||||
	stack;
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
    ondisk = (struct label_ondisk *)block;
 | 
			
		||||
 | 
			
		||||
    get_label_locations(size, sectsize, &offset[0], &offset[1]);
 | 
			
		||||
 | 
			
		||||
    /* Make into ondisk format */
 | 
			
		||||
    ondisk->magic = xlate32(LABEL_MAGIC);
 | 
			
		||||
    ondisk->version[0] = xlate32(label->version[0]);
 | 
			
		||||
    ondisk->version[1] = xlate32(label->version[1]);
 | 
			
		||||
    ondisk->version[2] = xlate32(label->version[2]);
 | 
			
		||||
    ondisk->label1_loc = xlate64(offset[0]);
 | 
			
		||||
    ondisk->label2_loc = xlate64(offset[1]);
 | 
			
		||||
    ondisk->datalen = xlate16(label->extra_len);
 | 
			
		||||
    strncpy(ondisk->disk_type, label->volume_type, sizeof(ondisk->disk_type));
 | 
			
		||||
    memcpy(block+sizeof(struct label_ondisk), label->extra_info, label->extra_len);
 | 
			
		||||
    ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
 | 
			
		||||
 | 
			
		||||
    /* Write metadata to disk */
 | 
			
		||||
    if (!dev_open(dev, O_RDWR))
 | 
			
		||||
    {
 | 
			
		||||
	dbg_free(block);
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    status1 = dev_write(dev, offset[0], sizeof(struct label_ondisk) + label->extra_len, block);
 | 
			
		||||
    if (!status1)
 | 
			
		||||
	log_error("Error writing label 1\n");
 | 
			
		||||
 | 
			
		||||
    /* Write another at the end of the device */
 | 
			
		||||
    status2 = dev_write(dev, offset[1], sizeof(struct label_ondisk) + label->extra_len, block);
 | 
			
		||||
    if (!status2)
 | 
			
		||||
    {
 | 
			
		||||
	char zerobuf[sizeof(struct label_ondisk)];
 | 
			
		||||
	log_error("Error writing label 2\n");
 | 
			
		||||
 | 
			
		||||
	/* Wipe the first label so it doesn't get confusing */
 | 
			
		||||
	memset(zerobuf, 0, sizeof(struct label_ondisk));
 | 
			
		||||
	if (!dev_write(dev, offset[0], sizeof(struct label_ondisk), zerobuf))
 | 
			
		||||
	    log_error("Error erasing label 1\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dbg_free(block);
 | 
			
		||||
    dev_close(dev);
 | 
			
		||||
 | 
			
		||||
    return ((status1 != 0) && (status2 != 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Return 1 for Yes, 0 for No */
 | 
			
		||||
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
    struct label *label;
 | 
			
		||||
    int status;
 | 
			
		||||
 | 
			
		||||
    status = lvm2_label_read(l, dev, &label);
 | 
			
		||||
    if (status) label_free(label);
 | 
			
		||||
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check the device is labelled and has the right format_type */
 | 
			
		||||
static int _accept_format(struct dev_filter *f, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
    struct label *l;
 | 
			
		||||
    int status;
 | 
			
		||||
    struct filter_private *fp = (struct filter_private *) f->private;
 | 
			
		||||
 | 
			
		||||
    status = lvm2_label_read(NULL, dev, &l);
 | 
			
		||||
 | 
			
		||||
    if (status)
 | 
			
		||||
    {
 | 
			
		||||
	if (strcmp(l->volume_type, fp->disk_type) == 0)
 | 
			
		||||
	{
 | 
			
		||||
	    switch (fp->version_match)
 | 
			
		||||
	    {
 | 
			
		||||
	    case VERSION_MATCH_EQUAL:
 | 
			
		||||
		if (l->version[0] == fp->version[0] &&
 | 
			
		||||
		    l->version[1] == fp->version[1] &&
 | 
			
		||||
		    l->version[2] == fp->version[2])
 | 
			
		||||
		    return 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case VERSION_MATCH_LESSTHAN:
 | 
			
		||||
		if (l->version[0] == fp->version[0] &&
 | 
			
		||||
		    l->version[1] <  fp->version[1])
 | 
			
		||||
		    return 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case VERSION_MATCH_LESSEQUAL:
 | 
			
		||||
		if (l->version[0] == fp->version[0] &&
 | 
			
		||||
		    l->version[1] <= fp->version[1])
 | 
			
		||||
		    return 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case VERSION_MATCH_ANY:
 | 
			
		||||
		return 1;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	label_free(l);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We just want to know if it's labelled or not */
 | 
			
		||||
static int _accept_label(struct dev_filter *f, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
    return lvm2_is_labelled(NULL, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _destroy(struct dev_filter *f)
 | 
			
		||||
{
 | 
			
		||||
    struct filter_private *fp = (struct filter_private *) f->private;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* A filter to find devices with a particular label type on them */
 | 
			
		||||
struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type)
 | 
			
		||||
{
 | 
			
		||||
        struct pool *mem;
 | 
			
		||||
	struct filter_private *fp;
 | 
			
		||||
	struct dev_filter *f;
 | 
			
		||||
 | 
			
		||||
	/* Validate the match type */
 | 
			
		||||
	if (match_type != VERSION_MATCH_EQUAL &&
 | 
			
		||||
	    match_type != VERSION_MATCH_LESSTHAN &&
 | 
			
		||||
	    match_type != VERSION_MATCH_LESSEQUAL &&
 | 
			
		||||
	    match_type != VERSION_MATCH_ANY)
 | 
			
		||||
	    return 0;
 | 
			
		||||
 | 
			
		||||
	mem = pool_create(10 * 1024);
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(f = pool_zalloc(mem, sizeof(*f)))) {
 | 
			
		||||
	    stack;
 | 
			
		||||
	    goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
 | 
			
		||||
	    stack;
 | 
			
		||||
	    goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fp->mem = mem;
 | 
			
		||||
	strcpy(fp->disk_type, disk_type);
 | 
			
		||||
	fp->version[0] = version[0];
 | 
			
		||||
	fp->version[1] = version[1];
 | 
			
		||||
	fp->version[2] = version[2];
 | 
			
		||||
	fp->version_match = match_type;
 | 
			
		||||
	f->passes_filter = _accept_format;
 | 
			
		||||
	f->destroy = _destroy;
 | 
			
		||||
	f->private = fp;
 | 
			
		||||
 | 
			
		||||
	return f;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* A filter to find devices with any label on them */
 | 
			
		||||
struct dev_filter *lvm2_label_filter_create()
 | 
			
		||||
{
 | 
			
		||||
	struct pool *mem = pool_create(10 * 1024);
 | 
			
		||||
	struct filter_private *fp;
 | 
			
		||||
	struct dev_filter *f;
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(f = pool_zalloc(mem, sizeof(*f)))) {
 | 
			
		||||
	    stack;
 | 
			
		||||
	    goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
 | 
			
		||||
	    stack;
 | 
			
		||||
	    goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fp->mem = mem;
 | 
			
		||||
	f->passes_filter = _accept_label;
 | 
			
		||||
	f->destroy = _destroy;
 | 
			
		||||
	f->private = fp;
 | 
			
		||||
 | 
			
		||||
	return f;
 | 
			
		||||
 | 
			
		||||
 bad:
 | 
			
		||||
	pool_destroy(mem);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return 1 if both labels are identical, 0 if not or there was an error */
 | 
			
		||||
static int lvm2_labels_match(struct labeller *l, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint32_t sectsize;
 | 
			
		||||
    char     *block1;
 | 
			
		||||
    char     *block2;
 | 
			
		||||
    struct   label_ondisk *ondisk1;
 | 
			
		||||
    struct   label_ondisk *ondisk2;
 | 
			
		||||
    int      status = 0;
 | 
			
		||||
    long     offset[2];
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_size(dev, &size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_sectsize(dev, §size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
/* Allocate some space for the blocks we are going to read in */
 | 
			
		||||
    block1 = dbg_malloc(sectsize);
 | 
			
		||||
    if (!block1)
 | 
			
		||||
    {
 | 
			
		||||
	stack;
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block2 = dbg_malloc(sectsize);
 | 
			
		||||
    if (!block2)
 | 
			
		||||
    {
 | 
			
		||||
	stack;
 | 
			
		||||
	dbg_free(block1);
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
    ondisk1 = (struct label_ondisk *)block1;
 | 
			
		||||
    ondisk2 = (struct label_ondisk *)block2;
 | 
			
		||||
 | 
			
		||||
    get_label_locations(size, sectsize, &offset[0], &offset[1]);
 | 
			
		||||
 | 
			
		||||
    /* Fetch em */
 | 
			
		||||
    if (!dev_open(dev, O_RDONLY))
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    if (!dev_read(dev, offset[0], sectsize, block1))
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    if (!dev_read(dev, offset[1], sectsize, block2))
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    dev_close(dev);
 | 
			
		||||
 | 
			
		||||
    /* Is it labelled? */
 | 
			
		||||
    if (xlate32(ondisk1->magic) != LABEL_MAGIC)
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    /* Compare the whole structs */
 | 
			
		||||
    if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    /* OK, check the data area */
 | 
			
		||||
    if (memcmp(block1 + sizeof(struct label_ondisk),
 | 
			
		||||
	       block2 + sizeof(struct label_ondisk),
 | 
			
		||||
	       xlate16(ondisk1->datalen)) != 0)
 | 
			
		||||
	goto finish;
 | 
			
		||||
 | 
			
		||||
    /* They match !! */
 | 
			
		||||
    status = 1;
 | 
			
		||||
 | 
			
		||||
 finish:
 | 
			
		||||
    dbg_free(block2);
 | 
			
		||||
    dbg_free(block1);
 | 
			
		||||
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lvm2_label_remove(struct labeller *l, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint32_t sectsize;
 | 
			
		||||
    char     block[BLOCK_SIZE];
 | 
			
		||||
    int      status1, status2;
 | 
			
		||||
    long     offset[2];
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_size(dev, &size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_get_sectsize(dev, §size))
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
    if (!dev_open(dev, O_RDWR))
 | 
			
		||||
    {
 | 
			
		||||
	dbg_free(block);
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get_label_locations(size, sectsize, &offset[0], &offset[1]);
 | 
			
		||||
    memset(block, 0, BLOCK_SIZE);
 | 
			
		||||
 | 
			
		||||
    /* Blank out the first label */
 | 
			
		||||
    status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
 | 
			
		||||
    if (!status1)
 | 
			
		||||
	log_error("Error erasing label 1\n");
 | 
			
		||||
 | 
			
		||||
    /* ...and the other at the end of the device */
 | 
			
		||||
    status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
 | 
			
		||||
    if (!status2)
 | 
			
		||||
	log_error("Error erasing label 2\n");
 | 
			
		||||
 | 
			
		||||
    dev_close(dev);
 | 
			
		||||
 | 
			
		||||
    return ((status1 != 0) && (status2 != 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lvm2_label_destroy(struct labeller *l)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct label_ops handler_ops =
 | 
			
		||||
{
 | 
			
		||||
    can_handle: lvm2_is_labelled,
 | 
			
		||||
    write:      lvm2_label_write,
 | 
			
		||||
    remove:     lvm2_label_remove,
 | 
			
		||||
    read:       lvm2_label_read,
 | 
			
		||||
    verify:     lvm2_labels_match,
 | 
			
		||||
    destroy:    lvm2_label_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct labeller this_labeller =
 | 
			
		||||
{
 | 
			
		||||
    private : NULL,
 | 
			
		||||
    ops     : &handler_ops,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Don't know how this gets called... */
 | 
			
		||||
void lvm2_label_init()
 | 
			
		||||
{
 | 
			
		||||
    label_register_handler("LVM2", &this_labeller);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the GPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct lvm2_label
 | 
			
		||||
{
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t crc;
 | 
			
		||||
    uint64_t label1_loc;
 | 
			
		||||
    uint64_t label2_loc;
 | 
			
		||||
    uint16_t datalen;
 | 
			
		||||
 | 
			
		||||
    char     disk_type[32];
 | 
			
		||||
    uint32_t version[3];
 | 
			
		||||
 | 
			
		||||
    char    *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define VERSION_MATCH_EQUAL     1
 | 
			
		||||
#define VERSION_MATCH_LESSTHAN  2
 | 
			
		||||
#define VERSION_MATCH_LESSEQUAL 3
 | 
			
		||||
#define VERSION_MATCH_ANY       4
 | 
			
		||||
 | 
			
		||||
extern struct dev_filter *lvm2_label_filter_create();
 | 
			
		||||
extern struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);
 | 
			
		||||
@@ -1,70 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_UUID_MAP_H
 | 
			
		||||
#define _LVM_UUID_MAP_H
 | 
			
		||||
 | 
			
		||||
#include "uuid-map.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
#include "dbg_malloc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
 | 
			
		||||
struct uuid_map {
 | 
			
		||||
	struct dev_filter *filter;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct uuid_map *uuid_map_create(struct dev_filter *devices)
 | 
			
		||||
{
 | 
			
		||||
	struct uuid_map *um;
 | 
			
		||||
 | 
			
		||||
	if (!(um = dbg_malloc(sizeof(*um)))) {
 | 
			
		||||
		log_err("Couldn't allocate uuid_map object.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	um->filter = devices;
 | 
			
		||||
	return um;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uuid_map_destroy(struct uuid_map *um)
 | 
			
		||||
{
 | 
			
		||||
	dbg_free(um);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Simple, non-caching implementation to start with.
 | 
			
		||||
 */
 | 
			
		||||
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
 | 
			
		||||
{
 | 
			
		||||
	struct dev_iter *iter;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	struct label *lab;
 | 
			
		||||
 | 
			
		||||
	if (!(iter = dev_iter_create(um->filter))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((dev = dev_iter_get(iter))) {
 | 
			
		||||
 | 
			
		||||
		if (!label_read(dev, &lab))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (id_equal(id, &lab->id)) {
 | 
			
		||||
			label_destroy(lab);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		label_destroy(lab);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_iter_destroy(iter);
 | 
			
		||||
	return dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_UUID_MAP_H
 | 
			
		||||
#define _LVM_UUID_MAP_H
 | 
			
		||||
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include "dev-cache.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Holds a mapping from uuid -> device.
 | 
			
		||||
 */
 | 
			
		||||
struct uuid_map;
 | 
			
		||||
 | 
			
		||||
struct uuid_map *uuid_map_create(struct dev_filter *devices);
 | 
			
		||||
void uuid_map_destroy(struct uuid_map *um);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Find the device with a particular uuid.
 | 
			
		||||
 */
 | 
			
		||||
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										74
									
								
								lib/locking/external_locking.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/locking/external_locking.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "locking_types.h"
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
#include "sharedlib.h"
 | 
			
		||||
 | 
			
		||||
static void *_locking_lib = NULL;
 | 
			
		||||
static void (*_end_fn) (void) = NULL;
 | 
			
		||||
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
 | 
			
		||||
			int flags) = NULL;
 | 
			
		||||
static int (*_init_fn) (int type, struct config_tree * cf) = NULL;
 | 
			
		||||
 | 
			
		||||
static int _lock_resource(struct cmd_context *cmd, const char *resource,
 | 
			
		||||
			  int flags)
 | 
			
		||||
{
 | 
			
		||||
	if (_lock_fn)
 | 
			
		||||
		return _lock_fn(cmd, resource, flags);
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _fin_external_locking(void)
 | 
			
		||||
{
 | 
			
		||||
	if (_end_fn)
 | 
			
		||||
		_end_fn();
 | 
			
		||||
 | 
			
		||||
	dlclose(_locking_lib);
 | 
			
		||||
 | 
			
		||||
	_locking_lib = NULL;
 | 
			
		||||
	_init_fn = NULL;
 | 
			
		||||
	_end_fn = NULL;
 | 
			
		||||
	_lock_fn = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	const char *libname;
 | 
			
		||||
 | 
			
		||||
	if (_locking_lib) {
 | 
			
		||||
		log_error("External locking already initialised");
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	locking->lock_resource = _lock_resource;
 | 
			
		||||
	locking->fin_locking = _fin_external_locking;
 | 
			
		||||
 | 
			
		||||
	libname = find_config_str(cf->root, "global/locking_library", '/',
 | 
			
		||||
				  DEFAULT_LOCKING_LIB);
 | 
			
		||||
 | 
			
		||||
	if (!(_locking_lib = load_shared_library(cf, libname, "locking"))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the functions we need */
 | 
			
		||||
	if (!(_init_fn = dlsym(_locking_lib, "init_locking")) ||
 | 
			
		||||
	    !(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
 | 
			
		||||
	    !(_end_fn = dlsym(_locking_lib, "end_locking"))) {
 | 
			
		||||
		log_error("Shared library %s does not contain locking "
 | 
			
		||||
			  "functions", libname);
 | 
			
		||||
		dlclose(_locking_lib);
 | 
			
		||||
		_locking_lib = NULL;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_verbose("Loaded external locking library %s", libname);
 | 
			
		||||
	return _init_fn(2, cf);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										286
									
								
								lib/locking/file_locking.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								lib/locking/file_locking.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,286 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "locking_types.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
#include "lvm-file.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
 | 
			
		||||
struct lock_list {
 | 
			
		||||
	struct list list;
 | 
			
		||||
	int lf;
 | 
			
		||||
	char *res;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct list _lock_list;
 | 
			
		||||
static char _lock_dir[NAME_LEN];
 | 
			
		||||
 | 
			
		||||
static sig_t _oldhandler;
 | 
			
		||||
static sigset_t _fullsigset, _intsigset;
 | 
			
		||||
static int _handler_installed;
 | 
			
		||||
 | 
			
		||||
static int _release_lock(const char *file, int unlock)
 | 
			
		||||
{
 | 
			
		||||
	struct lock_list *ll;
 | 
			
		||||
	struct list *llh, *llt;
 | 
			
		||||
 | 
			
		||||
	struct stat buf1, buf2;
 | 
			
		||||
 | 
			
		||||
	list_iterate_safe(llh, llt, &_lock_list) {
 | 
			
		||||
		ll = list_item(llh, struct lock_list);
 | 
			
		||||
 | 
			
		||||
		if (!file || !strcmp(ll->res, file)) {
 | 
			
		||||
			list_del(llh);
 | 
			
		||||
			if (unlock) {
 | 
			
		||||
				log_very_verbose("Unlocking %s", ll->res);
 | 
			
		||||
				if (flock(ll->lf, LOCK_NB | LOCK_UN))
 | 
			
		||||
					log_sys_error("flock", ll->res);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!flock(ll->lf, LOCK_NB | LOCK_EX) &&
 | 
			
		||||
			    !stat(ll->res, &buf1) &&
 | 
			
		||||
			    !fstat(ll->lf, &buf2) &&
 | 
			
		||||
			    !memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
 | 
			
		||||
				if (unlink(ll->res))
 | 
			
		||||
					log_sys_error("unlink", ll->res);
 | 
			
		||||
 | 
			
		||||
			if (close(ll->lf) < 0)
 | 
			
		||||
				log_sys_error("close", ll->res);
 | 
			
		||||
 | 
			
		||||
			dbg_free(ll->res);
 | 
			
		||||
			dbg_free(llh);
 | 
			
		||||
 | 
			
		||||
			if (file)
 | 
			
		||||
				return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _fin_file_locking(void)
 | 
			
		||||
{
 | 
			
		||||
	_release_lock(NULL, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _reset_file_locking(void)
 | 
			
		||||
{
 | 
			
		||||
	_release_lock(NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _remove_ctrl_c_handler()
 | 
			
		||||
{
 | 
			
		||||
	siginterrupt(SIGINT, 0);
 | 
			
		||||
	if (!_handler_installed || _oldhandler == SIG_ERR)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
 | 
			
		||||
	if (signal(SIGINT, _oldhandler) == SIG_ERR)
 | 
			
		||||
		log_sys_error("signal", "_remove_ctrl_c_handler");
 | 
			
		||||
 | 
			
		||||
	_handler_installed = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _trap_ctrl_c(int sig)
 | 
			
		||||
{
 | 
			
		||||
	_remove_ctrl_c_handler();
 | 
			
		||||
	log_error("CTRL-c detected: giving up waiting for lock");
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _install_ctrl_c_handler()
 | 
			
		||||
{
 | 
			
		||||
	if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	sigprocmask(SIG_SETMASK, &_intsigset, NULL);
 | 
			
		||||
	siginterrupt(SIGINT, 1);
 | 
			
		||||
 | 
			
		||||
	_handler_installed = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lock_file(const char *file, int flags)
 | 
			
		||||
{
 | 
			
		||||
	int operation;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	struct lock_list *ll;
 | 
			
		||||
	struct stat buf1, buf2;
 | 
			
		||||
	char state;
 | 
			
		||||
 | 
			
		||||
	switch (flags & LCK_TYPE_MASK) {
 | 
			
		||||
	case LCK_READ:
 | 
			
		||||
		operation = LOCK_SH;
 | 
			
		||||
		state = 'R';
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_WRITE:
 | 
			
		||||
		operation = LOCK_EX;
 | 
			
		||||
		state = 'W';
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_UNLOCK:
 | 
			
		||||
		return _release_lock(file, 1);
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(ll = dbg_malloc(sizeof(struct lock_list))))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!(ll->res = dbg_strdup(file))) {
 | 
			
		||||
		dbg_free(ll);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ll->lf = -1;
 | 
			
		||||
 | 
			
		||||
	log_very_verbose("Locking %s %c%c", ll->res, state,
 | 
			
		||||
			 flags & LCK_NONBLOCK ? ' ' : 'B');
 | 
			
		||||
	do {
 | 
			
		||||
		if (ll->lf > -1)
 | 
			
		||||
			close(ll->lf);
 | 
			
		||||
 | 
			
		||||
		if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
 | 
			
		||||
		    < 0) {
 | 
			
		||||
			log_sys_error("open", file);
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((flags & LCK_NONBLOCK))
 | 
			
		||||
			operation |= LOCK_NB;
 | 
			
		||||
		else
 | 
			
		||||
			_install_ctrl_c_handler();
 | 
			
		||||
 | 
			
		||||
		r = flock(ll->lf, operation);
 | 
			
		||||
		if (!(flags & LCK_NONBLOCK))
 | 
			
		||||
			_remove_ctrl_c_handler();
 | 
			
		||||
 | 
			
		||||
		if (r) {
 | 
			
		||||
			log_sys_error("flock", ll->res);
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!stat(ll->res, &buf1) && !fstat(ll->lf, &buf2) &&
 | 
			
		||||
		    !memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
 | 
			
		||||
			break;
 | 
			
		||||
	} while (!(flags & LCK_NONBLOCK));
 | 
			
		||||
 | 
			
		||||
	list_add(&_lock_list, &ll->list);
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
      err:
 | 
			
		||||
	dbg_free(ll->res);
 | 
			
		||||
	dbg_free(ll);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
 | 
			
		||||
			       int flags)
 | 
			
		||||
{
 | 
			
		||||
	char lockfile[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	switch (flags & LCK_SCOPE_MASK) {
 | 
			
		||||
	case LCK_VG:
 | 
			
		||||
		if (!resource || !*resource)
 | 
			
		||||
			lvm_snprintf(lockfile, sizeof(lockfile),
 | 
			
		||||
				     "%s/P_orphans", _lock_dir);
 | 
			
		||||
		else
 | 
			
		||||
			lvm_snprintf(lockfile, sizeof(lockfile),
 | 
			
		||||
				     "%s/V_%s", _lock_dir, resource);
 | 
			
		||||
 | 
			
		||||
		if (!_lock_file(lockfile, flags))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		switch (flags & LCK_TYPE_MASK) {
 | 
			
		||||
		case LCK_UNLOCK:
 | 
			
		||||
			lvmcache_unlock_vgname(resource);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			lvmcache_lock_vgname(resource,
 | 
			
		||||
					     (flags & LCK_TYPE_MASK) ==
 | 
			
		||||
					     LCK_READ);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_LV:
 | 
			
		||||
		switch (flags & LCK_TYPE_MASK) {
 | 
			
		||||
		case LCK_UNLOCK:
 | 
			
		||||
			log_debug("Unlocking LV %s", resource);
 | 
			
		||||
			if (!lv_resume_if_active(cmd, resource))
 | 
			
		||||
				return 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_READ:
 | 
			
		||||
			log_debug("Locking LV %s (R)", resource);
 | 
			
		||||
			if (!lv_activate(cmd, resource))
 | 
			
		||||
				return 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_WRITE:
 | 
			
		||||
			log_debug("Locking LV %s (W)", resource);
 | 
			
		||||
			if (!lv_suspend_if_active(cmd, resource))
 | 
			
		||||
				return 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_EXCL:
 | 
			
		||||
			log_debug("Locking LV %s (EX)", resource);
 | 
			
		||||
			if (!lv_deactivate(cmd, resource))
 | 
			
		||||
				return 0;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unrecognised lock scope: %d",
 | 
			
		||||
			  flags & LCK_SCOPE_MASK);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	locking->lock_resource = _file_lock_resource;
 | 
			
		||||
	locking->reset_locking = _reset_file_locking;
 | 
			
		||||
	locking->fin_locking = _fin_file_locking;
 | 
			
		||||
 | 
			
		||||
	/* Get lockfile directory from config file */
 | 
			
		||||
	strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir",
 | 
			
		||||
					   '/', DEFAULT_LOCK_DIR),
 | 
			
		||||
		sizeof(_lock_dir));
 | 
			
		||||
 | 
			
		||||
	if (!create_dir(_lock_dir))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Trap a read-only file system */
 | 
			
		||||
	if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	list_init(&_lock_list);
 | 
			
		||||
 | 
			
		||||
	if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
 | 
			
		||||
		log_sys_error("sigfillset", "init_file_locking");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sigdelset(&_intsigset, SIGINT)) {
 | 
			
		||||
		log_sys_error("sigdelset", "init_file_locking");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										211
									
								
								lib/locking/locking.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								lib/locking/locking.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "locking_types.h"
 | 
			
		||||
#include "lvm-string.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
static struct locking_type _locking;
 | 
			
		||||
static sigset_t _oldset;
 | 
			
		||||
 | 
			
		||||
static int _lock_count = 0;	/* Number of locks held */
 | 
			
		||||
static int _signals_blocked = 0;
 | 
			
		||||
 | 
			
		||||
static void _block_signals(int flags)
 | 
			
		||||
{
 | 
			
		||||
	sigset_t set;
 | 
			
		||||
 | 
			
		||||
	if (_signals_blocked)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (sigfillset(&set)) {
 | 
			
		||||
		log_sys_error("sigfillset", "_block_signals");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sigprocmask(SIG_SETMASK, &set, &_oldset)) {
 | 
			
		||||
		log_sys_error("sigprocmask", "_block_signals");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_signals_blocked = 1;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _unblock_signals(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Don't unblock signals while any locks are held */
 | 
			
		||||
	if (!_signals_blocked || _lock_count)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (sigprocmask(SIG_SETMASK, &_oldset, NULL)) {
 | 
			
		||||
		log_sys_error("sigprocmask", "_block_signals");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_signals_blocked = 0;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void reset_locking(void)
 | 
			
		||||
{
 | 
			
		||||
	int was_locked = _lock_count;
 | 
			
		||||
 | 
			
		||||
	_lock_count = 0;
 | 
			
		||||
 | 
			
		||||
	_locking.reset_locking();
 | 
			
		||||
 | 
			
		||||
	if (was_locked)
 | 
			
		||||
		_unblock_signals();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void _update_lock_count(int flags)
 | 
			
		||||
{
 | 
			
		||||
	if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
 | 
			
		||||
		_lock_count--;
 | 
			
		||||
	else
 | 
			
		||||
		_lock_count++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Select a locking type
 | 
			
		||||
 */
 | 
			
		||||
int init_locking(int type, struct config_tree *cf)
 | 
			
		||||
{
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		init_no_locking(&_locking, cf);
 | 
			
		||||
		log_print("WARNING: Locking disabled. Be careful! "
 | 
			
		||||
			  "This could corrupt your metadata.");
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	case 1:
 | 
			
		||||
		if (!init_file_locking(&_locking, cf))
 | 
			
		||||
			break;
 | 
			
		||||
		log_very_verbose("File-based locking enabled.");
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBDL
 | 
			
		||||
	case 2:
 | 
			
		||||
		if (!init_external_locking(&_locking, cf))
 | 
			
		||||
			break;
 | 
			
		||||
		log_very_verbose("External locking enabled.");
 | 
			
		||||
		return 1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unknown locking type requested.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!ignorelockingfailure())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* FIXME Ensure only read ops are permitted */
 | 
			
		||||
	log_verbose("Locking disabled - only read operations permitted.");
 | 
			
		||||
 | 
			
		||||
	init_no_locking(&_locking, cf);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fin_locking(void)
 | 
			
		||||
{
 | 
			
		||||
	_locking.fin_locking();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Does the LVM1 driver know of this VG name?
 | 
			
		||||
 */
 | 
			
		||||
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct stat info;
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
 | 
			
		||||
	/* We'll allow operations on orphans */
 | 
			
		||||
	if (!*vgname)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
 | 
			
		||||
			 vgname) < 0) {
 | 
			
		||||
		log_error("LVM1 proc VG pathname too long for %s", vgname);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (stat(path, &info) == 0) {
 | 
			
		||||
		log_error("%s exists: Is the original LVM driver using "
 | 
			
		||||
			  "this volume group?", path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (errno != ENOENT && errno != ENOTDIR) {
 | 
			
		||||
		log_sys_error("stat", path);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * VG locking is by VG name.
 | 
			
		||||
 * FIXME This should become VG uuid.
 | 
			
		||||
 */
 | 
			
		||||
static int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
 | 
			
		||||
{
 | 
			
		||||
	_block_signals(flags);
 | 
			
		||||
 | 
			
		||||
	if (!(_locking.lock_resource(cmd, resource, flags))) {
 | 
			
		||||
		_unblock_signals();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_update_lock_count(flags);
 | 
			
		||||
	_unblock_signals();
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
 | 
			
		||||
{
 | 
			
		||||
	char resource[258];
 | 
			
		||||
 | 
			
		||||
	switch (flags & LCK_SCOPE_MASK) {
 | 
			
		||||
	case LCK_VG:
 | 
			
		||||
		/* Lock VG to change on-disk metadata. */
 | 
			
		||||
		/* If LVM1 driver knows about the VG, it can't be accessed. */
 | 
			
		||||
		if (!check_lvm1_vg_inactive(cmd, vol))
 | 
			
		||||
			return 0;
 | 
			
		||||
	case LCK_LV:
 | 
			
		||||
		/* Suspend LV if it's active. */
 | 
			
		||||
		strncpy(resource, vol, sizeof(resource));
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unrecognised lock scope: %d",
 | 
			
		||||
			  flags & LCK_SCOPE_MASK);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_lock_vol(cmd, resource, flags))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Perform immediate unlock unless LCK_HOLD set */
 | 
			
		||||
	if (!(flags & LCK_HOLD) && ((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
 | 
			
		||||
		if (!_lock_vol(cmd, resource,
 | 
			
		||||
			       (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK))
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								lib/locking/locking.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/locking/locking.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "uuid.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
int init_locking(int type, struct config_tree *cf);
 | 
			
		||||
void fin_locking(void);
 | 
			
		||||
void reset_locking(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * LCK_VG:
 | 
			
		||||
 *   Lock/unlock on-disk volume group data
 | 
			
		||||
 *   Use "" to lock orphan PVs
 | 
			
		||||
 *   char *vol holds volume group name
 | 
			
		||||
 *
 | 
			
		||||
 * LCK_LV:
 | 
			
		||||
 *   Lock/unlock an individual logical volume
 | 
			
		||||
 *   char *vol holds lvid
 | 
			
		||||
 */
 | 
			
		||||
int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Does the LVM1 driver have this VG active?
 | 
			
		||||
 */
 | 
			
		||||
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Lock type - these numbers are the same as VMS and the IBM DLM
 | 
			
		||||
 */
 | 
			
		||||
#define LCK_TYPE_MASK	0x000000FF
 | 
			
		||||
 | 
			
		||||
#define LCK_NULL	0x00000000	/* LCK$_NLMODE */
 | 
			
		||||
#define LCK_READ	0x00000001	/* LCK$_CRMODE */
 | 
			
		||||
					/* LCK$_CWMODE */
 | 
			
		||||
					/* LCK$_PRMODE */
 | 
			
		||||
#define LCK_WRITE	0x00000004	/* LCK$_PWMODE */
 | 
			
		||||
#define LCK_EXCL	0x00000005	/* LCK$_EXMODE */
 | 
			
		||||
#define LCK_UNLOCK      0x00000010	/* This is ours */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Lock scope
 | 
			
		||||
 */
 | 
			
		||||
#define LCK_SCOPE_MASK	0x0000FF00
 | 
			
		||||
#define LCK_VG		0x00000000
 | 
			
		||||
#define LCK_LV		0x00000100
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Lock bits
 | 
			
		||||
 */
 | 
			
		||||
#define LCK_NONBLOCK	0x00010000	/* Don't block waiting for lock? */
 | 
			
		||||
#define LCK_HOLD	0x00020000	/* Hold lock when lock_vol returns? */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Common combinations
 | 
			
		||||
 */
 | 
			
		||||
#define LCK_VG_READ		(LCK_VG | LCK_READ | LCK_HOLD)
 | 
			
		||||
#define LCK_VG_WRITE		(LCK_VG | LCK_WRITE | LCK_HOLD)
 | 
			
		||||
#define LCK_VG_UNLOCK		(LCK_VG | LCK_UNLOCK)
 | 
			
		||||
 | 
			
		||||
#define LCK_LV_DEACTIVATE	(LCK_LV | LCK_EXCL)
 | 
			
		||||
#define LCK_LV_SUSPEND		(LCK_LV | LCK_WRITE)
 | 
			
		||||
#define LCK_LV_ACTIVATE		(LCK_LV | LCK_READ)
 | 
			
		||||
#define LCK_LV_UNLOCK		(LCK_LV | LCK_UNLOCK)
 | 
			
		||||
 | 
			
		||||
#define unlock_lv(cmd, vol)	lock_vol(cmd, vol, LCK_LV_UNLOCK)
 | 
			
		||||
#define unlock_vg(cmd, vol)	lock_vol(cmd, vol, LCK_VG_UNLOCK)
 | 
			
		||||
							
								
								
									
										31
									
								
								lib/locking/locking_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/locking/locking_types.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is released under the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
typedef int (*lock_resource_fn) (struct cmd_context * cmd, const char *resource,
 | 
			
		||||
				 int flags);
 | 
			
		||||
 | 
			
		||||
typedef void (*fin_lock_fn) (void);
 | 
			
		||||
typedef void (*reset_lock_fn) (void);
 | 
			
		||||
 | 
			
		||||
struct locking_type {
 | 
			
		||||
	lock_resource_fn lock_resource;
 | 
			
		||||
 | 
			
		||||
	reset_lock_fn reset_locking;
 | 
			
		||||
	fin_lock_fn fin_locking;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Locking types
 | 
			
		||||
 */
 | 
			
		||||
int init_no_locking(struct locking_type *locking, struct config_tree *cf);
 | 
			
		||||
 | 
			
		||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
 | 
			
		||||
 | 
			
		||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user