mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-27 11:33:19 +03:00 
			
		
		
		
	Compare commits
	
		
			2211 Commits
		
	
	
		
			dev-dct-de
			...
			v2_02_22
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 83edf68ff9 | ||
|  | c7588f91dd | ||
|  | 30b432adc5 | ||
|  | 7c9733eb5d | ||
|  | a223c3fea3 | ||
|  | d5250f4901 | ||
|  | 25f29f4712 | ||
|  | 382af5563d | ||
|  | 8cf3d165d3 | ||
|  | 0fd6ce546f | ||
|  | b881c372bc | ||
|  | 94c5e7deb0 | ||
|  | c344766f3c | ||
|  | 67895de0bc | ||
|  | ff00cb6990 | ||
|  | 2cc75c11ed | ||
|  | cd79e58eda | ||
|  | 6fa801f3d8 | ||
|  | 684eecba1d | ||
|  | da9cf7e5de | ||
|  | f57e7445fd | ||
|  | fba1388719 | ||
|  | 80ed029c17 | ||
|  | 34a74e81e3 | ||
|  | cb120ddb15 | ||
|  | f9ee4395b0 | ||
|  | 71f06d51ed | ||
|  | 217f70952f | ||
|  | f813d41a76 | ||
|  | d851289d8a | ||
|  | b115b8a2ea | ||
|  | d0f7067471 | ||
|  | be5b4c38a7 | ||
|  | d6d597e3dd | ||
|  | 84e348fade | ||
|  | 910054657e | ||
|  | 8357a11249 | ||
|  | 9b021ba057 | ||
|  | 317e588efd | ||
|  | b1d32a03c7 | ||
|  | ee6e6529ee | ||
|  | 9d944d6cf9 | ||
|  | 13635d281a | ||
|  | 2493c46970 | ||
|  | 63e4217271 | ||
|  | f4bd12e8e9 | ||
|  | df15f46900 | ||
|  | fb3a732361 | ||
|  | 2d74110feb | ||
|  | 19d102082d | ||
|  | d2af2c9487 | ||
|  | 82980149fa | ||
|  | a19bb7b909 | ||
|  | 9d98c3278d | ||
|  | 26376ac1c9 | ||
|  | 8459f99341 | ||
|  | e5bdb0e0b5 | ||
|  | 1106b7775a | ||
|  | ae2852156d | ||
|  | 44c6c36c43 | ||
|  | a81926503d | ||
|  | af13ccddda | ||
|  | 392e1bc2e8 | ||
|  | 9268d92c70 | ||
|  | bb3366c07d | ||
|  | d24d563ebc | ||
|  | 954bd9257b | ||
|  | 5d51a56c02 | ||
|  | f48648552e | ||
|  | edb9c3cc9f | ||
|  | 01dc83b936 | ||
|  | 3a8dff3a62 | ||
|  | 13b234ccba | ||
|  | e451e93664 | ||
|  | b4f9531475 | ||
|  | 3184ff75c4 | ||
|  | 43243f4d30 | ||
|  | c975a100b1 | ||
|  | 02bf389425 | ||
|  | bcb9a3dd04 | ||
|  | cce3baa275 | ||
|  | 2b48fad426 | ||
|  | d554b2bc94 | ||
|  | f66943de43 | ||
|  | 9d1e9bc2fb | ||
|  | 2d6a014920 | ||
|  | c1952bf257 | ||
|  | a10227eb03 | ||
|  | 475ae29b85 | ||
|  | 0b9cfc278b | ||
|  | b57b6b4fba | ||
|  | 7d948f7bc5 | ||
|  | 459023d171 | ||
|  | fd6570720a | ||
|  | 7831665417 | ||
|  | 7c9920d982 | ||
|  | cbdccf0a9c | ||
|  | 64fa83ec3f | ||
|  | faff865cfd | ||
|  | 742ab55a9a | ||
|  | 66e623fb2a | ||
|  | 4ab17ee965 | ||
|  | 7f48ca5132 | ||
|  | da983848b4 | ||
|  | bc03f7bad3 | ||
|  | a1c8bd3846 | ||
|  | 404bc284e0 | ||
|  | 9dee30ff0e | ||
|  | f91aadbea8 | ||
|  | aa15a10c91 | ||
|  | 5b03e36351 | ||
|  | b9ba9ffad2 | ||
|  | 642be5d16c | ||
|  | ee68d715bf | ||
|  | 224084f056 | ||
|  | 1cd8c849b8 | ||
|  | 169f68bfcd | ||
|  | d2b7cfa2d1 | ||
|  | a40c7dff5d | ||
|  | e8e00630d3 | ||
|  | e33720c854 | ||
|  | bd8a4e0d17 | ||
|  | 586a2aef76 | ||
|  | ce1d8f6754 | ||
|  | 7b0f401065 | ||
|  | 8387016eef | ||
|  | 4e1342b641 | ||
|  | e45a184d90 | ||
|  | 979e1012d2 | ||
|  | fe10a50e23 | ||
|  | 8ab6d72519 | ||
|  | 3aada6dd1d | ||
|  | 0933036366 | ||
|  | 05f5abdc06 | ||
|  | fb875e0709 | ||
|  | 9acdc2f6bf | ||
|  | 028ce4bff6 | ||
|  | 3f245ad6db | ||
|  | 23115f4116 | ||
|  | cf5f48e6cc | ||
|  | 997fa756ad | ||
|  | e23f75b1cc | ||
|  | 6531e88761 | ||
|  | e76a9c2618 | ||
|  | 45be8a836b | ||
|  | 954b6032e7 | ||
|  | bd95416f27 | ||
|  | df2577ace2 | ||
|  | 720e6558c9 | ||
|  | c239f15d8a | ||
|  | dfa1f80a57 | ||
|  | 15dfb93b17 | ||
|  | 0ec8488c2b | ||
|  | 94b2e29cb1 | ||
|  | fefa8e9b4d | ||
|  | 32c4c44812 | ||
|  | 05195e2b1d | ||
|  | 4c2ff675b8 | ||
|  | e5692a4721 | ||
|  | 312e6a0d31 | ||
|  | 5bb8efa41f | ||
|  | 949a835f4a | ||
|  | 85e6042941 | ||
|  | 3cd2f28975 | ||
|  | 2179a72c3a | ||
|  | a5f282f156 | ||
|  | 40e8631f63 | ||
|  | 9ded05bb97 | ||
|  | ec8efa35a1 | ||
|  | f72bf20482 | ||
|  | ebde2002e8 | ||
|  | 352a66f46f | ||
|  | d84c5391f7 | ||
|  | f4c582472b | ||
|  | 1485586f7e | ||
|  | d5c9024335 | ||
|  | 860cf80703 | ||
|  | 897ff3161f | ||
|  | b356b2e501 | ||
|  | 1d2733c893 | ||
|  | 32d9126094 | ||
|  | db43314e50 | ||
|  | 68d2baeb65 | ||
|  | 1fd5f562d3 | ||
|  | 48e02f2086 | ||
|  | eab7b2b581 | ||
|  | 45abade7fc | ||
|  | 5372fc4b43 | ||
|  | 4e2f240c98 | ||
|  | bb3605518d | ||
|  | 3ef6d37f27 | ||
|  | 88e9f2f7f4 | ||
|  | 704a447df9 | ||
|  | a5fcb26a33 | ||
|  | 2491a61481 | ||
|  | 91831d51ed | ||
|  | 174f0c19f7 | ||
|  | de6fadfb4f | ||
|  | f946db3e00 | ||
|  | 8d05e5bc31 | ||
|  | cfb46820e4 | ||
|  | 081f1cbcc2 | ||
|  | 7bc6da326f | ||
|  | cd95a0df7b | ||
|  | 82fa497c16 | ||
|  | 44fd345206 | ||
|  | 088e1c9db4 | ||
|  | d4f16e666e | ||
|  | 8233cfd371 | ||
|  | ff05e2e30d | ||
|  | a8ea7dd3fb | ||
|  | 96f70a5303 | ||
|  | f1604c3e69 | ||
|  | c42c8c5192 | ||
|  | 5facb53a41 | ||
|  | d039ce89af | ||
|  | bc7605103f | ||
|  | d305d655d4 | ||
|  | 4ef1220b16 | ||
|  | a4fef143cd | ||
|  | 74ecb724a9 | ||
|  | af235897ab | ||
|  | 5ec4e458b5 | ||
|  | 2dae63ce21 | ||
|  | be748fe33b | ||
|  | 7408340b6a | ||
|  | 29eb92446e | ||
|  | ae6918742e | ||
|  | 863484bb65 | ||
|  | 1cd7ebce4c | ||
|  | eef8c7862e | ||
|  | b52375d446 | ||
|  | 6e2babc2ce | ||
|  | 08e253bed1 | ||
|  | c6661477a2 | ||
|  | 415cfd99a0 | ||
|  | 8c2e37381a | ||
|  | 45df79feba | ||
|  | 5824f992b7 | ||
|  | b0b60fafd5 | ||
|  | 8d98b02ba2 | ||
|  | a93fe79bc4 | ||
|  | 4aebd7be37 | ||
|  | 3170a5db32 | ||
|  | 3605b9eef6 | ||
|  | a945f1fde2 | ||
|  | 461a997b5b | ||
|  | a80afd7b4e | ||
|  | aad2b51d85 | ||
|  | 36a9a81ff1 | ||
|  | 42c88546ae | ||
|  | 0f0e86ef9b | ||
|  | 98efd9a857 | ||
|  | a0c27d95b7 | ||
|  | 984651d99d | ||
|  | c6f7370b30 | ||
|  | 3e4b8e8985 | ||
|  | 73f08b98d2 | ||
|  | 8607a74206 | ||
|  | 8339f3ceb3 | ||
|  | c0c9f3cc19 | ||
|  | 81f4813c29 | ||
|  | 94f57745b9 | ||
|  | 54fb2ebbe0 | ||
|  | 02d122b65b | ||
|  | df0a5561a1 | ||
|  | f7c55da7d0 | ||
|  | b385f701ce | ||
|  | 05dd42f443 | ||
|  | 36d816d5cb | ||
|  | 92a6746e70 | ||
|  | 1728848a39 | ||
|  | f9eb4e7487 | ||
|  | d0b9f33aeb | ||
|  | 718583b241 | ||
|  | 6737127e9a | ||
|  | 19a7b4479b | ||
|  | c340647502 | ||
|  | 0f987d2982 | ||
|  | 52bcaed169 | ||
|  | 177bd565ac | ||
|  | c801c32fc5 | ||
|  | d090cf3058 | ||
|  | 1e4b82cc94 | ||
|  | 3426f31184 | ||
|  | b4fb7af1df | ||
|  | b36647598b | ||
|  | fd6b94f20e | ||
|  | 296dc0ed8a | ||
|  | 4f869e14d6 | ||
|  | 5704270e9d | ||
|  | 505b381e85 | ||
|  | da6cb15393 | ||
|  | 16843f6cc8 | ||
|  | 64f3ad1fd4 | ||
|  | ff4c4f99b3 | ||
|  | f5d2e09569 | ||
|  | f2bdbe0d4d | ||
|  | c51a13caa6 | ||
|  | 7840c78a23 | ||
|  | c706f3246b | ||
|  | 608eedf88d | ||
|  | a564ca82be | ||
|  | c868b1fee2 | ||
|  | 22374f718f | ||
|  | abe3cfcf41 | ||
|  | 59db4b50cd | ||
|  | bdae38765d | ||
|  | 66d3ceeb61 | ||
|  | 445dd17db3 | ||
|  | cff78a2577 | ||
|  | 6a09e64195 | ||
|  | 22eabe5eab | ||
|  | b69ba36c2d | ||
|  | 5240aad22b | ||
|  | 2897eb3cb3 | ||
|  | d3f2f00c25 | ||
|  | bacfb913a0 | ||
|  | c99d0236a0 | ||
|  | aac2b655f7 | ||
|  | 126c41e73a | ||
|  | 359ee54f0d | ||
|  | 28ab560907 | ||
|  | ead252fee4 | ||
|  | abf67914c4 | ||
|  | 127884e9dd | ||
|  | 654f5049eb | ||
|  | 979ca34259 | ||
|  | 4dd1086805 | ||
|  | 3503d4b72c | ||
|  | b8d32a0d33 | ||
|  | 45dca55fc8 | ||
|  | 445d8ecd9f | ||
|  | c980add503 | ||
|  | 133842392a | ||
|  | 8baf2ef155 | ||
|  | 20b71340bc | ||
|  | 61d8baf8b1 | ||
|  | 56a9645aa5 | ||
|  | 85877000a6 | ||
|  | 2f7d2477b6 | ||
|  | 21ea3f05f4 | ||
|  | 79d3492e90 | ||
|  | 5972777abe | ||
|  | 8e373ff868 | ||
|  | a4db92da3a | ||
|  | 9b777eb281 | ||
|  | bd3c652184 | ||
|  | 800f747570 | ||
|  | 2b8423437e | ||
|  | 8b4b6945f8 | ||
|  | e5ecfec5c4 | ||
|  | f95dbff71f | ||
|  | 098f6830a6 | ||
|  | d1ecebdb52 | ||
|  | 590b654251 | ||
|  | 3bf190c8ab | ||
|  | dcca7638e0 | ||
|  | 70e45ad37b | ||
|  | db88210289 | ||
|  | d2e0d96cc3 | ||
|  | 3feba82ccc | ||
|  | db924da231 | ||
|  | fc55ae7e6d | ||
|  | 86e757a6ad | ||
|  | 4790715cd3 | ||
|  | e7e9c60042 | ||
|  | 1c3bc52cc4 | ||
|  | 5227dff0e1 | ||
|  | 33f0b5b7c2 | ||
|  | 0a02968303 | ||
|  | f7bf658c07 | ||
|  | 8d16a0abad | ||
|  | c974b97ca3 | ||
|  | b8025bfebd | ||
|  | 30323b253f | ||
|  | 535c3ede96 | ||
|  | 89fed8ca33 | ||
|  | f43c77aaed | ||
|  | 96c676b371 | ||
|  | 113047e1a2 | ||
|  | abed57cb53 | ||
|  | c01a800a6b | ||
|  | d648832a2d | ||
|  | f06833fbd2 | ||
|  | c561addc94 | ||
|  | 702f5f1f4c | ||
|  | 1273f179e8 | ||
|  | 5d02f60bde | ||
|  | 4cf7a108e8 | ||
|  | 42635c3938 | ||
|  | ed43dc842b | ||
|  | 49d4db6cd2 | ||
|  | ea80ab2cae | ||
|  | 382e808b8d | ||
|  | 846befa7e0 | ||
|  | 74dd29f843 | ||
|  | b0473bffcb | ||
|  | 24dd9ab1a7 | ||
|  | 49d3037e87 | ||
|  | 37ad2bd4e8 | ||
|  | 7d7b332b02 | ||
|  | ac033b8612 | ||
|  | a7b98dfe25 | ||
|  | 7fb7c86c46 | ||
|  | ed036598a9 | ||
|  | 160bb70cdf | ||
|  | c2e61f3c21 | ||
|  | 18218467f3 | ||
|  | 17e298ad2a | ||
|  | d031a374f9 | ||
|  | 55f69c98cb | ||
|  | 71f2e4306d | ||
|  | f8af23a025 | ||
|  | 4ef55a6cd3 | ||
|  | 312f866723 | ||
|  | 0ebe1f6dec | ||
|  | 2ad92e0e6e | ||
|  | ac8823cdcf | ||
|  | 77565f7ee4 | ||
|  | d656d90fa8 | ||
|  | 175b3b0834 | ||
|  | 7477e6b714 | ||
|  | cd6568db69 | ||
|  | 6aff325fb2 | ||
|  | 0d603cfe9c | ||
|  | 34a1f14a17 | ||
|  | efe1c8a070 | ||
|  | 1575844344 | ||
|  | 221ac1c208 | ||
|  | 57442db759 | ||
|  | 5fdb3e7cd6 | ||
|  | 96f259726c | ||
|  | 4936efba5e | ||
|  | d5a3559a2f | ||
|  | 114a1c7f52 | ||
|  | ce5265c203 | ||
|  | 1a575d926f | ||
|  | 85c818a39e | ||
|  | 4ffa2defe4 | ||
|  | 8825157fbb | ||
|  | 966d608dc5 | ||
|  | b808c89471 | ||
|  | 75d4e6490f | ||
|  | a82775f544 | ||
|  | 6a22ad0171 | ||
|  | c854e88186 | ||
|  | d02203060c | ||
|  | cf703b0433 | ||
|  | c0197a72d3 | ||
|  | e5a543e283 | ||
|  | b8b029b7d3 | ||
|  | 370f368b1a | ||
|  | 8288b45b4f | ||
|  | fe529faf8e | ||
|  | ab931b177d | ||
|  | 9aa3465513 | ||
|  | 6c70fc1a6c | ||
|  | 1ccc39962a | ||
|  | 99c941fc85 | ||
|  | 19729fdcc2 | ||
|  | 02e17998ce | ||
|  | 459e00c67a | ||
|  | 292f665650 | ||
|  | 93bbb79569 | ||
|  | 273e724f2b | ||
|  | 5d2615c56f | ||
|  | bfaaf21330 | ||
|  | dcb8415b7a | ||
|  | 699e1c75ce | ||
|  | 465b6e613e | ||
|  | 05fa105855 | ||
|  | d7a0cdebe5 | ||
|  | b049ab31eb | ||
|  | 6db4dcff7a | ||
|  | 3eeaef00ec | ||
|  | 8bf4c38a00 | ||
|  | 3a32b09ad1 | ||
|  | 6315982752 | ||
|  | 374a171e82 | ||
|  | fc5d801f91 | ||
|  | 5146641848 | ||
|  | cdd0ac42cf | ||
|  | e5895500a2 | ||
|  | 9cb4dde3fa | ||
|  | 3c2a4370a5 | ||
|  | e7a360dd6f | ||
|  | c814c2fd35 | ||
|  | fefa7fe262 | ||
|  | 26f01a29d1 | ||
|  | 169d4090ab | ||
|  | 0b43754d60 | ||
|  | 8b3b26b813 | ||
|  | 5426af4f81 | ||
|  | 4e2c3a579d | ||
|  | 5ae2693241 | ||
|  | 41c86b0d19 | ||
|  | 40788e8c3d | ||
|  | 0d29120033 | ||
|  | 4be598f865 | ||
|  | 558a6d509e | ||
|  | 75cd02aad2 | ||
|  | e4c4451482 | ||
|  | 0671632477 | ||
|  | 54c230c264 | ||
|  | 64ba878eda | ||
|  | 01acd6dd76 | ||
|  | 9d819b52d3 | ||
|  | 37bac5cdc9 | ||
|  | 78c718c591 | ||
|  | 284b8bf6ca | ||
|  | 5a5084b837 | ||
|  | 3b8058e1f1 | ||
|  | 2a3168e0d6 | ||
|  | a8ac6e4a15 | ||
|  | 6172cf9fba | ||
|  | b728ec3909 | ||
|  | 61a53bbcff | ||
|  | 17d13dd084 | ||
|  | edcb28d591 | ||
|  | ad101119a7 | ||
|  | bc36676d31 | ||
|  | d76fe120ab | ||
|  | 2e95949b80 | ||
|  | ae14d85e24 | ||
|  | fad6304c60 | ||
|  | a4dd3c8ce9 | ||
|  | 6d1a5d45e2 | ||
|  | a6c7043e03 | ||
|  | bcc400dafa | ||
|  | 8fbedf3441 | ||
|  | 2e8a9c9874 | ||
|  | 44fc41b3e5 | ||
|  | 7212c20a1b | ||
|  | 7ff142de1c | ||
|  | e67efb199d | ||
|  | 20128bd04b | ||
|  | c0fefdde28 | ||
|  | f6ee160e66 | ||
|  | 06acc2004f | ||
|  | 43ac2ce4c8 | ||
|  | b32bf72b5f | ||
|  | c6880c957e | ||
|  | 095b71ed96 | ||
|  | 9160e496bc | ||
|  | 2a7ac78f02 | ||
|  | 64efa4627d | ||
|  | f7e35569ce | ||
|  | e8af32ec2b | ||
|  | e092ce51f6 | ||
|  | 7b78edb1b7 | ||
|  | b332e7090e | ||
|  | 67eb7723d6 | ||
|  | 251d138474 | ||
|  | 1170dfac05 | ||
|  | 4157f141c7 | ||
|  | f569abd28a | ||
|  | 088f9687c0 | ||
|  | e23df1f07a | ||
|  | c818540dfd | ||
|  | 21365cbe1a | ||
|  | 5471a80a96 | ||
|  | d7b6fa9cd0 | ||
|  | dfdc2e02ef | ||
|  | 893ec9a302 | ||
|  | 05f65c38e6 | ||
|  | 2e9d062ec0 | ||
|  | 6b0b394e61 | ||
|  | 25621396c9 | ||
|  | 82aa0271f3 | ||
|  | 653cab13f8 | ||
|  | b526f86b49 | ||
|  | 53c0f00888 | ||
|  | f0c4d9de40 | ||
|  | 03ef8cec83 | ||
|  | 85f2a2e8c2 | ||
|  | 584b3e6642 | ||
|  | 39b7ef841d | ||
|  | aa16a9098d | ||
|  | 7b8c2707bc | ||
|  | 60e26a31a7 | ||
|  | 3473c25c14 | ||
|  | e52f022026 | ||
|  | b1a7df8e43 | ||
|  | 0fd2479b7c | ||
|  | 273857f914 | ||
|  | a08b85dbc8 | ||
|  | a0aedf299a | ||
|  | 3c61426844 | ||
|  | 786f228076 | ||
|  | 004da28792 | ||
|  | 6e2be6efb6 | ||
|  | a994dfcfbc | ||
|  | 7a8ea2ac93 | ||
|  | 0da3965d19 | ||
|  | 885fd7bb46 | ||
|  | 08771f9c89 | ||
|  | 8be48195a5 | ||
|  | 98ce2d650e | ||
|  | 3af327116a | ||
|  | b75434db93 | ||
|  | 04e912aacd | ||
|  | d7be352f87 | ||
|  | 96be3ec22c | ||
|  | 32e7e0d790 | ||
|  | becc320e62 | ||
|  | 7666ed57d1 | ||
|  | 5e61d0955e | ||
|  | e8a4662ae7 | ||
|  | a48da3bd3b | ||
|  | 5f1a5d7b99 | ||
|  | 3e28a9db8f | ||
|  | ebf6071d77 | ||
|  | 47a35fb9fb | ||
|  | 48e88aba44 | ||
|  | b85f99c140 | ||
|  | 0a5e0e1f71 | ||
|  | 85dc22ebb7 | ||
|  | 5c21526009 | ||
|  | 14dff1cefc | ||
|  | 39fbb844f9 | ||
|  | ca4e0c973a | ||
|  | ecb42bee80 | ||
|  | 674ed2a9f3 | ||
|  | 252daf9717 | ||
|  | 196b8eaad3 | ||
|  | 8e526ba1bf | ||
|  | 19225828d9 | ||
|  | 7e594126be | ||
|  | d2529e6334 | ||
|  | 97344f18e2 | ||
|  | 33934db629 | ||
|  | 6c6165c9f5 | ||
|  | 853460b20d | ||
|  | cc4d9676c5 | ||
|  | 1cf1b819f4 | ||
|  | f916c66d2b | ||
|  | 550aa86b45 | ||
|  | 014e764758 | ||
|  | d1fc28432b | ||
|  | 879576f0a2 | ||
|  | 69098210be | ||
|  | 99df4f892d | ||
|  | 7bc04fbad3 | ||
|  | 8a74ce578d | ||
|  | 0805e4e5de | ||
|  | f1060fc88e | ||
|  | 7d3d3d0a3a | ||
|  | 40377032e3 | ||
|  | b2971edd7d | ||
|  | c37d723692 | ||
|  | 30f9026e1d | ||
|  | 332286072e | ||
|  | d6da172a2a | ||
|  | ebfe584afc | ||
|  | 6250023583 | ||
|  | 6b4f3d63b8 | ||
|  | 56db773a09 | ||
|  | fc6c472401 | ||
|  | 2cd42a6866 | ||
|  | 36a90c345c | ||
|  | ef1e82c72c | ||
|  | 88f9534685 | ||
|  | 68254a052a | ||
|  | 2425b3a166 | ||
|  | 5524ed753b | ||
|  | 89711723da | ||
|  | bed2740ffd | ||
|  | 751d633c3d | ||
|  | 45952cbdf2 | ||
|  | b355dd7b23 | ||
|  | 48a186f172 | ||
|  | 39dc7ec2ab | ||
|  | 2fedabd3b9 | ||
|  | 6d719e9480 | ||
|  | 05e278afda | ||
|  | 87dbf462cb | ||
|  | 40e896bc5b | ||
|  | 3e940f80c7 | ||
|  | dbf2888d43 | ||
|  | d412355324 | ||
|  | 178732217f | ||
|  | de17b95c3d | ||
|  | d14e774525 | ||
|  | ca5402a7fa | ||
|  | 7a6fa7c5b4 | ||
|  | da36c286a6 | ||
|  | d3901bcf2e | ||
|  | 94c8d4fdfb | ||
|  | ab8bdc18bb | ||
|  | c9dcd7442a | ||
|  | 34c8f13346 | ||
|  | 7a8ccda95c | ||
|  | 44a1448542 | ||
|  | c87d89ffaf | ||
|  | 0868749d42 | ||
|  | 1d40ee23f0 | ||
|  | 8893f32603 | ||
|  | adcf7e8dc3 | ||
|  | 901f7c5c36 | ||
|  | 775bb413b3 | ||
|  | 64cd5b5a46 | ||
|  | ae356609b1 | ||
|  | 6102a5d2b0 | ||
|  | f8782ee2d7 | ||
|  | 6181ec4c77 | ||
|  | e0e7a685ef | ||
|  | ae1f8cdad2 | ||
|  | a4cf792e6d | ||
|  | 89109ded53 | ||
|  | e20e52a4b2 | ||
|  | 20c4b1cbec | ||
|  | 5238b0241d | ||
|  | 9cdf6c203d | ||
|  | 839335cae6 | ||
|  | a99b2ce167 | ||
|  | b695141d87 | ||
|  | 92d5c9f866 | ||
|  | 7f18a1ffe0 | ||
|  | 8c3fdaaa62 | ||
|  | 5ac1c69710 | ||
|  | de2d5fba63 | ||
|  | 33d516748f | ||
|  | de17f6f0fd | ||
|  | 756731fc02 | ||
|  | e46be0415f | ||
|  | aa02fb50bf | ||
|  | 8b6cd9c772 | ||
|  | cdd0d3351a | ||
|  | 8b6d584529 | ||
|  | f49fdd4141 | ||
|  | b26e1be81a | ||
|  | bacab38d7f | ||
|  | 701c05ce96 | ||
|  | 438c452585 | ||
|  | 0a7a1eff3f | ||
|  | 87e743e381 | ||
|  | a03f1b3d55 | ||
|  | 2d8dc3d243 | ||
|  | b982232cc5 | ||
|  | 61c8d728ac | ||
|  | 851a2bf855 | ||
|  | e0bdde3630 | ||
|  | 6a0dcd7f0e | ||
|  | 75f0b4c879 | ||
|  | db536a9504 | ||
|  | 0fb114dede | ||
|  | e703342179 | ||
|  | 35c8f4a611 | ||
|  | 7c89ae44a9 | ||
|  | 84fe06da22 | ||
|  | 806318c8b3 | ||
|  | 3aac2e1822 | ||
|  | 168baef433 | ||
|  | 6dba6cd78d | ||
|  | 502250d08f | ||
|  | 7395f0e680 | ||
|  | 494d3fdaca | ||
|  | 7b86a157de | ||
|  | 0988c41785 | ||
|  | 522db1bf01 | ||
|  | 06f066f90d | ||
|  | f37b20677b | ||
|  | cd2eac1032 | ||
|  | 8ac38d58d7 | ||
|  | 4c80cc313a | ||
|  | 1c65fee9b4 | ||
|  | 90dda7edc1 | ||
|  | da054fae20 | ||
|  | bdb6611e30 | ||
|  | 9284f973f1 | ||
|  | 2bfd64c3c9 | ||
|  | 939d24cce5 | ||
|  | 27b0183c46 | ||
|  | d14efacac7 | ||
|  | 150a002c40 | ||
|  | ce0def3bd8 | ||
|  | ee20fa97c2 | ||
|  | 7403b7d700 | ||
|  | 87ef173e0a | ||
|  | 52a3fb6bc7 | ||
|  | 92e2a257a6 | ||
|  | 32e175752c | ||
|  | d43f7180dc | ||
|  | 0129c2b0fc | ||
|  | 4ed1990001 | ||
|  | 5bd6ab27ae | ||
|  | f3593b89fa | ||
|  | 23d84b2310 | ||
|  | fdc49402ec | ||
|  | 5457c133e1 | ||
|  | 292e588ee3 | ||
|  | 243494c25e | ||
|  | e4365f3706 | ||
|  | 310f3038d3 | ||
|  | 4e6033273d | ||
|  | 73718586d3 | ||
|  | 011abe61e8 | ||
|  | fe3a37f89d | ||
|  | 8aea44e77b | ||
|  | 5529aec0d6 | ||
|  | 369549d23f | ||
|  | 181ea9a381 | ||
|  | 76b8f2854e | ||
|  | 320e5198f9 | ||
|  | e522539e2d | ||
|  | 7c996b83d2 | ||
|  | 3dd354d7aa | ||
|  | f4ad6e2157 | ||
|  | 8b170dc2bf | ||
|  | dcb9d779bf | ||
|  | 80f736d670 | ||
|  | 8502c6da3c | ||
|  | b131449422 | ||
|  | 6eebc4a620 | ||
|  | 4661ab1179 | ||
|  | 86046445ed | ||
|  | baea9bf944 | ||
|  | 0951ee9e63 | ||
|  | 5492528287 | ||
|  | 14dbd220c2 | ||
|  | babc890c59 | ||
|  | 6f7b47ff40 | ||
|  | 3991f03202 | ||
|  | 27271d5da7 | ||
|  | 627312e1de | ||
|  | bfc9550e4e | ||
|  | 2b9c21268b | ||
|  | 3dce4ed6f1 | ||
|  | 0f16c2ea87 | ||
|  | 9a635f0686 | ||
|  | 6a0d4b2baa | ||
|  | ac017098ad | ||
|  | 98fef2640d | ||
|  | 8bb66e133a | ||
|  | 68a582901d | ||
|  | c094f4c06e | ||
|  | f7ca545544 | ||
|  | 69b4716894 | ||
|  | 7e44dcc5bf | ||
|  | ab9843e183 | ||
|  | 01af706ade | ||
|  | 9ebdb08e99 | ||
|  | a74ffe25d9 | ||
|  | 7f95e27707 | ||
|  | 1facf5bba3 | ||
|  | 03d77009eb | ||
|  | 8afd6812b5 | ||
|  | ec9ad78fcf | ||
|  | 6f4e93dc90 | ||
|  | a38e43862d | ||
|  | 39294bb037 | ||
|  | edc5e59b78 | ||
|  | c00fd9fd37 | ||
|  | b3e621dd9f | ||
|  | 6e8c49b978 | ||
|  | 398d57133d | ||
|  | 16521a6feb | ||
|  | 3ca0b37a3e | ||
|  | cf2ec1229d | ||
|  | fe9b1e5f9b | ||
|  | f5b96ddf01 | ||
|  | 2fe076fb27 | ||
|  | 99249cff04 | ||
|  | 0cdf7b0613 | ||
|  | 90bcf4f157 | ||
|  | 03c3ec4e12 | ||
|  | ca9bb20d64 | ||
|  | c6bc078fd9 | ||
|  | 2f4bd6e52c | ||
|  | 2affe53727 | ||
|  | 09654d7dd8 | ||
|  | 90a4e37815 | ||
|  | 60889c0c79 | ||
|  | 20f3408d96 | ||
|  | e9d86789db | ||
|  | 5152b7c66c | ||
|  | c494c4e12c | ||
|  | 54d58ccb7e | ||
|  | 714a77bfbe | ||
|  | d48f8bf5cc | ||
|  | 99d97754a6 | ||
|  | b9d437de2a | ||
|  | 11403f2019 | ||
|  | 1ca102d639 | ||
|  | 339ba55111 | ||
|  | 14ae59885a | ||
|  | e3ef54f99b | ||
|  | 001901f9a9 | ||
|  | 6a98f60e2e | ||
|  | 6f2e24c47d | ||
|  | aafa368923 | ||
|  | eb783cab4c | ||
|  | 6533aa865a | ||
|  | f1a1e1bc07 | ||
|  | 953f4838dd | ||
|  | 130b892d34 | ||
|  | 6ad525c77e | ||
|  | d0ca74ad27 | ||
|  | 9806f69b4d | ||
|  | 34d9b5e3d7 | ||
|  | 3bf5189d86 | ||
|  | 12e5b0681b | ||
|  | 8c0285d608 | ||
|  | 36558fa3b8 | ||
|  | 235f940cde | ||
|  | 803d61fcbc | ||
|  | ffbd7d8de4 | ||
|  | 4ed924d7c7 | ||
|  | 798dc9948b | ||
|  | 13515f7ee4 | ||
|  | ef80824c26 | ||
|  | c8503fd65e | ||
|  | b3c454fb1c | ||
|  | 1d7723e873 | ||
|  | 77100b2365 | ||
|  | 259a788134 | ||
|  | 39511455cb | ||
|  | b04c16178e | ||
|  | 49a959c06e | ||
|  | 096a8932b4 | ||
|  | e39e66df93 | ||
|  | 513633f49a | ||
|  | eb3740daaf | ||
|  | f7947b148a | ||
|  | 9a2a702f3f | ||
|  | c65d95bf29 | ||
|  | 753a5edc4f | ||
|  | 0b3f853c2d | ||
|  | 3527fcf1d5 | ||
|  | 4544a89c7a | ||
|  | ffeae9005e | ||
|  | 47217bcfb7 | ||
|  | 80ff58b57a | ||
|  | d15dd368f1 | ||
|  | 8a2ec32bd8 | ||
|  | 410496ed52 | ||
|  | b7b07552e5 | ||
|  | 44486e80d9 | ||
|  | 7890c527d8 | ||
|  | 2c82ab79a7 | ||
|  | e3ebe5fc53 | ||
|  | 0ac430892e | ||
|  | a7739c942c | ||
|  | 24581482d0 | ||
|  | 0571c3b453 | ||
|  | 73e7f5a0b0 | ||
|  | 20c0adb961 | ||
|  | a01e03562f | ||
|  | d184ed0130 | ||
|  | 089e1c2aee | ||
|  | ebab0e91ee | ||
|  | 858a2b1b88 | ||
|  | 02bd59827c | ||
|  | 4991428510 | ||
|  | 3b245f5dc1 | ||
|  | c9c81da901 | ||
|  | 4919cdc3fb | ||
|  | e90e1f577d | ||
|  | afd4284403 | ||
|  | 150b350d31 | ||
|  | 2818520bd1 | ||
|  | 2819952292 | ||
|  | 5af71af51c | ||
|  | 07a55b51df | ||
|  | 66dd68b49d | ||
|  | 9812657777 | ||
|  | 0b09312fc6 | ||
|  | d0a7ac6b74 | ||
|  | ff9a238fbd | ||
|  | 359fffa5f1 | ||
|  | 5bf92ced1a | ||
|  | 340bcc7b45 | ||
|  | ef03742bd4 | ||
|  | 20431ec16d | ||
|  | becba8157b | ||
|  | 51fd3bb0eb | ||
|  | 4bbd3acb4e | ||
|  | 3bc930ea7b | ||
|  | d1b26f8e86 | ||
|  | fdf15caaff | ||
|  | c7b4a53c0b | ||
|  | af78dc0308 | ||
|  | 5ad39493c4 | ||
|  | 61f597b408 | ||
|  | 2162825240 | ||
|  | 2b780e70d1 | ||
|  | a3823f818e | ||
|  | 1f7c47bcaf | ||
|  | ec53c365a2 | ||
|  | 793ad1f2d4 | ||
|  | 9bc733b76c | ||
|  | 21b28f0217 | ||
|  | d3e23caa52 | ||
|  | 9e7518de67 | ||
|  | 679f0047aa | ||
|  | d77d5ce14b | ||
|  | 33ec22a2af | ||
|  | 353053225f | ||
|  | b7f3d6f7f7 | ||
|  | e34577499d | ||
|  | 4cf8960c0c | ||
|  | 1f93ea0675 | ||
|  | 25b705c3a8 | ||
|  | 0725588731 | ||
|  | fc5c61cc8b | ||
|  | ac282e63c6 | ||
|  | c3941941ce | ||
|  | 46cdd53323 | ||
|  | 3ff3e302c3 | ||
|  | f2ceecf95c | ||
|  | 9314c7c881 | ||
|  | 54abb2c572 | ||
|  | 8fa3bdd025 | ||
|  | 5e7a308528 | ||
|  | 7952177786 | ||
|  | 9afbe49c84 | ||
|  | 9f06ba2db3 | ||
|  | fe55bfddcf | ||
|  | c0842e6444 | ||
|  | 3fed20d06a | ||
|  | 5e8f2e2c04 | ||
|  | e4df99ea84 | ||
|  | b3276f5f11 | ||
|  | 32667ca256 | ||
|  | bed122a170 | ||
|  | 14adc9b875 | ||
|  | a8778bbc5a | ||
|  | a54e641f44 | ||
|  | 5c99efe87a | ||
|  | 7da1d731ff | ||
|  | af9828e819 | ||
|  | 7a27136142 | ||
|  | 012ad2d423 | ||
|  | ef3bdbf4da | ||
|  | b3bb698f7b | ||
|  | 1ed5d1e4c1 | ||
|  | bdee01a03d | ||
|  | 458f7376d7 | ||
|  | cb3a00e027 | ||
|  | 482eb1f3fb | ||
|  | 6e0f638f5e | ||
|  | bab349047d | ||
|  | 28ea6b8de8 | ||
|  | 9d51bbdae8 | ||
|  | d622f79533 | ||
|  | 04c8515ad1 | ||
|  | 53bc4251d1 | ||
|  | a5a751f02f | ||
|  | 66ed5f82c4 | ||
|  | c802a9e6aa | ||
|  | 880f210946 | ||
|  | 4f9f7eb6a6 | ||
|  | f910c4a8e7 | ||
|  | 529686d965 | ||
|  | 84dfd1536f | ||
|  | 85dedc324c | ||
|  | d639237411 | ||
|  | 449aaf75f1 | ||
|  | b1fda66caa | ||
|  | 66a8e90fd9 | ||
|  | 37b487d191 | ||
|  | 6c59fe3577 | ||
|  | 1cbb70c992 | ||
|  | e06b39f882 | ||
|  | 2602b1493e | ||
|  | 989d14502d | ||
|  | f78a550282 | ||
|  | 54a1abb284 | ||
|  | 97b492a8e2 | ||
|  | 0873bd14a9 | ||
|  | eff6ba429a | ||
|  | 8c18064be4 | ||
|  | 44a1ac0cf3 | ||
|  | 28dc8d88dd | ||
|  | 2c0c2b64ba | ||
|  | bd3e0f5248 | ||
|  | cd52d98938 | ||
|  | 894c70e7f8 | ||
|  | 51d70c2edd | ||
|  | 7d4b355240 | ||
|  | 3b56193b98 | ||
|  | b16045b57d | ||
|  | 9e8b0fca5b | ||
|  | 35cf1b3b5b | ||
|  | 83f788af57 | ||
|  | 2ffe378d3f | ||
|  | 38b33a4a5e | ||
|  | 60bf9ed0a0 | ||
|  | 16adf4de1b | ||
|  | 80de983023 | ||
|  | 8703ca623f | ||
|  | 286253a73f | ||
|  | bd806a41df | ||
|  | b89c4e9002 | ||
|  | 6dbf31c0c3 | ||
|  | 060c45d8a1 | ||
|  | 33d3e82e4d | ||
|  | 4bb074514d | ||
|  | e3f8892003 | ||
|  | 9d00ad5f18 | ||
|  | dae4344850 | ||
|  | aa7f3fabe2 | ||
|  | f93434a8ce | ||
|  | 25dee56be9 | ||
|  | ce9a3f3797 | ||
|  | 11e384920a | ||
|  | a0a1f1e536 | ||
|  | 3b3d0ea9eb | ||
|  | 2f4d78286d | ||
|  | 677dc6f985 | ||
|  | d52057e732 | ||
|  | fa2a1cb1fb | ||
|  | 19a0fb04ad | ||
|  | 947352f2fe | ||
|  | adcbedb686 | ||
|  | 7732f92acd | ||
|  | ad8a001688 | ||
|  | 9121eada08 | ||
|  | 49bd4d25a2 | ||
|  | d80b4129c6 | ||
|  | 7edb4172d5 | ||
|  | c3a4677990 | ||
|  | 5cbb893a3b | ||
|  | f28a2a432b | ||
|  | 03b75a2d27 | ||
|  | 859fe69083 | ||
|  | f6f2205ddb | ||
|  | 0f9a03ef61 | ||
|  | 9aa417c084 | ||
|  | 7b70952f5d | ||
|  | edd3d07b49 | ||
|  | 5293d0a4ec | ||
|  | 3c8c7beae1 | ||
|  | 9c3ba9fdcd | ||
|  | fb1748fb0f | ||
|  | 0a109fbd03 | ||
|  | 5cf64db74e | ||
|  | 488cc94f36 | ||
|  | e15846bf79 | ||
|  | 752bd00674 | ||
|  | 7fadfcbe32 | ||
|  | 41141e75bb | ||
|  | 50f641e627 | ||
|  | c7883fd093 | ||
|  | 4fcb24b2b1 | ||
|  | 5003557935 | ||
|  | bdf1ba84da | ||
|  | b0b4def983 | ||
|  | cc184bbe9e | ||
|  | ad30c830aa | ||
|  | 1d791a8af4 | ||
|  | e63c51cd97 | ||
|  | f202e32908 | ||
|  | 26e1a08e82 | ||
|  | 4d5119d435 | ||
|  | 75e34ea62e | ||
|  | 0a183d6274 | ||
|  | 21d8060aea | ||
|  | 9cbe906f60 | ||
|  | 8ce4137399 | ||
|  | 5f8a139347 | ||
|  | 9bb009a3fe | ||
|  | 726d65923f | ||
|  | 8a6be4cb2d | ||
|  | 10b06beb8e | ||
|  | 81318c7968 | ||
|  | 47a2c1c6e5 | ||
|  | 39cee65c6b | ||
|  | 8582ec724e | ||
|  | b0139682e8 | ||
|  | d39c475a6d | ||
|  | 48f38354c6 | ||
|  | cd5a920ed5 | ||
|  | 71bc1f378d | ||
|  | 0ee6c31cff | ||
|  | af89a9971e | ||
|  | c718a8ef72 | ||
|  | 8c8ad0faf0 | ||
|  | 314d5bbb7f | ||
|  | 102255757a | ||
|  | 914067a0d0 | ||
|  | 06e3ae2536 | ||
|  | 7f9b252556 | ||
|  | 3d700e243f | ||
|  | bcfc78ce11 | ||
|  | 09241765d5 | ||
|  | 671c83c265 | ||
|  | 772d28b766 | ||
|  | c26fcea58d | ||
|  | 1e5e26dbff | ||
|  | 742fc54864 | ||
|  | 49738f43c0 | ||
|  | 9f85f61010 | ||
|  | 239f422039 | ||
|  | 67af3c37be | ||
|  | a9442385c4 | ||
|  | 8c9cd10b8b | ||
|  | 72542059dd | ||
|  | a843fc6d40 | ||
|  | 4beed60c08 | ||
|  | 4049c1e480 | ||
|  | 8449314da2 | ||
|  | 63ad057028 | ||
|  | e720464330 | ||
|  | 24036afef9 | ||
|  | c78fa1a1bc | ||
|  | faa8b9022c | ||
|  | 729bafef7a | ||
|  | 590b028632 | ||
|  | 8150d00f36 | ||
|  | 060065926f | ||
|  | 70babe8a28 | ||
|  | c36e09664f | ||
|  | a9672246f3 | ||
|  | ff571884e9 | ||
|  | 475138bceb | ||
|  | 4a8af199c2 | ||
|  | bdabf5db72 | ||
|  | 6a5f21b34e | ||
|  | d608be103c | ||
|  | 374bb5d18a | ||
|  | 031d6c25ff | ||
|  | 223fb7b075 | ||
|  | a746741971 | ||
|  | 120faf2a58 | ||
|  | 990bca0dc6 | ||
|  | 3406472db7 | ||
|  | 1bd733c9f6 | ||
|  | 238c7f982e | ||
|  | fcb81147cb | ||
|  | 1915b73783 | ||
|  | ee79e621fb | ||
|  | d203275a3b | ||
|  | 9e8a996222 | ||
|  | 0126b0b3ed | ||
|  | 458928612c | ||
|  | e33f88e28d | ||
|  | be570bbf9e | ||
|  | f59b4be110 | ||
|  | 37336e41be | ||
|  | d24a1a3f0a | ||
|  | f7258955bd | ||
|  | 2a1eae5d6f | ||
|  | 50ee0a4adb | ||
|  | 955a26584e | ||
|  | 1d3e407c8f | ||
|  | cb809c4596 | ||
|  | 53bbe2888e | ||
|  | 7246f476a5 | ||
|  | 0785d1c390 | ||
|  | 85d2c49d14 | ||
|  | 8b77d62b7f | ||
|  | 373058a32a | ||
|  | e6293c2c8c | ||
|  | eff181c959 | ||
|  | 54752c2305 | ||
|  | b4753c044f | ||
|  | 26493424ae | ||
|  | 0282fd1332 | ||
|  | b9a019a08b | ||
|  | 66f6a0e687 | ||
|  | 2dd1b9f97d | ||
|  | 89615f3045 | ||
|  | 7e46192f67 | ||
|  | e78d985cdf | ||
|  | e8c4bf56fe | ||
|  | e6aa7d323d | ||
|  | fca8e25929 | ||
|  | 8e8ac286b4 | ||
|  | 7d9770b9a2 | ||
|  | 1996230460 | ||
|  | de7897a864 | ||
|  | e2884dcdb7 | ||
|  | 544a53a42b | ||
|  | 2e4787bfc8 | ||
|  | 1829eeb171 | ||
|  | c7488e3c4a | ||
|  | 3bf9606383 | ||
|  | 4f43f18f0a | ||
|  | 5b7f197397 | ||
|  | 018141c97f | ||
|  | 4d7813e57c | ||
|  | 605c60208f | ||
|  | 884fafcc30 | ||
|  | 56baa90320 | ||
|  | 6bb20ee09e | ||
|  | 541356430c | ||
|  | 2f4d91fd69 | ||
|  | f58c5e6b30 | ||
|  | 0311d0132c | ||
|  | c946c97402 | ||
|  | 84a6f51318 | ||
|  | 24a1501b0d | ||
|  | 383b6f5fcc | ||
|  | 633dd7ff9b | ||
|  | 580624fad6 | ||
|  | a8190f7efa | ||
|  | dd2157534b | ||
|  | 38a90e7669 | ||
|  | 6bfc526dcd | ||
|  | aadb8a7405 | ||
|  | 27082bf77e | ||
|  | a2903c80cd | ||
|  | 9a77c5369c | ||
|  | 3c30741a19 | ||
|  | 7028ad4ec0 | ||
|  | 8de750c6aa | ||
|  | 04f98de9ee | ||
|  | a1a019784b | ||
|  | 4aeeae77bd | ||
|  | 651cfc2b78 | ||
|  | 2ef8af25e2 | ||
|  | 0b13852a5b | ||
|  | 13427578c9 | ||
|  | d89ca2087e | ||
|  | 8b0ea9fba6 | ||
|  | 9f0b653d5a | ||
|  | 659a339233 | ||
|  | 4c29f177a0 | ||
|  | d664e63d55 | ||
|  | 2493509dbe | ||
|  | 1c8b27f554 | ||
|  | 68297b7186 | ||
|  | 34dd8d0a91 | ||
|  | 81c44790d5 | ||
|  | d557b335cf | ||
|  | e2adc28cff | ||
|  | 0fef6a6ecc | ||
|  | f2fd4b8a1f | ||
|  | 95bd5605a8 | ||
|  | 497cca7eca | ||
|  | 54f78feedd | ||
|  | 76408e53ae | ||
|  | be19e74d30 | ||
|  | dac578a775 | ||
|  | 04732ce74b | ||
|  | a6c95a2374 | ||
|  | f68622abe9 | ||
|  | 83a9a7bdb2 | ||
|  | 6500afc0ca | ||
|  | c69b7ecc96 | ||
|  | 615ef1e2d2 | ||
|  | cf69a0cd7f | ||
|  | 06e892fb33 | ||
|  | e6c5dd6865 | ||
|  | 247efdebdb | ||
|  | 76f3792287 | ||
|  | 64d8e2c727 | ||
|  | ead0bd9cb0 | ||
|  | 66fc13b2ec | ||
|  | f3af4128b0 | ||
|  | 0e43107c87 | ||
|  | 1ee3e7997e | ||
|  | 50fd61d91f | ||
|  | e4cdc051a9 | ||
|  | 778e846e96 | ||
|  | a27759b647 | ||
|  | b75eceab41 | ||
|  | e748a5d5f4 | ||
|  | 99c5a3ae46 | ||
|  | 51da710f5a | ||
|  | 569d69b3d2 | ||
|  | 059a6b1d90 | ||
|  | 990af7548a | ||
|  | a38aefdfc8 | ||
|  | 3bcb12e7d1 | ||
|  | 7904ecb462 | ||
|  | 9ba4d45109 | ||
|  | 56b8afe19d | ||
|  | f7aed9a94c | ||
|  | e12a7e881d | ||
|  | 5afb65325d | ||
|  | 135f520f32 | ||
|  | bc251f4ff6 | ||
|  | b8769751f6 | ||
|  | eff96d839e | ||
|  | aa34c23807 | ||
|  | 195acdac8c | ||
|  | 903e03c56c | ||
|  | 0892767b8a | ||
|  | 83ebfa772c | ||
|  | 1583641322 | ||
|  | 9510e2c256 | ||
|  | a9dbabe07e | ||
|  | 12884008fa | ||
|  | 02543bad1c | ||
|  | a8c56a5251 | ||
|  | 4e5a855f3f | ||
|  | 7e497a951e | ||
|  | cd08eabbfa | ||
|  | f7e62d9f81 | ||
|  | 9a3761e86e | ||
|  | 3619a68693 | ||
|  | efaf3c3bf9 | ||
|  | 0e4e6a6f67 | ||
|  | 42458e6278 | ||
|  | 41ec995377 | ||
|  | 4f37599326 | ||
|  | 4144520e5c | ||
|  | 6c4800546c | ||
|  | 733733c8a7 | ||
|  | 2aa67cc946 | ||
|  | 9385981a9d | ||
|  | fff780035d | ||
|  | 46127e673d | ||
|  | 70df59b224 | ||
|  | 0fdbaa803f | ||
|  | 6af1830eff | ||
|  | 6f860e2bd5 | ||
|  | 20a492f7ee | ||
|  | 63875e7591 | ||
|  | 0ad98cabde | ||
|  | 668879d2e1 | ||
|  | 2e09783302 | ||
|  | 49734114b3 | ||
|  | 950d9d6ee7 | ||
|  | f7974aee2e | ||
|  | c870a82621 | ||
|  | 984929a001 | ||
|  | 7f9e2c1db8 | ||
|  | 324e8389dc | ||
|  | 6f448c5a38 | ||
|  | ec43efbb20 | ||
|  | 3ed065de37 | ||
|  | 8152f0d72c | ||
|  | f8047f4736 | ||
|  | b93c66dc2d | ||
|  | ac877b3065 | ||
|  | dee8abfdde | ||
|  | cef3841d73 | ||
|  | 3cd5e8a041 | ||
|  | 515b5f866e | ||
|  | 321f62bf92 | ||
|  | f94fa47b52 | ||
|  | c502f8a722 | ||
|  | 59b4868ac3 | ||
|  | 3634e12cce | ||
|  | 6d45445391 | ||
|  | 4f47e268cc | ||
|  | 0035b31cdb | ||
|  | f2565aee03 | ||
|  | 5bd85668dd | ||
|  | 20f990b6ce | ||
|  | 6821379586 | ||
|  | 73b040eb49 | ||
|  | 49aa4b2e1e | ||
|  | 972241c74c | ||
|  | 680750e3c2 | ||
|  | 5e7d4d9d15 | ||
|  | 1e57e60613 | ||
|  | 3ac7ce605a | ||
|  | b720dea9f0 | ||
|  | c80722aefe | ||
|  | a84fa69f28 | ||
|  | e33781e59f | ||
|  | 8824bc7ece | ||
|  | c2e3b0e448 | ||
|  | f61a38e85a | ||
|  | d23e948216 | ||
|  | 58bdaa31f0 | ||
|  | b6491d88a6 | ||
|  | f6061ba62e | ||
|  | 427899ddce | ||
|  | c4ab7d2dbd | ||
|  | 0fd2ba033f | ||
|  | ed38939a93 | ||
|  | c7ee26ce5a | ||
|  | 909b8cb303 | ||
|  | b0277370cf | ||
|  | 2ec8656bea | ||
|  | b2ef256910 | ||
|  | 63d6ce95db | ||
|  | a9532b189c | ||
|  | 844545411f | ||
|  | 4e23a2b9b8 | ||
|  | 5deba027eb | ||
|  | fc8b7efc6f | ||
|  | a1c2d9c0f3 | ||
|  | 4ca49a0501 | ||
|  | 493c53d090 | ||
|  | b27e956d35 | ||
|  | 35ebed75c6 | ||
|  | 7bfdb5f77f | ||
|  | 8d8c02317f | ||
|  | a34482feab | ||
|  | cbdc8fd4a6 | ||
|  | 8d3afaa53c | ||
|  | 7ced9ef3df | ||
|  | e8a9ae7e80 | ||
|  | 73a88ab3d3 | ||
|  | aaed82738a | ||
|  | de7f7b96db | ||
|  | 1a669b3e68 | ||
|  | 333af9b13a | ||
|  | a5bca5e240 | ||
|  | c885633e02 | ||
|  | ca7e20b7ca | ||
|  | 545e11a3d7 | ||
|  | 44f5287664 | ||
|  | cf510897f1 | ||
|  | 1d171345f8 | ||
|  | 4fa7e1cd49 | ||
|  | acd008298e | ||
|  | 83a8021515 | ||
|  | cf88dfb1db | ||
|  | 8937c4b481 | ||
|  | cc6af10a4d | ||
|  | 6d94578955 | ||
|  | 08442ab71e | ||
|  | 10d91d213f | ||
|  | b7a3b06994 | ||
|  | 5f12c37f23 | ||
|  | 585edebccd | ||
|  | 9921c62234 | ||
|  | 1ac76d2e16 | ||
|  | 6e983bf400 | ||
|  | 6a8fd4fa6e | ||
|  | 3698eaa2d2 | ||
|  | 8d97ca433c | ||
|  | 23cc65e537 | ||
|  | 2f5a3c2bbe | ||
|  | f6485616cd | ||
|  | 6544fb43d9 | ||
|  | a954b32dcc | ||
|  | 426dc7836c | ||
|  | ff941ffc16 | ||
|  | a063c201df | ||
|  | e2be3fa0aa | ||
|  | 609da6fb50 | ||
|  | fc9f3ccec3 | ||
|  | f7baa67a0a | ||
|  | e8d78c2cdb | ||
|  | 9d33366092 | ||
|  | f5d61515c2 | ||
|  | 711a04a972 | ||
|  | e5b470a3f1 | ||
|  | 31820e1e22 | ||
|  | 4849e8cd6d | ||
|  | 77e3b460aa | ||
|  | b5321001f8 | ||
|  | 38eba9f5ea | ||
|  | ea6f399454 | ||
|  | f8bf2d7b7d | ||
|  | c4856caebb | ||
|  | fc1030bb22 | ||
|  | 9eb6cad8dc | ||
|  | 0fa2a78dce | ||
|  | a56fa1558b | ||
|  | 261c73a997 | ||
|  | 929c1333ca | ||
|  | 286a79d94d | ||
|  | 8b951f99da | ||
|  | abb449bca0 | ||
|  | bd084028d1 | ||
|  | 138a27570b | ||
|  | c2ed40a74f | ||
|  | a7e7a00cab | ||
|  | 64a31ab3cd | ||
|  | 71958bc0f1 | ||
|  | 366ec35612 | ||
|  | 3738f6e8ae | ||
|  | 051a8e2af1 | ||
|  | 2f43f28d5e | ||
|  | b64769754b | ||
|  | a97daa18d1 | ||
|  | b6556dce8b | ||
|  | aa8d8bc8b5 | ||
|  | 0800dcfdc4 | ||
|  | 12b0101e94 | ||
|  | 021b391a02 | ||
|  | d11e2b6057 | ||
|  | 264d90e7e5 | ||
|  | f9f3da9e78 | ||
|  | 6435b49153 | ||
|  | f9aa2941cf | ||
|  | 5a933d4bee | ||
|  | 5536aea0df | ||
|  | 976666d216 | ||
|  | 9a5bcd4392 | ||
|  | 812060a118 | ||
|  | 089b5052e6 | ||
|  | 874e5d72f4 | ||
|  | 6b11de1329 | ||
|  | 2245a7ad8d | ||
|  | ee5ec1b870 | ||
|  | 74ccfe851b | ||
|  | e1c24bd5a2 | ||
|  | 1349b79728 | ||
|  | d294d7604c | ||
|  | 01df2cf464 | ||
|  | 45b7322488 | ||
|  | b3055e992f | ||
|  | 3da548565c | ||
|  | a975e85548 | ||
|  | c4b5ade752 | ||
|  | a4b61b0794 | ||
|  | f6011184b8 | ||
|  | 74de118c6e | ||
|  | 9c25e77c17 | ||
|  | 440113e67e | ||
|  | a11b60c445 | ||
|  | a6052681ad | ||
|  | 482d50536a | ||
|  | 25c79a4fcd | ||
|  | 02946144ac | ||
|  | 71a360e9a3 | ||
|  | f7912d88b1 | ||
|  | 975101d7d2 | ||
|  | ef58c5ff55 | ||
|  | e10221804a | ||
|  | 284ed9ee0e | ||
|  | 5d7b961997 | ||
|  | c699a5c4b4 | ||
|  | 1f4ceb89cf | ||
|  | 0934ca0040 | ||
|  | 4738f892c2 | ||
|  | 33004fcf33 | ||
|  | 34d214c166 | ||
|  | a56cd92a1e | ||
|  | 7251348507 | ||
|  | 01cd5c84d6 | ||
|  | e210599fa6 | ||
|  | dbe7cee7e9 | ||
|  | 7370d88ceb | ||
|  | 34458e0c57 | ||
|  | 05c8c3abf2 | ||
|  | e9d464b4d3 | ||
|  | 6968c3ab9b | ||
|  | 131a8a9650 | ||
|  | 379ecbf9a9 | ||
|  | 7b9dfa9a28 | ||
|  | fbd0f5eed2 | ||
|  | 5970f904ae | ||
|  | 8cbcb2868d | ||
|  | 8ff2a4b026 | ||
|  | ae14d205a5 | ||
|  | ec5d560ec5 | ||
|  | fb543b53c0 | ||
|  | 39c16422e2 | ||
|  | 4d5b273ebe | ||
|  | ed6a860fad | ||
|  | 423e579292 | ||
|  | ee11aa9e75 | ||
|  | c46d20fa92 | ||
|  | dc8d17574c | ||
|  | 5c17cd04c8 | ||
|  | 67ada02076 | ||
|  | 32d94c2eaf | ||
|  | 687b39a12a | ||
|  | 705af407bf | ||
|  | 080052da2e | ||
|  | ef735fd92a | ||
|  | 17c16dcafc | ||
|  | a89b3018fb | ||
|  | 851e2ebd32 | ||
|  | 1225ce7fe8 | ||
|  | 7e77a31b96 | ||
|  | d146b9002f | ||
|  | 1f9d567b23 | ||
|  | ed1b3a023c | ||
|  | 1ca18f501a | ||
|  | 49588ccd98 | ||
|  | 098dedc092 | ||
|  | b06f6b9545 | ||
|  | ba3cb94999 | ||
|  | 74c67fbf4b | ||
|  | 32b46e4910 | ||
|  | ecf5539ed2 | ||
|  | ac9db4e4d5 | ||
|  | 0eb96094b0 | ||
|  | 30b3ac7dc5 | ||
|  | 0092790c7d | ||
|  | 28909d8a51 | ||
|  | b20cfbb7b6 | ||
|  | 97639bd0a8 | ||
|  | 161ec73c96 | ||
|  | 957d6bea15 | ||
|  | f8b6e5b414 | ||
|  | 1ab450870e | ||
|  | de45f4884c | ||
|  | 5da1f3e7c8 | ||
|  | 983014952b | ||
|  | 55298019a3 | ||
|  | a1ffc3f271 | ||
|  | 2fb60aa997 | ||
|  | f5ec76537a | ||
|  | 728491fd2b | ||
|  | d9d3f2b9e4 | ||
|  | 3fe4864f65 | ||
|  | 0b156f22a4 | ||
|  | 35b1d93813 | ||
|  | d770851ac0 | ||
|  | 989e7b1033 | ||
|  | c4e0eb7b49 | ||
|  | 71f5d0dac7 | ||
|  | 561b0c4381 | ||
|  | 995fbc7330 | ||
|  | 10ab8949c4 | ||
|  | c441202fea | ||
|  | ca261b0bee | ||
|  | 52f3709f67 | ||
|  | c2ca6187fe | ||
|  | 671a13d295 | ||
|  | 14c3e2eccf | ||
|  | 08e5b852c2 | ||
|  | 1c9606c824 | ||
|  | 3cd47b5c9b | ||
|  | aedc729087 | ||
|  | 5f7cfa3fa9 | ||
|  | 0083f30af5 | ||
|  | 4a06f05ef5 | ||
|  | 8f37cadce8 | ||
|  | a11603ca6c | ||
|  | 86274842e9 | ||
|  | cf9c955a44 | ||
|  | 55d828c35f | ||
|  | cdff28aca6 | ||
|  | b9da39274f | ||
|  | c379aa5782 | ||
|  | 9dcabac9dd | ||
|  | 794f3a2b9f | ||
|  | 2066121b7c | ||
|  | 0c4067f143 | ||
|  | 8aa69243b7 | ||
|  | 8697263bde | ||
|  | ea25c4f65c | ||
|  | 82ac3ebd7e | ||
|  | 13cb94909c | ||
|  | b57ca2a763 | ||
|  | 83c49e9745 | ||
|  | e15771d78d | ||
|  | 6edc4920ba | ||
|  | 302bb1bd93 | ||
|  | 529b1bceee | ||
|  | 42cd47d32e | ||
|  | 711d884c2e | ||
|  | 183d1c4674 | ||
|  | faed63a0bb | ||
|  | 53bff262f8 | ||
|  | 3251a708e4 | ||
|  | b5dbdbf7b2 | ||
|  | a9649e92c9 | ||
|  | b561f1fa8b | ||
|  | cecd7491b5 | ||
|  | 55a66322b5 | ||
|  | 155c31a2d7 | ||
|  | a89ce91089 | ||
|  | b897fe6700 | ||
|  | 548a351b06 | ||
|  | 4b1da57ca1 | ||
|  | 529aec7f25 | ||
|  | 1661e545cb | ||
|  | ec71d08878 | ||
|  | ac258b7dd7 | ||
|  | 0f57876233 | ||
|  | 1d25a3693d | ||
|  | 45fa428bf1 | ||
|  | 177fa80f1a | ||
|  | 3261261bfe | ||
|  | d4de7934f8 | ||
|  | c3475af809 | ||
|  | b12f707812 | ||
|  | 22c0c34d60 | ||
|  | a60b66f230 | ||
|  | 83f6e93628 | ||
|  | 222b5f0229 | ||
|  | 30aa383e26 | ||
|  | 676b401294 | ||
|  | ebf57159de | ||
|  | 199d2aafec | ||
|  | 81952f56fd | ||
|  | c5bac82b43 | ||
|  | 081b86109c | ||
|  | 8ac2028a75 | ||
|  | 264fed1c9f | ||
|  | dd59f7b2c7 | ||
|  | 9245a760db | ||
|  | b61b32bbc3 | ||
|  | 09b3914f5d | ||
|  | fe644e4c9e | ||
|  | 7b09bf2156 | ||
|  | 987d0aae66 | ||
|  | 9cbcbc1c22 | ||
|  | cfc4e2bc60 | ||
|  | a03405fa81 | ||
|  | d5c9ccbe6e | ||
|  | e52772d65f | ||
|  | 1e3259e728 | ||
|  | e905a20a60 | ||
|  | 88e2be7a33 | ||
|  | 8939131600 | ||
|  | ba37ebff8b | ||
|  | 28f4cb7e07 | ||
|  | db1e7102cd | ||
|  | 07eb7a5830 | ||
|  | b7c6c685fa | ||
|  | 212134df70 | ||
|  | 6eeb5528f5 | ||
|  | 54fad845c9 | ||
|  | d6c0de6fc7 | ||
|  | 649c8649f7 | ||
|  | da2f53d1b1 | ||
|  | 405139e3b8 | ||
|  | 4f8d347171 | ||
|  | bf0db4876c | ||
|  | 47a14884d6 | ||
|  | 3a7bbc8b08 | ||
|  | 1b1d65372c | ||
|  | fd2faaa16e | ||
|  | 0609cdb9ea | ||
|  | d3bb140f89 | ||
|  | b31dc66628 | ||
|  | 09476171a6 | ||
|  | 33dee813b5 | ||
|  | bb4e73c40b | ||
|  | b1f23ffa94 | ||
|  | b0e8cec1e7 | ||
|  | 5077ae19bc | ||
|  | 0d8447bf59 | ||
|  | c6cf08a274 | ||
|  | dc49ae519e | ||
|  | 904539476a | ||
|  | 3fbf02dc82 | ||
|  | c9392a840d | ||
|  | d164e8ab72 | ||
|  | 6dc62c9fb6 | ||
|  | 87a9684d66 | ||
|  | 94525e2f44 | ||
|  | b408b1b3b9 | ||
|  | 27c2f09e32 | ||
|  | 19bc4d3349 | ||
|  | f2b6c424d6 | ||
|  | a49d4453e9 | ||
|  | 65e50087b9 | ||
|  | 2d90f759d9 | ||
|  | 4230ac7674 | ||
|  | d96e9182e9 | ||
|  | 68c87b9616 | ||
|  | 7f8e9a0b6d | ||
|  | 81a229f2a5 | ||
|  | 8be7ae2733 | ||
|  | 846bca4cb1 | ||
|  | f36f353789 | ||
|  | 939a2731ed | ||
|  | 835dab97ff | ||
|  | fa904b53be | ||
|  | 0ec52dddce | ||
|  | c289355a3a | ||
|  | 02a13a5a18 | ||
|  | 6cf2a0281b | ||
|  | 120d35f9af | ||
|  | 2b15d5e7b3 | ||
|  | fc167bd3f0 | ||
|  | 91b04abf05 | ||
|  | 77faac8740 | ||
|  | 43b3d54855 | ||
|  | 69e9b85700 | ||
|  | 0b6d132759 | ||
|  | 7c233c6c0c | ||
|  | c35b290fa4 | ||
|  | 3d95cfb367 | ||
|  | b90fc3a56e | ||
|  | 1ef3fdccf5 | ||
|  | 02b7f77bd8 | ||
|  | 0ac7ead922 | ||
|  | da9d0e03ce | ||
|  | 120f65f672 | ||
|  | 200a14caa4 | ||
|  | 35bf6da8e2 | ||
|  | f08f70276c | ||
|  | 1ae50fd95b | ||
|  | 40512beb47 | ||
|  | 0d7f9b2c94 | ||
|  | 52f42140a7 | ||
|  | 3f6c50297f | ||
|  | f72d80afc5 | ||
|  | 7c5cb13b22 | ||
|  | d728750eb2 | ||
|  | 02a70e5667 | ||
|  | 44e51ea5fa | ||
|  | 87e201460a | ||
|  | 039bd945e2 | ||
|  | e9e52d2b4b | ||
|  | 2bf92e7399 | ||
|  | 5b0df241f0 | ||
|  | 76f5b05eff | ||
|  | 40fb6c998f | ||
|  | 33f50a342d | ||
|  | 81523ab68a | ||
|  | 2bf8cc62cf | ||
|  | 1ae8247af3 | ||
|  | 5ef32227ec | ||
|  | 6456e773bd | ||
|  | 234fe53ca3 | ||
|  | 7c93e7a7b3 | ||
|  | 8afc6c7f4b | ||
|  | 4609d0fa3a | ||
|  | d452c035c6 | ||
|  | 45113c8f5a | ||
|  | 0acdd3c62b | ||
|  | 96d7d0a33e | ||
|  | b6b280267b | ||
|  | 6e6d253b1a | ||
|  | d92c105db2 | ||
|  | 906db728d6 | ||
|  | c4b7411565 | ||
|  | de06396046 | ||
|  | ee6bfeb8e3 | ||
|  | 058347321f | ||
|  | feefe49324 | ||
|  | 187381a9a2 | ||
|  | 993dfa4368 | ||
|  | 7e35a16440 | ||
|  | e4eeb15926 | ||
|  | 634e0db26d | ||
|  | 56855c23e1 | ||
|  | 0b00f742e3 | ||
|  | b7ab3f673c | ||
|  | be04ea1e35 | ||
|  | 1f8e695802 | ||
|  | 2d82b2c64f | ||
|  | d076caf473 | ||
|  | c7abdefa31 | ||
|  | ba772c0bca | ||
|  | 5bad234119 | ||
|  | c7e7baaf23 | ||
|  | 36658a671b | ||
|  | 045f2e10ba | ||
|  | fb5a7db66d | ||
|  | ba7d33982e | ||
|  | c62279a755 | ||
|  | 17fa1a7ffb | ||
|  | e89ceac351 | ||
|  | 0b8c30c109 | ||
|  | 9ab0f463cc | ||
|  | 6433dda7b8 | ||
|  | fa7a2f4be4 | ||
|  | ba90e16505 | ||
|  | 008f710203 | ||
|  | df2740f126 | ||
|  | 2db89d143e | ||
|  | 0525d49da3 | ||
|  | e2b0745882 | ||
|  | 92e804fc50 | ||
|  | 67abf45576 | ||
|  | d2c9c814e7 | ||
|  | 22f8881a64 | ||
|  | 4ab20322fe | ||
|  | 5370eeecea | ||
|  | ba71cb5dd7 | ||
|  | 9aad6c2c52 | ||
|  | 4d9627f20c | ||
|  | c142492e91 | ||
|  | 6bf8d9e207 | ||
|  | 4f9a6168c1 | ||
|  | 38397f99aa | ||
|  | f8686d0e75 | ||
|  | 549e3c8f9d | ||
|  | bb56225b95 | ||
|  | f00be261ba | ||
|  | 9cd94f26d0 | ||
|  | 4d8f5c80a7 | ||
|  | 24a23acc3d | ||
|  | ca8703cfd8 | ||
|  | 6dcbb5b2f8 | ||
|  | a84fdddb2a | ||
|  | 38bb2f8ceb | ||
|  | 23f5ef4345 | ||
|  | ef8a2a9054 | ||
|  | 96103d0e36 | ||
|  | ff5f6748df | ||
|  | 1c1fd6c366 | ||
|  | 32d37d00cb | ||
|  | 82f6cda966 | ||
|  | f1ff8ff0d0 | ||
|  | 756c72902f | ||
|  | 73f8f0bbd0 | ||
|  | 18ed528f5d | ||
|  | 8fd2f136bc | ||
|  | 0524b1bf67 | ||
|  | 15716f65ce | ||
|  | d46bdba332 | ||
|  | 760728110a | ||
|  | 12d0a194ca | ||
|  | 4104543508 | ||
|  | 5c211db015 | ||
|  | 2dc6180f8d | ||
|  | e222a34b69 | ||
|  | ef17d95063 | ||
|  | 853502e5d7 | ||
|  | c18e297e77 | ||
|  | c5a49599ba | ||
|  | df9da9edf5 | ||
|  | e2200fd050 | ||
|  | c6207f5d9c | ||
|  | 4302b7ff6b | ||
|  | 50a7923438 | ||
|  | ab416445c8 | ||
|  | a54698d43c | ||
|  | c5a77cc1c0 | ||
|  | a9ffa811fc | ||
|  | 080a2608e0 | ||
|  | 57f2e83d6a | ||
|  | 5b030139d3 | ||
|  | 0da1ff42d1 | ||
|  | 2c599b7baa | ||
|  | 5c8af8d21a | ||
|  | 026f3cfde2 | ||
|  | f6349180e8 | ||
|  | aa6421921c | ||
|  | 7d41d2dab2 | ||
|  | f0b4d18f93 | ||
|  | 6750f06e10 | ||
|  | b2bd38fa9e | ||
|  | 3482a01e22 | ||
|  | 6335467552 | ||
|  | 4a39e65b62 | ||
|  | c50a23e918 | ||
|  | 1e76b72b98 | ||
|  | b94cf39eef | ||
|  | fef254ffff | ||
|  | e5495863a2 | ||
|  | 3b4df2abf0 | ||
|  | aef2aee6a4 | ||
|  | d0d9519149 | ||
|  | 685df1d2c5 | ||
|  | 08e6b6f2e7 | ||
|  | 66c887d0f3 | ||
|  | 22e9960697 | ||
|  | 64aa6e1f2d | ||
|  | 7a93ed9d04 | ||
|  | a905e922e9 | ||
|  | f9f08fc720 | ||
|  | 8d402d76d0 | ||
|  | 46fda6281c | ||
|  | a14dbe1ea6 | ||
|  | 18810a4c16 | ||
|  | 147bc80dba | ||
|  | c7a484195a | ||
|  | 4968eb6503 | ||
|  | a6f2d698a9 | ||
|  | ea5ed93ea5 | ||
|  | e1140134c6 | ||
|  | 5ed11e012e | ||
|  | 5380bd39ca | ||
|  | 2ee2685688 | ||
|  | 782002245b | ||
|  | 7fc0905843 | ||
|  | 72ecb99e54 | ||
|  | c863507d08 | ||
|  | cff86c9093 | ||
|  | 0479dfcc54 | ||
|  | 68dd67f21c | ||
|  | 540f6858b5 | ||
|  | b61e791a4f | ||
|  | d0986f9482 | ||
|  | 112cb0dc28 | ||
|  | 0d3d7fdcf2 | ||
|  | 5d6b89ef3b | ||
|  | ed0b26c09e | ||
|  | ae292bd920 | ||
|  | 6c85a90723 | ||
|  | 852592066c | ||
|  | 96e1bc9b44 | ||
|  | b41d81ed31 | ||
|  | e241ec2244 | ||
|  | 16e1f1a94c | ||
|  | 7a68c42b26 | ||
|  | 37ccc2e118 | ||
|  | 4192fe1ab2 | ||
|  | d5c743d7bb | ||
|  | 11814d63e8 | ||
|  | b753656d50 | ||
|  | f7e87611fc | ||
|  | 1fb0e1900e | ||
|  | 954a9731e0 | ||
|  | 65c3364ad8 | ||
|  | 3d72b7dccc | ||
|  | 13ee569f06 | ||
|  | d79ef23a75 | ||
|  | 5d0797d4ba | ||
|  | 47a8d7475f | ||
|  | 4939053121 | ||
|  | b525bf554e | ||
|  | f00285d2b2 | ||
|  | 040f8d6eda | ||
|  | 66d905325c | ||
|  | 8b0cd95e73 | ||
|  | d867cca6d9 | ||
|  | a28f736369 | ||
|  | 5c3a71cc59 | ||
|  | cef6dadb08 | ||
|  | 36be817a3e | ||
|  | 02f571f081 | ||
|  | 157159e487 | ||
|  | 02ada9f800 | ||
|  | 6fcf9a97bb | ||
|  | 17a5d8799f | ||
|  | 31f3fe7a22 | ||
|  | 89e46d3d83 | ||
|  | 885795e67d | ||
|  | 92bfb53dd4 | ||
|  | 4cecbeb115 | ||
|  | 5971480f55 | ||
|  | 05bebea511 | ||
|  | 76fa6c5cfb | ||
|  | 633b68b518 | ||
|  | 6913d8e995 | ||
|  | f3654e6f8d | ||
|  | d685dbcf22 | ||
|  | 6a57fa079e | ||
|  | 0a91d145ba | ||
|  | c2866e799d | ||
|  | d8cffcaae7 | ||
|  | 30abca7be2 | ||
|  | edce87f3fb | ||
|  | 66bac98fc2 | ||
|  | 59156de92b | ||
|  | e0d7d10600 | ||
|  | daaf862257 | ||
|  | 9de53d4b59 | ||
|  | f1571e2d46 | ||
|  | bd28d06298 | ||
|  | a24e4655eb | ||
|  | 20a6c8d8e5 | ||
|  | 98d264faf4 | ||
|  | 321902a9b5 | ||
|  | 8df5d06f9a | ||
|  | e69ea529cc | ||
|  | 15405b1119 | ||
|  | d2f97ce2da | ||
|  | 543ca631e9 | ||
|  | f184886db1 | ||
|  | 8432ab4324 | ||
|  | 6c05b37ca3 | ||
|  | 35f4beeb47 | ||
|  | cbad7caa68 | ||
|  | b0388a4012 | ||
|  | df3fab4d55 | ||
|  | da49f88a03 | ||
|  | e28feceb06 | ||
|  | 50496a164d | ||
|  | 6f1dce1572 | ||
|  | 6847776ae7 | ||
|  | 67bd53bdd8 | ||
|  | e735abfdfd | ||
|  | 1de93a2d6d | ||
|  | 36f9e7c742 | ||
|  | 9462763bbb | ||
|  | 4ae0880ea6 | ||
|  | 6ae2b6c835 | ||
|  | a0f180fd48 | ||
|  | bf1cf89914 | ||
|  | 297a047fb4 | ||
|  | 52ffc15ffc | ||
|  | e478c9c693 | ||
|  | d004f28074 | ||
|  | bc68ed8b1d | ||
|  | 04555ae650 | ||
|  | e8f62085be | ||
|  | f430bffe2a | ||
|  | 1f0520634f | ||
|  | 902d4c31fb | ||
|  | 17364ac09f | ||
|  | 0b889f8f81 | ||
|  | 40e349ff35 | ||
|  | c943b1b1df | ||
|  | 912bc1d4e1 | ||
|  | cacb1533a3 | ||
|  | f0feaca9d7 | ||
|  | b6656f171b | ||
|  | 6206ab3931 | ||
|  | c35fc58b1f | ||
|  | deed8abed7 | ||
|  | 7151ad23f0 | ||
|  | 0166d938af | ||
|  | 6194aeddb0 | ||
|  | 903dbf2c30 | ||
|  | 9380f9ff57 | ||
|  | 259ed95486 | ||
|  | 2ebc92681e | ||
|  | 195a1ffe13 | ||
|  | a8c2978185 | ||
|  | 140f97a457 | ||
|  | 7f94445a1e | ||
|  | 82a89aec65 | ||
|  | 7e95110232 | ||
|  | ec4aaaad89 | ||
|  | 1b790fde24 | ||
|  | aaccea731e | ||
|  | 29e31d7610 | ||
|  | aa51f4a98f | ||
|  | e6ccd12f00 | ||
|  | b134315df1 | ||
|  | 7f34dffa13 | ||
|  | fa239e78c9 | ||
|  | 707a6c4d6a | ||
|  | e5da303b43 | ||
|  | 84ccd66331 | ||
|  | ad8cc2baea | ||
|  | 7c4cf70309 | ||
|  | c3211e9b4f | ||
|  | 268d94c983 | ||
|  | 0bcacbba58 | ||
|  | 8cdc26add9 | ||
|  | e0b2238886 | ||
|  | 369a2e4029 | ||
|  | c4089e3b51 | ||
|  | 9e2e9bc5b8 | ||
|  | a9e44426ed | 
							
								
								
									
										165
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										165
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,165 +0,0 @@ | ||||
| *.5 | ||||
| *.7 | ||||
| *.8 | ||||
| *.8_gen | ||||
| *.a | ||||
| *.d | ||||
| *.o | ||||
| *.orig | ||||
| *.pc | ||||
| *.pot | ||||
| *.pyc | ||||
| *.pyo | ||||
| *.rej | ||||
| *.so | ||||
| *.so.* | ||||
| *.sw* | ||||
| *.su | ||||
| *.patch | ||||
| *~ | ||||
|  | ||||
| # gcov files: | ||||
| *.gcda | ||||
| *.gcno | ||||
|  | ||||
| .export.sym | ||||
| .exported_symbols_generated | ||||
| .gdb_history | ||||
|  | ||||
| Makefile | ||||
| make.tmpl | ||||
|  | ||||
| /autom4te.cache/ | ||||
| /autoscan.log | ||||
| /build/ | ||||
| /config.cache | ||||
| /config.log | ||||
| /config.status | ||||
| /configure.scan | ||||
| /cscope.* | ||||
| /html/ | ||||
| /python/ | ||||
| /reports/ | ||||
| /tags | ||||
| /tmp/ | ||||
|  | ||||
| coverity/coverity_model.xml | ||||
|  | ||||
| /libdm/.symver_check | ||||
|  | ||||
| daemons/clvmd | ||||
| daemons/dmfilemapd | ||||
| daemons/lvmetad/ | ||||
|  | ||||
| tools/man-generator | ||||
|  | ||||
| test/.lib-dir-stamp | ||||
| test/.tests-stamp | ||||
| test/lib/dmsecuretest | ||||
| test/lib/lvchange | ||||
| test/lib/lvconvert | ||||
| test/lib/lvcreate | ||||
| test/lib/lvdisplay | ||||
| test/lib/lvextend | ||||
| test/lib/lvmconfig | ||||
| test/lib/lvmdiskscan | ||||
| test/lib/lvmsadc | ||||
| test/lib/lvmsar | ||||
| test/lib/lvreduce | ||||
| test/lib/lvremove | ||||
| test/lib/lvrename | ||||
| test/lib/lvresize | ||||
| test/lib/lvs | ||||
| test/lib/lvscan | ||||
| test/lib/pvchange | ||||
| test/lib/pvck | ||||
| test/lib/pvcreate | ||||
| test/lib/pvdisplay | ||||
| test/lib/pvmove | ||||
| test/lib/pvremove | ||||
| test/lib/pvresize | ||||
| test/lib/pvs | ||||
| test/lib/pvscan | ||||
| test/lib/securetest | ||||
| test/lib/vgcfgbackup | ||||
| test/lib/vgcfgrestore | ||||
| test/lib/vgchange | ||||
| test/lib/vgck | ||||
| test/lib/vgconvert | ||||
| test/lib/vgcreate | ||||
| test/lib/vgdisplay | ||||
| test/lib/vgexport | ||||
| test/lib/vgextend | ||||
| test/lib/vgimport | ||||
| test/lib/vgimportclone | ||||
| test/lib/vgmerge | ||||
| test/lib/vgmknodes | ||||
| test/lib/vgreduce | ||||
| test/lib/vgremove | ||||
| test/lib/vgrename | ||||
| test/lib/vgs | ||||
| test/lib/vgscan | ||||
| test/lib/vgsplit | ||||
| test/api/lvtest.t | ||||
| test/api/pe_start.t | ||||
| test/api/percent.t | ||||
| test/api/python_lvm_unit.py | ||||
| test/api/test | ||||
| test/api/thin_percent.t | ||||
| test/api/vglist.t | ||||
| test/api/vgtest.t | ||||
| test/lib/aux | ||||
| test/lib/cache-mq.profile | ||||
| test/lib/cache-smq.profile | ||||
| test/lib/check | ||||
| test/lib/clvmd | ||||
| test/lib/dm-version-expected | ||||
| test/lib/dmeventd | ||||
| test/lib/dmsetup | ||||
| test/lib/dmstats | ||||
| test/lib/fail | ||||
| test/lib/flavour-ndev-cluster | ||||
| test/lib/flavour-ndev-cluster-lvmpolld | ||||
| test/lib/flavour-ndev-devicesfile | ||||
| test/lib/flavour-ndev-lvmetad | ||||
| test/lib/flavour-ndev-lvmetad-lvmpolld | ||||
| test/lib/flavour-ndev-lvmpolld | ||||
| test/lib/flavour-ndev-vanilla | ||||
| test/lib/flavour-udev-cluster | ||||
| test/lib/flavour-udev-cluster-lvmpolld | ||||
| test/lib/flavour-udev-lvmetad | ||||
| test/lib/flavour-udev-lvmetad-lvmpolld | ||||
| test/lib/flavour-udev-lvmlockd-dlm | ||||
| test/lib/flavour-udev-lvmlockd-idm | ||||
| test/lib/flavour-udev-lvmlockd-sanlock | ||||
| test/lib/flavour-udev-lvmlockd-test | ||||
| test/lib/flavour-udev-lvmpolld | ||||
| test/lib/flavour-udev-vanilla | ||||
| test/lib/fsadm | ||||
| test/lib/get | ||||
| test/lib/inittest | ||||
| test/lib/invalid | ||||
| test/lib/lvm | ||||
| test/lib/lvm-wrapper | ||||
| test/lib/lvmchange | ||||
| test/lib/lvmdbusd.profile | ||||
| test/lib/lvmdevices | ||||
| test/lib/lvmetad | ||||
| test/lib/lvmlockctl | ||||
| test/lib/lvmlockd | ||||
| test/lib/lvmpolld | ||||
| test/lib/lvm_import_vdo | ||||
| test/lib/lvm_vdo_wrapper | ||||
| test/lib/not | ||||
| test/lib/paths | ||||
| test/lib/paths-common | ||||
| test/lib/runner | ||||
| test/lib/should | ||||
| test/lib/test | ||||
| test/lib/thin-performance.profile | ||||
| test/lib/utils | ||||
| test/lib/version-expected | ||||
| test/lib/vgimportdevices | ||||
|  | ||||
| test/unit/dmraid_t.c | ||||
| test/unit/unit-test | ||||
							
								
								
									
										104
									
								
								.gitlab-ci.yml
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								.gitlab-ci.yml
									
									
									
									
									
								
							| @@ -1,104 +0,0 @@ | ||||
| stages: | ||||
|   - approve | ||||
|   - test | ||||
|  | ||||
| approve1: | ||||
|   stage: approve | ||||
|   script: | ||||
|     - echo "Approved..." | ||||
|   rules: | ||||
|     # TODO: Filter only safe repositories, or user in developers | ||||
|     - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2" | ||||
|       when: manual | ||||
|     # TODO: for other branches than main/rhel: run pipeline only when requested: | ||||
|     - if: $CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH !~ "^rhel.*" | ||||
|       when: manual | ||||
|     - when: on_success | ||||
|   allow_failure: false | ||||
|  | ||||
|  | ||||
| pages: | ||||
|   image: elecnix/ikiwiki | ||||
|   stage: test | ||||
|   script: | ||||
|     - ikiwiki --setup ikiwiki.setup --libdir themes/ikistrap/lib | ||||
|   artifacts: | ||||
|     paths: | ||||
|       - public | ||||
|   only: | ||||
|     refs: | ||||
|       - main | ||||
|     changes: | ||||
|       - doc/**/* | ||||
|       - ikiwiki.setup | ||||
|  | ||||
|  | ||||
| # TODO: | ||||
| # - check results of autoreconf and make generate - may need additional commit | ||||
| #     - we need a particular setup (rawhide OR latest supported fedora?) | ||||
| # - do make rpm and publish results as artifacts - we will use packit/COPR for this eventually | ||||
|  | ||||
| # Run on any commits to main (master), rhel8, rhel9 branches | ||||
| test-job: | ||||
|   stage: test | ||||
|   parallel: | ||||
|     matrix: | ||||
|       - TAG: rhel8 | ||||
|         CONFIGURE: > | ||||
|           --with-cluster=internal | ||||
|           --enable-cmirrord | ||||
|       - TAG: rhel9 | ||||
|         CONFIGURE: > | ||||
|           --with-default-use-devices-file=1 | ||||
|           --enable-app-machineid | ||||
|           --enable-editline | ||||
|           --disable-readline | ||||
|   artifacts: | ||||
|     paths: | ||||
|       - test/results/ | ||||
|     expire_in: 1 week | ||||
|   tags: | ||||
|       - ${TAG} | ||||
|   timeout: 2h | ||||
|   script: | ||||
|     # Common options go here, diffs to the above matrix | ||||
|     - > | ||||
|       ./configure ${CONFIGURE} | ||||
|       --enable-fsadm | ||||
|       --enable-write_install | ||||
|       --enable-pkgconfig | ||||
|       --enable-cmdlib | ||||
|       --enable-dmeventd | ||||
|       --enable-blkid_wiping | ||||
|       --enable-udev_sync | ||||
|       --with-thin=internal | ||||
|       --with-cache=internal | ||||
|       --enable-lvmpolld | ||||
|       --enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol | ||||
|       --enable-lvmlockd-sanlock | ||||
|       --enable-dbus-service --enable-notify-dbus | ||||
|       --enable-dmfilemapd | ||||
|       --with-writecache=internal | ||||
|       --with-vdo=internal --with-vdo-format=/usr/bin/vdoformat | ||||
|       --with-integrity=internal | ||||
|       --disable-silent-rules | ||||
|     - make | ||||
|     - rm -rf test/results | ||||
|     - mkdir -p /dev/shm/lvm2-test | ||||
|     - mount -o remount,dev /dev/shm | ||||
|     # TODO: Need to distinguish failed test from failed harness | ||||
|     # TODO: Also need a way to find if run is incomplete, e.g. full disk resulting in many skipped tests | ||||
|     - VERBOSE=0 BATCH=1 LVM_TEST_DIR=/dev/shm/lvm2-test make check || true | ||||
|     - rm -rf /dev/shm/lvm2-test | ||||
|     - cut -d' ' -f2 test/results/list | sort | uniq -c | ||||
|     # Filter artifacts - keep only logs from tests which are not pass | ||||
|     - cd test/results && rm $(grep 'passed$' list | cut -d' ' -f1 | sed -e 's|/|_|g' -e 's|.*|\0.txt|') | ||||
|     # TODO: Keep a list of known failures, and translate into regexp - or simply use python... | ||||
|     - if grep failed test/results/list | grep -v '\\\(dbustest\|lvconvert-mirror\)\.sh' | sort; then false; else true; fi | ||||
|   rules: | ||||
|     # Filter only safe repositories, or user in developers: | ||||
|     # NOTE: Already done in approve stage, may be more caution than necessary | ||||
|     - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2" | ||||
|       when: manual | ||||
|     - when: on_success | ||||
|  | ||||
							
								
								
									
										4
									
								
								COPYING
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								COPYING
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| @@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|   | ||||
							
								
								
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| BSD 2-Clause License | ||||
|  | ||||
| Copyright (c) 2014, Red Hat, Inc. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		       Version 2.1, February 1999 | ||||
|  | ||||
|  Copyright (C) 1991, 1999 Free Software Foundation, Inc. | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1991 Free Software Foundation, Inc. | ||||
|  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| [This is the first released version of the Lesser GPL.  It also counts | ||||
|  as the successor of the GNU Library Public License, version 2, hence | ||||
|  the version number 2.1.] | ||||
| [This is the first released version of the library GPL.  It is | ||||
|  numbered 2 because it goes with version 2 of the ordinary GPL.] | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
| @@ -17,109 +17,97 @@ freedom to share and change it.  By contrast, the GNU General Public | ||||
| Licenses are intended to guarantee your freedom to share and change | ||||
| free software--to make sure the software is free for all its users. | ||||
|  | ||||
|   This license, the Lesser General Public License, applies to some | ||||
| specially designated software packages--typically libraries--of the | ||||
| Free Software Foundation and other authors who decide to use it.  You | ||||
| can use it too, but we suggest you first think carefully about whether | ||||
| this license or the ordinary General Public License is the better | ||||
| strategy to use in any particular case, based on the explanations below. | ||||
|   This license, the Library General Public License, applies to some | ||||
| specially designated Free Software Foundation software, and to any | ||||
| other libraries whose authors decide to use it.  You can use it for | ||||
| your libraries, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom of use, | ||||
| not price.  Our General Public Licenses are designed to make sure that | ||||
| you have the freedom to distribute copies of free software (and charge | ||||
| for this service if you wish); that you receive source code or can get | ||||
| it if you want it; that you can change the software and use pieces of | ||||
| it in new free programs; and that you are informed that you can do | ||||
| these things. | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| distributors to deny you these rights or to ask you to surrender these | ||||
| rights.  These restrictions translate to certain responsibilities for | ||||
| you if you distribute copies of the library or if you modify it. | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if | ||||
| you distribute copies of the library, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of the library, whether gratis | ||||
| or for a fee, you must give the recipients all the rights that we gave | ||||
| you.  You must make sure that they, too, receive or can get the source | ||||
| code.  If you link other code with the library, you must provide | ||||
| complete object files to the recipients, so that they can relink them | ||||
| with the library after making changes to the library and recompiling | ||||
| code.  If you link a program with the library, you must provide | ||||
| complete object files to the recipients so that they can relink them | ||||
| with the library, after making changes to the library and recompiling | ||||
| it.  And you must show them these terms so they know their rights. | ||||
|  | ||||
|   We protect your rights with a two-step method: (1) we copyright the | ||||
| library, and (2) we offer you this license, which gives you legal | ||||
|   Our method of protecting your rights has two steps: (1) copyright | ||||
| the library, and (2) offer you this license which gives you legal | ||||
| permission to copy, distribute and/or modify the library. | ||||
|  | ||||
|   To protect each distributor, we want to make it very clear that | ||||
| there is no warranty for the free library.  Also, if the library is | ||||
| modified by someone else and passed on, the recipients should know | ||||
| that what they have is not the original version, so that the original | ||||
| author's reputation will not be affected by problems that might be | ||||
| introduced by others. | ||||
|   Also, for each distributor's protection, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| library.  If the library is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original | ||||
| version, so that any problems introduced by others will not reflect on | ||||
| the original authors' reputations. | ||||
|  | ||||
|   Finally, software patents pose a constant threat to the existence of | ||||
| any free program.  We wish to make sure that a company cannot | ||||
| effectively restrict the users of a free program by obtaining a | ||||
| restrictive license from a patent holder.  Therefore, we insist that | ||||
| any patent license obtained for a version of the library must be | ||||
| consistent with the full freedom of use specified in this license. | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that companies distributing free | ||||
| software will individually obtain patent licenses, thus in effect | ||||
| transforming the program into proprietary software.  To prevent this, | ||||
| we have made it clear that any patent must be licensed for everyone's | ||||
| free use or not licensed at all. | ||||
|  | ||||
|   Most GNU software, including some libraries, is covered by the | ||||
| ordinary GNU General Public License.  This license, the GNU Lesser | ||||
| General Public License, applies to certain designated libraries, and | ||||
| is quite different from the ordinary General Public License.  We use | ||||
| this license for certain libraries in order to permit linking those | ||||
| libraries into non-free programs. | ||||
|   Most GNU software, including some libraries, is covered by the ordinary | ||||
| GNU General Public License, which was designed for utility programs.  This | ||||
| license, the GNU Library General Public License, applies to certain | ||||
| designated libraries.  This license is quite different from the ordinary | ||||
| one; be sure to read it in full, and don't assume that anything in it is | ||||
| the same as in the ordinary license. | ||||
|  | ||||
|   When a program is linked with a library, whether statically or using | ||||
| a shared library, the combination of the two is legally speaking a | ||||
| combined work, a derivative of the original library.  The ordinary | ||||
| General Public License therefore permits such linking only if the | ||||
| entire combination fits its criteria of freedom.  The Lesser General | ||||
| Public License permits more lax criteria for linking other code with | ||||
| the library. | ||||
|   The reason we have a separate public license for some libraries is that | ||||
| they blur the distinction we usually make between modifying or adding to a | ||||
| program and simply using it.  Linking a program with a library, without | ||||
| changing the library, is in some sense simply using the library, and is | ||||
| analogous to running a utility program or application program.  However, in | ||||
| a textual and legal sense, the linked executable is a combined work, a | ||||
| derivative of the original library, and the ordinary General Public License | ||||
| treats it as such. | ||||
|  | ||||
|   We call this license the "Lesser" General Public License because it | ||||
| does Less to protect the user's freedom than the ordinary General | ||||
| Public License.  It also provides other free software developers Less | ||||
| of an advantage over competing non-free programs.  These disadvantages | ||||
| are the reason we use the ordinary General Public License for many | ||||
| libraries.  However, the Lesser license provides advantages in certain | ||||
| special circumstances. | ||||
|   Because of this blurred distinction, using the ordinary General | ||||
| Public License for libraries did not effectively promote software | ||||
| sharing, because most developers did not use the libraries.  We | ||||
| concluded that weaker conditions might promote sharing better. | ||||
|  | ||||
|   For example, on rare occasions, there may be a special need to | ||||
| encourage the widest possible use of a certain library, so that it becomes | ||||
| a de-facto standard.  To achieve this, non-free programs must be | ||||
| allowed to use the library.  A more frequent case is that a free | ||||
| library does the same job as widely used non-free libraries.  In this | ||||
| case, there is little to gain by limiting the free library to free | ||||
| software only, so we use the Lesser General Public License. | ||||
|  | ||||
|   In other cases, permission to use a particular library in non-free | ||||
| programs enables a greater number of people to use a large body of | ||||
| free software.  For example, permission to use the GNU C Library in | ||||
| non-free programs enables many more people to use the whole GNU | ||||
| operating system, as well as its variant, the GNU/Linux operating | ||||
| system. | ||||
|  | ||||
|   Although the Lesser General Public License is Less protective of the | ||||
| users' freedom, it does ensure that the user of a program that is | ||||
| linked with the Library has the freedom and the wherewithal to run | ||||
| that program using a modified version of the Library. | ||||
|   However, unrestricted linking of non-free programs would deprive the | ||||
| users of those programs of all benefit from the free status of the | ||||
| libraries themselves.  This Library General Public License is intended to | ||||
| permit developers of non-free programs to use free libraries, while | ||||
| preserving your freedom as a user of such programs to change the free | ||||
| libraries that are incorporated in them.  (We have not seen how to achieve | ||||
| this as regards changes in header files, but we have achieved it as regards | ||||
| changes in the actual functions of the Library.)  The hope is that this | ||||
| will lead to faster development of free libraries. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow.  Pay close attention to the difference between a | ||||
| "work based on the library" and a "work that uses the library".  The | ||||
| former contains code derived from the library, whereas the latter must | ||||
| be combined with the library in order to run. | ||||
| former contains code derived from the library, while the latter only | ||||
| works together with the library. | ||||
|  | ||||
|   Note that it is possible for a library to be covered by the ordinary | ||||
| General Public License rather than by this special one. | ||||
|  | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License Agreement applies to any software library or other | ||||
| program which contains a notice placed by the copyright holder or | ||||
| other authorized party saying it may be distributed under the terms of | ||||
| this Lesser General Public License (also called "this License"). | ||||
| Each licensee is addressed as "you". | ||||
|   0. This License Agreement applies to any software library which | ||||
| contains a notice placed by the copyright holder or other authorized | ||||
| party saying it may be distributed under the terms of this Library | ||||
| General Public License (also called "this License").  Each licensee is | ||||
| addressed as "you". | ||||
|  | ||||
|   A "library" means a collection of software functions and/or data | ||||
| prepared so as to be conveniently linked with application programs | ||||
| @@ -268,7 +256,7 @@ distribute the object code for the work under the terms of Section 6. | ||||
| Any executables containing that work also fall under Section 6, | ||||
| whether or not they are linked directly with the Library itself. | ||||
|  | ||||
|   6. As an exception to the Sections above, you may also combine or | ||||
|   6. As an exception to the Sections above, you may also compile or | ||||
| link a "work that uses the Library" with the Library to produce a | ||||
| work containing portions of the Library, and distribute that work | ||||
| under terms of your choice, provided that the terms permit | ||||
| @@ -295,31 +283,23 @@ of these things: | ||||
|     Library will not necessarily be able to recompile the application | ||||
|     to use the modified definitions.) | ||||
|  | ||||
|     b) Use a suitable shared library mechanism for linking with the | ||||
|     Library.  A suitable mechanism is one that (1) uses at run time a | ||||
|     copy of the library already present on the user's computer system, | ||||
|     rather than copying library functions into the executable, and (2) | ||||
|     will operate properly with a modified version of the library, if | ||||
|     the user installs one, as long as the modified version is | ||||
|     interface-compatible with the version that the work was made with. | ||||
|  | ||||
|     c) Accompany the work with a written offer, valid for at | ||||
|     b) Accompany the work with a written offer, valid for at | ||||
|     least three years, to give the same user the materials | ||||
|     specified in Subsection 6a, above, for a charge no more | ||||
|     than the cost of performing this distribution. | ||||
|  | ||||
|     d) If distribution of the work is made by offering access to copy | ||||
|     c) If distribution of the work is made by offering access to copy | ||||
|     from a designated place, offer equivalent access to copy the above | ||||
|     specified materials from the same place. | ||||
|  | ||||
|     e) Verify that the user has already received a copy of these | ||||
|     d) Verify that the user has already received a copy of these | ||||
|     materials or that you have already sent this user a copy. | ||||
|  | ||||
|   For an executable, the required form of the "work that uses the | ||||
| Library" must include any data and utility programs needed for | ||||
| reproducing the executable from it.  However, as a special exception, | ||||
| the materials to be distributed need not include anything that is | ||||
| normally distributed (in either source or binary form) with the major | ||||
| the source code distributed need not include anything that is normally | ||||
| distributed (in either source or binary form) with the major | ||||
| components (compiler, kernel, and so on) of the operating system on | ||||
| which the executable runs, unless that component itself accompanies | ||||
| the executable. | ||||
| @@ -368,7 +348,7 @@ Library), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute, link with or modify the Library | ||||
| subject to these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties with | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   11. If, as a consequence of a court judgment or allegation of patent | ||||
| @@ -411,7 +391,7 @@ excluded.  In such case, this License incorporates the limitation as if | ||||
| written in the body of this License. | ||||
|  | ||||
|   13. The Free Software Foundation may publish revised and/or new | ||||
| versions of the Lesser General Public License from time to time. | ||||
| versions of the Library General Public License from time to time. | ||||
| Such new versions will be similar in spirit to the present version, | ||||
| but may differ in detail to address new problems or concerns. | ||||
|  | ||||
| @@ -457,7 +437,7 @@ DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
|            How to Apply These Terms to Your New Libraries | ||||
|      Appendix: How to Apply These Terms to Your New Libraries | ||||
|  | ||||
|   If you develop a new library, and you want it to be of the greatest | ||||
| possible use to the public, we recommend making it free software that | ||||
| @@ -474,18 +454,19 @@ convey the exclusion of warranty; and each file should have at least the | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This library is free software; you can redistribute it and/or | ||||
|     modify it under the terms of the GNU Lesser General Public | ||||
|     modify it under the terms of the GNU Library General Public | ||||
|     License as published by the Free Software Foundation; either | ||||
|     version 2.1 of the License, or (at your option) any later version. | ||||
|     version 2 of the License, or (at your option) any later version. | ||||
|  | ||||
|     This library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|     Lesser General Public License for more details. | ||||
|     Library General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Lesser General Public | ||||
|     License along with this library; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|     You should have received a copy of the GNU Library General Public | ||||
|     License along with this library; if not, write to the Free | ||||
|     Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||||
|     MA 02111-1307, USA | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| @@ -500,5 +481,3 @@ necessary.  Here is a sample; alter the names: | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| That's all there is to it! | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -1,30 +1,44 @@ | ||||
| Installation | ||||
| ============ | ||||
| LVM2 installation | ||||
| ================= | ||||
|  | ||||
| 1) Generate custom makefiles. | ||||
| 1) Install device-mapper | ||||
|  | ||||
|    Ensure the device-mapper has been installed on the machine. | ||||
|  | ||||
|    The device-mapper should be in the kernel (look for 'device-mapper' | ||||
|    messages in the kernel logs) and /usr/include/libdevmapper.h  | ||||
|    and libdevmapper.so should be present. | ||||
|  | ||||
|    The device-mapper is available from: | ||||
|      ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
|  | ||||
| 2) Generate custom makefiles. | ||||
|  | ||||
|    Run the 'configure' script from the top directory. | ||||
|  | ||||
|    If you wish to use the built-in LVM2 shell and have GNU readline  | ||||
|    installed (http://www.gnu.org/directory/readline.html) use: | ||||
|      ./configure --enable-readline | ||||
|  | ||||
|    If you don't want to include the LVM1 backwards-compatibility code use: | ||||
|      ./configure --with-lvm1=none  | ||||
|  | ||||
|    To separate the LVM1 support into a shared library loaded by lvm.conf use: | ||||
|      ./configure --with-lvm1=shared | ||||
|  | ||||
|    Use ./configure --help to see other options. | ||||
|  | ||||
| 2) Build and install. | ||||
| 3) Build and install LVM2. | ||||
|  | ||||
|    Run 'make' from the top directory to build everything you configured. | ||||
|    Run 'make install' to build and install everything you configured. | ||||
|    Run 'make install' from the top directory. | ||||
|  | ||||
|    If you only want the device-mapper libraries and tools use | ||||
|    'make device-mapper' or 'make install_device-mapper'. | ||||
|  | ||||
| 3) If using LVM2, create a configuration file. | ||||
| 4) Create a configuration file | ||||
|  | ||||
|    The tools will work fine without a configuration file being | ||||
|    present, but you ought to review the example file in doc/example.conf. | ||||
|    For example, specifying the devices that LVM2 is to use can | ||||
|    make the tools run more efficiently - and avoid scanning /dev/cdrom! | ||||
|  | ||||
| Please also refer to the WHATS_NEW file and the manual pages for the  | ||||
| individual commands. | ||||
|   | ||||
							
								
								
									
										207
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								Makefile.in
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| @@ -10,204 +10,61 @@ | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| abs_top_builddir = @abs_top_builddir@ | ||||
| abs_top_srcdir = @abs_top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS = libdm conf daemons include lib libdaemon man scripts tools | ||||
|  | ||||
| ifeq ("@UDEV_RULES@", "yes") | ||||
|   SUBDIRS += udev | ||||
| endif | ||||
| SUBDIRS = doc include man scripts | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),clean) | ||||
|   SUBDIRS += test | ||||
| SUBDIRS += lib tools daemons | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
|   SUBDIRS += dmeventd | ||||
| endif | ||||
| # FIXME Should use intermediate Makefiles here! | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = conf include man test scripts \ | ||||
|     libdaemon lib tools daemons libdm \ | ||||
|     udev po | ||||
| tools.distclean: test.distclean | ||||
|   SUBDIRS += daemons/clvmd \ | ||||
| 	     dmeventd \ | ||||
| 	     lib/format1 \ | ||||
| 	     lib/format_pool \ | ||||
| 	     lib/locking \ | ||||
| 	     lib/mirror \ | ||||
| 	     lib/snapshot \ | ||||
| 	     po \ | ||||
| 	     test/mm test/device test/format1 test/regex test/filters | ||||
|   DISTCLEAN_TARGETS += lib/misc/configure.h | ||||
| endif | ||||
| DISTCLEAN_DIRS += lcov_reports* autom4te.cache | ||||
| DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| include $(top_srcdir)/base/Makefile | ||||
| include $(top_srcdir)/device_mapper/Makefile | ||||
| include $(top_srcdir)/test/unit/Makefile | ||||
|  | ||||
| lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET) | ||||
| daemons: lib libdaemon tools | ||||
| scripts: lib | ||||
| tools: lib libdaemon | ||||
| po: tools daemons | ||||
| man: tools | ||||
| all_man: tools | ||||
| test: tools daemons | ||||
| unit-test  run-unit-test: test libdm | ||||
|  | ||||
| daemons.device-mapper: libdm.device-mapper | ||||
| tools.device-mapper: libdm.device-mapper | ||||
| device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper | ||||
| device_mapper: device-mapper | ||||
| daemons: lib | ||||
| lib: include | ||||
| tools: lib | ||||
| dmeventd: tools | ||||
| po: tools daemons dmeventd | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| daemons.pofile: lib.pofile | ||||
| po.pofile: tools.pofile daemons.pofile | ||||
| dmeventd.pofile: tools.pofile | ||||
| po.pofile: tools.pofile daemons.pofile dmeventd.pofile | ||||
| pofile: po.pofile | ||||
| endif | ||||
|  | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| tools.cflow: libdm.cflow lib.cflow | ||||
| daemons.cflow: tools.cflow | ||||
| cflow: include.cflow | ||||
| ifneq ("@CFLOW_CMD@", "") | ||||
| tools.cflow: lib.cflow | ||||
| cflow: tools.cflow | ||||
| endif | ||||
|  | ||||
| CSCOPE_DIRS = base daemons device_mapper include lib libdaemon scripts tools libdm test | ||||
| ifneq ("@CSCOPE_CMD@", "") | ||||
| cscope.out: | ||||
| 	@CSCOPE_CMD@ -b -R $(patsubst %,-s%,$(addprefix $(srcdir)/,$(CSCOPE_DIRS))) | ||||
| cscope.out: tools | ||||
| 	@CSCOPE_CMD@ -b -R | ||||
| all: cscope.out | ||||
| endif | ||||
| DISTCLEAN_TARGETS += cscope.out | ||||
| CLEAN_DIRS += autom4te.cache | ||||
|  | ||||
| check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test | ||||
| 	$(MAKE) -C test $(@) | ||||
|  | ||||
| conf.generate man.generate: tools | ||||
|  | ||||
| # how to use parenthesis in makefiles | ||||
| leftparen:=( | ||||
| LVM_VER := $(firstword $(subst $(leftparen), ,$(LVM_VERSION))) | ||||
| VER := LVM2.$(LVM_VER) | ||||
| # release file name | ||||
| FILE_VER := $(VER).tgz | ||||
| CLEAN_TARGETS += $(FILE_VER) | ||||
| CLEAN_DIRS += $(rpmbuilddir) | ||||
|  | ||||
| dist: | ||||
| 	@echo "Generating $(FILE_VER)";\ | ||||
| 	(cd $(top_srcdir); git ls-tree -r HEAD --name-only | xargs tar --transform "s,^,$(VER)/," -c) | gzip >$(FILE_VER) | ||||
|  | ||||
| rpm: dist | ||||
| 	$(RM) -r $(rpmbuilddir)/SOURCES | ||||
| 	$(MKDIR_P) $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_builddir)/$(FILE_VER) $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES | ||||
| 	$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES | ||||
| 	DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\ | ||||
| 	GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\ | ||||
| 	$(SED) -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \ | ||||
| 	    -e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \ | ||||
| 	    -e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \ | ||||
| 	    $(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc | ||||
| 	V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec | ||||
|  | ||||
| generate: conf.generate man.generate | ||||
| 	$(MAKE) -C conf generate | ||||
| 	$(MAKE) -C man generate | ||||
|  | ||||
| all_man: | ||||
| 	$(MAKE) -C man all_man | ||||
|  | ||||
| install_system_dirs: | ||||
| 	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)/devices | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR) | ||||
| 	$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache | ||||
|  | ||||
| install_initscripts: | ||||
| 	$(MAKE) -C scripts install_initscripts | ||||
|  | ||||
| install_systemd_generators: | ||||
| 	$(MAKE) -C scripts install_systemd_generators | ||||
| 	$(MAKE) -C man install_systemd_generators | ||||
|  | ||||
| install_systemd_units: | ||||
| 	$(MAKE) -C scripts install_systemd_units | ||||
|  | ||||
| install_all_man: | ||||
| 	$(MAKE) -C man install_all_man | ||||
|  | ||||
| install_tmpfiles_configuration: | ||||
| 	$(MAKE) -C scripts install_tmpfiles_configuration | ||||
|  | ||||
| help: | ||||
| 	@echo -e "\nAvailable targets:" | ||||
| 	@echo "  all			Default target." | ||||
| 	@echo "  all_man		Build all man pages with generators." | ||||
| 	@echo "  clean			Remove all compile files." | ||||
| 	@echo "  device-mapper		Device mapper part of lvm2." | ||||
| 	@echo "  dist			Generate distributable file." | ||||
| 	@echo "  distclean		Remove all build files." | ||||
| 	@echo "  generate		Generate man pages for sources." | ||||
| 	@echo "  help			Display callable targets." | ||||
| 	@echo "  install		Install all files." | ||||
| 	@echo "  install_all_man	Install all man pages." | ||||
| 	@echo "  install_cluster	Install cmirrord." | ||||
| 	@echo "  install_device-mapper	Install device mapper files." | ||||
| 	@echo "  install_initscripts	Install initialization scripts." | ||||
| 	@echo "  install_lvm2		Install lvm2 files." | ||||
| 	@echo "  install_systemd_units	Install systemd units." | ||||
| 	@echo "  lcov			Generate lcov output." | ||||
| 	@echo "  lcov-dated		Generate lcov with timedate suffix." | ||||
| 	@echo "  lcov-reset		Reset lcov counters" | ||||
| 	@echo "  man			Build man pages." | ||||
| 	@echo "  print-VARIABLE		Resolve make variable." | ||||
| 	@echo "  rpm			Build rpm." | ||||
| 	@echo "  run-unit-test		Run unit tests." | ||||
| 	@echo "  tags			Generate c/etags." | ||||
|  | ||||
| ifneq ("$(LCOV)", "") | ||||
| .PHONY: lcov-reset lcov lcov-dated | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),lcov-dated) | ||||
| LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S) | ||||
| lcov-dated: lcov | ||||
| else | ||||
| LCOV_REPORTS_DIR := lcov_reports | ||||
| endif | ||||
|  | ||||
| lcov-reset: | ||||
| 	$(LCOV) --zerocounters --directory $(top_builddir) | ||||
|  | ||||
| ifneq ("$(GENHTML)", "") | ||||
| lcov: | ||||
| 	$(RM) -rf $(LCOV_REPORTS_DIR) | ||||
| 	$(MKDIR_P) $(LCOV_REPORTS_DIR) | ||||
| 	$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \ | ||||
| 		--output-file $(LCOV_REPORTS_DIR)/out.info | ||||
| 	-test ! -s $(LCOV_REPORTS_DIR)/out.info || \ | ||||
| 		$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \ | ||||
| 		$(LCOV_REPORTS_DIR)/out.info | ||||
| endif | ||||
|  | ||||
| endif | ||||
|  | ||||
| ifneq ($(shell which ctags 2>/dev/null),) | ||||
| .PHONY: tags | ||||
| tags: | ||||
| 	test -z "$(shell find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags | ||||
| 	test -f tags || find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' + | ||||
|  | ||||
| CLEAN_TARGETS += tags | ||||
| endif | ||||
|   | ||||
							
								
								
									
										65
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								README
									
									
									
									
									
								
							| @@ -1,60 +1,23 @@ | ||||
| This tree contains the LVM2 and device-mapper tools and libraries. | ||||
| This directory contains LVM2, the new version of the userland LVM | ||||
| tools designed for the new device-mapper for the Linux kernel. | ||||
|  | ||||
| For more information about LVM2 read the changelog in the WHATS_NEW file. | ||||
| The device-mapper needs to be installed before compiling these LVM2 tools. | ||||
|  | ||||
| For more information about LVM2 read the WHATS_NEW file. | ||||
| Installation instructions are in INSTALL. | ||||
|  | ||||
| There is no warranty - see COPYING and COPYING.LIB. | ||||
|  | ||||
| Tarballs are available from: | ||||
|   ftp://sourceware.org/pub/lvm2/ | ||||
|   https://github.com/lvmteam/lvm2/releases | ||||
|   ftp://sources.redhat.com/pub/lvm2/ | ||||
|   ftp://sources.redhat.com/pub/dm/ | ||||
|  | ||||
| The source code is stored in git: | ||||
|   https://gitlab.com/lvmteam/lvm2 | ||||
| Clone: | ||||
|   git clone git@gitlab.com:lvmteam/lvm2.git | ||||
| Anonymous access: | ||||
|   git clone https://gitlab.com/lvmteam/lvm2.git | ||||
| Mirrored to: | ||||
| * https://github.com/lvmteam/lvm2 | ||||
|   git clone https://github.com/lvmteam/lvm2.git | ||||
|   git clone git@github.com:lvmteam/lvm2.git | ||||
| * https://sourceware.org/git/?p=lvm2.git | ||||
|   git clone https://sourceware.org/git/lvm2.git | ||||
|   git clone git://sourceware.org/git/lvm2.git | ||||
| To access the CVS tree use: | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login | ||||
|   CVS password: cvs | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2 | ||||
|  | ||||
| Mailing list for general discussion related to LVM2: | ||||
|   linux-lvm@lists.linux.dev | ||||
|   Subscribe via email to: linux-lvm+subscribe@lists.linux.dev | ||||
|   Archive https://lore.kernel.org/linux-lvm/ | ||||
|   Older archive https://listman.redhat.com/archives/linux-lvm/ | ||||
| Mailing list for discussion/bug reports etc. | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| Mailing lists for LVM2 development, patches and commits: | ||||
|   lvm-devel@lists.linux.dev | ||||
|   Subscribe via email to: lvm-devel+subscribe@lists.linux.dev | ||||
|   Archive https://lore.kernel.org/lvm-devel/ | ||||
|   Older archive https://listman.redhat.com/archives/lvm-devel/ | ||||
|  | ||||
|   lvm2-commits@lists.fedorahosted.org (Read-only archive of commits) | ||||
|   Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits | ||||
|  | ||||
| Mailing list for device-mapper development, including kernel patches | ||||
| and multipath-tools: | ||||
|   dm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel | ||||
|  | ||||
| Website: | ||||
|   https://sourceware.org/lvm2/ | ||||
|  | ||||
| Report upstream bugs at: | ||||
|   https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper | ||||
| or open issues at: | ||||
|   https://gitlab.com/groups/lvmteam/-/issues | ||||
|   https://github.com/lvmteam/lvm2/issues | ||||
|  | ||||
| The source code repository used until 7th June 2012 is accessible using CVS: | ||||
|  | ||||
|   cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs | ||||
|   cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2 | ||||
|  | ||||
| The password is cvs. | ||||
|   | ||||
							
								
								
									
										67
									
								
								TESTING
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								TESTING
									
									
									
									
									
								
							| @@ -1,67 +0,0 @@ | ||||
| LVM2 Test Suite | ||||
| =============== | ||||
|  | ||||
| The codebase contains many tests in the test subdirectory. | ||||
|  | ||||
| Before running tests | ||||
| -------------------- | ||||
|  | ||||
| Keep in mind the testsuite MUST run under root user. | ||||
|  | ||||
| It is recommended not to use LVM on the test machine, especially when running | ||||
| tests with udev (`make check_system`.) | ||||
|  | ||||
| You MUST disable (or mask) any LVM daemons: | ||||
|  | ||||
| - lvmetad | ||||
| - dmeventd | ||||
| - lvmpolld | ||||
| - lvmdbusd | ||||
| - lvmlockd | ||||
| - clvmd | ||||
| - cmirrord | ||||
|  | ||||
| Some lvm.conf options should be set: | ||||
|  | ||||
| - global/event_activation = 0 | ||||
| - activation/monitoring = 0 | ||||
|  | ||||
| For running cluster tests, we are using singlenode locking. Pass | ||||
| `--with-clvmd=singlenode` to configure. | ||||
|  | ||||
| NOTE: This is useful only for testing, and should not be used in production | ||||
| code. | ||||
|  | ||||
| To run D-Bus daemon tests, existing D-Bus session is required. | ||||
|  | ||||
| Running tests | ||||
| ------------- | ||||
|  | ||||
| As root run: | ||||
|  | ||||
|     make check | ||||
|  | ||||
| To run only tests matching a string: | ||||
|  | ||||
|     make check T=test | ||||
|  | ||||
| To skip tests matching a string: | ||||
|  | ||||
|     make check S=test | ||||
|  | ||||
| There are other targets and many environment variables can be used to tweak the | ||||
| testsuite - for full list and description run `make -C test help`. | ||||
|  | ||||
| Installing testsuite | ||||
| -------------------- | ||||
|  | ||||
| It is possible to install and run a testsuite against installed LVM. Run the | ||||
| following: | ||||
|  | ||||
|     make -C test install | ||||
|  | ||||
| Then lvm2-testsuite binary can be executed to test installed binaries. | ||||
|  | ||||
| See `lvm2-testsuite --help` for options. The same environment variables can be | ||||
| used as with `make check`. | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 1.02.199-git (2024-05-16) | ||||
							
								
								
									
										1290
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										1290
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										252
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								acinclude.m4
									
									
									
									
									
								
							| @@ -1,252 +0,0 @@ | ||||
| dnl AC_GCC_VERSION | ||||
| dnl check for compiler version | ||||
| dnl sets COMPILER_VERSION and GCC_VERSION | ||||
|  | ||||
| AC_DEFUN([AC_CC_VERSION], | ||||
| [ | ||||
|     AC_MSG_CHECKING([C compiler version]) | ||||
|     COMPILER_VERSION=`$CC -v 2>&1 | grep version` | ||||
|     case "$COMPILER_VERSION" in | ||||
|         *gcc*) | ||||
| 	   dnl Ok, how to turn $3 into the real $3 | ||||
| 	   GCC_VERSION=`echo $COMPILER_VERSION | \ | ||||
| 	   sed -e 's/[[^ ]]*\ [[^ ]]*\ \([[^ ]]*\)\ .*/\1/'` ;; | ||||
| 	*) GCC_VERSION=unknown ;; | ||||
|     esac | ||||
|     AC_MSG_RESULT($GCC_VERSION) | ||||
| ]) | ||||
|  | ||||
| dnl AC_TRY_CCFLAG([CCFLAG], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports a given flag | ||||
|  | ||||
| AC_DEFUN([AC_TRY_CCFLAG], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_CFLAGS=$CFLAGS | ||||
|     CFLAGS=$1 | ||||
|     AC_CACHE_CHECK([whether $CC accepts $1 flag], [ac_cv_flag_$2], | ||||
| 	[AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     CFLAGS=$ac_save_CFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| dnl AC_IF_YES([TEST-FOR-YES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) | ||||
| dnl AS_IF() abstraction, checks shell variable for 'yes' | ||||
| AC_DEFUN([AC_IF_YES], [AS_IF([test $$1 = yes], [$2], [$3])]) | ||||
|  | ||||
| dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports given ld flags | ||||
|  | ||||
| AC_DEFUN([AC_TRY_LDFLAGS], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_LDFLAGS=$LDFLAGS | ||||
|     LDFLAGS=$1 | ||||
| 	AC_CACHE_CHECK([whether $CC accepts $1 ld flags], [ac_cv_flag_$2], | ||||
| 	[AC_LINK_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     LDFLAGS=$ac_save_LDFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, | ||||
| dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| dnl ------------------------------------------- | ||||
| dnl Since: 0.28 | ||||
| dnl | ||||
| dnl Retrieves the value of the pkg-config variable for the given module. | ||||
| AC_DEFUN([PKG_CHECK_VAR], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl | ||||
|  | ||||
| _PKG_CONFIG([$1], [variable="][$3]["], [$2]) | ||||
| AS_VAR_COPY([$1], [pkg_cv_][$1]) | ||||
|  | ||||
| AS_VAR_IF([$1], [""], [$5], [$4])dnl | ||||
| ])dnl PKG_CHECK_VAR | ||||
|  | ||||
|  | ||||
| # =========================================================================== | ||||
| #      http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html | ||||
| # =========================================================================== | ||||
| # | ||||
| # SYNOPSIS | ||||
| # | ||||
| #   AX_GCC_BUILTIN(BUILTIN) | ||||
| # | ||||
| # DESCRIPTION | ||||
| # | ||||
| #   This macro checks if the compiler supports one of GCC's built-in | ||||
| #   functions; many other compilers also provide those same built-ins. | ||||
| # | ||||
| #   The BUILTIN parameter is the name of the built-in function. | ||||
| # | ||||
| #   If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since | ||||
| #   builtins usually start with two underscores they will be copied over | ||||
| #   into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for | ||||
| #   __builtin_expect()). | ||||
| # | ||||
| #   The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g. | ||||
| #   ax_cv_have___builtin_expect). | ||||
| # | ||||
| #   The macro currently supports the following built-in functions: | ||||
| # | ||||
| #    __builtin_assume_aligned | ||||
| #    __builtin_bswap16 | ||||
| #    __builtin_bswap32 | ||||
| #    __builtin_bswap64 | ||||
| #    __builtin_choose_expr | ||||
| #    __builtin___clear_cache | ||||
| #    __builtin_clrsb | ||||
| #    __builtin_clrsbl | ||||
| #    __builtin_clrsbll | ||||
| #    __builtin_clz | ||||
| #    __builtin_clzl | ||||
| #    __builtin_clzll | ||||
| #    __builtin_complex | ||||
| #    __builtin_constant_p | ||||
| #    __builtin_ctz | ||||
| #    __builtin_ctzl | ||||
| #    __builtin_ctzll | ||||
| #    __builtin_expect | ||||
| #    __builtin_ffs | ||||
| #    __builtin_ffsl | ||||
| #    __builtin_ffsll | ||||
| #    __builtin_fpclassify | ||||
| #    __builtin_huge_val | ||||
| #    __builtin_huge_valf | ||||
| #    __builtin_huge_vall | ||||
| #    __builtin_inf | ||||
| #    __builtin_infd128 | ||||
| #    __builtin_infd32 | ||||
| #    __builtin_infd64 | ||||
| #    __builtin_inff | ||||
| #    __builtin_infl | ||||
| #    __builtin_isinf_sign | ||||
| #    __builtin_nan | ||||
| #    __builtin_nand128 | ||||
| #    __builtin_nand32 | ||||
| #    __builtin_nand64 | ||||
| #    __builtin_nanf | ||||
| #    __builtin_nanl | ||||
| #    __builtin_nans | ||||
| #    __builtin_nansf | ||||
| #    __builtin_nansl | ||||
| #    __builtin_object_size | ||||
| #    __builtin_parity | ||||
| #    __builtin_parityl | ||||
| #    __builtin_parityll | ||||
| #    __builtin_popcount | ||||
| #    __builtin_popcountl | ||||
| #    __builtin_popcountll | ||||
| #    __builtin_powi | ||||
| #    __builtin_powif | ||||
| #    __builtin_powil | ||||
| #    __builtin_prefetch | ||||
| #    __builtin_trap | ||||
| #    __builtin_types_compatible_p | ||||
| #    __builtin_unreachable | ||||
| # | ||||
| #   Unsuppored built-ins will be tested with an empty parameter set and the | ||||
| #   result of the check might be wrong or meaningless so use with care. | ||||
| # | ||||
| # LICENSE | ||||
| # | ||||
| #   Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com> | ||||
| # | ||||
| #   Copying and distribution of this file, with or without modification, are | ||||
| #   permitted in any medium without royalty provided the copyright notice | ||||
| #   and this notice are preserved.  This file is offered as-is, without any | ||||
| #   warranty. | ||||
|  | ||||
| serial 3 | ||||
|  | ||||
| AC_DEFUN([AX_GCC_BUILTIN], [ | ||||
|     AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) | ||||
|  | ||||
|     AC_CACHE_CHECK([for $1], [ac_var], [ | ||||
|         AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ | ||||
|             m4_case([$1], | ||||
|                 [__builtin_assume_aligned], [$1("", 0)], | ||||
|                 [__builtin_bswap16], [$1(0)], | ||||
|                 [__builtin_bswap32], [$1(0)], | ||||
|                 [__builtin_bswap64], [$1(0)], | ||||
|                 [__builtin_choose_expr], [$1(0, 0, 0)], | ||||
|                 [__builtin___clear_cache], [$1("", "")], | ||||
|                 [__builtin_clrsb], [$1(0)], | ||||
|                 [__builtin_clrsbl], [$1(0)], | ||||
|                 [__builtin_clrsbll], [$1(0)], | ||||
|                 [__builtin_clz], [$1(0)], | ||||
|                 [__builtin_clzl], [$1(0)], | ||||
|                 [__builtin_clzll], [$1(0)], | ||||
|                 [__builtin_complex], [$1(0.0, 0.0)], | ||||
|                 [__builtin_constant_p], [$1(0)], | ||||
|                 [__builtin_ctz], [$1(0)], | ||||
|                 [__builtin_ctzl], [$1(0)], | ||||
|                 [__builtin_ctzll], [$1(0)], | ||||
|                 [__builtin_expect], [$1(0, 0)], | ||||
|                 [__builtin_ffs], [$1(0)], | ||||
|                 [__builtin_ffsl], [$1(0)], | ||||
|                 [__builtin_ffsll], [$1(0)], | ||||
|                 [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], | ||||
|                 [__builtin_huge_val], [$1()], | ||||
|                 [__builtin_huge_valf], [$1()], | ||||
|                 [__builtin_huge_vall], [$1()], | ||||
|                 [__builtin_inf], [$1()], | ||||
|                 [__builtin_infd128], [$1()], | ||||
|                 [__builtin_infd32], [$1()], | ||||
|                 [__builtin_infd64], [$1()], | ||||
|                 [__builtin_inff], [$1()], | ||||
|                 [__builtin_infl], [$1()], | ||||
|                 [__builtin_isinf_sign], [$1(0.0)], | ||||
|                 [__builtin_nan], [$1("")], | ||||
|                 [__builtin_nand128], [$1("")], | ||||
|                 [__builtin_nand32], [$1("")], | ||||
|                 [__builtin_nand64], [$1("")], | ||||
|                 [__builtin_nanf], [$1("")], | ||||
|                 [__builtin_nanl], [$1("")], | ||||
|                 [__builtin_nans], [$1("")], | ||||
|                 [__builtin_nansf], [$1("")], | ||||
|                 [__builtin_nansl], [$1("")], | ||||
|                 [__builtin_object_size], [$1("", 0)], | ||||
|                 [__builtin_parity], [$1(0)], | ||||
|                 [__builtin_parityl], [$1(0)], | ||||
|                 [__builtin_parityll], [$1(0)], | ||||
|                 [__builtin_popcount], [$1(0)], | ||||
|                 [__builtin_popcountl], [$1(0)], | ||||
|                 [__builtin_popcountll], [$1(0)], | ||||
|                 [__builtin_powi], [$1(0, 0)], | ||||
|                 [__builtin_powif], [$1(0, 0)], | ||||
|                 [__builtin_powil], [$1(0, 0)], | ||||
|                 [__builtin_prefetch], [$1("")], | ||||
|                 [__builtin_trap], [$1()], | ||||
|                 [__builtin_types_compatible_p], [$1(int, int)], | ||||
|                 [__builtin_unreachable], [$1()], | ||||
|                 [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) | ||||
|                  $1()] | ||||
|             ) | ||||
|             ])], | ||||
|             [AS_VAR_SET([ac_var], [yes])], | ||||
|             [AS_VAR_SET([ac_var], [no])]) | ||||
|     ]) | ||||
|  | ||||
|     AS_IF([test yes = AS_VAR_GET([ac_var])], | ||||
|         [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, | ||||
|             [Define to 1 if the system has the `$1' built-in function])], []) | ||||
|  | ||||
|     AS_VAR_POPDEF([ac_var]) | ||||
| ]) | ||||
							
								
								
									
										777
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										777
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							| @@ -1,777 +0,0 @@ | ||||
| # generated automatically by aclocal 1.16.5 -*- Autoconf -*- | ||||
|  | ||||
| # Copyright (C) 1996-2021 Free Software Foundation, Inc. | ||||
|  | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||||
| # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||||
| # PARTICULAR PURPOSE. | ||||
|  | ||||
| m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) | ||||
| # =========================================================================== | ||||
| #     https://www.gnu.org/software/autoconf-archive/ax_python_module.html | ||||
| # =========================================================================== | ||||
| # | ||||
| # SYNOPSIS | ||||
| # | ||||
| #   AX_PYTHON_MODULE(modname[, fatal, python]) | ||||
| # | ||||
| # DESCRIPTION | ||||
| # | ||||
| #   Checks for Python module. | ||||
| # | ||||
| #   If fatal is non-empty then absence of a module will trigger an error. | ||||
| #   The third parameter can either be "python" for Python 2 or "python3" for | ||||
| #   Python 3; defaults to Python 3. | ||||
| # | ||||
| # LICENSE | ||||
| # | ||||
| #   Copyright (c) 2008 Andrew Collier | ||||
| # | ||||
| #   Copying and distribution of this file, with or without modification, are | ||||
| #   permitted in any medium without royalty provided the copyright notice | ||||
| #   and this notice are preserved. This file is offered as-is, without any | ||||
| #   warranty. | ||||
|  | ||||
| #serial 9 | ||||
|  | ||||
| AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE]) | ||||
| AC_DEFUN([AX_PYTHON_MODULE],[ | ||||
|     if test -z $PYTHON; | ||||
|     then | ||||
|         if test -z "$3"; | ||||
|         then | ||||
|             PYTHON="python3" | ||||
|         else | ||||
|             PYTHON="$3" | ||||
|         fi | ||||
|     fi | ||||
|     PYTHON_NAME=`basename $PYTHON` | ||||
|     AC_MSG_CHECKING($PYTHON_NAME module: $1) | ||||
|     $PYTHON -c "import $1" 2>/dev/null | ||||
|     if test $? -eq 0; | ||||
|     then | ||||
|         AC_MSG_RESULT(yes) | ||||
|         eval AS_TR_CPP(HAVE_PYMOD_$1)=yes | ||||
|     else | ||||
|         AC_MSG_RESULT(no) | ||||
|         eval AS_TR_CPP(HAVE_PYMOD_$1)=no | ||||
|         # | ||||
|         if test -n "$2" | ||||
|         then | ||||
|             AC_MSG_ERROR(failed to find required module $1) | ||||
|             exit 1 | ||||
|         fi | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| # pkg.m4 - Macros to locate and use pkg-config.   -*- Autoconf -*- | ||||
| # serial 12 (pkg-config-0.29.2) | ||||
|  | ||||
| dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. | ||||
| dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> | ||||
| dnl | ||||
| dnl This program is free software; you can redistribute it and/or modify | ||||
| dnl it under the terms of the GNU General Public License as published by | ||||
| dnl the Free Software Foundation; either version 2 of the License, or | ||||
| dnl (at your option) any later version. | ||||
| dnl | ||||
| dnl This program is distributed in the hope that it will be useful, but | ||||
| dnl WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| dnl General Public License for more details. | ||||
| dnl | ||||
| dnl You should have received a copy of the GNU General Public License | ||||
| dnl along with this program; if not, write to the Free Software | ||||
| dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
| dnl 02111-1307, USA. | ||||
| dnl | ||||
| dnl As a special exception to the GNU General Public License, if you | ||||
| dnl distribute this file as part of a program that contains a | ||||
| dnl configuration script generated by Autoconf, you may include it under | ||||
| dnl the same distribution terms that you use for the rest of that | ||||
| dnl program. | ||||
|  | ||||
| dnl PKG_PREREQ(MIN-VERSION) | ||||
| dnl ----------------------- | ||||
| dnl Since: 0.29 | ||||
| dnl | ||||
| dnl Verify that the version of the pkg-config macros are at least | ||||
| dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's | ||||
| dnl installed version of pkg-config, this checks the developer's version | ||||
| dnl of pkg.m4 when generating configure. | ||||
| dnl | ||||
| dnl To ensure that this macro is defined, also add: | ||||
| dnl m4_ifndef([PKG_PREREQ], | ||||
| dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) | ||||
| dnl | ||||
| dnl See the "Since" comment for each macro you use to see what version | ||||
| dnl of the macros you require. | ||||
| m4_defun([PKG_PREREQ], | ||||
| [m4_define([PKG_MACROS_VERSION], [0.29.2]) | ||||
| m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, | ||||
|     [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) | ||||
| ])dnl PKG_PREREQ | ||||
|  | ||||
| dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) | ||||
| dnl ---------------------------------- | ||||
| dnl Since: 0.16 | ||||
| dnl | ||||
| dnl Search for the pkg-config tool and set the PKG_CONFIG variable to | ||||
| dnl first found in the path. Checks that the version of pkg-config found | ||||
| dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is | ||||
| dnl used since that's the first version where most current features of | ||||
| dnl pkg-config existed. | ||||
| AC_DEFUN([PKG_PROG_PKG_CONFIG], | ||||
| [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) | ||||
| m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) | ||||
| m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) | ||||
| AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) | ||||
| AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) | ||||
| AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) | ||||
|  | ||||
| if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then | ||||
| 	AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) | ||||
| fi | ||||
| if test -n "$PKG_CONFIG"; then | ||||
| 	_pkg_min_version=m4_default([$1], [0.9.0]) | ||||
| 	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) | ||||
| 	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then | ||||
| 		AC_MSG_RESULT([yes]) | ||||
| 	else | ||||
| 		AC_MSG_RESULT([no]) | ||||
| 		PKG_CONFIG="" | ||||
| 	fi | ||||
| fi[]dnl | ||||
| ])dnl PKG_PROG_PKG_CONFIG | ||||
|  | ||||
| dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| dnl ------------------------------------------------------------------- | ||||
| dnl Since: 0.18 | ||||
| dnl | ||||
| dnl Check to see whether a particular set of modules exists. Similar to | ||||
| dnl PKG_CHECK_MODULES(), but does not set variables or print errors. | ||||
| dnl | ||||
| dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| dnl only at the first occurrence in configure.ac, so if the first place | ||||
| dnl it's called might be skipped (such as if it is within an "if", you | ||||
| dnl have to call PKG_CHECK_EXISTS manually | ||||
| AC_DEFUN([PKG_CHECK_EXISTS], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| if test -n "$PKG_CONFIG" && \ | ||||
|     AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then | ||||
|   m4_default([$2], [:]) | ||||
| m4_ifvaln([$3], [else | ||||
|   $3])dnl | ||||
| fi]) | ||||
|  | ||||
| dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) | ||||
| dnl --------------------------------------------- | ||||
| dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting | ||||
| dnl pkg_failed based on the result. | ||||
| m4_define([_PKG_CONFIG], | ||||
| [if test -n "$$1"; then | ||||
|     pkg_cv_[]$1="$$1" | ||||
|  elif test -n "$PKG_CONFIG"; then | ||||
|     PKG_CHECK_EXISTS([$3], | ||||
|                      [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` | ||||
| 		      test "x$?" != "x0" && pkg_failed=yes ], | ||||
| 		     [pkg_failed=yes]) | ||||
|  else | ||||
|     pkg_failed=untried | ||||
| fi[]dnl | ||||
| ])dnl _PKG_CONFIG | ||||
|  | ||||
| dnl _PKG_SHORT_ERRORS_SUPPORTED | ||||
| dnl --------------------------- | ||||
| dnl Internal check to see if pkg-config supports short errors. | ||||
| AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then | ||||
|         _pkg_short_errors_supported=yes | ||||
| else | ||||
|         _pkg_short_errors_supported=no | ||||
| fi[]dnl | ||||
| ])dnl _PKG_SHORT_ERRORS_SUPPORTED | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||||
| dnl   [ACTION-IF-NOT-FOUND]) | ||||
| dnl -------------------------------------------------------------- | ||||
| dnl Since: 0.4.0 | ||||
| dnl | ||||
| dnl Note that if there is a possibility the first call to | ||||
| dnl PKG_CHECK_MODULES might not happen, you should be sure to include an | ||||
| dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac | ||||
| AC_DEFUN([PKG_CHECK_MODULES], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl | ||||
| AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl | ||||
|  | ||||
| pkg_failed=no | ||||
| AC_MSG_CHECKING([for $2]) | ||||
|  | ||||
| _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) | ||||
| _PKG_CONFIG([$1][_LIBS], [libs], [$2]) | ||||
|  | ||||
| m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS | ||||
| and $1[]_LIBS to avoid the need to call pkg-config. | ||||
| See the pkg-config man page for more details.]) | ||||
|  | ||||
| if test $pkg_failed = yes; then | ||||
|         AC_MSG_RESULT([no]) | ||||
|         _PKG_SHORT_ERRORS_SUPPORTED | ||||
|         if test $_pkg_short_errors_supported = yes; then | ||||
|                 $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` | ||||
|         else | ||||
|                 $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` | ||||
|         fi | ||||
|         # Put the nasty error message in config.log where it belongs | ||||
|         echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD | ||||
|  | ||||
|         m4_default([$4], [AC_MSG_ERROR( | ||||
| [Package requirements ($2) were not met: | ||||
|  | ||||
| $$1_PKG_ERRORS | ||||
|  | ||||
| Consider adjusting the PKG_CONFIG_PATH environment variable if you | ||||
| installed software in a non-standard prefix. | ||||
|  | ||||
| _PKG_TEXT])[]dnl | ||||
|         ]) | ||||
| elif test $pkg_failed = untried; then | ||||
|         AC_MSG_RESULT([no]) | ||||
|         m4_default([$4], [AC_MSG_FAILURE( | ||||
| [The pkg-config script could not be found or is too old.  Make sure it | ||||
| is in your PATH or set the PKG_CONFIG environment variable to the full | ||||
| path to pkg-config. | ||||
|  | ||||
| _PKG_TEXT | ||||
|  | ||||
| To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl | ||||
|         ]) | ||||
| else | ||||
|         $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS | ||||
|         $1[]_LIBS=$pkg_cv_[]$1[]_LIBS | ||||
|         AC_MSG_RESULT([yes]) | ||||
|         $3 | ||||
| fi[]dnl | ||||
| ])dnl PKG_CHECK_MODULES | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||||
| dnl   [ACTION-IF-NOT-FOUND]) | ||||
| dnl --------------------------------------------------------------------- | ||||
| dnl Since: 0.29 | ||||
| dnl | ||||
| dnl Checks for existence of MODULES and gathers its build flags with | ||||
| dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags | ||||
| dnl and VARIABLE-PREFIX_LIBS from --libs. | ||||
| dnl | ||||
| dnl Note that if there is a possibility the first call to | ||||
| dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to | ||||
| dnl include an explicit call to PKG_PROG_PKG_CONFIG in your | ||||
| dnl configure.ac. | ||||
| AC_DEFUN([PKG_CHECK_MODULES_STATIC], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| _save_PKG_CONFIG=$PKG_CONFIG | ||||
| PKG_CONFIG="$PKG_CONFIG --static" | ||||
| PKG_CHECK_MODULES($@) | ||||
| PKG_CONFIG=$_save_PKG_CONFIG[]dnl | ||||
| ])dnl PKG_CHECK_MODULES_STATIC | ||||
|  | ||||
|  | ||||
| dnl PKG_INSTALLDIR([DIRECTORY]) | ||||
| dnl ------------------------- | ||||
| dnl Since: 0.27 | ||||
| dnl | ||||
| dnl Substitutes the variable pkgconfigdir as the location where a module | ||||
| dnl should install pkg-config .pc files. By default the directory is | ||||
| dnl $libdir/pkgconfig, but the default can be changed by passing | ||||
| dnl DIRECTORY. The user can override through the --with-pkgconfigdir | ||||
| dnl parameter. | ||||
| AC_DEFUN([PKG_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, | ||||
|     [with_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ])dnl PKG_INSTALLDIR | ||||
|  | ||||
|  | ||||
| dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) | ||||
| dnl -------------------------------- | ||||
| dnl Since: 0.27 | ||||
| dnl | ||||
| dnl Substitutes the variable noarch_pkgconfigdir as the location where a | ||||
| dnl module should install arch-independent pkg-config .pc files. By | ||||
| dnl default the directory is $datadir/pkgconfig, but the default can be | ||||
| dnl changed by passing DIRECTORY. The user can override through the | ||||
| dnl --with-noarch-pkgconfigdir parameter. | ||||
| AC_DEFUN([PKG_NOARCH_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([noarch-pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, | ||||
|     [with_noarch_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ])dnl PKG_NOARCH_INSTALLDIR | ||||
|  | ||||
|  | ||||
| dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, | ||||
| dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| dnl ------------------------------------------- | ||||
| dnl Since: 0.28 | ||||
| dnl | ||||
| dnl Retrieves the value of the pkg-config variable for the given module. | ||||
| AC_DEFUN([PKG_CHECK_VAR], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl | ||||
|  | ||||
| _PKG_CONFIG([$1], [variable="][$3]["], [$2]) | ||||
| AS_VAR_COPY([$1], [pkg_cv_][$1]) | ||||
|  | ||||
| AS_VAR_IF([$1], [""], [$5], [$4])dnl | ||||
| ])dnl PKG_CHECK_VAR | ||||
|  | ||||
| dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ------------------------------------------ | ||||
| dnl | ||||
| dnl Prepare a "--with-" configure option using the lowercase | ||||
| dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and | ||||
| dnl PKG_CHECK_MODULES in a single macro. | ||||
| AC_DEFUN([PKG_WITH_MODULES], | ||||
| [ | ||||
| m4_pushdef([with_arg], m4_tolower([$1])) | ||||
|  | ||||
| m4_pushdef([description], | ||||
|            [m4_default([$5], [build with ]with_arg[ support])]) | ||||
|  | ||||
| m4_pushdef([def_arg], [m4_default([$6], [auto])]) | ||||
| m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) | ||||
| m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) | ||||
|  | ||||
| m4_case(def_arg, | ||||
|             [yes],[m4_pushdef([with_without], [--without-]with_arg)], | ||||
|             [m4_pushdef([with_without],[--with-]with_arg)]) | ||||
|  | ||||
| AC_ARG_WITH(with_arg, | ||||
|      AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, | ||||
|     [AS_TR_SH([with_]with_arg)=def_arg]) | ||||
|  | ||||
| AS_CASE([$AS_TR_SH([with_]with_arg)], | ||||
|             [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], | ||||
|             [auto],[PKG_CHECK_MODULES([$1],[$2], | ||||
|                                         [m4_n([def_action_if_found]) $3], | ||||
|                                         [m4_n([def_action_if_not_found]) $4])]) | ||||
|  | ||||
| m4_popdef([with_arg]) | ||||
| m4_popdef([description]) | ||||
| m4_popdef([def_arg]) | ||||
|  | ||||
| ])dnl PKG_WITH_MODULES | ||||
|  | ||||
| dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ----------------------------------------------- | ||||
| dnl | ||||
| dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES | ||||
| dnl check._[VARIABLE-PREFIX] is exported as make variable. | ||||
| AC_DEFUN([PKG_HAVE_WITH_MODULES], | ||||
| [ | ||||
| PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) | ||||
|  | ||||
| AM_CONDITIONAL([HAVE_][$1], | ||||
|                [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) | ||||
| ])dnl PKG_HAVE_WITH_MODULES | ||||
|  | ||||
| dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, | ||||
| dnl   [DESCRIPTION], [DEFAULT]) | ||||
| dnl ------------------------------------------------------ | ||||
| dnl | ||||
| dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after | ||||
| dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make | ||||
| dnl and preprocessor variable. | ||||
| AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], | ||||
| [ | ||||
| PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) | ||||
|  | ||||
| AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], | ||||
|         [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) | ||||
| ])dnl PKG_HAVE_DEFINE_WITH_MODULES | ||||
|  | ||||
| # Copyright (C) 1999-2021 Free Software Foundation, Inc. | ||||
| # | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
|  | ||||
| # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| # --------------------------------------------------------------------------- | ||||
| # Adds support for distributing Python modules and packages.  To | ||||
| # install modules, copy them to $(pythondir), using the python_PYTHON | ||||
| # automake variable.  To install a package with the same name as the | ||||
| # automake package, install to $(pkgpythondir), or use the | ||||
| # pkgpython_PYTHON automake variable. | ||||
| # | ||||
| # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as | ||||
| # locations to install python extension modules (shared libraries). | ||||
| # Another macro is required to find the appropriate flags to compile | ||||
| # extension modules. | ||||
| # | ||||
| # If your package is configured with a different prefix to python, | ||||
| # users will have to add the install directory to the PYTHONPATH | ||||
| # environment variable, or create a .pth file (see the python | ||||
| # documentation for details). | ||||
| # | ||||
| # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will | ||||
| # cause an error if the version of python installed on the system | ||||
| # doesn't meet the requirement.  MINIMUM-VERSION should consist of | ||||
| # numbers and dots only. | ||||
| AC_DEFUN([AM_PATH_PYTHON], | ||||
|  [ | ||||
|   dnl Find a Python interpreter.  Python versions prior to 2.0 are not | ||||
|   dnl supported. (2.0 was released on October 16, 2000). | ||||
|   m4_define_default([_AM_PYTHON_INTERPRETER_LIST], | ||||
| [python python2 python3 dnl | ||||
|  python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl | ||||
|  python3.2 python3.1 python3.0 dnl | ||||
|  python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl | ||||
|  python2.0]) | ||||
|  | ||||
|   AC_ARG_VAR([PYTHON], [the Python interpreter]) | ||||
|  | ||||
|   m4_if([$1],[],[ | ||||
|     dnl No version check is needed. | ||||
|     # Find any Python interpreter. | ||||
|     if test -z "$PYTHON"; then | ||||
|       AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) | ||||
|     fi | ||||
|     am_display_PYTHON=python | ||||
|   ], [ | ||||
|     dnl A version check is needed. | ||||
|     if test -n "$PYTHON"; then | ||||
|       # If the user set $PYTHON, use it and don't search something else. | ||||
|       AC_MSG_CHECKING([whether $PYTHON version is >= $1]) | ||||
|       AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], | ||||
| 			      [AC_MSG_RESULT([yes])], | ||||
| 			      [AC_MSG_RESULT([no]) | ||||
| 			       AC_MSG_ERROR([Python interpreter is too old])]) | ||||
|       am_display_PYTHON=$PYTHON | ||||
|     else | ||||
|       # Otherwise, try each interpreter until we find one that satisfies | ||||
|       # VERSION. | ||||
|       AC_CACHE_CHECK([for a Python interpreter with version >= $1], | ||||
| 	[am_cv_pathless_PYTHON],[ | ||||
| 	for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do | ||||
| 	  test "$am_cv_pathless_PYTHON" = none && break | ||||
| 	  AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) | ||||
| 	done]) | ||||
|       # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. | ||||
|       if test "$am_cv_pathless_PYTHON" = none; then | ||||
| 	PYTHON=: | ||||
|       else | ||||
|         AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) | ||||
|       fi | ||||
|       am_display_PYTHON=$am_cv_pathless_PYTHON | ||||
|     fi | ||||
|   ]) | ||||
|  | ||||
|   if test "$PYTHON" = :; then | ||||
|     dnl Run any user-specified action, or abort. | ||||
|     m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) | ||||
|   else | ||||
|  | ||||
|   dnl Query Python for its version number.  Although site.py simply uses | ||||
|   dnl sys.version[:3], printing that failed with Python 3.10, since the | ||||
|   dnl trailing zero was eliminated. So now we output just the major | ||||
|   dnl and minor version numbers, as numbers. Apparently the tertiary | ||||
|   dnl version is not of interest. | ||||
|   dnl | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], | ||||
|     [am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`]) | ||||
|   AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) | ||||
|  | ||||
|   dnl At times, e.g., when building shared libraries, you may want | ||||
|   dnl to know which OS platform Python thinks this is. | ||||
|   dnl | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], | ||||
|     [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) | ||||
|   AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) | ||||
|  | ||||
|   dnl emacs-page | ||||
|   dnl If --with-python-sys-prefix is given, use the values of sys.prefix | ||||
|   dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX | ||||
|   dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and | ||||
|   dnl ${exec_prefix} variables. | ||||
|   dnl | ||||
|   dnl The two are made distinct variables so they can be overridden if | ||||
|   dnl need be, although general consensus is that you shouldn't need | ||||
|   dnl this separation. | ||||
|   dnl | ||||
|   dnl Also allow directly setting the prefixes via configure options, | ||||
|   dnl overriding any default. | ||||
|   dnl | ||||
|   if test "x$prefix" = xNONE; then | ||||
|     am__usable_prefix=$ac_default_prefix | ||||
|   else | ||||
|     am__usable_prefix=$prefix | ||||
|   fi | ||||
|  | ||||
|   # Allow user to request using sys.* values from Python, | ||||
|   # instead of the GNU $prefix values. | ||||
|   AC_ARG_WITH([python-sys-prefix], | ||||
|   [AS_HELP_STRING([--with-python-sys-prefix], | ||||
|                   [use Python's sys.prefix and sys.exec_prefix values])], | ||||
|   [am_use_python_sys=:], | ||||
|   [am_use_python_sys=false]) | ||||
|  | ||||
|   # Allow user to override whatever the default Python prefix is. | ||||
|   AC_ARG_WITH([python_prefix], | ||||
|   [AS_HELP_STRING([--with-python_prefix], | ||||
|                   [override the default PYTHON_PREFIX])], | ||||
|   [am_python_prefix_subst=$withval | ||||
|    am_cv_python_prefix=$withval | ||||
|    AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix]) | ||||
|    AC_MSG_RESULT([$am_cv_python_prefix])], | ||||
|   [ | ||||
|    if $am_use_python_sys; then | ||||
|      # using python sys.prefix value, not GNU | ||||
|      AC_CACHE_CHECK([for python default $am_display_PYTHON prefix], | ||||
|      [am_cv_python_prefix], | ||||
|      [am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`]) | ||||
|  | ||||
|      dnl If sys.prefix is a subdir of $prefix, replace the literal value of | ||||
|      dnl $prefix with a variable reference so it can be overridden. | ||||
|      case $am_cv_python_prefix in | ||||
|      $am__usable_prefix*) | ||||
|        am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'` | ||||
|        am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"` | ||||
|        ;; | ||||
|      *) | ||||
|        am_python_prefix_subst=$am_cv_python_prefix | ||||
|        ;; | ||||
|      esac | ||||
|    else # using GNU prefix value, not python sys.prefix | ||||
|      am_python_prefix_subst='${prefix}' | ||||
|      am_python_prefix=$am_python_prefix_subst | ||||
|      AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix]) | ||||
|      AC_MSG_RESULT([$am_python_prefix]) | ||||
|    fi]) | ||||
|   # Substituting python_prefix_subst value. | ||||
|   AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst]) | ||||
|  | ||||
|   # emacs-page Now do it all over again for Python exec_prefix, but with yet | ||||
|   # another conditional: fall back to regular prefix if that was specified. | ||||
|   AC_ARG_WITH([python_exec_prefix], | ||||
|   [AS_HELP_STRING([--with-python_exec_prefix], | ||||
|                   [override the default PYTHON_EXEC_PREFIX])], | ||||
|   [am_python_exec_prefix_subst=$withval | ||||
|    am_cv_python_exec_prefix=$withval | ||||
|    AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix]) | ||||
|    AC_MSG_RESULT([$am_cv_python_exec_prefix])], | ||||
|   [ | ||||
|    # no explicit --with-python_exec_prefix, but if | ||||
|    # --with-python_prefix was given, use its value for python_exec_prefix too. | ||||
|    AS_IF([test -n "$with_python_prefix"], | ||||
|    [am_python_exec_prefix_subst=$with_python_prefix | ||||
|     am_cv_python_exec_prefix=$with_python_prefix | ||||
|     AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix]) | ||||
|     AC_MSG_RESULT([$am_cv_python_exec_prefix])], | ||||
|    [ | ||||
|     # Set am__usable_exec_prefix whether using GNU or Python values, | ||||
|     # since we use that variable for pyexecdir. | ||||
|     if test "x$exec_prefix" = xNONE; then | ||||
|       am__usable_exec_prefix=$am__usable_prefix | ||||
|     else | ||||
|       am__usable_exec_prefix=$exec_prefix | ||||
|     fi | ||||
|     # | ||||
|     if $am_use_python_sys; then # using python sys.exec_prefix, not GNU | ||||
|       AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix], | ||||
|       [am_cv_python_exec_prefix], | ||||
|       [am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`]) | ||||
|       dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the | ||||
|       dnl literal value of $exec_prefix with a variable reference so it can | ||||
|       dnl be overridden. | ||||
|       case $am_cv_python_exec_prefix in | ||||
|       $am__usable_exec_prefix*) | ||||
|         am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'` | ||||
|         am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"` | ||||
|         ;; | ||||
|       *) | ||||
|         am_python_exec_prefix_subst=$am_cv_python_exec_prefix | ||||
|         ;; | ||||
|      esac | ||||
|    else # using GNU $exec_prefix, not python sys.exec_prefix | ||||
|      am_python_exec_prefix_subst='${exec_prefix}' | ||||
|      am_python_exec_prefix=$am_python_exec_prefix_subst | ||||
|      AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix]) | ||||
|      AC_MSG_RESULT([$am_python_exec_prefix]) | ||||
|    fi])]) | ||||
|   # Substituting python_exec_prefix_subst. | ||||
|   AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst]) | ||||
|  | ||||
|   # Factor out some code duplication into this shell variable. | ||||
|   am_python_setup_sysconfig="\ | ||||
| import sys | ||||
| # Prefer sysconfig over distutils.sysconfig, for better compatibility | ||||
| # with python 3.x.  See automake bug#10227. | ||||
| try: | ||||
|     import sysconfig | ||||
| except ImportError: | ||||
|     can_use_sysconfig = 0 | ||||
| else: | ||||
|     can_use_sysconfig = 1 | ||||
| # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: | ||||
| # <https://github.com/pypa/virtualenv/issues/118> | ||||
| try: | ||||
|     from platform import python_implementation | ||||
|     if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': | ||||
|         can_use_sysconfig = 0 | ||||
| except ImportError: | ||||
|     pass" | ||||
|  | ||||
|   dnl emacs-page Set up 4 directories: | ||||
|  | ||||
|   dnl 1. pythondir: where to install python scripts.  This is the | ||||
|   dnl    site-packages directory, not the python standard library | ||||
|   dnl    directory like in previous automake betas.  This behavior | ||||
|   dnl    is more consistent with lispdir.m4 for example. | ||||
|   dnl Query distutils for this directory. | ||||
|   dnl | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)], | ||||
|   [am_cv_python_pythondir], | ||||
|   [if test "x$am_cv_python_prefix" = x; then | ||||
|      am_py_prefix=$am__usable_prefix | ||||
|    else | ||||
|      am_py_prefix=$am_cv_python_prefix | ||||
|    fi | ||||
|    am_cv_python_pythondir=`$PYTHON -c " | ||||
| $am_python_setup_sysconfig | ||||
| if can_use_sysconfig: | ||||
|   sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) | ||||
| else: | ||||
|   from distutils import sysconfig | ||||
|   sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') | ||||
| sys.stdout.write(sitedir)"` | ||||
|    # | ||||
|    case $am_cv_python_pythondir in | ||||
|    $am_py_prefix*) | ||||
|      am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` | ||||
|      am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"` | ||||
|      ;; | ||||
|    *) | ||||
|      case $am_py_prefix in | ||||
|        /usr|/System*) ;; | ||||
|        *) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages" | ||||
|           ;; | ||||
|      esac | ||||
|      ;; | ||||
|    esac | ||||
|   ]) | ||||
|   AC_SUBST([pythondir], [$am_cv_python_pythondir]) | ||||
|  | ||||
|   dnl 2. pkgpythondir: $PACKAGE directory under pythondir.  Was | ||||
|   dnl    PYTHON_SITE_PACKAGE in previous betas, but this naming is | ||||
|   dnl    more consistent with the rest of automake. | ||||
|   dnl | ||||
|   AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) | ||||
|  | ||||
|   dnl 3. pyexecdir: directory for installing python extension modules | ||||
|   dnl    (shared libraries). | ||||
|   dnl Query distutils for this directory. | ||||
|   dnl | ||||
|   AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)], | ||||
|   [am_cv_python_pyexecdir], | ||||
|   [if test "x$am_cv_python_exec_prefix" = x; then | ||||
|      am_py_exec_prefix=$am__usable_exec_prefix | ||||
|    else | ||||
|      am_py_exec_prefix=$am_cv_python_exec_prefix | ||||
|    fi | ||||
|    am_cv_python_pyexecdir=`$PYTHON -c " | ||||
| $am_python_setup_sysconfig | ||||
| if can_use_sysconfig: | ||||
|   sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'}) | ||||
| else: | ||||
|   from distutils import sysconfig | ||||
|   sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix') | ||||
| sys.stdout.write(sitedir)"` | ||||
|    # | ||||
|    case $am_cv_python_pyexecdir in | ||||
|    $am_py_exec_prefix*) | ||||
|      am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` | ||||
|      am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"` | ||||
|      ;; | ||||
|    *) | ||||
|      case $am_py_exec_prefix in | ||||
|        /usr|/System*) ;; | ||||
|        *) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages" | ||||
|           ;; | ||||
|      esac | ||||
|      ;; | ||||
|    esac | ||||
|   ]) | ||||
|   AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) | ||||
|  | ||||
|   dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE) | ||||
|   dnl | ||||
|   AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) | ||||
|  | ||||
|   dnl Run any user-specified action. | ||||
|   $2 | ||||
|   fi | ||||
| ]) | ||||
|  | ||||
|  | ||||
| # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) | ||||
| # --------------------------------------------------------------------------- | ||||
| # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. | ||||
| # Run ACTION-IF-FALSE otherwise. | ||||
| # This test uses sys.hexversion instead of the string equivalent (first | ||||
| # word of sys.version), in order to cope with versions such as 2.2c1. | ||||
| # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). | ||||
| AC_DEFUN([AM_PYTHON_CHECK_VERSION], | ||||
|  [prog="import sys | ||||
| # split strings by '.' and convert to numeric.  Append some zeros | ||||
| # because we need at least 4 digits for the hex conversion. | ||||
| # map returns an iterator in Python 3.0 and a list in 2.x | ||||
| minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] | ||||
| minverhex = 0 | ||||
| # xrange is not present in Python 3.0 and range returns an iterator | ||||
| for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] | ||||
| sys.exit(sys.hexversion < minverhex)" | ||||
|   AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) | ||||
|  | ||||
| # Copyright (C) 2001-2021 Free Software Foundation, Inc. | ||||
| # | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
| # AM_RUN_LOG(COMMAND) | ||||
| # ------------------- | ||||
| # Run COMMAND, save the exit status in ac_status, and log it. | ||||
| # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) | ||||
| AC_DEFUN([AM_RUN_LOG], | ||||
| [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD | ||||
|    ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD | ||||
|    ac_status=$? | ||||
|    echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD | ||||
|    (exit $ac_status); }]) | ||||
|  | ||||
| m4_include([acinclude.m4]) | ||||
							
								
								
									
										1982
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1982
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2714
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2714
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/sh | ||||
| #!/bin/sh | ||||
| # install - install a program, script, or datafile | ||||
|  | ||||
| scriptversion=2020-11-14.01; # UTC | ||||
| scriptversion=2003-06-13.21 | ||||
|  | ||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||
| # later released in X11R6 (xc/config/util/install.sh) with the | ||||
| @@ -35,507 +35,252 @@ scriptversion=2020-11-14.01; # UTC | ||||
| # FSF changes to this file are in the public domain. | ||||
| # | ||||
| # Calling this script install-sh is preferred over install.sh, to prevent | ||||
| # 'make' implicit rules from creating a file called install from it | ||||
| # `make' implicit rules from creating a file called install from it | ||||
| # when there is no Makefile. | ||||
| # | ||||
| # This script is compatible with the BSD install script, but was written | ||||
| # from scratch. | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
|  | ||||
| tab='	' | ||||
| nl=' | ||||
| ' | ||||
| IFS=" $tab$nl" | ||||
| # set DOITPROG to echo to test this script | ||||
|  | ||||
| # Set DOITPROG to "echo" to test this script. | ||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||
| doit="${DOITPROG-}" | ||||
|  | ||||
| doit=${DOITPROG-} | ||||
| doit_exec=${doit:-exec} | ||||
| # put in absolute paths if you don't have them in your path; or use env. vars. | ||||
|  | ||||
| # Put in absolute file names if you don't have them in your path; | ||||
| # or use environment vars. | ||||
| mvprog="${MVPROG-mv}" | ||||
| cpprog="${CPPROG-cp}" | ||||
| chmodprog="${CHMODPROG-chmod}" | ||||
| chownprog="${CHOWNPROG-chown}" | ||||
| chgrpprog="${CHGRPPROG-chgrp}" | ||||
| stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| chgrpprog=${CHGRPPROG-chgrp} | ||||
| chmodprog=${CHMODPROG-chmod} | ||||
| chownprog=${CHOWNPROG-chown} | ||||
| cmpprog=${CMPPROG-cmp} | ||||
| cpprog=${CPPROG-cp} | ||||
| mkdirprog=${MKDIRPROG-mkdir} | ||||
| mvprog=${MVPROG-mv} | ||||
| rmprog=${RMPROG-rm} | ||||
| stripprog=${STRIPPROG-strip} | ||||
|  | ||||
| posix_mkdir= | ||||
|  | ||||
| # Desired mode of installed file. | ||||
| mode=0755 | ||||
|  | ||||
| # Create dirs (including intermediate dirs) using mode 755. | ||||
| # This is like GNU 'install' as of coreutils 8.32 (2020). | ||||
| mkdir_umask=22 | ||||
|  | ||||
| backupsuffix= | ||||
| chgrpcmd= | ||||
| chmodcmd=$chmodprog | ||||
| transformbasename= | ||||
| transform_arg= | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd= | ||||
| mvcmd=$mvprog | ||||
| rmcmd="$rmprog -f" | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
|  | ||||
| rmcmd="$rmprog -f" | ||||
| mvcmd="$mvprog" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
| dst_arg= | ||||
|  | ||||
| copy_on_change=false | ||||
| is_target_a_directory=possibly | ||||
| usage="Usage: $0 [OPTION]... SRCFILE DSTFILE | ||||
|    or: $0 -d DIR1 DIR2... | ||||
|  | ||||
| usage="\ | ||||
| Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||
|    or: $0 [OPTION]... -d DIRECTORIES... | ||||
|  | ||||
| In the 1st form, copy SRCFILE to DSTFILE. | ||||
| In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | ||||
| In the 4th, create DIRECTORIES. | ||||
| In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. | ||||
| In the second, create the directory path DIR. | ||||
|  | ||||
| Options: | ||||
|      --help     display this help and exit. | ||||
|      --version  display version info and exit. | ||||
|  | ||||
|   -c            (ignored) | ||||
|   -C            install only if different (preserve data modification time) | ||||
|   -d            create directories instead of installing files. | ||||
|   -g GROUP      $chgrpprog installed files to GROUP. | ||||
|   -m MODE       $chmodprog installed files to MODE. | ||||
|   -o USER       $chownprog installed files to USER. | ||||
|   -p            pass -p to $cpprog. | ||||
|   -s            $stripprog installed files. | ||||
|   -S SUFFIX     attempt to back up existing files, with suffix SUFFIX. | ||||
|   -t DIRECTORY  install into DIRECTORY. | ||||
|   -T            report an error if DSTFILE is a directory. | ||||
| -b=TRANSFORMBASENAME | ||||
| -c         copy source (using $cpprog) instead of moving (using $mvprog). | ||||
| -d         create directories instead of installing files. | ||||
| -g GROUP   $chgrp installed files to GROUP. | ||||
| -m MODE    $chmod installed files to MODE. | ||||
| -o USER    $chown installed files to USER. | ||||
| -s         strip installed files (using $stripprog). | ||||
| -t=TRANSFORM | ||||
| --help     display this help and exit. | ||||
| --version  display version info and exit. | ||||
|  | ||||
| Environment variables override the default commands: | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG | ||||
|   RMPROG STRIPPROG | ||||
|  | ||||
| By default, rm is invoked with -f; when overridden with RMPROG, | ||||
| it's up to you to specify -f if you want it. | ||||
|  | ||||
| If -S is not specified, no backups are attempted. | ||||
|  | ||||
| Email bug reports to bug-automake@gnu.org. | ||||
| Automake home page: https://www.gnu.org/software/automake/ | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG | ||||
| " | ||||
|  | ||||
| while test $# -ne 0; do | ||||
| while test -n "$1"; do | ||||
|   case $1 in | ||||
|     -c) ;; | ||||
|     -b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -C) copy_on_change=true;; | ||||
|     -c) instcmd=$cpprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -d) dir_arg=true;; | ||||
|     -d) dir_arg=true | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -g) chgrpcmd="$chgrpprog $2" | ||||
|         shift;; | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     --help) echo "$usage"; exit $?;; | ||||
|     --help) echo "$usage"; exit 0;; | ||||
|  | ||||
|     -m) mode=$2 | ||||
|         case $mode in | ||||
|           *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) | ||||
|             echo "$0: invalid mode: $mode" >&2 | ||||
|             exit 1;; | ||||
|         esac | ||||
|         shift;; | ||||
|     -m) chmodcmd="$chmodprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -o) chowncmd="$chownprog $2" | ||||
|         shift;; | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -p) cpprog="$cpprog -p";; | ||||
|     -s) stripcmd=$stripprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -s) stripcmd=$stripprog;; | ||||
|     -t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -S) backupsuffix="$2" | ||||
|         shift;; | ||||
|     --version) echo "$0 $scriptversion"; exit 0;; | ||||
|  | ||||
|     -t) | ||||
|         is_target_a_directory=always | ||||
|         dst_arg=$2 | ||||
|         # Protect names problematic for 'test' and other utilities. | ||||
|         case $dst_arg in | ||||
|           -* | [=\(\)!]) dst_arg=./$dst_arg;; | ||||
|         esac | ||||
|         shift;; | ||||
|  | ||||
|     -T) is_target_a_directory=never;; | ||||
|  | ||||
|     --version) echo "$0 $scriptversion"; exit $?;; | ||||
|  | ||||
|     --) shift | ||||
|         break;; | ||||
|  | ||||
|     -*) echo "$0: invalid option: $1" >&2 | ||||
|         exit 1;; | ||||
|  | ||||
|     *)  break;; | ||||
|     *)  if test -z "$src"; then | ||||
|           src=$1 | ||||
|         else | ||||
|           # this colon is to work around a 386BSD /bin/sh bug | ||||
|           : | ||||
|           dst=$1 | ||||
|         fi | ||||
|         shift | ||||
|         continue;; | ||||
|   esac | ||||
|   shift | ||||
| done | ||||
|  | ||||
| # We allow the use of options -d and -T together, by making -d | ||||
| # take the precedence; this is for compatibility with GNU install. | ||||
| if test -z "$src"; then | ||||
|   echo "$0: no input file specified." >&2 | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| if test -n "$dir_arg"; then | ||||
|   if test -n "$dst_arg"; then | ||||
|     echo "$0: target directory not allowed when installing a directory." >&2 | ||||
|   dst=$src | ||||
|   src= | ||||
|  | ||||
|   if test -d "$dst"; then | ||||
|     instcmd=: | ||||
|     chmodcmd= | ||||
|   else | ||||
|     instcmd=$mkdirprog | ||||
|   fi | ||||
| else | ||||
|   # Waiting for this to be detected by the "$instcmd $src $dsttmp" command | ||||
|   # might cause directories to be created, which would be especially bad | ||||
|   # if $src (and thus $dsttmp) contains '*'. | ||||
|   if test ! -f "$src" && test ! -d "$src"; then | ||||
|     echo "$0: $src does not exist." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   if test -z "$dst"; then | ||||
|     echo "$0: no destination specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   # If destination is a directory, append the input filename; won't work | ||||
|   # if double slashes aren't ignored. | ||||
|   if test -d "$dst"; then | ||||
|     dst=$dst/`basename "$src"` | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then | ||||
|   # When -d is used, all remaining arguments are directories to create. | ||||
|   # When -t is used, the destination is already specified. | ||||
|   # Otherwise, the last argument is the destination.  Remove it from $@. | ||||
|   for arg | ||||
|   do | ||||
|     if test -n "$dst_arg"; then | ||||
|       # $@ is not empty: it contains at least $arg. | ||||
|       set fnord "$@" "$dst_arg" | ||||
|       shift # fnord | ||||
|     fi | ||||
|     shift # arg | ||||
|     dst_arg=$arg | ||||
|     # Protect names problematic for 'test' and other utilities. | ||||
|     case $dst_arg in | ||||
|       -* | [=\(\)!]) dst_arg=./$dst_arg;; | ||||
|     esac | ||||
| ## this sed command emulates the dirname command | ||||
| dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | ||||
|  | ||||
| # Make sure that the destination directory exists. | ||||
| # (this part is taken from Noah Friedman's mkinstalldirs script.) | ||||
|  | ||||
| # Skip lots of stat calls in the usual case. | ||||
| if test ! -d "$dstdir"; then | ||||
|   defaultIFS=' | ||||
| 	' | ||||
|   IFS="${IFS-$defaultIFS}" | ||||
|  | ||||
|   oIFS=$IFS | ||||
|   # Some sh's can't handle IFS=/ for some reason. | ||||
|   IFS='%' | ||||
|   set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` | ||||
|   IFS=$oIFS | ||||
|  | ||||
|   pathcomp= | ||||
|  | ||||
|   while test $# -ne 0 ; do | ||||
|     pathcomp=$pathcomp$1 | ||||
|     shift | ||||
|     test -d "$pathcomp" || $mkdirprog "$pathcomp" | ||||
|     pathcomp=$pathcomp/ | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if test $# -eq 0; then | ||||
|   if test -z "$dir_arg"; then | ||||
|     echo "$0: no input file specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|   # It's OK to call 'install-sh -d' without argument. | ||||
|   # This can happen when creating conditional directories. | ||||
|   exit 0 | ||||
| fi | ||||
| if test -n "$dir_arg"; then | ||||
|   $doit $instcmd "$dst" \ | ||||
|     && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ | ||||
|     && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ | ||||
|     && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ | ||||
|     && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } | ||||
|  | ||||
| if test -z "$dir_arg"; then | ||||
|   if test $# -gt 1 || test "$is_target_a_directory" = always; then | ||||
|     if test ! -d "$dst_arg"; then | ||||
|       echo "$0: $dst_arg: Is not a directory." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| if test -z "$dir_arg"; then | ||||
|   do_exit='(exit $ret); exit $ret' | ||||
|   trap "ret=129; $do_exit" 1 | ||||
|   trap "ret=130; $do_exit" 2 | ||||
|   trap "ret=141; $do_exit" 13 | ||||
|   trap "ret=143; $do_exit" 15 | ||||
|  | ||||
|   # Set umask so as not to create temps with too-generous modes. | ||||
|   # However, 'strip' requires both read and write access to temps. | ||||
|   case $mode in | ||||
|     # Optimize common cases. | ||||
|     *644) cp_umask=133;; | ||||
|     *755) cp_umask=22;; | ||||
|  | ||||
|     *[0-7]) | ||||
|       if test -z "$stripcmd"; then | ||||
|         u_plus_rw= | ||||
|       else | ||||
|         u_plus_rw='% 200' | ||||
|       fi | ||||
|       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; | ||||
|     *) | ||||
|       if test -z "$stripcmd"; then | ||||
|         u_plus_rw= | ||||
|       else | ||||
|         u_plus_rw=,u+rw | ||||
|       fi | ||||
|       cp_umask=$mode$u_plus_rw;; | ||||
|   esac | ||||
| fi | ||||
|  | ||||
| for src | ||||
| do | ||||
|   # Protect names problematic for 'test' and other utilities. | ||||
|   case $src in | ||||
|     -* | [=\(\)!]) src=./$src;; | ||||
|   esac | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     dst=$src | ||||
|     dstdir=$dst | ||||
|     test -d "$dstdir" | ||||
|     dstdir_status=$? | ||||
|     # Don't chown directories that already exist. | ||||
|     if test $dstdir_status = 0; then | ||||
|       chowncmd="" | ||||
|     fi | ||||
| else | ||||
|   # If we're going to rename the final executable, determine the name now. | ||||
|   if test -z "$transformarg"; then | ||||
|     dstfile=`basename "$dst"` | ||||
|   else | ||||
|  | ||||
|     # Waiting for this to be detected by the "$cpprog $src $dsttmp" command | ||||
|     # might cause directories to be created, which would be especially bad | ||||
|     # if $src (and thus $dsttmp) contains '*'. | ||||
|     if test ! -f "$src" && test ! -d "$src"; then | ||||
|       echo "$0: $src does not exist." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     if test -z "$dst_arg"; then | ||||
|       echo "$0: no destination specified." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|     dst=$dst_arg | ||||
|  | ||||
|     # If destination is a directory, append the input filename. | ||||
|     if test -d "$dst"; then | ||||
|       if test "$is_target_a_directory" = never; then | ||||
|         echo "$0: $dst_arg: Is a directory" >&2 | ||||
|         exit 1 | ||||
|       fi | ||||
|       dstdir=$dst | ||||
|       dstbase=`basename "$src"` | ||||
|       case $dst in | ||||
| 	*/) dst=$dst$dstbase;; | ||||
| 	*)  dst=$dst/$dstbase;; | ||||
|       esac | ||||
|       dstdir_status=0 | ||||
|     else | ||||
|       dstdir=`dirname "$dst"` | ||||
|       test -d "$dstdir" | ||||
|       dstdir_status=$? | ||||
|     fi | ||||
|     dstfile=`basename "$dst" $transformbasename \ | ||||
|              | sed $transformarg`$transformbasename | ||||
|   fi | ||||
|  | ||||
|   case $dstdir in | ||||
|     */) dstdirslash=$dstdir;; | ||||
|     *)  dstdirslash=$dstdir/;; | ||||
|   esac | ||||
|   # don't allow the sed command to completely eliminate the filename. | ||||
|   test -z "$dstfile" && dstfile=`basename "$dst"` | ||||
|  | ||||
|   obsolete_mkdir_used=false | ||||
|   # Make a couple of temp file names in the proper directory. | ||||
|   dsttmp=$dstdir/_inst.$$_ | ||||
|   rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
|   if test $dstdir_status != 0; then | ||||
|     case $posix_mkdir in | ||||
|       '') | ||||
|         # With -d, create the new directory with the user-specified mode. | ||||
|         # Otherwise, rely on $mkdir_umask. | ||||
|         if test -n "$dir_arg"; then | ||||
|           mkdir_mode=-m$mode | ||||
|         else | ||||
|           mkdir_mode= | ||||
|         fi | ||||
|   # Trap to clean up those temp files at exit. | ||||
|   trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
|         posix_mkdir=false | ||||
| 	# The $RANDOM variable is not portable (e.g., dash).  Use it | ||||
| 	# here however when possible just to lower collision chance. | ||||
| 	tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ | ||||
|   # Move or copy the file name to the temp name | ||||
|   $doit $instcmd "$src" "$dsttmp" && | ||||
|  | ||||
| 	trap ' | ||||
| 	  ret=$? | ||||
| 	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null | ||||
| 	  exit $ret | ||||
| 	' 0 | ||||
|   # and set any options; do chmod last to preserve setuid bits. | ||||
|   # | ||||
|   # If any of these fail, we abort the whole thing.  If we want to | ||||
|   # ignore errors from any of these, just make sure not to ignore | ||||
|   # errors from the above "$doit $instcmd $src $dsttmp" command. | ||||
|   # | ||||
|   { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ | ||||
|     && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ | ||||
|     && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ | ||||
|     && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && | ||||
|  | ||||
| 	# Because "mkdir -p" follows existing symlinks and we likely work | ||||
| 	# directly in world-writeable /tmp, make sure that the '$tmpdir' | ||||
| 	# directory is successfully created first before we actually test | ||||
| 	# 'mkdir -p'. | ||||
| 	if (umask $mkdir_umask && | ||||
| 	    $mkdirprog $mkdir_mode "$tmpdir" && | ||||
| 	    exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 | ||||
| 	then | ||||
| 	  if test -z "$dir_arg" || { | ||||
| 	       # Check for POSIX incompatibilities with -m. | ||||
| 	       # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | ||||
| 	       # other-writable bit of parent directory when it shouldn't. | ||||
| 	       # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | ||||
| 	       test_tmpdir="$tmpdir/a" | ||||
| 	       ls_ld_tmpdir=`ls -ld "$test_tmpdir"` | ||||
| 	       case $ls_ld_tmpdir in | ||||
| 		 d????-?r-*) different_mode=700;; | ||||
| 		 d????-?--*) different_mode=755;; | ||||
| 		 *) false;; | ||||
| 	       esac && | ||||
| 	       $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { | ||||
| 		 ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` | ||||
| 		 test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" | ||||
| 	       } | ||||
| 	     } | ||||
| 	  then posix_mkdir=: | ||||
| 	  fi | ||||
| 	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" | ||||
| 	else | ||||
| 	  # Remove any dirs left behind by ancient mkdir implementations. | ||||
| 	  rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null | ||||
| 	fi | ||||
| 	trap '' 0;; | ||||
|     esac | ||||
|  | ||||
|     if | ||||
|       $posix_mkdir && ( | ||||
|         umask $mkdir_umask && | ||||
|         $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" | ||||
|       ) | ||||
|     then : | ||||
|     else | ||||
|  | ||||
|       # mkdir does not conform to POSIX, | ||||
|       # or it failed possibly due to a race condition.  Create the | ||||
|       # directory the slow way, step by step, checking for races as we go. | ||||
|  | ||||
|       case $dstdir in | ||||
|         /*) prefix='/';; | ||||
|         [-=\(\)!]*) prefix='./';; | ||||
|         *)  prefix='';; | ||||
|       esac | ||||
|  | ||||
|       oIFS=$IFS | ||||
|       IFS=/ | ||||
|       set -f | ||||
|       set fnord $dstdir | ||||
|       shift | ||||
|       set +f | ||||
|       IFS=$oIFS | ||||
|  | ||||
|       prefixes= | ||||
|  | ||||
|       for d | ||||
|       do | ||||
|         test X"$d" = X && continue | ||||
|  | ||||
|         prefix=$prefix$d | ||||
|         if test -d "$prefix"; then | ||||
|           prefixes= | ||||
|         else | ||||
|           if $posix_mkdir; then | ||||
|             (umask $mkdir_umask && | ||||
|              $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break | ||||
|             # Don't fail if two instances are running concurrently. | ||||
|             test -d "$prefix" || exit 1 | ||||
|           else | ||||
|             case $prefix in | ||||
|               *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; | ||||
|               *) qprefix=$prefix;; | ||||
|             esac | ||||
|             prefixes="$prefixes '$qprefix'" | ||||
|           fi | ||||
|         fi | ||||
|         prefix=$prefix/ | ||||
|       done | ||||
|  | ||||
|       if test -n "$prefixes"; then | ||||
|         # Don't fail if two instances are running concurrently. | ||||
|         (umask $mkdir_umask && | ||||
|          eval "\$doit_exec \$mkdirprog $prefixes") || | ||||
|           test -d "$dstdir" || exit 1 | ||||
|         obsolete_mkdir_used=true | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && | ||||
|     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && | ||||
|     { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || | ||||
|       test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 | ||||
|   else | ||||
|  | ||||
|     # Make a couple of temp file names in the proper directory. | ||||
|     dsttmp=${dstdirslash}_inst.$$_ | ||||
|     rmtmp=${dstdirslash}_rm.$$_ | ||||
|  | ||||
|     # Trap to clean up those temp files at exit. | ||||
|     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | ||||
|  | ||||
|     # Copy the file name to the temp name. | ||||
|     (umask $cp_umask && | ||||
|      { test -z "$stripcmd" || { | ||||
| 	 # Create $dsttmp read-write so that cp doesn't create it read-only, | ||||
| 	 # which would cause strip to fail. | ||||
| 	 if test -z "$doit"; then | ||||
| 	   : >"$dsttmp" # No need to fork-exec 'touch'. | ||||
| 	 else | ||||
| 	   $doit touch "$dsttmp" | ||||
| 	 fi | ||||
|        } | ||||
|      } && | ||||
|      $doit_exec $cpprog "$src" "$dsttmp") && | ||||
|  | ||||
|     # and set any options; do chmod last to preserve setuid bits. | ||||
|     # | ||||
|     # If any of these fail, we abort the whole thing.  If we want to | ||||
|     # ignore errors from any of these, just make sure not to ignore | ||||
|     # errors from the above "$doit $cpprog $src $dsttmp" command. | ||||
|     # | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && | ||||
|     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && | ||||
|     { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && | ||||
|     { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | ||||
|  | ||||
|     # If -C, don't bother to copy if it wouldn't change the file. | ||||
|     if $copy_on_change && | ||||
|        old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` && | ||||
|        new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` && | ||||
|        set -f && | ||||
|        set X $old && old=:$2:$4:$5:$6 && | ||||
|        set X $new && new=:$2:$4:$5:$6 && | ||||
|        set +f && | ||||
|        test "$old" = "$new" && | ||||
|        $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 | ||||
|     then | ||||
|       rm -f "$dsttmp" | ||||
|     else | ||||
|       # If $backupsuffix is set, and the file being installed | ||||
|       # already exists, attempt a backup.  Don't worry if it fails, | ||||
|       # e.g., if mv doesn't support -f. | ||||
|       if test -n "$backupsuffix" && test -f "$dst"; then | ||||
|         $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null | ||||
|       fi | ||||
|  | ||||
|       # Rename the file to the real destination. | ||||
|       $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || | ||||
|  | ||||
|       # The rename failed, perhaps because mv can't rename something else | ||||
|       # to itself, or perhaps because mv is so ancient that it does not | ||||
|       # support -f. | ||||
|       { | ||||
|         # Now remove or move aside any old file at destination location. | ||||
|         # We try this two ways since rm can't unlink itself on some | ||||
|         # systems and the destination file might be busy for other | ||||
|         # reasons.  In this case, the final cleanup might fail but the new | ||||
|         # file should still install successfully. | ||||
|         { | ||||
|           test ! -f "$dst" || | ||||
|           $doit $rmcmd "$dst" 2>/dev/null || | ||||
|           { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && | ||||
|             { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } | ||||
|           } || | ||||
|           { echo "$0: cannot unlink or rename $dst" >&2 | ||||
|             (exit 1); exit 1 | ||||
|           } | ||||
|         } && | ||||
|  | ||||
|         # Now rename the file to the real destination. | ||||
|         $doit $mvcmd "$dsttmp" "$dst" | ||||
|   # Now remove or move aside any old file at destination location.  We | ||||
|   # try this two ways since rm can't unlink itself on some systems and | ||||
|   # the destination file might be busy for other reasons.  In this case, | ||||
|   # the final cleanup might fail but the new file should still install | ||||
|   # successfully. | ||||
|   { | ||||
|     if test -f "$dstdir/$dstfile"; then | ||||
|       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ | ||||
|       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ | ||||
|       || { | ||||
| 	  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 | ||||
| 	  (exit 1); exit | ||||
|       } | ||||
|     fi || exit 1 | ||||
|     else | ||||
|       : | ||||
|     fi | ||||
|   } && | ||||
|  | ||||
|     trap '' 0 | ||||
|   fi | ||||
| done | ||||
|   # Now rename the file to the real destination. | ||||
|   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" | ||||
| fi && | ||||
|  | ||||
| # The final little trick to "correctly" pass the exit status to the exit trap. | ||||
| { | ||||
|   (exit 0); exit | ||||
| } | ||||
|  | ||||
| # Local variables: | ||||
| # eval: (add-hook 'before-save-hook 'time-stamp) | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
| # time-stamp-start: "scriptversion=" | ||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||
| # time-stamp-time-zone: "UTC0" | ||||
| # time-stamp-end: "; # UTC" | ||||
| # time-stamp-end: "$" | ||||
| # End: | ||||
|   | ||||
| @@ -1,242 +0,0 @@ | ||||
| #!/bin/sh | ||||
| # py-compile - Compile a Python program | ||||
|  | ||||
| scriptversion=2023-03-30.00; # UTC | ||||
|  | ||||
| # Copyright (C) 2000-2023 Free Software Foundation, Inc. | ||||
|  | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2, or (at your option) | ||||
| # any later version. | ||||
|  | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
|  | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| # As a special exception to the GNU General Public License, if you | ||||
| # distribute this file as part of a program that contains a | ||||
| # configuration script generated by Autoconf, you may include it under | ||||
| # the same distribution terms that you use for the rest of that program. | ||||
|  | ||||
| # This file is maintained in Automake, please report | ||||
| # bugs to <bug-automake@gnu.org> or send patches to | ||||
| # <automake-patches@gnu.org>. | ||||
|  | ||||
| if test -z "$PYTHON"; then | ||||
|   PYTHON=python | ||||
| fi | ||||
|  | ||||
| me=py-compile | ||||
|  | ||||
| usage_error () | ||||
| { | ||||
|   echo "$me: $*" >&2 | ||||
|   echo "Try '$me --help' for more information." >&2 | ||||
|   exit 1 | ||||
| } | ||||
|  | ||||
| basedir= | ||||
| destdir= | ||||
| while test $# -ne 0; do | ||||
|   case "$1" in | ||||
|     --basedir) | ||||
|       if test $# -lt 2; then | ||||
|         usage_error "option '--basedir' requires an argument" | ||||
|       else | ||||
|         basedir=$2 | ||||
|       fi | ||||
|       shift | ||||
|       ;; | ||||
|     --destdir) | ||||
|       if test $# -lt 2; then | ||||
|         usage_error "option '--destdir' requires an argument" | ||||
|       else | ||||
|         destdir=$2 | ||||
|       fi | ||||
|       shift | ||||
|       ;; | ||||
|     -h|--help) | ||||
|       cat <<\EOF | ||||
| Usage: py-compile [options] FILES... | ||||
|  | ||||
| Byte compile some python scripts FILES.  Use --destdir to specify any | ||||
| leading directory path to the FILES that you don't want to include in the | ||||
| byte compiled file.  Specify --basedir for any additional path information you | ||||
| do want to be shown in the byte compiled file. | ||||
|  | ||||
| Options: | ||||
|   --basedir DIR   Prefix all FILES with DIR, and include in error messages. | ||||
|   --destdir DIR   Prefix all FILES with DIR before compiling. | ||||
|   -v, --version   Display version information. | ||||
|   -h, --help      This help screen. | ||||
|  | ||||
| Example: | ||||
|   py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py | ||||
|  | ||||
| Report bugs to <bug-automake@gnu.org>. | ||||
| EOF | ||||
|       exit $? | ||||
|       ;; | ||||
|     -v|--version) | ||||
|       echo "$me $scriptversion" | ||||
|       exit $? | ||||
|       ;; | ||||
|     --) | ||||
|       shift | ||||
|       break | ||||
|       ;; | ||||
|     -*) | ||||
|       usage_error "unrecognized option '$1'" | ||||
|       ;; | ||||
|     *) | ||||
|       break | ||||
|       ;; | ||||
|   esac | ||||
|   shift | ||||
| done | ||||
|  | ||||
| if test $# -eq 0; then | ||||
|   usage_error "no files given" | ||||
| fi | ||||
|  | ||||
| # if basedir was given, then it should be prepended to filenames before | ||||
| # byte compilation. | ||||
| if test -z "$basedir"; then | ||||
|   pathtrans="path = file" | ||||
| else | ||||
|   pathtrans="path = os.path.join('$basedir', file)" | ||||
| fi | ||||
|  | ||||
| # if destdir was given, then it needs to be prepended to the filename to | ||||
| # byte compile but not go into the compiled file. | ||||
| if test -z "$destdir"; then | ||||
|   filetrans="filepath = path" | ||||
| else | ||||
|   filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)" | ||||
| fi | ||||
|  | ||||
| python_major=`$PYTHON -c 'import sys; print(sys.version_info[0])'` | ||||
| if test -z "$python_major"; then | ||||
|   usage_error "could not determine $PYTHON major version" | ||||
| fi | ||||
|  | ||||
| case $python_major in | ||||
| [01]) | ||||
|   usage_error "python version 0.x and 1.x not supported" | ||||
|   ;; | ||||
| esac | ||||
|  | ||||
| python_minor=`$PYTHON -c 'import sys; print(sys.version_info[1])'` | ||||
|  | ||||
| # NB: When adding support for newer versions, prefer copying & adding new cases | ||||
| # rather than try to keep things merged with shell variables. | ||||
|  | ||||
| # First byte compile (no optimization) all the modules. | ||||
| # This works for all currently known Python versions. | ||||
| $PYTHON -c " | ||||
| import sys, os, py_compile | ||||
|  | ||||
| try: | ||||
|     import importlib | ||||
| except ImportError: | ||||
|     importlib = None | ||||
|  | ||||
| # importlib.util.cache_from_source was added in 3.4 | ||||
| if ( | ||||
|         hasattr(importlib, 'util') | ||||
|         and hasattr(importlib.util, 'cache_from_source') | ||||
| ): | ||||
|     destpath = importlib.util.cache_from_source | ||||
| else: | ||||
|     destpath = lambda filepath: filepath + 'c' | ||||
|  | ||||
| sys.stdout.write('Byte-compiling python modules...\n') | ||||
| for file in sys.argv[1:]: | ||||
|     $pathtrans | ||||
|     $filetrans | ||||
|     if ( | ||||
|             not os.path.exists(filepath) | ||||
|             or not (len(filepath) >= 3 and filepath[-3:] == '.py') | ||||
|      ): | ||||
|         continue | ||||
|     sys.stdout.write(file + ' ') | ||||
|     sys.stdout.flush() | ||||
|     py_compile.compile(filepath, destpath(filepath), path) | ||||
| sys.stdout.write('\n')" "$@" || exit $? | ||||
|  | ||||
| # Then byte compile w/optimization all the modules. | ||||
| $PYTHON -O -c " | ||||
| import sys, os, py_compile | ||||
|  | ||||
| try: | ||||
|     import importlib | ||||
| except ImportError: | ||||
|     importlib = None | ||||
|  | ||||
| # importlib.util.cache_from_source was added in 3.4 | ||||
| if ( | ||||
|         hasattr(importlib, 'util') | ||||
|         and hasattr(importlib.util, 'cache_from_source') | ||||
| ): | ||||
|     destpath = importlib.util.cache_from_source | ||||
| else: | ||||
|     destpath = lambda filepath: filepath + 'o' | ||||
|  | ||||
| # pypy2 does not use .pyo optimization | ||||
| if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'): | ||||
|     sys.exit(0) | ||||
|  | ||||
| sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n') | ||||
| for file in sys.argv[1:]: | ||||
|     $pathtrans | ||||
|     $filetrans | ||||
|     if ( | ||||
|             not os.path.exists(filepath) | ||||
|             or not (len(filepath) >= 3 and filepath[-3:] == '.py') | ||||
|     ): | ||||
|         continue | ||||
|     sys.stdout.write(file + ' ') | ||||
|     sys.stdout.flush() | ||||
|     py_compile.compile(filepath, destpath(filepath), path) | ||||
| sys.stdout.write('\n')" "$@" 2>/dev/null || exit $? | ||||
|  | ||||
| # Then byte compile w/more optimization. | ||||
| # Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background. | ||||
| case $python_major.$python_minor in | ||||
| 2.*|3.[0-4]) | ||||
|   ;; | ||||
| *) | ||||
|   $PYTHON -OO -c " | ||||
| import sys, os, py_compile, importlib | ||||
|  | ||||
| sys.stdout.write('Byte-compiling python modules (more optimized versions)' | ||||
|                  ' ...\n') | ||||
| for file in sys.argv[1:]: | ||||
|     $pathtrans | ||||
|     $filetrans | ||||
|     if ( | ||||
|             not os.path.exists(filepath) | ||||
|             or not (len(filepath) >= 3 and filepath[-3:] == '.py') | ||||
|     ): | ||||
|         continue | ||||
|     sys.stdout.write(file + ' ') | ||||
|     sys.stdout.flush() | ||||
|     py_compile.compile(filepath, importlib.util.cache_from_source(filepath), path) | ||||
| sys.stdout.write('\n')" "$@" 2>/dev/null || exit $? | ||||
|   ;; | ||||
| esac | ||||
|  | ||||
| # Local Variables: | ||||
| # mode: shell-script | ||||
| # sh-indentation: 2 | ||||
| # eval: (add-hook 'before-save-hook 'time-stamp) | ||||
| # time-stamp-start: "scriptversion=" | ||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||
| # time-stamp-time-zone: "UTC0" | ||||
| # time-stamp-end: "; # UTC" | ||||
| # End: | ||||
| @@ -1,40 +0,0 @@ | ||||
| # Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| # Uncomment this to build the simple radix tree.  You'll need to make clean too. | ||||
| # Comment to build the advanced radix tree. | ||||
| #base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE | ||||
|  | ||||
| # NOTE: this Makefile only works as 'include' for toplevel Makefile | ||||
| #       which defined all top_* variables | ||||
|  | ||||
| BASE_SOURCE=\ | ||||
| 	base/data-struct/hash.c \ | ||||
| 	base/data-struct/list.c \ | ||||
| 	base/data-struct/radix-tree.c | ||||
|  | ||||
| BASE_TARGET = base/libbase.a | ||||
| BASE_DEPENDS = $(BASE_SOURCE:%.c=%.d) | ||||
| BASE_OBJECTS = $(BASE_SOURCE:%.c=%.o) | ||||
| CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \ | ||||
| 	$(BASE_SOURCE:%.c=%.gcda) \ | ||||
| 	$(BASE_SOURCE:%.c=%.gcno) \ | ||||
| 	$(BASE_TARGET) | ||||
|  | ||||
| $(BASE_TARGET): $(BASE_OBJECTS) | ||||
| 	$(SHOW) "    [AR] $@" | ||||
| 	$(Q) $(RM) $@ | ||||
| 	$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null | ||||
|  | ||||
| ifeq ("$(USE_TRACKING)","yes") | ||||
| -include $(BASE_DEPENDS) | ||||
| endif | ||||
| @@ -1,477 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "device_mapper/misc/dmlib.h" | ||||
| #include "base/memory/zalloc.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| struct dm_hash_node { | ||||
| 	struct dm_hash_node *next; | ||||
| 	void *data; | ||||
| 	unsigned data_len; | ||||
| 	unsigned keylen; | ||||
| 	unsigned hash; | ||||
| 	char key[0]; | ||||
| }; | ||||
|  | ||||
| struct dm_hash_table { | ||||
| 	unsigned num_nodes; | ||||
| 	unsigned num_hint; | ||||
| 	unsigned mask_slots;    /* (slots - 1) -> used as hash mask */ | ||||
| 	unsigned collisions;    /* Collissions of hash keys */ | ||||
| 	unsigned search;        /* How many keys were searched */ | ||||
| 	unsigned found;         /* How many nodes were found */ | ||||
| 	unsigned same_hash;     /* Was there a colision with same masked hash and len ? */ | ||||
| 	struct dm_hash_node **slots; | ||||
| }; | ||||
|  | ||||
| #if 0 /* TO BE REMOVED */ | ||||
| static unsigned _hash(const void *key, unsigned len) | ||||
| { | ||||
| 	/* Permutation of the Integers 0 through 255 */ | ||||
| 	static const unsigned char _nums[] = { | ||||
| 	1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51, | ||||
| 	87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, | ||||
| 	49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, | ||||
| 	12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172, | ||||
| 	144, | ||||
| 	176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254, | ||||
| 	178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54, | ||||
| 	221, | ||||
| 	102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93, | ||||
| 	166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189, | ||||
| 	121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185, | ||||
| 	194, | ||||
| 	193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232, | ||||
| 	139, | ||||
| 	6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, | ||||
| 	84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, | ||||
| 	43, | ||||
| 	249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, | ||||
| 	71, | ||||
| 	230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, | ||||
| 	109, | ||||
| 	44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184, | ||||
| 	163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120, | ||||
| 	209 | ||||
| 	}; | ||||
|  | ||||
| 	const uint8_t *str = key; | ||||
| 	unsigned h = 0, g; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		h <<= 4; | ||||
| 		h += _nums[*str++]; | ||||
| 		g = h & ((unsigned) 0xf << 16u); | ||||
| 		if (g) { | ||||
| 			h ^= g >> 16u; | ||||
| 			h ^= g >> 5u; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| /* In-kernel DM hashing, still lots of collisions */ | ||||
| static unsigned _hash_in_kernel(const char *key, unsigned len) | ||||
| { | ||||
| 	const unsigned char *str = (unsigned char *)key; | ||||
| 	const unsigned hash_mult = 2654435387U; | ||||
| 	unsigned hash = 0, i; | ||||
|  | ||||
| 	for (i = 0; i < len; ++i) | ||||
| 		hash = (hash + str[i]) * hash_mult; | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #undef get16bits | ||||
| #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) | ||||
| #define get16bits(d) (*((const uint16_t *) (d))) | ||||
| #endif | ||||
|  | ||||
| #if !defined (get16bits) | ||||
| #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ | ||||
|                        +(uint32_t)(((const uint8_t *)(d))[0]) ) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Adapted Bob Jenkins hash to read by 2 bytes if possible. | ||||
|  * https://secure.wikimedia.org/wikipedia/en/wiki/Jenkins_hash_function | ||||
|  * | ||||
|  * Reduces amount of hash collisions | ||||
|  */ | ||||
| static unsigned _hash(const void *key, unsigned len) | ||||
| { | ||||
| 	const uint8_t *str = (uint8_t*) key; | ||||
| 	unsigned hash = 0, i; | ||||
| 	unsigned sz = len / 2; | ||||
|  | ||||
| 	for(i = 0; i < sz; ++i) { | ||||
| 		hash += get16bits(str + 2 * i); | ||||
| 		hash += (hash << 10); | ||||
| 		hash ^= (hash >> 6); | ||||
| 	} | ||||
|  | ||||
| 	if (len & 1) { | ||||
| 		hash += str[len - 1]; | ||||
| 		hash += (hash << 10); | ||||
| 		hash ^= (hash >> 6); | ||||
| 	} | ||||
|  | ||||
| 	hash += (hash << 3); | ||||
| 	hash ^= (hash >> 11); | ||||
| 	hash += (hash << 15); | ||||
|  | ||||
| 	return hash; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node *_create_node(const void *key, unsigned len) | ||||
| { | ||||
| 	struct dm_hash_node *n = malloc(sizeof(*n) + len); | ||||
|  | ||||
| 	if (n) { | ||||
| 		memcpy(n->key, key, len); | ||||
| 		n->keylen = len; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| struct dm_hash_table *dm_hash_create(unsigned size_hint) | ||||
| { | ||||
| 	size_t len; | ||||
| 	unsigned new_size = 16u; | ||||
| 	struct dm_hash_table *hc = zalloc(sizeof(*hc)); | ||||
|  | ||||
| 	if (!hc) { | ||||
| 		log_error("Failed to allocate memory for hash."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	hc->num_hint = size_hint; | ||||
|  | ||||
| 	/* round size hint up to a power of two */ | ||||
| 	while (new_size < size_hint) | ||||
| 		new_size = new_size << 1; | ||||
|  | ||||
| 	hc->mask_slots = new_size - 1; | ||||
| 	len = sizeof(*(hc->slots)) * new_size; | ||||
| 	if (!(hc->slots = zalloc(len))) { | ||||
| 		free(hc); | ||||
| 		log_error("Failed to allocate slots for hash."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return hc; | ||||
| } | ||||
|  | ||||
| static void _free_nodes(struct dm_hash_table *t) | ||||
| { | ||||
| 	struct dm_hash_node *c, *n; | ||||
| 	unsigned i; | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	log_debug("Free hash hint:%d slots:%d nodes:%d (s:%d f:%d c:%d h:%d)", | ||||
| 		  t->num_hint, t->mask_slots + 1, t->num_nodes, | ||||
| 		  t->search, t->found, t->collisions, t->same_hash); | ||||
| #endif | ||||
|  | ||||
| 	if (!t->num_nodes) | ||||
| 		return; | ||||
|  | ||||
| 	for (i = 0; i <= t->mask_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = n) { | ||||
| 			n = c->next; | ||||
| 			free(c); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void dm_hash_destroy(struct dm_hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	free(t->slots); | ||||
| 	free(t); | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_findh(struct dm_hash_table *t, const void *key, | ||||
| 				    uint32_t len, unsigned hash) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	++t->search; | ||||
| 	for (c = &t->slots[hash & t->mask_slots]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen == len && (*c)->hash == hash) { | ||||
| 			if (!memcmp(key, (*c)->key, len)) { | ||||
| 				++t->found; | ||||
| 				break; | ||||
| 			} | ||||
| 			++t->same_hash; | ||||
| 		} | ||||
| 		++t->collisions; | ||||
| 	} | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key, | ||||
| 				   uint32_t len) | ||||
| { | ||||
| 	return _findh(t, key, len, _hash(key, len)); | ||||
| } | ||||
|  | ||||
| void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, | ||||
| 			    uint32_t len) | ||||
| { | ||||
| 	struct dm_hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	return *c ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, | ||||
| 			  uint32_t len, void *data) | ||||
| { | ||||
| 	unsigned hash = _hash(key, len); | ||||
| 	struct dm_hash_node **c = _findh(t, key, len, hash); | ||||
|  | ||||
| 	if (*c) | ||||
| 		(*c)->data = data; | ||||
| 	else { | ||||
| 		struct dm_hash_node *n = _create_node(key, len); | ||||
|  | ||||
| 		if (!n) | ||||
| 			return 0; | ||||
|  | ||||
| 		n->data = data; | ||||
| 		n->hash = hash; | ||||
| 		n->next = 0; | ||||
| 		*c = n; | ||||
| 		t->num_nodes++; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, | ||||
| 			uint32_t len) | ||||
| { | ||||
| 	struct dm_hash_node **c = _find(t, key, len); | ||||
|  | ||||
| 	if (*c) { | ||||
| 		struct dm_hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void *dm_hash_lookup(struct dm_hash_table *t, const char *key) | ||||
| { | ||||
| 	return dm_hash_lookup_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data) | ||||
| { | ||||
| 	return dm_hash_insert_binary(t, key, strlen(key) + 1, data); | ||||
| } | ||||
|  | ||||
| void dm_hash_remove(struct dm_hash_table *t, const char *key) | ||||
| { | ||||
| 	dm_hash_remove_binary(t, key, strlen(key) + 1); | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t, | ||||
| 					        const void *key, const void *val, | ||||
| 					        uint32_t len, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
| 	unsigned h; | ||||
|         | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen != len) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!memcmp(key, (*c)->key, len) && (*c)->data) { | ||||
| 			if (((*c)->data_len == val_len) && | ||||
| 			    !memcmp(val, (*c)->data, val_len)) | ||||
| 				return c; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key, | ||||
| 				  const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node *n; | ||||
| 	struct dm_hash_node *first; | ||||
| 	int len = strlen(key) + 1; | ||||
| 	unsigned h; | ||||
|  | ||||
| 	n = _create_node(key, len); | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	n->data = (void *)val; | ||||
| 	n->data_len = val_len; | ||||
|  | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	first = t->slots[h]; | ||||
|  | ||||
| 	if (first) | ||||
| 		n->next = first; | ||||
| 	else | ||||
| 		n->next = 0; | ||||
| 	t->slots[h] = n; | ||||
|  | ||||
| 	t->num_nodes++; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look through multiple entries with the same key for one that has a | ||||
|  * matching val and return that.  If none have maching val, return NULL. | ||||
|  */ | ||||
| void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key, | ||||
| 			      const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len); | ||||
|  | ||||
| 	return (c && *c) ? (*c)->data : 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look through multiple entries with the same key for one that has a | ||||
|  * matching val and remove that. | ||||
|  */ | ||||
| void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key, | ||||
| 			     const void *val, uint32_t val_len) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
|  | ||||
| 	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len); | ||||
|  | ||||
| 	if (c && *c) { | ||||
| 		struct dm_hash_node *old = *c; | ||||
| 		*c = (*c)->next; | ||||
| 		free(old); | ||||
| 		t->num_nodes--; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Look up the value for a key and count how many | ||||
|  * entries have the same key. | ||||
|  * | ||||
|  * If no entries have key, return NULL and set count to 0. | ||||
|  * | ||||
|  * If one entry has the key, the function returns the val, | ||||
|  * and sets count to 1. | ||||
|  * | ||||
|  * If N entries have the key, the function returns the val | ||||
|  * from the first entry, and sets count to N. | ||||
|  */ | ||||
| void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count) | ||||
| { | ||||
| 	struct dm_hash_node **c; | ||||
| 	struct dm_hash_node **c1 = NULL; | ||||
| 	uint32_t len = strlen(key) + 1; | ||||
| 	unsigned h; | ||||
|  | ||||
| 	*count = 0; | ||||
|  | ||||
| 	h = _hash(key, len) & t->mask_slots; | ||||
|  | ||||
| 	for (c = &t->slots[h]; *c; c = &((*c)->next)) { | ||||
| 		if ((*c)->keylen != len) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!memcmp(key, (*c)->key, len)) { | ||||
| 			(*count)++; | ||||
| 			if (!c1) | ||||
| 				c1 = c; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!c1) | ||||
| 		return NULL; | ||||
| 	else | ||||
| 		return *c1 ? (*c1)->data : 0; | ||||
| } | ||||
|  | ||||
| unsigned dm_hash_get_num_entries(struct dm_hash_table *t) | ||||
| { | ||||
| 	return t->num_nodes; | ||||
| } | ||||
|  | ||||
| void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f) | ||||
| { | ||||
| 	struct dm_hash_node *c, *n; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i <= t->mask_slots; i++) | ||||
| 		for (c = t->slots[i]; c; c = n) { | ||||
| 			n = c->next; | ||||
| 			f(c->data); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void dm_hash_wipe(struct dm_hash_table *t) | ||||
| { | ||||
| 	_free_nodes(t); | ||||
| 	memset(t->slots, 0, sizeof(struct dm_hash_node *) * (t->mask_slots + 1)); | ||||
| 	t->num_nodes = t->collisions = t->search = t->same_hash = 0u; | ||||
| } | ||||
|  | ||||
| char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)), | ||||
| 		      struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->key; | ||||
| } | ||||
|  | ||||
| void *dm_hash_get_data(struct dm_hash_table *t __attribute__((unused)), | ||||
| 		       struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->data; | ||||
| } | ||||
|  | ||||
| static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s) | ||||
| { | ||||
| 	struct dm_hash_node *c = NULL; | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = s; i <= t->mask_slots && !c; i++) | ||||
| 		c = t->slots[i]; | ||||
|  | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t) | ||||
| { | ||||
| 	return _next_slot(t, 0); | ||||
| } | ||||
|  | ||||
| struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n) | ||||
| { | ||||
| 	return n->next ? n->next : _next_slot(t, (n->hash & t->mask_slots) + 1); | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| #ifndef BASE_DATA_STRUCT_HASH_H | ||||
| #define BASE_DATA_STRUCT_HASH_H | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| struct dm_hash_table; | ||||
| struct dm_hash_node; | ||||
|  | ||||
| typedef void (*dm_hash_iterate_fn) (void *data); | ||||
|  | ||||
| struct dm_hash_table *dm_hash_create(unsigned size_hint) | ||||
| 	__attribute__((__warn_unused_result__)); | ||||
| void dm_hash_destroy(struct dm_hash_table *t); | ||||
| void dm_hash_wipe(struct dm_hash_table *t); | ||||
|  | ||||
| void *dm_hash_lookup(struct dm_hash_table *t, const char *key); | ||||
| int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data); | ||||
| void dm_hash_remove(struct dm_hash_table *t, const char *key); | ||||
|  | ||||
| void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len); | ||||
| int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len, | ||||
| 			  void *data); | ||||
| void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len); | ||||
|  | ||||
| unsigned dm_hash_get_num_entries(struct dm_hash_table *t); | ||||
| void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f); | ||||
|  | ||||
| char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
| void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
| struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t); | ||||
| struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n); | ||||
|  | ||||
| /* | ||||
|  * dm_hash_insert() replaces the value of an existing | ||||
|  * entry with a matching key if one exists.  Otherwise | ||||
|  * it adds a new entry. | ||||
|  * | ||||
|  * dm_hash_insert_with_val() inserts a new entry if | ||||
|  * another entry with the same key already exists. | ||||
|  * val_len is the size of the data being inserted. | ||||
|  * | ||||
|  * If two entries with the same key exist, | ||||
|  * (added using dm_hash_insert_allow_multiple), then: | ||||
|  * . dm_hash_lookup() returns the first one it finds, and | ||||
|  *   dm_hash_lookup_with_val() returns the one with a matching | ||||
|  *   val_len/val. | ||||
|  * . dm_hash_remove() removes the first one it finds, and | ||||
|  *   dm_hash_remove_with_val() removes the one with a matching | ||||
|  *   val_len/val. | ||||
|  * | ||||
|  * If a single entry with a given key exists, and it has | ||||
|  * zero val_len, then: | ||||
|  * . dm_hash_lookup() returns it | ||||
|  * . dm_hash_lookup_with_val(val_len=0) returns it | ||||
|  * . dm_hash_remove() removes it | ||||
|  * . dm_hash_remove_with_val(val_len=0) removes it | ||||
|  * | ||||
|  * dm_hash_lookup_with_count() is a single call that will | ||||
|  * both lookup a key's value and check if there is more | ||||
|  * than one entry with the given key. | ||||
|  * | ||||
|  * (It is not meant to retrieve all the entries with the | ||||
|  * given key.  In the common case where a single entry exists | ||||
|  * for the key, it is useful to have a single call that will | ||||
|  * both look up the value and indicate if multiple values | ||||
|  * exist for the key.) | ||||
|  * | ||||
|  * dm_hash_lookup_with_count: | ||||
|  * . If no entries exist, the function returns NULL, and | ||||
|  *   the count is set to 0. | ||||
|  * . If only one entry exists, the value of that entry is | ||||
|  *   returned and count is set to 1. | ||||
|  * . If N entries exists, the value of the first entry is | ||||
|  *   returned and count is set to N. | ||||
|  */ | ||||
|  | ||||
| void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key, | ||||
|                               const void *val, uint32_t val_len); | ||||
| void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key, | ||||
|                              const void *val, uint32_t val_len); | ||||
| int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key, | ||||
|                                   const void *val, uint32_t val_len); | ||||
| void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count); | ||||
|  | ||||
|  | ||||
| #define dm_hash_iterate(v, h) \ | ||||
| 	for (v = dm_hash_get_first((h)); v; \ | ||||
| 	     v = dm_hash_get_next((h), v)) | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,170 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "list.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| void dm_list_init(struct dm_list *head) | ||||
| { | ||||
| 	head->n = head->p = head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head; | ||||
| 	elem->p = head->p; | ||||
|  | ||||
| 	head->p->n = elem; | ||||
| 	head->p = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
| 	assert(head->n); | ||||
|  | ||||
| 	elem->n = head->n; | ||||
| 	elem->p = head; | ||||
|  | ||||
| 	head->n->p = elem; | ||||
| 	head->n = elem; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem) | ||||
| { | ||||
| 	elem->n->p = elem->p; | ||||
| 	elem->p->n = elem->n; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem) | ||||
| { | ||||
|         dm_list_del(elem); | ||||
|         dm_list_add(head, elem); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head) | ||||
| { | ||||
| 	return head->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->p == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return elem->n == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head) | ||||
| { | ||||
| 	return (dm_list_empty(head) ? NULL : head->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_start(head, elem) ? NULL : elem->p); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem) | ||||
| { | ||||
| 	return (dm_list_end(head, elem) ? NULL : elem->n); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head) | ||||
| { | ||||
| 	unsigned int s = 0; | ||||
| 	const struct dm_list *v; | ||||
|  | ||||
| 	dm_list_iterate(v, head) | ||||
| 	    s++; | ||||
|  | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Join two lists together. | ||||
|  * This moves all the elements of the list 'head1' to the end of the list | ||||
|  * 'head', leaving 'head1' empty. | ||||
|  */ | ||||
| void dm_list_splice(struct dm_list *head, struct dm_list *head1) | ||||
| { | ||||
| 	assert(head->n); | ||||
| 	assert(head1->n); | ||||
|  | ||||
| 	if (dm_list_empty(head1)) | ||||
| 	    return; | ||||
|  | ||||
| 	head1->p->n = head; | ||||
| 	head1->n->p = head->p; | ||||
|  | ||||
| 	head->p->n = head1->n; | ||||
| 	head->p = head1->p; | ||||
|  | ||||
| 	dm_list_init(head1); | ||||
| } | ||||
| @@ -1,211 +0,0 @@ | ||||
| #ifndef BASE_DATA_STRUCT_LIST_H | ||||
| #define BASE_DATA_STRUCT_LIST_H | ||||
|  | ||||
| #include "base/memory/container_of.h" | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| /* | ||||
|  * A list consists of a list head plus elements. | ||||
|  * Each element has 'next' and 'previous' pointers. | ||||
|  * The list head's pointers point to the first and the last element. | ||||
|  */ | ||||
|  | ||||
| struct dm_list { | ||||
| 	struct dm_list *n, *p; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * String list. | ||||
|  */ | ||||
| struct dm_str_list { | ||||
| 	struct dm_list list; | ||||
| 	const char *str; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Initialise a list before use. | ||||
|  * The list head's next and previous pointers point back to itself. | ||||
|  */ | ||||
| #define DM_LIST_HEAD_INIT(name)	 { &(name), &(name) } | ||||
| #define DM_LIST_INIT(name)	struct dm_list name = DM_LIST_HEAD_INIT(name) | ||||
| void dm_list_init(struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Insert an element before 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the end of the list. | ||||
|  */ | ||||
| void dm_list_add(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Insert an element after 'head'. | ||||
|  * If 'head' is the list head, this adds an element to the front of the list. | ||||
|  */ | ||||
| void dm_list_add_h(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Delete an element from its list. | ||||
|  * Note that this doesn't change the element itself - it may still be safe | ||||
|  * to follow its pointers. | ||||
|  */ | ||||
| void dm_list_del(struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Remove an element from existing list and insert before 'head'. | ||||
|  */ | ||||
| void dm_list_move(struct dm_list *head, struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Join 'head1' to the end of 'head'. | ||||
|  */ | ||||
| void dm_list_splice(struct dm_list *head, struct dm_list *head1); | ||||
|  | ||||
| /* | ||||
|  * Is the list empty? | ||||
|  */ | ||||
| int dm_list_empty(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Is this the first element of the list? | ||||
|  */ | ||||
| int dm_list_start(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Is this the last element of the list? | ||||
|  */ | ||||
| int dm_list_end(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return first element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_first(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return last element of the list or NULL if empty | ||||
|  */ | ||||
| struct dm_list *dm_list_last(const struct dm_list *head); | ||||
|  | ||||
| /* | ||||
|  * Return the previous element of the list, or NULL if we've reached the start. | ||||
|  */ | ||||
| struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Return the next element of the list, or NULL if we've reached the end. | ||||
|  */ | ||||
| struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem); | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list' called 'head' | ||||
|  * contained in a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_struct_base(v, t, head) \ | ||||
|     container_of(v, t, head) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of an instance of 'struct dm_list list' contained in | ||||
|  * a structure of type t, return the containing structure. | ||||
|  */ | ||||
| #define dm_list_item(v, t) dm_list_struct_base((v), t, list) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of one known element e in a known structure of type t, | ||||
|  * return another element f. | ||||
|  */ | ||||
| #define dm_struct_field(v, t, e, f) \ | ||||
|     (((t *)((uintptr_t)(v) - offsetof(t, e)))->f) | ||||
|  | ||||
| /* | ||||
|  * Given the address v of a known element e in a known structure of type t, | ||||
|  * return the list head 'list' | ||||
|  */ | ||||
| #define dm_list_head(v, t, e) dm_struct_field(v, t, e, list) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element of a list in turn. | ||||
|  */ | ||||
| #define dm_list_iterate(v, head) \ | ||||
| 	for (v = (head)->n; v != head; v = v->n) | ||||
|  | ||||
| /* | ||||
|  * Set v to each element in a list in turn, starting from the element | ||||
|  * in front of 'start'. | ||||
|  * You can use this to 'unwind' a list_iterate and back out actions on | ||||
|  * already-processed elements. | ||||
|  * If 'start' is 'head' it walks the list backwards. | ||||
|  */ | ||||
| #define dm_list_uniterate(v, head, start) \ | ||||
| 	for (v = (start)->p; v != head; v = v->p) | ||||
|  | ||||
| /* | ||||
|  * A safe way to walk a list and delete and free some elements along | ||||
|  * the way. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_safe(v, t, head) \ | ||||
| 	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.n, __typeof__(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_items(v, head) dm_list_iterate_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_gen_safe(v, t, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field), \ | ||||
| 	     t = dm_list_struct_base(v->field.n, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = t, t = dm_list_struct_base(v->field.n, __typeof__(*v), field)) | ||||
| /* | ||||
|  * Walk a list, setting 'v' in turn to the containing structure of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  * t must be defined as a temporary variable of the same type as v. | ||||
|  */ | ||||
| #define dm_list_iterate_items_safe(v, t, head) \ | ||||
| 	dm_list_iterate_items_gen_safe(v, t, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The 'struct dm_list' variable within the containing structure is 'field'. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items_gen(v, head, field) \ | ||||
| 	for (v = dm_list_struct_base((head)->p, __typeof__(*v), field); \ | ||||
| 	     &v->field != (head); \ | ||||
| 	     v = dm_list_struct_base(v->field.p, __typeof__(*v), field)) | ||||
|  | ||||
| /* | ||||
|  * Walk a list backwards, setting 'v' in turn to the containing structure | ||||
|  * of each item. | ||||
|  * The containing structure should be the same type as 'v'. | ||||
|  * The list should be 'struct dm_list list' within the containing structure. | ||||
|  */ | ||||
| #define dm_list_iterate_back_items(v, head) dm_list_iterate_back_items_gen(v, (head), list) | ||||
|  | ||||
| /* | ||||
|  * Return the number of elements in a list by walking it. | ||||
|  */ | ||||
| unsigned int dm_list_size(const struct dm_list *head); | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,299 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| // | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #include "radix-tree.h" | ||||
|  | ||||
| #include "base/memory/container_of.h" | ||||
| #include "base/memory/zalloc.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <ctype.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| // This implementation is based around nested binary trees.  Very | ||||
| // simple (and hopefully correct). | ||||
|  | ||||
| struct node { | ||||
| 	struct node *left; | ||||
| 	struct node *right; | ||||
|  | ||||
| 	uint8_t key; | ||||
| 	struct node *center; | ||||
|  | ||||
| 	bool has_value; | ||||
| 	union radix_value value; | ||||
| }; | ||||
|  | ||||
| struct radix_tree { | ||||
| 	radix_value_dtr dtr; | ||||
| 	void *dtr_context; | ||||
| 	unsigned nr_entries; | ||||
|  | ||||
| 	struct node *root; | ||||
| }; | ||||
|  | ||||
| struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context) | ||||
| { | ||||
| 	struct radix_tree *rt = zalloc(sizeof(*rt)); | ||||
|  | ||||
| 	if (rt) { | ||||
| 		rt->dtr = dtr; | ||||
| 		rt->dtr_context = dtr_context; | ||||
| 	} | ||||
|  | ||||
| 	return rt; | ||||
| } | ||||
|  | ||||
| // Returns the number of entries in the tree | ||||
| static unsigned _destroy_tree(struct node *n, radix_value_dtr dtr, void *context) | ||||
| { | ||||
| 	unsigned r; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = _destroy_tree(n->left, dtr, context); | ||||
| 	r += _destroy_tree(n->right, dtr, context); | ||||
| 	r += _destroy_tree(n->center, dtr, context); | ||||
|  | ||||
| 	if (n->has_value) { | ||||
| 		if (dtr) | ||||
| 			dtr(context, n->value); | ||||
| 		r++; | ||||
| 	} | ||||
|  | ||||
| 	free(n); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void radix_tree_destroy(struct radix_tree *rt) | ||||
| { | ||||
| 	_destroy_tree(rt->root, rt->dtr, rt->dtr_context); | ||||
| 	free(rt); | ||||
| } | ||||
|  | ||||
| static unsigned _count(struct node *n) | ||||
| { | ||||
| 	unsigned r; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = _count(n->left); | ||||
| 	r += _count(n->right); | ||||
| 	r += _count(n->center); | ||||
|  | ||||
| 	if (n->has_value) | ||||
| 		r++; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| unsigned radix_tree_size(struct radix_tree *rt) | ||||
| { | ||||
| 	return _count(rt->root); | ||||
| } | ||||
|  | ||||
| static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t *ke) | ||||
| { | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n || (kb == ke)) | ||||
| 		return pn; | ||||
|  | ||||
| 	if (*kb < n->key) | ||||
| 		return _lookup(&n->left, kb, ke); | ||||
|  | ||||
| 	else if (*kb > n->key) | ||||
| 		return _lookup(&n->right, kb, ke); | ||||
|  | ||||
| 	else | ||||
| 		return _lookup(&n->center, kb + 1, ke); | ||||
| } | ||||
|  | ||||
| static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, union radix_value v) | ||||
| { | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n) { | ||||
| 		n = zalloc(sizeof(*n)); | ||||
| 		if (!n) | ||||
| 			return false; | ||||
|  | ||||
| 		n->key = *kb; | ||||
| 		*pn = n; | ||||
| 	} | ||||
|  | ||||
| 	if (kb == ke) { | ||||
| 		n->has_value = true; | ||||
| 		n->value = v; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	if (*kb < n->key) | ||||
| 		return _insert(&n->left, kb, ke, v); | ||||
|  | ||||
| 	else if (*kb > n->key) | ||||
| 		return _insert(&n->right, kb, ke, v); | ||||
|  | ||||
| 	else | ||||
| 		return _insert(&n->center, kb + 1, ke, v); | ||||
| } | ||||
|  | ||||
| bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       union radix_value v) | ||||
| { | ||||
| 	const uint8_t *kb = key; | ||||
| 	const uint8_t *ke = kb + keylen; | ||||
|  | ||||
| 	if (!_insert(&rt->root, kb, ke, v)) | ||||
| 		return false; | ||||
|  | ||||
| 	rt->nr_entries++; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen) | ||||
| { | ||||
| 	const uint8_t *kb = key; | ||||
| 	const uint8_t *ke = kb + keylen; | ||||
| 	struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (!n || !n->has_value) | ||||
| 		return false; | ||||
|  | ||||
| 	rt->nr_entries--; | ||||
|  | ||||
| 	if (rt->dtr) | ||||
| 	    rt->dtr(rt->dtr_context, n->value); | ||||
|  | ||||
| 	if (n->left || n->center || n->right) { | ||||
| 	    n->has_value = false; | ||||
| 	    return true; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	// FIXME: delete parent if this was the last entry | ||||
| 	free(n); | ||||
| 	*pn = NULL; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *key, size_t keylen) | ||||
| { | ||||
| 	const uint8_t *kb = key; | ||||
| 	const uint8_t *ke = kb + keylen; | ||||
| 	struct node **pn; | ||||
| 	unsigned count; | ||||
|  | ||||
| 	pn = _lookup(&rt->root, kb, ke); | ||||
|  | ||||
| 	if (*pn) { | ||||
| 		count = _destroy_tree(*pn, rt->dtr, rt->dtr_context); | ||||
| 		*pn = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       union radix_value *result) | ||||
| { | ||||
| 	const uint8_t *kb = key; | ||||
| 	const uint8_t *ke = kb + keylen; | ||||
| 	struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 	struct node *n = *pn; | ||||
|  | ||||
| 	if (n && n->has_value) { | ||||
| 		*result = n->value; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| static void _iterate(struct node *n, struct radix_tree_iterator *it) | ||||
| { | ||||
| 	if (!n) | ||||
| 		return; | ||||
|  | ||||
| 	_iterate(n->left, it); | ||||
|  | ||||
| 	if (n->has_value) | ||||
| 		// FIXME: fill out the key | ||||
| 		it->visit(it, NULL, 0, n->value); | ||||
|  | ||||
| 	_iterate(n->center, it); | ||||
| 	_iterate(n->right, it); | ||||
| } | ||||
|  | ||||
| void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen, | ||||
|                         struct radix_tree_iterator *it) | ||||
| { | ||||
| 	const uint8_t *kb = key; | ||||
| 	const uint8_t *ke = kb + keylen; | ||||
|  | ||||
| 	if (kb == ke) | ||||
| 		_iterate(rt->root, it); | ||||
|  | ||||
| 	else { | ||||
| 		struct node **pn = _lookup(&rt->root, kb, ke); | ||||
| 		struct node *n = *pn; | ||||
|  | ||||
| 		if (n) { | ||||
| 			if (n->has_value) | ||||
| 				it->visit(it, NULL, 0, n->value); | ||||
| 			_iterate(n->center, it); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool radix_tree_is_well_formed(struct radix_tree *rt) | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static void _dump(FILE *out, struct node *n, unsigned indent) | ||||
| { | ||||
| 	unsigned i; | ||||
|  | ||||
| 	if (!n) | ||||
| 		return; | ||||
|  | ||||
| 	_dump(out, n->left, indent + 1); | ||||
|  | ||||
| 	for (i = 0; i < 2 * indent; i++) | ||||
| 		fprintf(out, " "); | ||||
|  | ||||
| 	if (n->has_value) { | ||||
| 		fprintf(out, "value: %llu\n", n->value.n); | ||||
| 	} else { | ||||
| 		fprintf(out, "key: '%c' [0x%02x] %u\n", | ||||
| 			isprint(n->key) ? n->key : ' ', n->key, indent); | ||||
| 	} | ||||
|  | ||||
| 	_dump(out, n->center, indent + 1); | ||||
| 	_dump(out, n->right, indent + 1); | ||||
| } | ||||
|  | ||||
| void radix_tree_dump(struct radix_tree *rt, FILE *out) | ||||
| { | ||||
| 	_dump(out, rt->root, 0); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| @@ -1,63 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #ifdef SIMPLE_RADIX_TREE | ||||
| #include "base/data-struct/radix-tree-simple.c" | ||||
| #else | ||||
| #include "base/data-struct/radix-tree-adaptive.c" | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| struct visitor { | ||||
| 	struct radix_tree_iterator it; | ||||
| 	unsigned pos, nr_entries; | ||||
| 	union radix_value *values; | ||||
| }; | ||||
|  | ||||
| static bool _visitor(struct radix_tree_iterator *it, | ||||
| 		     const void *key, size_t keylen, | ||||
| 		     union radix_value v) | ||||
| { | ||||
| 	struct visitor *vt = container_of(it, struct visitor, it); | ||||
|  | ||||
| 	if (vt->pos >= vt->nr_entries) | ||||
| 		return false; | ||||
|  | ||||
| 	vt->values[vt->pos++] = v; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       union radix_value **values, unsigned *nr_values) | ||||
| { | ||||
| 	struct visitor vt = { | ||||
| 		.it.visit = _visitor, | ||||
| 		.nr_entries = rt->nr_entries, | ||||
| 		.values = calloc(rt->nr_entries + 1, sizeof(union radix_value)), | ||||
| 	}; | ||||
|  | ||||
| 	if (vt.values) { | ||||
| 		// build set of all values in current radix tree | ||||
| 		radix_tree_iterate(rt, key, keylen, &vt.it); | ||||
| 		*nr_values = vt.pos; | ||||
| 		*values = vt.values; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| @@ -1,83 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|   | ||||
| #ifndef BASE_DATA_STRUCT_RADIX_TREE_H | ||||
| #define BASE_DATA_STRUCT_RADIX_TREE_H | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| struct radix_tree; | ||||
|  | ||||
| union radix_value { | ||||
| 	void *ptr; | ||||
| 	uint64_t n; | ||||
| }; | ||||
|  | ||||
| typedef void (*radix_value_dtr)(void *context, union radix_value v); | ||||
|  | ||||
| // dtr will be called on any deleted entries.  dtr may be NULL. | ||||
| struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context); | ||||
| void radix_tree_destroy(struct radix_tree *rt); | ||||
|  | ||||
| unsigned radix_tree_size(struct radix_tree *rt); | ||||
| bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v); | ||||
| bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen); | ||||
|  | ||||
| // Returns the number of values removed | ||||
| unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len); | ||||
|  | ||||
| bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       union radix_value *result); | ||||
|  | ||||
| // The radix tree stores entries in lexicographical order.  Which means | ||||
| // we can iterate entries, in order.  Or iterate entries with a particular | ||||
| // prefix. | ||||
| struct radix_tree_iterator { | ||||
| 	// Returns false if the iteration should end. | ||||
| 	bool (*visit)(struct radix_tree_iterator *it, | ||||
| 		      const void *key, size_t keylen, union radix_value v); | ||||
| }; | ||||
|  | ||||
| void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 			struct radix_tree_iterator *it); | ||||
|  | ||||
| // Alternative traversing radix_tree. | ||||
| // Builds whole set all radix_tree  nr_values values. | ||||
| // After use, free(values). | ||||
| bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       union radix_value **values, unsigned *nr_values); | ||||
|  | ||||
| // Checks that some constraints on the shape of the tree are | ||||
| // being held.  For debug only. | ||||
| bool radix_tree_is_well_formed(struct radix_tree *rt); | ||||
| void radix_tree_dump(struct radix_tree *rt, FILE *out); | ||||
|  | ||||
| // Shortcut for ptr value return | ||||
| // Note: if value would be NULL, it's same result for not/found case. | ||||
| static inline void *radix_tree_lookup_ptr(struct radix_tree *rt, const void *key, size_t keylen) | ||||
| { | ||||
| 	union radix_value v; | ||||
| 	return radix_tree_lookup(rt, key, keylen, &v) ? v.ptr : NULL; | ||||
| } | ||||
|  | ||||
| static inline bool radix_tree_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr) | ||||
| { | ||||
| 	union radix_value v = { .ptr = ptr }; | ||||
| 	return radix_tree_insert(rt, key, keylen, v); | ||||
| } | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,25 +0,0 @@ | ||||
| // Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #ifndef BASE_MEMORY_CONTAINER_OF_H | ||||
| #define BASE_MEMORY_CONTAINER_OF_H | ||||
|  | ||||
| #include <stddef.h>  // offsetof | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #define container_of(v, t, head) \ | ||||
|     ((t *)((char *)(v) - offsetof(t, head))) | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -1,27 +0,0 @@ | ||||
| // Copyright (C) 2018 Red Hat, Inc. All rights reserved. | ||||
| //  | ||||
| // This file is part of LVM2. | ||||
| // | ||||
| // This copyrighted material is made available to anyone wishing to use, | ||||
| // modify, copy, or redistribute it subject to the terms and conditions | ||||
| // of the GNU Lesser General Public License v.2.1. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with this program; if not, write to the Free Software Foundation, | ||||
| // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| #ifndef BASE_MEMORY_ZALLOC_H | ||||
| #define BASE_MEMORY_ZALLOC_H | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| static inline void *zalloc(size_t len) | ||||
| { | ||||
| 	return calloc(1, len); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										6
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +0,0 @@ | ||||
| command_profile_template.profile | ||||
| example.conf | ||||
| lvmlocal.conf | ||||
| metadata_profile_template.profile | ||||
| configure.h | ||||
| lvm-version.h | ||||
| @@ -1,60 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CONFSRC=example.conf | ||||
| CONFDEST=lvm.conf | ||||
| CONFLOCAL=lvmlocal.conf | ||||
|  | ||||
| PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile | ||||
| PROFILES=$(PROFILE_TEMPLATES) \ | ||||
| 	$(srcdir)/cache-mq.profile \ | ||||
| 	$(srcdir)/cache-smq.profile \ | ||||
| 	$(srcdir)/thin-generic.profile \ | ||||
| 	$(srcdir)/thin-performance.profile \ | ||||
| 	$(srcdir)/vdo-small.profile \ | ||||
| 	$(srcdir)/lvmdbusd.profile | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| .PHONY: install_conf install_localconf install_profiles | ||||
|  | ||||
| generate: | ||||
| 	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in | ||||
| 	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in | ||||
|  | ||||
| install_conf: $(CONFSRC) | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \ | ||||
| 	fi | ||||
|  | ||||
| install_localconf: $(CONFLOCAL) | ||||
| 	@if [ ! -e $(confdir)/$(CONFLOCAL) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL); \ | ||||
| 	fi | ||||
|  | ||||
| install_profiles: $(PROFILES) | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DIR) $(profiledir) | ||||
| 	$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/ | ||||
|  | ||||
| install_lvm2: install_conf install_localconf install_profiles | ||||
|  | ||||
| install: install_lvm2 | ||||
|  | ||||
| DISTCLEAN_TARGETS += $(CONFSRC) $(CONFLOCAL) $(PROFILE_TEMPLATES) | ||||
| @@ -1,20 +0,0 @@ | ||||
| # Demo configuration 'mq' cache policy | ||||
| # | ||||
| # Note: This policy has been deprecated in favor of the smq policy | ||||
| # keyword "default" means, setting is left with kernel defaults. | ||||
| # | ||||
|  | ||||
| allocation { | ||||
| 	cache_pool_chunk_size = 64 | ||||
| 	cache_mode = "writethrough" | ||||
| 	cache_policy = "mq" | ||||
| 	cache_settings { | ||||
| 		mq { | ||||
| 			sequential_threshold = "default"	#  #nr_sequential_ios | ||||
| 			random_threshold = "default"		#  #nr_random_ios | ||||
| 			read_promote_adjustment = "default" | ||||
| 			write_promote_adjustment = "default" | ||||
| 			discard_promote_adjustment = "default" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| # Demo configuration 'smq' cache policy | ||||
| # | ||||
| # The stochastic multi-queue (smq) policy addresses some of the problems | ||||
| # with the multiqueue (mq) policy and uses less memory. | ||||
| # | ||||
|  | ||||
| allocation { | ||||
| 	cache_pool_chunk_size = 64 | ||||
| 	cache_mode = "writethrough" | ||||
| 	cache_policy = "smq" | ||||
| 	cache_settings { | ||||
| 	        # currently no settings for "smq" policy | ||||
| 	} | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| # This is a command profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by command | ||||
| # profiles. To create a new command profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Command profiles can be referenced by using the --commandprofile option then. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| allocation { | ||||
| 	cache_mode="writethrough" | ||||
| 	cache_settings { | ||||
| 	} | ||||
| } | ||||
| log { | ||||
| 	report_command_log=0 | ||||
| 	command_log_sort="log_seq_num" | ||||
| 	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code" | ||||
| 	command_log_selection="!(log_type=status && message=success)" | ||||
| } | ||||
| global { | ||||
| 	units="h" | ||||
| 	si_unit_consistency=1 | ||||
| 	suffix=1 | ||||
| 	lvdisplay_shows_full_device_path=0 | ||||
| } | ||||
| report { | ||||
| 	output_format="basic" | ||||
| 	compact_output=0 | ||||
| 	compact_output_cols="" | ||||
| 	aligned=1 | ||||
| 	buffered=1 | ||||
| 	headings=1 | ||||
| 	separator=" " | ||||
| 	list_item_separator="," | ||||
| 	prefixes=0 | ||||
| 	quoted=1 | ||||
| 	columns_as_rows=0 | ||||
| 	binary_values_as_numeric=0 | ||||
| 	time_format="%Y-%m-%d %T %z" | ||||
| 	devtypes_sort="devtype_name" | ||||
| 	devtypes_cols="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	lvs_sort="vg_name,lv_name" | ||||
| 	lvs_cols="lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv" | ||||
| 	lvs_cols_verbose="lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid,lv_profile" | ||||
| 	vgs_sort="vg_name" | ||||
| 	vgs_cols="vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" | ||||
| 	vgs_cols_verbose="vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile" | ||||
| 	pvs_sort="pv_name" | ||||
| 	pvs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" | ||||
| 	pvs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" | ||||
| 	segs_sort="vg_name,lv_name,seg_start" | ||||
| 	segs_cols="lv_name,vg_name,lv_attr,stripes,segtype,seg_size" | ||||
| 	segs_cols_verbose="lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" | ||||
| 	pvsegs_sort="pv_name,pvseg_start" | ||||
| 	pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" | ||||
| 	pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges" | ||||
| 	vgs_cols_full="vg_all" | ||||
| 	pvs_cols_full="pv_all" | ||||
| 	lvs_cols_full="lv_all" | ||||
| 	pvsegs_cols_full="pvseg_all,pv_uuid,lv_uuid" | ||||
| 	segs_cols_full="seg_all,lv_uuid" | ||||
| 	vgs_sort_full="vg_name" | ||||
| 	pvs_sort_full="pv_name" | ||||
| 	lvs_sort_full="vg_name,lv_name" | ||||
| 	pvsegs_sort_full="pv_uuid,pvseg_start" | ||||
| 	segs_sort_full="lv_uuid,seg_start" | ||||
| 	mark_hidden_devices=1 | ||||
| } | ||||
							
								
								
									
										2504
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
							
						
						
									
										2504
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,50 +0,0 @@ | ||||
| # | ||||
| # DO NOT EDIT THIS FILE! | ||||
| # | ||||
| # LVM configuration profile used by lvmdbusd daemon. | ||||
| # | ||||
| # This sets up LVM to produce output in the most suitable format for processing | ||||
| # by lvmdbusd daemon which utilizes LVM shell to execute LVM commands. | ||||
| # | ||||
| # Do not edit this file in any way. This profile is distributed together with | ||||
| # lvmdbusd and it contains configuration that is important for lvmdbusd to | ||||
| # cooperate and interface with LVM correctly. | ||||
| # | ||||
|  | ||||
| global { | ||||
| 	# use bytes for expected and deterministic output | ||||
| 	units=b | ||||
| 	# no need for suffix if we have units set | ||||
| 	suffix=0 | ||||
| } | ||||
|  | ||||
| report { | ||||
| 	compact_output=0 | ||||
| 	compact_output_cols="" | ||||
| 	binary_values_as_numeric=0 | ||||
| 	# time in number of seconds since the Epoch | ||||
| 	time_format="%s" | ||||
| 	mark_hidden_devices=1 | ||||
| 	# lvmdbusd expects JSON output | ||||
| 	output_format=json | ||||
| 	# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state | ||||
| 	vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags" | ||||
| 	pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid" | ||||
| 	lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout" | ||||
| 	pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name" | ||||
| 	segs_cols_full="seg_pe_ranges,segtype,lv_uuid" | ||||
| 	vgs_sort_full="vg_name" | ||||
| 	pvs_sort_full="pv_name" | ||||
| 	lvs_sort_full="vg_name,lv_name" | ||||
| 	pvsegs_sort_full="pv_uuid,pvseg_start" | ||||
| 	segs_sort_full="lv_uuid,seg_start" | ||||
| } | ||||
|  | ||||
| log { | ||||
| 	# lvmdbusd relies on command log report to inspect LVM command's execution status | ||||
| 	report_command_log=1 | ||||
| 	# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed) | ||||
| 	command_log_selection="log_context=shell" | ||||
| 	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code" | ||||
| 	command_log_sort="log_seq_num" | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| # This is a local configuration file template for the LVM2 system | ||||
| # which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf . | ||||
| # | ||||
| # Refer to 'man lvm.conf' for information about the file layout. | ||||
| # | ||||
| # To put this file in a different directory and override | ||||
| # @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before | ||||
| # running the tools. | ||||
| # | ||||
| # The lvmlocal.conf file is normally expected to contain only the | ||||
| # "local" section which contains settings that should not be shared or | ||||
| # repeated among different hosts.  (But if other sections are present, | ||||
| # they *will* get processed.  Settings in this file override equivalent | ||||
| # ones in lvm.conf and are in turn overridden by ones in any enabled | ||||
| # lvm_<tag>.conf files.) | ||||
| # | ||||
| # Please take care that each setting only appears once if uncommenting | ||||
| # example settings in this file and never copy this file between hosts. | ||||
|  | ||||
|  | ||||
| # Configuration section local. | ||||
| # LVM settings that are specific to the local host. | ||||
| local { | ||||
|  | ||||
| 	# Configuration option local/system_id. | ||||
| 	# Defines the local system ID for lvmlocal mode. | ||||
| 	# This is used when global/system_id_source is set to 'lvmlocal' in the | ||||
| 	# main configuration file, e.g. lvm.conf. When used, it must be set to | ||||
| 	# a unique value among all hosts sharing access to the storage, | ||||
| 	# e.g. a host name. | ||||
| 	# | ||||
| 	# Example | ||||
| 	# Set no system ID: | ||||
| 	# system_id = "" | ||||
| 	# Set the system_id to a specific name: | ||||
| 	# system_id = "host1" | ||||
| 	# | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# system_id = "" | ||||
|  | ||||
| 	# Configuration option local/extra_system_ids. | ||||
| 	# A list of extra VG system IDs the local host can access. | ||||
| 	# VGs with the system IDs listed here (in addition to the host's own | ||||
| 	# system ID) can be fully accessed by the local host. (These are | ||||
| 	# system IDs that the host sees in VGs, not system IDs that identify | ||||
| 	# the local host, which is determined by system_id_source.) | ||||
| 	# Use this only after consulting 'man lvmsystemid' to be certain of | ||||
| 	# correct usage and possible dangers. | ||||
| 	# This configuration option does not have a default value defined. | ||||
|  | ||||
| 	# Configuration option local/host_id. | ||||
| 	# The lvmlockd sanlock host_id. | ||||
| 	# This must be unique among all hosts, and must be between 1 and 2000. | ||||
| 	# Applicable only if LVM is compiled with lockd support | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# host_id = 0 | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| # This is a metadata profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by metadata | ||||
| # profiles. To create a new metadata profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Metadata profiles can be referenced by using the --metadataprofile LVM2 | ||||
| # command line option. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| allocation { | ||||
| 	thin_pool_zero=1 | ||||
| 	thin_pool_discards="passdown" | ||||
| 	thin_pool_chunk_size_policy="generic" | ||||
| #	thin_pool_chunk_size=128 | ||||
| } | ||||
| activation { | ||||
| 	thin_pool_autoextend_threshold=100 | ||||
| 	thin_pool_autoextend_percent=20 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "generic" | ||||
| 	thin_pool_zero = 1 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "performance" | ||||
| 	thin_pool_zero = 0 | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| # Demo configuration for 'VDO' using less memory. | ||||
| # ~lvmconfig --type full | grep vdo | ||||
|  | ||||
| allocation { | ||||
| 	vdo_use_compression=1 | ||||
| 	vdo_use_deduplication=1 | ||||
| 	vdo_use_metadata_hints=1 | ||||
| 	vdo_minimum_io_size=4096 | ||||
| 	vdo_block_map_cache_size_mb=128 | ||||
| 	vdo_block_map_period=16380 | ||||
| 	vdo_use_sparse_index=0 | ||||
| 	vdo_index_memory_size_mb=256 | ||||
| 	vdo_slab_size_mb=2048 | ||||
| 	vdo_ack_threads=1 | ||||
| 	vdo_bio_threads=1 | ||||
| 	vdo_bio_rotation=64 | ||||
| 	vdo_cpu_threads=2 | ||||
| 	vdo_hash_zone_threads=1 | ||||
| 	vdo_logical_threads=1 | ||||
| 	vdo_physical_threads=1 | ||||
| 	vdo_write_policy="auto" | ||||
| 	vdo_max_discard=1 | ||||
| } | ||||
							
								
								
									
										2077
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										2077
									
								
								configure.ac
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										661
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										661
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,661 @@ | ||||
| ## | ||||
| ## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved. | ||||
| ## Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| ## | ||||
| ## This file is part of the LVM2. | ||||
| ## | ||||
| ## This copyrighted material is made available to anyone wishing to use, | ||||
| ## modify, copy, or redistribute it subject to the terms and conditions | ||||
| ## of the GNU General Public License v.2. | ||||
| ## | ||||
| ## You should have received a copy of the GNU General Public License | ||||
| ## along with this program; if not, write to the Free Software Foundation, | ||||
| ## Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| ################################################################################ | ||||
|  | ||||
| AC_PREREQ(2.53) | ||||
| ################################################################################ | ||||
| dnl -- Process this file with autoconf to produce a configure script. | ||||
| AC_INIT(lib/device/dev-cache.h) | ||||
|  | ||||
| ################################################################################ | ||||
| AC_CONFIG_HEADERS(lib/misc/configure.h) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the directory where autoconf has auxilary files | ||||
| AC_CONFIG_AUX_DIR(autoconf)  | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Get system type | ||||
| AC_CANONICAL_SYSTEM | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		CFLAGS="$CFLAGS" | ||||
| 		COPTIMISE_FLAG="-O2" | ||||
| 		CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym" | ||||
| 		CLDWHOLEARCHIVE="-Wl,-whole-archive" | ||||
| 		CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" | ||||
| 		LDDEPS="$LDDEPS .export.sym" | ||||
| 		LDFLAGS="$LDFLAGS -Wl,--export-dynamic" | ||||
| 		LIB_SUFFIX="so" | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=yes | ||||
| 		SELINUX=yes | ||||
| 		REALTIME=yes | ||||
| 		CLUSTER=internal | ||||
| 		FSADM=no ;; | ||||
| 	darwin*) | ||||
| 		CFLAGS="$CFLAGS -no-cpp-precomp -fno-common" | ||||
| 		COPTIMISE_FLAG="-O2" | ||||
| 		CLDFLAGS="$CLDFLAGS" | ||||
| 		CLDWHOLEARCHIVE="-all_load" | ||||
| 		CLDNOWHOLEARCHIVE= | ||||
| 		LDDEPS="$LDDEPS" | ||||
| 		LDFLAGS="$LDFLAGS" | ||||
| 		LIB_SUFFIX="dylib" | ||||
| 		DEVMAPPER=yes | ||||
| 		ODIRECT=no | ||||
| 		SELINUX=no | ||||
| 		REALTIME=no | ||||
| 		CLUSTER=none | ||||
| 		FSADM=no ;; | ||||
| esac | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for programs. | ||||
| AC_PROG_AWK | ||||
| AC_PROG_CC | ||||
| AC_PROG_INSTALL | ||||
| AC_PROG_LN_S | ||||
| AC_PROG_MAKE_SET | ||||
| AC_PROG_RANLIB | ||||
| AC_PATH_PROG(CFLOW_CMD, cflow) | ||||
| AC_PATH_PROG(CSCOPE_CMD, cscope) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for header files. | ||||
| AC_HEADER_DIRENT | ||||
| AC_HEADER_STDC | ||||
| AC_HEADER_SYS_WAIT | ||||
| AC_HEADER_TIME | ||||
|  | ||||
| AC_CHECK_HEADERS(fcntl.h limits.h locale.h stddef.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h,,AC_MSG_ERROR(bailing out)) | ||||
| AC_CHECK_HEADERS(assert.h ctype.h libgen.h signal.h stdio.h sys/mman.h sys/resource.h sys/stat.h sys/types.h sys/utsname.h sys/wait.h time.h,,AC_MSG_ERROR(bailing out)) | ||||
|  | ||||
| case "$host_os" in | ||||
| 	linux*) | ||||
| 		AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;; | ||||
| 	darwin*) | ||||
| 		AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;; | ||||
| esac | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for typedefs, structures, and compiler characteristics. | ||||
| AC_C_CONST | ||||
| AC_C_INLINE | ||||
| AC_TYPE_OFF_T | ||||
| AC_TYPE_PID_T | ||||
| AC_TYPE_SIZE_T | ||||
| AC_TYPE_MODE_T | ||||
| AC_STRUCT_ST_RDEV | ||||
| AC_STRUCT_TM | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for functions | ||||
| AC_CHECK_FUNCS(gethostname getpagesize memset munmap setlocale strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul,,AC_MSG_ERROR(bailing out)) | ||||
| AC_FUNC_ALLOCA | ||||
| AC_FUNC_CLOSEDIR_VOID | ||||
| AC_FUNC_FORK | ||||
| AC_FUNC_LSTAT | ||||
| AC_FUNC_MALLOC | ||||
| AC_FUNC_MEMCMP | ||||
| AC_FUNC_MMAP | ||||
| AC_FUNC_STAT | ||||
| AC_FUNC_STRTOD | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Prefix is /usr by default, the exec_prefix default is setup later | ||||
| AC_PREFIX_DEFAULT(/usr) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Parallel make jobs? | ||||
| AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the ownership of the files | ||||
| AC_MSG_CHECKING(file owner) | ||||
| OWNER="root" | ||||
|  | ||||
| AC_ARG_WITH(user, | ||||
|   [  --with-user=USER        Set the owner of installed files ], | ||||
|   [ OWNER="$withval" ]) | ||||
| AC_MSG_RESULT($OWNER) | ||||
|  | ||||
| if test x$OWNER != x; then | ||||
| 	OWNER="-o $OWNER" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Setup the group ownership of the files | ||||
| AC_MSG_CHECKING(group owner) | ||||
| GROUP="root" | ||||
| AC_ARG_WITH(group, | ||||
|   [  --with-group=GROUP      Set the group owner of installed files ], | ||||
|   [ GROUP="$withval" ]) | ||||
| AC_MSG_RESULT($GROUP) | ||||
|  | ||||
| if test x$GROUP != x; then | ||||
| 	GROUP="-g $GROUP" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- LVM1 tool fallback option | ||||
| AC_MSG_CHECKING(whether to enable lvm1 fallback) | ||||
| AC_ARG_ENABLE(lvm1_fallback, [  --enable-lvm1_fallback  Use this to fall back and use LVM1 binaries if | ||||
|                           device-mapper is missing from the kernel],  LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no) | ||||
| AC_MSG_RESULT($LVM1_FALLBACK) | ||||
|  | ||||
| if test x$LVM1_FALLBACK = xyes; then | ||||
| 	AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- format1 inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for lvm1 metadata) | ||||
| AC_ARG_WITH(lvm1, | ||||
|   [  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ LVM1="$withval" ], | ||||
|   [ LVM1="internal" ]) | ||||
| AC_MSG_RESULT($LVM1) | ||||
|  | ||||
| if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-lvm1 parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$LVM1 = xinternal; then | ||||
| 	AC_DEFINE([LVM1_INTERNAL], 1, [Define to 1 to include built-in support for LVM1 metadata.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- format_pool inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for GFS pool metadata) | ||||
| AC_ARG_WITH(pool, | ||||
|   [  --with-pool=TYPE        GFS pool read-only support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ POOL="$withval" ], | ||||
|   [ POOL="internal" ]) | ||||
| AC_MSG_RESULT($POOL) | ||||
|  | ||||
| if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-pool parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$POOL = xinternal; then | ||||
| 	AC_DEFINE([POOL_INTERNAL], 1, [Define to 1 to include built-in support for GFS pool metadata.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- cluster_locking inclusion type | ||||
| AC_MSG_CHECKING(whether to include support for cluster locking) | ||||
| AC_ARG_WITH(cluster, | ||||
|   [  --with-cluster=TYPE     Cluster LVM locking support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ CLUSTER="$withval" ]) | ||||
| AC_MSG_RESULT($CLUSTER) | ||||
|  | ||||
| if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-cluster parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$CLUSTER = xinternal; then | ||||
| 	AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1, [Define to 1 to include built-in support for clustered LVM locking.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- snapshots inclusion type | ||||
| AC_MSG_CHECKING(whether to include snapshots) | ||||
| AC_ARG_WITH(snapshots, | ||||
|   [  --with-snapshots=TYPE   Snapshot support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ SNAPSHOTS="$withval" ], | ||||
|   [ SNAPSHOTS="internal" ]) | ||||
| AC_MSG_RESULT($SNAPSHOTS) | ||||
|  | ||||
| if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-snapshots parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$SNAPSHOTS = xinternal; then | ||||
| 	AC_DEFINE([SNAPSHOT_INTERNAL], 1, [Define to 1 to include built-in support for snapshots.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- mirrors inclusion type | ||||
| AC_MSG_CHECKING(whether to include mirrors) | ||||
| AC_ARG_WITH(mirrors, | ||||
|   [  --with-mirrors=TYPE     Mirror support: internal/shared/none | ||||
|                           [TYPE=internal] ], | ||||
|   [ MIRRORS="$withval" ], | ||||
|   [ MIRRORS="internal" ]) | ||||
| AC_MSG_RESULT($MIRRORS) | ||||
|  | ||||
| if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| --with-mirrors parameter invalid | ||||
| ) | ||||
| fi; | ||||
|  | ||||
| if test x$MIRRORS = xinternal; then | ||||
| 	AC_DEFINE([MIRRORED_INTERNAL], 1, [Define to 1 to include built-in support for mirrors.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enables staticly-linked tools | ||||
| AC_MSG_CHECKING(whether to use static linking) | ||||
| AC_ARG_ENABLE(static_link, [  --enable-static_link    Use this to link the tools to their libraries | ||||
|                           statically.  Default is dynamic linking],  STATIC_LINK=$enableval, STATIC_LINK=no) | ||||
| AC_MSG_RESULT($STATIC_LINK) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable readline | ||||
| AC_MSG_CHECKING(whether to enable readline) | ||||
| AC_ARG_ENABLE(readline, [  --enable-readline       Enable readline support], | ||||
| READLINE=$enableval, READLINE=no) | ||||
| AC_MSG_RESULT($READLINE) | ||||
|  | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_DEFINE([READLINE_SUPPORT], 1, [Define to 1 to include the LVM readline shell.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable selinux | ||||
| AC_MSG_CHECKING(whether to enable selinux support) | ||||
| AC_ARG_ENABLE(selinux, [  --disable-selinux       Disable selinux support], | ||||
| SELINUX=$enableval) | ||||
| AC_MSG_RESULT($SELINUX) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable realtime clock support | ||||
| AC_MSG_CHECKING(whether to enable realtime support) | ||||
| AC_ARG_ENABLE(realtime, [  --disable-realtime      Disable realtime clock support], | ||||
| REALTIME=$enableval) | ||||
| AC_MSG_RESULT($REALTIME) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Build cluster LVM daemon | ||||
| AC_MSG_CHECKING(whether to build cluster LVM daemon) | ||||
| AC_ARG_WITH(clvmd, | ||||
|   [  --with-clvmd=TYPE       Build cluster LVM Daemon: cman/gulm/none/all | ||||
|                           [TYPE=none] ], | ||||
|   [ CLVMD="$withval" ], | ||||
|   [ CLVMD="none" ]) | ||||
| if test x$CLVMD = xyes; then | ||||
| 	CLVMD=all | ||||
| fi | ||||
| AC_MSG_RESULT($CLVMD) | ||||
|  | ||||
| dnl -- If clvmd enabled without cluster locking, automagically include it | ||||
| if  test x$CLVMD != xnone && test x$CLUSTER = xnone; then | ||||
| 	CLUSTER=internal | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable debugging | ||||
| AC_MSG_CHECKING(whether to enable debugging) | ||||
| AC_ARG_ENABLE(debug,    [  --enable-debug          Enable debugging], | ||||
| DEBUG=$enableval, DEBUG=no) | ||||
| AC_MSG_RESULT($DEBUG) | ||||
|  | ||||
| dnl -- Normally turn off optimisation for debug builds | ||||
| if test x$DEBUG = xyes; then | ||||
| 	COPTIMISE_FLAG= | ||||
| else | ||||
| 	CSCOPE_CMD= | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Override optimisation | ||||
| AC_MSG_CHECKING(for C optimisation flag) | ||||
| AC_ARG_WITH(optimisation, | ||||
|   [  --with-optimisation=OPT C optimisation flag [OPT=-O2] ], | ||||
|   [ COPTIMISE_FLAG="$withval" ]) | ||||
| AC_MSG_RESULT($COPTIMISE_FLAG) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable devmapper | ||||
| AC_MSG_CHECKING(whether to use device-mapper) | ||||
| AC_ARG_ENABLE(devmapper, [  --disable-devmapper     Disable device-mapper interaction], | ||||
| DEVMAPPER=$enableval) | ||||
| AC_MSG_RESULT($DEVMAPPER) | ||||
|  | ||||
| if test x$DEVMAPPER = xyes; then | ||||
| 	AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable device-mapper interaction.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Disable O_DIRECT | ||||
| AC_MSG_CHECKING(whether to enable O_DIRECT) | ||||
| AC_ARG_ENABLE(o_direct, [  --disable-o_direct      Disable O_DIRECT], | ||||
| ODIRECT=$enableval) | ||||
| AC_MSG_RESULT($ODIRECT) | ||||
|  | ||||
| if test x$ODIRECT = xyes; then | ||||
| 	AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable cmdlib | ||||
| AC_MSG_CHECKING(whether to compile liblvm2cmd.so) | ||||
| AC_ARG_ENABLE(cmdlib, [  --enable-cmdlib         Build shared command library], | ||||
| CMDLIB=$enableval, CMDLIB=no) | ||||
| AC_MSG_RESULT($CMDLIB) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Enable fsadm | ||||
| AC_MSG_CHECKING(whether to build fsadm) | ||||
| AC_ARG_ENABLE(fsadm, [  --enable-fsadm          Enable fsadm], | ||||
| FSADM=$enableval) | ||||
| AC_MSG_RESULT($FSADM) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- enable dmeventd handling | ||||
| AC_MSG_CHECKING(whether to use dmeventd) | ||||
| AC_ARG_ENABLE(dmeventd, [  --enable-dmeventd       Enable the device-mapper event daemon], | ||||
| DMEVENTD=$enableval) | ||||
| AC_MSG_RESULT($DMEVENTD) | ||||
|  | ||||
| dnl -- dmeventd currently requires internal mirror support | ||||
| if test x$DMEVENTD = xyes && test x$MIRRORS != xinternal; then | ||||
| AC_MSG_ERROR( | ||||
| --enable-dmeventd currently requires --with-mirrors=internal | ||||
| ) | ||||
| fi | ||||
|  | ||||
| if test x$DMEVENTD = xyes; then | ||||
| 	AC_DEFINE([DMEVENTD], 1, [Define to 1 to enable the device-mapper event daemon.]) | ||||
| fi | ||||
| ################################################################################ | ||||
| dnl -- Mess with default exec_prefix | ||||
| if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; | ||||
|  then  exec_prefix=""; | ||||
| fi; | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Checks for library functions. | ||||
| AC_PROG_GCC_TRADITIONAL | ||||
| AC_TYPE_SIGNAL | ||||
| AC_FUNC_VPRINTF | ||||
| AC_CHECK_FUNCS(mkdir rmdir uname,,AC_MSG_ERROR(bailing out)) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for termcap (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, , | ||||
| 		AC_MSG_ERROR( | ||||
| termcap could not be found which is required for the | ||||
| --enable-readline option (which is enabled by default).  Either disable readline | ||||
| support with --disable-readline or download and install termcap from: | ||||
| 	ftp.gnu.org/gnu/termcap | ||||
| Note: if you are using precompiled packages you will also need the development | ||||
|   package as well (which may be called termcap-devel or something similar). | ||||
| Note: (n)curses also seems to work as a substitute for termcap.  This was | ||||
|   not found either - but you could try installing that as well. | ||||
| ) | ||||
| 	) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for dlopen | ||||
| AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no) | ||||
|  | ||||
| if [[ "x$HAVE_LIBDL" = xyes ]]; then | ||||
| 	AC_DEFINE([HAVE_LIBDL], 1, [Define to 1 if dynamic libraries are available.]) | ||||
| 	LIBS="-ldl $LIBS" | ||||
| else | ||||
| 	HAVE_LIBDL=no | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for shared/static conflicts | ||||
| if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ | ||||
|       -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ | ||||
|       \) -a "x$STATIC_LINK" = xyes ]]; | ||||
|  then  AC_MSG_ERROR( | ||||
| Features cannot be 'shared' when building statically | ||||
| ) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for selinux | ||||
| if test x$SELINUX = xyes; then | ||||
| 	AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no) | ||||
|  | ||||
| 	if test x$HAVE_SEPOL = xyes; then | ||||
| 		LIBS="-lsepol $LIBS" | ||||
| 	fi | ||||
|  | ||||
| 	AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no) | ||||
|  | ||||
| 	if test x$HAVE_SELINUX = xyes; then | ||||
| 		AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.]) | ||||
| 		LIBS="-lselinux $LIBS" | ||||
| 	else | ||||
| 		AC_MSG_WARN(Disabling selinux) | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for realtime clock support | ||||
| if test x$REALTIME = xyes; then | ||||
| 	AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no) | ||||
|  | ||||
| 	if test x$HAVE_REALTIME = xyes; then | ||||
| 		AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.]) | ||||
| 		LIBS="-lrt $LIBS" | ||||
| 	else | ||||
| 		AC_MSG_WARN(Disabling realtime clock) | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for getopt | ||||
| AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.])) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Check for readline (Shamelessly copied from parted 1.4.17) | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_CHECK_LIB(readline, readline, , | ||||
| 		AC_MSG_ERROR( | ||||
| GNU Readline could not be found which is required for the | ||||
| --enable-readline option (which is enabled by default).  Either disable readline | ||||
| support with --disable-readline or download and install readline from: | ||||
| 	ftp.gnu.org/gnu/readline | ||||
| Note: if you are using precompiled packages you will also need the development | ||||
| package as well (which may be called readline-devel or something similar). | ||||
| ) | ||||
| 	) | ||||
| 	AC_CHECK_FUNC(rl_completion_matches, AC_DEFINE([HAVE_RL_COMPLETION_MATCHES], 1, [Define to 1 if rl_completion_matches() is available.])) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Internationalisation stuff | ||||
| AC_MSG_CHECKING(whether to enable internationalisation) | ||||
| AC_ARG_ENABLE(nls, [  --enable-nls            Enable Native Language Support], | ||||
| 		INTL=$enableval, INTL=no) | ||||
| AC_MSG_RESULT($INTL) | ||||
|  | ||||
| if test x$INTL = xyes; then | ||||
| 	INTL_PACKAGE="lvm2" | ||||
| 	AC_PATH_PROG(MSGFMT, msgfmt) | ||||
| 	if [[ "x$MSGFMT" == x ]]; | ||||
| 		then  AC_MSG_ERROR( | ||||
| 		msgfmt not found in path $PATH | ||||
| 		) | ||||
| 	fi; | ||||
|  | ||||
| 	AC_ARG_WITH(localedir, | ||||
|   		    [  --with-localedir=DIR    Translation files in DIR [PREFIX/share/locale]], | ||||
|   		    [ LOCALEDIR="$withval" ], | ||||
|   		    [ LOCALEDIR='${prefix}/share/locale' ]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_ARG_WITH(confdir, | ||||
| 	    [  --with-confdir=DIR      Configuration files in DIR [/etc]], | ||||
|   	    [ CONFDIR="$withval" ], | ||||
|  	    [ CONFDIR='/etc' ]) | ||||
|  | ||||
| AC_ARG_WITH(staticdir, | ||||
| 	    [  --with-staticdir=DIR    Static binary in DIR [EXEC_PREFIX/sbin]], | ||||
|   	    [ STATICDIR="$withval" ], | ||||
|  	    [ STATICDIR='${exec_prefix}/sbin' ]) | ||||
|  | ||||
| AC_ARG_WITH(dmdir, | ||||
| 	    [  --with-dmdir=DIR        Build against device-mapper source tree in DIR], | ||||
|   	    [ DMDIR="$withval" ], | ||||
| 	    [ DMDIR= ]) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- Ensure additional headers required | ||||
| if test x$READLINE = xyes; then | ||||
| 	AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$CLVMD != xnone; then | ||||
| 	AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_FUNC_GETMNTENT | ||||
| #	AC_FUNC_REALLOC | ||||
| 	AC_FUNC_SELECT_ARGTYPES | ||||
| fi | ||||
|  | ||||
| if test x$FSADM = xyes; then | ||||
| 	AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$CLUSTER != xnone; then | ||||
| 	AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out)) | ||||
| 	AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$HAVE_LIBDL = xyes; then | ||||
| 	AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| if test x$INTL = xyes; then | ||||
| 	AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out)) | ||||
|  | ||||
| if test x$HAVE_SELINUX = xyes; then | ||||
| 	AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out)) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_PATH_PROG(MODPROBE_CMD, modprobe) | ||||
|  | ||||
| if test x$MODPROBE_CMD != x; then | ||||
| 	AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.]) | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| if test "-f VERSION"; then | ||||
|   LVM_VERSION="\"`cat VERSION`\"" | ||||
| else | ||||
|   LVM_VERSION="Unknown" | ||||
| fi | ||||
|  | ||||
| ################################################################################ | ||||
| AC_SUBST(JOBS) | ||||
| AC_SUBST(STATIC_LINK) | ||||
| AC_SUBST(LVM1) | ||||
| AC_SUBST(POOL) | ||||
| AC_SUBST(SNAPSHOTS) | ||||
| AC_SUBST(MIRRORS) | ||||
| AC_SUBST(OWNER) | ||||
| AC_SUBST(GROUP) | ||||
| AC_SUBST(CFLAGS) | ||||
| AC_SUBST(COPTIMISE_FLAG) | ||||
| AC_SUBST(CLDFLAGS) | ||||
| AC_SUBST(CLDWHOLEARCHIVE) | ||||
| AC_SUBST(CLDNOWHOLEARCHIVE) | ||||
| AC_SUBST(LDDEPS) | ||||
| AC_SUBST(LDFLAGS) | ||||
| AC_SUBST(LIB_SUFFIX) | ||||
| AC_SUBST(LIBS) | ||||
| AC_SUBST(LVM_VERSION) | ||||
| AC_SUBST(LVM1_FALLBACK) | ||||
| AC_SUBST(DEBUG) | ||||
| AC_SUBST(DEVMAPPER) | ||||
| AC_SUBST(HAVE_LIBDL) | ||||
| AC_SUBST(HAVE_SELINUX) | ||||
| AC_SUBST(HAVE_REALTIME) | ||||
| AC_SUBST(CMDLIB) | ||||
| AC_SUBST(MSGFMT) | ||||
| AC_SUBST(LOCALEDIR) | ||||
| AC_SUBST(CONFDIR) | ||||
| AC_SUBST(STATICDIR) | ||||
| AC_SUBST(DMDIR) | ||||
| AC_SUBST(INTL_PACKAGE) | ||||
| AC_SUBST(INTL) | ||||
| AC_SUBST(CLVMD) | ||||
| AC_SUBST(CLUSTER) | ||||
| AC_SUBST(FSADM) | ||||
| AC_SUBST(DMEVENTD) | ||||
| AC_SUBST(CFLOW_CMD) | ||||
| AC_SUBST(CSCOPE_CMD) | ||||
|  | ||||
| ################################################################################ | ||||
| dnl -- First and last lines should not contain files to generate in order to  | ||||
| dnl -- keep utility scripts running properly | ||||
| AC_OUTPUT( 								\ | ||||
| Makefile								\ | ||||
| make.tmpl								\ | ||||
| daemons/Makefile							\ | ||||
| daemons/clvmd/Makefile							\ | ||||
| dmeventd/Makefile							\ | ||||
| dmeventd/mirror/Makefile						\ | ||||
| doc/Makefile								\ | ||||
| include/Makefile						 	\ | ||||
| lib/Makefile							 	\ | ||||
| lib/format1/Makefile						 	\ | ||||
| lib/format_pool/Makefile						\ | ||||
| lib/locking/Makefile							\ | ||||
| lib/mirror/Makefile							\ | ||||
| lib/snapshot/Makefile							\ | ||||
| man/Makefile							 	\ | ||||
| po/Makefile								\ | ||||
| scripts/Makefile								\ | ||||
| tools/Makefile							 	\ | ||||
| tools/version.h								\ | ||||
| tools/fsadm/Makefile							\ | ||||
| test/mm/Makefile							\ | ||||
| test/device/Makefile							\ | ||||
| test/format1/Makefile							\ | ||||
| test/regex/Makefile                                                     \ | ||||
| test/filters/Makefile                                                   \ | ||||
| ) | ||||
|  | ||||
| if test x$ODIRECT != xyes; then | ||||
|   AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up) | ||||
| fi | ||||
|  | ||||
| if test x$FSADM == xyes; then | ||||
|   AC_MSG_WARN(fsadm support is untested) | ||||
| fi | ||||
|  | ||||
| if test x$DMEVENTD == xyes; then | ||||
|   AC_MSG_WARN(dmeventd support is untested) | ||||
| fi | ||||
| @@ -1,148 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Coverity usage: | ||||
|  * | ||||
|  * translate model into xml | ||||
|  * cov-make-library -of coverity_model.xml coverity_model.c | ||||
|  * | ||||
|  * compile (using outdir 'cov'): | ||||
|  * cov-build --dir=cov make CC=gcc | ||||
|  * | ||||
|  * analyze (agressively, using 'cov') | ||||
|  * cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml | ||||
|  * | ||||
|  * generate html output (to 'html' from 'cov'): | ||||
|  * cov-format-errors --dir cov  --html-output html | ||||
|  */ | ||||
|  | ||||
| struct lv_segment; | ||||
| struct logical_volume; | ||||
|  | ||||
| struct lv_segment *first_seg(const struct logical_volume *lv) | ||||
| { | ||||
| 	return ((struct lv_segment **)lv)[0]; | ||||
| } | ||||
|  | ||||
| struct lv_segment *last_seg(const struct logical_volume *lv) | ||||
| { | ||||
| 	return ((struct lv_segment **)lv)[0]; | ||||
| } | ||||
|  | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	return "STRING"; | ||||
| } | ||||
|  | ||||
| /* | ||||
| struct logical_volume *origin_from_cow(const struct logical_volume *lv) | ||||
| { | ||||
| 	if (lv) | ||||
| 		return lv; | ||||
|  | ||||
| 	__coverity_panic__(); | ||||
| } | ||||
| */ | ||||
|  | ||||
| /* simple_memccpy() from glibc */ | ||||
| void *memccpy(void *dest, const void *src, int c, size_t n) | ||||
| { | ||||
| 	const char *s = src; | ||||
| 	char *d = dest; | ||||
|  | ||||
| 	while (n-- > 0) | ||||
| 		if ((*d++ = *s++) == (char) c) | ||||
| 			return d; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h | ||||
|  * Not sure about any other way. | ||||
|  * Without them, coverity shows warning since x86 system header files | ||||
|  * are using inline assembly to reset fdset | ||||
|  */ | ||||
| //#nodef FD_ZERO model_FD_ZERO | ||||
| //void model_FD_ZERO(void *fdset); | ||||
|  | ||||
| void model_FD_ZERO(void *fdset) | ||||
| { | ||||
| 	unsigned i; | ||||
|  | ||||
| 	for (i = 0; i < 1024 / 8 / sizeof(long); ++i) | ||||
| 		((long*)fdset)[i] = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Resent Coverity reports quite weird errors... */ | ||||
| int *__errno_location(void) | ||||
| { | ||||
| } | ||||
| const unsigned short **__ctype_b_loc (void) | ||||
| { | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Added extra pointer check to not need these models, | ||||
|  * for now just keep then in file | ||||
|  */ | ||||
|  | ||||
| /* | ||||
| struct cmd_context; | ||||
| struct profile; | ||||
|  | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
|         return "text"; | ||||
| } | ||||
|  | ||||
| const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
|         return "text"; | ||||
| } | ||||
| */ | ||||
|  | ||||
| /* | ||||
|  * Until fixed coverity case# 00531860: | ||||
|  *   A FORWARD_NULL false positive on a recursive function call | ||||
|  * | ||||
|  * model also these functions: | ||||
|  */ | ||||
| /* | ||||
| const struct dm_config_node; | ||||
| const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	const struct dm_config_node *cn; | ||||
|  | ||||
| 	return cn; | ||||
| } | ||||
|  | ||||
| const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	const struct dm_config_node *cn; | ||||
|  | ||||
| 	return cn; | ||||
| } | ||||
|  | ||||
| int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile) | ||||
| { | ||||
| 	int b; | ||||
|  | ||||
| 	return b; | ||||
| } | ||||
| */ | ||||
| @@ -1,7 +1,7 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| @@ -9,43 +9,15 @@ | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| .PHONY: dmeventd cmirrord lvmpolld lvmlockd | ||||
|  | ||||
| ifeq ("@BUILD_CMIRRORD@", "yes") | ||||
|   SUBDIRS += cmirrord | ||||
| ifneq ("@CLVMD@", "none") | ||||
|   SUBDIRS = clvmd | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
|   SUBDIRS += dmeventd | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| daemons.cflow: dmeventd.cflow | ||||
| endif | ||||
| endif | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| ifeq ("@BUILD_LVMPOLLD@", "yes") | ||||
|   SUBDIRS += lvmpolld | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMLOCKD@", "yes") | ||||
|   SUBDIRS += lvmlockd | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMDBUSD@", "yes") | ||||
|   SUBDIRS += lvmdbusd | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
| device-mapper: dmeventd.device-mapper | ||||
| endif | ||||
|   | ||||
							
								
								
									
										86
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| # | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SOURCES = \ | ||||
| 	clvmd-command.c  \ | ||||
| 	clvmd.c          \ | ||||
| 	lvm-functions.c  \ | ||||
| 	refresh_clvmd.c \ | ||||
| 	system-lv.c | ||||
|  | ||||
| ifeq ("@CLVMD@", "gulm") | ||||
| 	GULM = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "cman") | ||||
| 	CMAN = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLVMD@", "all") | ||||
| 	GULM = yes | ||||
| 	CMAN = yes | ||||
| endif | ||||
|  | ||||
| ifeq ("@DEBUG@", "yes") | ||||
| 	DEFS += -DDEBUG | ||||
| endif | ||||
|  | ||||
| ifeq ("$(GULM)", "yes") | ||||
| 	SOURCES += clvmd-gulm.c tcp-comms.c | ||||
| 	LMLIBS += -lccs -lgulm | ||||
| 	DEFS += -DUSE_GULM | ||||
| endif | ||||
|  | ||||
| ifeq ("$(CMAN)", "yes") | ||||
| 	SOURCES += clvmd-cman.c | ||||
| 	LMLIBS += -ldlm -lcman | ||||
| 	DEFS += -DUSE_CMAN | ||||
| endif | ||||
|  | ||||
| TARGETS = \ | ||||
| 	clvmd | ||||
|  | ||||
| LVMLIBS = -llvm -lpthread | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
| 	LVMLIBS += -ldevmapper-event | ||||
| endif | ||||
|   | ||||
| LVMLIBS += -ldevmapper | ||||
|  | ||||
| DEFS += -D_REENTRANT | ||||
| CFLAGS += -fno-strict-aliasing | ||||
|  | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| INSTALL_TARGETS = \ | ||||
| 	install_clvmd | ||||
|  | ||||
| clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a | ||||
| 	$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \ | ||||
| 		$(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| .PHONY: install_clvmd | ||||
|  | ||||
| install_clvmd: $(TARGETS) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) clvmd \ | ||||
| 		$(sbindir)/clvmd | ||||
|  | ||||
| install: $(INSTALL_TARGETS) | ||||
|  | ||||
| install_cluster: $(INSTALL_TARGETS) | ||||
|  | ||||
							
								
								
									
										70
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Definitions for CLVMD server and clients */ | ||||
|  | ||||
| /* | ||||
|  * The protocol spoken over the cluster and across the local socket. | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVM_H | ||||
| #define _CLVM_H | ||||
|  | ||||
| struct clvm_header { | ||||
| 	uint8_t  cmd;	        /* See below */ | ||||
| 	uint8_t  flags;	        /* See below */ | ||||
| 	uint16_t xid;	        /* Transaction ID */ | ||||
| 	uint32_t clientid;	/* Only used in Daemon->Daemon comms */ | ||||
| 	int32_t  status;	/* For replies, whether request succeeded */ | ||||
| 	uint32_t arglen;	/* Length of argument below.  | ||||
| 				   If >1500 then it will be passed  | ||||
| 				   around the cluster in the system LV */ | ||||
| 	char node[1];		/* Actually a NUL-terminated string, node name. | ||||
| 				   If this is empty then the command is  | ||||
| 				   forwarded to all cluster nodes unless  | ||||
| 				   FLAG_LOCAL is also set. */ | ||||
| 	char args[1];		/* Arguments for the command follow the  | ||||
| 				   node name, This member is only | ||||
| 				   valid if the node name is empty */ | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| /* Flags */ | ||||
| #define CLVMD_FLAG_LOCAL        1	/* Only do this on the local node */ | ||||
| #define CLVMD_FLAG_SYSTEMLV     2	/* Data in system LV under my node name */ | ||||
| #define CLVMD_FLAG_NODEERRS     4       /* Reply has errors in node-specific portion */ | ||||
|  | ||||
| /* Name of the local socket to communicate between libclvm and clvmd */ | ||||
| //static const char CLVMD_SOCKNAME[]="/var/run/clvmd"; | ||||
| static const char CLVMD_SOCKNAME[] = "\0clvmd"; | ||||
|  | ||||
| /* Internal commands & replies */ | ||||
| #define CLVMD_CMD_REPLY    1 | ||||
| #define CLVMD_CMD_VERSION  2	/* Send version around cluster when we start */ | ||||
| #define CLVMD_CMD_GOAWAY   3	/* Die if received this - we are running  | ||||
| 				   an incompatible version */ | ||||
| #define CLVMD_CMD_TEST     4	/* Just for mucking about */ | ||||
|  | ||||
| #define CLVMD_CMD_LOCK              30 | ||||
| #define CLVMD_CMD_UNLOCK            31 | ||||
|  | ||||
| /* Lock/Unlock commands */ | ||||
| #define CLVMD_CMD_LOCK_LV           50 | ||||
| #define CLVMD_CMD_LOCK_VG           51 | ||||
|  | ||||
| /* Misc functions */ | ||||
| #define CLVMD_CMD_REFRESH	    40 | ||||
| #define CLVMD_CMD_GET_CLUSTERNAME   41 | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										510
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * CMAN communication layer for clvmd. | ||||
|  */ | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <syslog.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stddef.h> | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <getopt.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "libdlm.h" | ||||
| #include "log.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #define LOCKSPACE_NAME "clvmd" | ||||
|  | ||||
| static int num_nodes; | ||||
| static struct cman_node *nodes = NULL; | ||||
| static struct cman_node this_node; | ||||
| static int count_nodes; /* size of allocated nodes array */ | ||||
| static int max_updown_nodes = 50;	/* Current size of the allocated array */ | ||||
| /* Node up/down status, indexed by nodeid */ | ||||
| static int *node_updown = NULL; | ||||
| static dlm_lshandle_t *lockspace; | ||||
| static cman_handle_t c_handle; | ||||
|  | ||||
| static void count_clvmds_running(void); | ||||
| static void get_members(void); | ||||
| static int nodeid_from_csid(char *csid); | ||||
| static int name_from_nodeid(int nodeid, char *name); | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg); | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid); | ||||
|  | ||||
| struct lock_wait { | ||||
| 	pthread_cond_t cond; | ||||
| 	pthread_mutex_t mutex; | ||||
| 	struct dlm_lksb lksb; | ||||
| }; | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	/* Open the cluster communication socket */ | ||||
| 	c_handle = cman_init(NULL); | ||||
| 	if (!c_handle) { | ||||
| 		syslog(LOG_ERR, "Can't open cluster manager socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) { | ||||
| 		syslog(LOG_ERR, "Can't bind cluster socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (cman_start_notification(c_handle, event_callback)) { | ||||
| 		syslog(LOG_ERR, "Can't start cluster event listening"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the cluster members list */ | ||||
| 	get_members(); | ||||
| 	count_clvmds_running(); | ||||
|  | ||||
| 	/* Create a lockspace for LV & VG locks to live in */ | ||||
| 	lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 	if (!lockspace) { | ||||
| 		syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	dlm_ls_pthread_init(lockspace); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_init_completed(void) | ||||
| { | ||||
| 	clvmd_cluster_init_completed(); | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd() | ||||
| { | ||||
| 	return cman_get_fd(c_handle); | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	int i; | ||||
| 	int nnodes = 0; | ||||
|  | ||||
| 	/* return number of ACTIVE nodes */ | ||||
| 	for (i=0; i<num_nodes; i++) { | ||||
| 		if (nodes[i].cn_member) | ||||
| 			nnodes++; | ||||
| 	} | ||||
| 	return nnodes; | ||||
| } | ||||
|  | ||||
| /* send_message with the fd check removed */ | ||||
| static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext) | ||||
| { | ||||
| 	int nodeid = 0; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0) | ||||
| 	{ | ||||
| 		log_error(errtext); | ||||
| 	} | ||||
| 	return msglen; | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	if (this_node.cn_nodeid == 0) { | ||||
| 		cman_get_node(c_handle, 0, &this_node); | ||||
| 	} | ||||
| 	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| /* Call a callback routine for each node is that known (down means not running a clvmd) */ | ||||
| static int _cluster_do_node_callback(struct local_client *client, | ||||
| 				     void (*callback) (struct local_client *, char *, | ||||
| 						       int)) | ||||
| { | ||||
| 	int i; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	for (i = 0; i < _get_num_nodes(); i++) { | ||||
| 		if (nodes[i].cn_member) { | ||||
| 			callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]); | ||||
| 			if (!node_updown[nodes[i].cn_nodeid]) | ||||
| 				somedown = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Process OOB message from the cluster socket, | ||||
|    this currently just means that a node has stopped listening on our port */ | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg) | ||||
| { | ||||
| 	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
| 	switch (reason) { | ||||
|         case CMAN_REASON_PORTCLOSED: | ||||
| 		name_from_nodeid(arg, namebuf); | ||||
| 		log_notice("clvmd on node %s has died\n", namebuf); | ||||
| 		DEBUGLOG("Got port closed message, removing node %s\n", namebuf); | ||||
|  | ||||
| 		node_updown[arg] = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_STATECHANGE: | ||||
| 		DEBUGLOG("Got state change message, re-reading members list\n"); | ||||
| 		get_members(); | ||||
| 		break; | ||||
|  | ||||
| #if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2 | ||||
| 	case CMAN_REASON_PORTOPENED: | ||||
| 		/* Ignore this, wait for startup message from clvmd itself */ | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_TRY_SHUTDOWN: | ||||
| 		DEBUGLOG("Got try shutdown, sending OK\n"); | ||||
| 		cman_replyto_shutdown(c_handle, 1); | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		/* ERROR */ | ||||
| 		DEBUGLOG("Got unknown event callback message: %d\n", reason); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static struct local_client *cman_client; | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
|  | ||||
| 	/* Save this for data_callback */ | ||||
| 	cman_client = fd; | ||||
|  | ||||
| 	/* We never return a new client */ | ||||
| 	*new_client = NULL; | ||||
|  | ||||
| 	return cman_dispatch(c_handle, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid) | ||||
| { | ||||
| 	/* Ignore looped back messages */ | ||||
| 	if (nodeid == this_node.cn_nodeid) | ||||
| 		return; | ||||
| 	process_message(cman_client, buf, len, (char *)&nodeid); | ||||
| } | ||||
|  | ||||
| static void _add_up_node(char *csid) | ||||
| { | ||||
| 	/* It's up ! */ | ||||
| 	int nodeid = nodeid_from_csid(csid); | ||||
|  | ||||
| 	if (nodeid >= max_updown_nodes) { | ||||
| 	        int new_size = nodeid + 10; | ||||
| 		int *new_updown = realloc(node_updown, new_size); | ||||
|  | ||||
| 		if (new_updown) { | ||||
| 			node_updown = new_updown; | ||||
| 			max_updown_nodes = new_size; | ||||
| 			DEBUGLOG("realloced more space for nodes. now %d\n", | ||||
| 				 max_updown_nodes); | ||||
| 		} else { | ||||
| 			log_error | ||||
| 				("Realloc failed. Node status for clvmd will be wrong. quitting\n"); | ||||
| 			exit(999); | ||||
| 		} | ||||
| 	} | ||||
| 	node_updown[nodeid] = 1; | ||||
| 	DEBUGLOG("Added new node %d to updown list\n", nodeid); | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown() | ||||
| { | ||||
| 	unlock_all(); | ||||
| 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 	cman_finish(c_handle); | ||||
| } | ||||
|  | ||||
| static int is_listening(int nodeid) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	do { | ||||
| 		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD); | ||||
| 		if (status < 0 && errno == EBUSY) {	/* Don't busywait */ | ||||
| 			sleep(1); | ||||
| 			errno = EBUSY;	/* In case sleep trashes it */ | ||||
| 		} | ||||
| 	} | ||||
| 	while (status < 0 && errno == EBUSY); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Populate the list of CLVMDs running. | ||||
|    called only at startup time */ | ||||
| static void count_clvmds_running(void) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		node_updown[nodes[i].cn_nodeid] = is_listening(nodes[i].cn_nodeid); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get a list of active cluster members */ | ||||
| static void get_members() | ||||
| { | ||||
| 	int retnodes; | ||||
| 	int status; | ||||
|  | ||||
| 	num_nodes = cman_get_node_count(c_handle); | ||||
| 	if (num_nodes == -1) { | ||||
| 		log_error("Unable to get node count"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* Not enough room for new nodes list ? */ | ||||
| 	if (num_nodes > count_nodes && nodes) { | ||||
| 		free(nodes); | ||||
| 		nodes = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (nodes == NULL) { | ||||
| 		count_nodes = num_nodes + 10; /* Overallocate a little */ | ||||
| 		nodes = malloc(count_nodes * sizeof(struct cman_node)); | ||||
| 		if (!nodes) { | ||||
| 			log_error("Unable to allocate nodes array\n"); | ||||
| 			exit(5); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes); | ||||
| 	if (status < 0) { | ||||
| 		log_error("Unable to get node details"); | ||||
| 		exit(6); | ||||
| 	} | ||||
|  | ||||
| 	if (node_updown == NULL) { | ||||
| 		node_updown = | ||||
| 			(int *) malloc(sizeof(int) * | ||||
| 				       max(num_nodes, max_updown_nodes)); | ||||
| 		memset(node_updown, 0, | ||||
| 		       sizeof(int) * max(num_nodes, max_updown_nodes)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Convert a node name to a CSID */ | ||||
| static int _csid_from_name(char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (strcmp(name, nodes[i].cn_name) == 0) { | ||||
| 			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node name */ | ||||
| static int _name_from_csid(char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a node ID to a node name */ | ||||
| static int name_from_nodeid(int nodeid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (nodeid == nodes[i].cn_nodeid) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node ID */ | ||||
| static int nodeid_from_csid(char *csid) | ||||
| { | ||||
|         int nodeid; | ||||
|  | ||||
| 	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	return nodeid; | ||||
| } | ||||
|  | ||||
| static int _is_quorate() | ||||
| { | ||||
| 	return cman_is_quorate(c_handle); | ||||
| } | ||||
|  | ||||
| static void sync_ast_routine(void *arg) | ||||
| { | ||||
| 	struct lock_wait *lwait = arg; | ||||
|  | ||||
| 	pthread_mutex_lock(&lwait->mutex); | ||||
| 	pthread_cond_signal(&lwait->cond); | ||||
| 	pthread_mutex_unlock(&lwait->mutex); | ||||
| } | ||||
|  | ||||
| static int _sync_lock(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	if (!lockid) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags); | ||||
| 	/* Conversions need the lockid in the LKSB */ | ||||
| 	if (flags & LKF_CONVERT) | ||||
| 		lwait.lksb.sb_lkid = *lockid; | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_lock(lockspace, | ||||
| 			     mode, | ||||
| 			     &lwait.lksb, | ||||
| 			     flags, | ||||
| 			     resource, | ||||
| 			     strlen(resource), | ||||
| 			     0, sync_ast_routine, &lwait, NULL, NULL); | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	*lockid = lwait.lksb.sb_lkid; | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	DEBUGLOG("sync_lock: returning lkid %x\n", *lockid); | ||||
| 	if (lwait.lksb.sb_status) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| static int _sync_unlock(const char *resource /* UNUSED */, int lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid); | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait); | ||||
|  | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	if (lwait.lksb.sb_status != EUNLOCK) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	cman_cluster_t cluster_info; | ||||
| 	int status; | ||||
|  | ||||
| 	status = cman_get_cluster(c_handle, &cluster_info); | ||||
| 	if (!status) { | ||||
| 		strncpy(buf, cluster_info.ci_name, buflen); | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_cman_ops = { | ||||
| 	.cluster_init_completed   = _cluster_init_completed, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_cman_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_cman_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										306
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,306 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  | ||||
|   CLVMD Cluster LVM daemon command processor. | ||||
|  | ||||
|   To add commands to the daemon simply add a processor in do_command and return | ||||
|   and messages back in buf and the length in *retlen. The initial value of | ||||
|   buflen is the maximum size of the buffer. if buf is not large enough then it | ||||
|   may be reallocated by the functions in here to a suitable size bearing in | ||||
|   mind that anything larger than the passed-in size will have to be returned | ||||
|   using the system LV and so performance will suffer. | ||||
|  | ||||
|   The status return will be negated and passed back to the originating node. | ||||
|  | ||||
|   pre- and post- command routines are called only on the local node. The | ||||
|   purpose is primarily to get and release locks, though the pre- routine should | ||||
|   also do any other local setups required by the command (if any) and can | ||||
|   return a failure code that prevents the command from being distributed around | ||||
|   the cluster | ||||
|  | ||||
|   The pre- and post- routines are run in their own thread so can block as long | ||||
|   they like, do_command is run in the main clvmd thread so should not block for | ||||
|   too long. If the pre-command returns an error code (!=0) then the command | ||||
|   will not be propogated around the cluster but the post-command WILL be called | ||||
|  | ||||
|   Also note that the pre and post routine are *always* called on the local | ||||
|   node, even if the command to be executed was only requested to run on a | ||||
|   remote node. It may peek inside the client structure to check the status of | ||||
|   the command. | ||||
|  | ||||
|   The clients of the daemon must, naturally, understand the return messages and | ||||
|   codes. | ||||
|  | ||||
|   Routines in here may only READ the values in the client structure passed in | ||||
|   apart from client->private which they are free to do what they like with. | ||||
|  | ||||
| */ | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
| #include "list.h" | ||||
| #include "locking.h" | ||||
| #include "log.h" | ||||
| #include "lvm-functions.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
| #include "libdlm.h" | ||||
|  | ||||
| extern struct cluster_ops *clops; | ||||
|  | ||||
| /* This is where all the real work happens: | ||||
|    NOTE: client will be NULL when this is executed on a remote node */ | ||||
| int do_command(struct local_client *client, struct clvm_header *msg, int msglen, | ||||
| 	       char **buf, int buflen, int *retlen) | ||||
| { | ||||
| 	char *args = msg->node + strlen(msg->node) + 1; | ||||
| 	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node); | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
| 	struct utsname nodeinfo; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
|  | ||||
| 	/* Do the command */ | ||||
| 	switch (msg->cmd) { | ||||
| 		/* Just a test message */ | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		if (arglen > buflen) { | ||||
| 			buflen = arglen + 200; | ||||
| 			*buf = realloc(*buf, buflen); | ||||
| 		} | ||||
| 		uname(&nodeinfo); | ||||
| 		*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s", | ||||
| 				       nodeinfo.nodename, args, | ||||
| 				       nodeinfo.release); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		/* Check to see if the VG is in use by LVM1 */ | ||||
| 		status = do_check_lvm1(&args[2]); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		/* This is the biggie */ | ||||
| 		lock_cmd = args[0] & 0x3F; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = do_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		/* Replace EIO with something less scary */ | ||||
| 		if (status == EIO) { | ||||
| 			*retlen = | ||||
| 			    1 + snprintf(*buf, buflen, | ||||
| 					 get_last_lvm_error()); | ||||
| 			return EIO; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 		do_refresh_cache(); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 		status = clops->get_cluster_name(*buf, buflen); | ||||
| 		if (!status) | ||||
| 			*retlen = strlen(*buf); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		/* Won't get here because command is validated in pre_command */ | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	/* Check the status of the command and return the error text */ | ||||
| 	if (status) { | ||||
| 		*retlen = 1 + snprintf(*buf, buflen, strerror(status)); | ||||
| 	} | ||||
|  | ||||
| 	return status; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int lock_vg(struct local_client *client) | ||||
| { | ||||
|     struct dm_hash_table *lock_hash; | ||||
|     struct clvm_header *header = | ||||
| 	(struct clvm_header *) client->bits.localsock.cmd; | ||||
|     unsigned char lock_cmd; | ||||
|     unsigned char lock_flags; | ||||
|     char *args = header->node + strlen(header->node) + 1; | ||||
|     int lkid; | ||||
|     int status = 0; | ||||
|     char *lockname; | ||||
|  | ||||
|     /* Keep a track of VG locks in our own hash table. In current | ||||
|        practice there should only ever be more than two VGs locked | ||||
|        if a user tries to merge lots of them at once */ | ||||
|     if (client->bits.localsock.private) { | ||||
| 	lock_hash = (struct dm_hash_table *)client->bits.localsock.private; | ||||
|     } | ||||
|     else { | ||||
| 	lock_hash = dm_hash_create(3); | ||||
| 	if (!lock_hash) | ||||
| 	    return ENOMEM; | ||||
| 	client->bits.localsock.private = (void *)lock_hash; | ||||
|     } | ||||
|  | ||||
|     lock_cmd = args[0] & 0x3F; | ||||
|     lock_flags = args[1]; | ||||
|     lockname = &args[2]; | ||||
|     DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client); | ||||
|  | ||||
|     if (lock_cmd == LCK_UNLOCK) { | ||||
|  | ||||
| 	lkid = (int)(long)dm_hash_lookup(lock_hash, lockname); | ||||
| 	if (lkid == 0) | ||||
| 	    return EINVAL; | ||||
|  | ||||
| 	status = sync_unlock(lockname, lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    dm_hash_remove(lock_hash, lockname); | ||||
|     } | ||||
|     else { | ||||
| 	/* Read locks need to be PR; other modes get passed through */ | ||||
| 	if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) { | ||||
| 	    lock_cmd &= ~LCK_TYPE_MASK; | ||||
| 	    lock_cmd |= LCK_PREAD; | ||||
| 	} | ||||
| 	status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    dm_hash_insert(lock_hash, lockname, (void *)(long)lkid); | ||||
|     } | ||||
|  | ||||
|     return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Pre-command is a good place to get locks that are needed only for the duration | ||||
|    of the commands around the cluster (don't forget to free them in post-command), | ||||
|    and to sanity check the command arguments */ | ||||
| int do_pre_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	int lockid; | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid); | ||||
| 		client->bits.localsock.private = (void *)(long)lockid; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
|        	        status = lock_vg(client); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = pre_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_error("Unknown command %d received\n", header->cmd); | ||||
| 		status = EINVAL; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Note that the post-command routine is called even if the pre-command or the real command | ||||
|    failed */ | ||||
| int do_post_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	int status = 0; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = | ||||
| 		    sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private); | ||||
| 		client->bits.localsock.private = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		/* Nothing to do here */ | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = post_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Called when the client is about to be deleted */ | ||||
| void cmd_client_cleanup(struct local_client *client) | ||||
| { | ||||
|     if (client->bits.localsock.private) { | ||||
|  | ||||
| 	struct dm_hash_node *v; | ||||
| 	struct dm_hash_table *lock_hash = | ||||
| 	    (struct dm_hash_table *)client->bits.localsock.private; | ||||
|  | ||||
| 	dm_hash_iterate(v, lock_hash) { | ||||
| 		int lkid = (int)(long)dm_hash_get_data(lock_hash, v); | ||||
| 		char *lockname = dm_hash_get_key(lock_hash, v); | ||||
|  | ||||
| 		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid); | ||||
| 		sync_unlock(lockname, lkid); | ||||
| 	} | ||||
|  | ||||
| 	dm_hash_destroy(lock_hash); | ||||
| 	client->bits.localsock.private = 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Abstraction layer for clvmd cluster communications | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_COMMS_H | ||||
| #define _CLVMD_COMMS_H | ||||
|  | ||||
| struct local_client; | ||||
|  | ||||
| struct cluster_ops { | ||||
| 	void (*cluster_init_completed) (void); | ||||
|  | ||||
| 	int (*cluster_send_message) (void *buf, int msglen, char *csid, | ||||
| 				const char *errtext); | ||||
| 	int (*name_from_csid) (char *csid, char *name); | ||||
| 	int (*csid_from_name) (char *csid, char *name); | ||||
| 	int (*get_num_nodes) (void); | ||||
| 	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len, | ||||
| 			       char *csid, struct local_client **new_client); | ||||
| 	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */ | ||||
| 	int (*cluster_do_node_callback) (struct local_client *client, | ||||
| 				    void (*callback) (struct local_client *, | ||||
| 						      char *csid, int node_up)); | ||||
| 	int (*is_quorate) (void); | ||||
|  | ||||
| 	void (*get_our_csid) (char *csid); | ||||
| 	void (*add_up_node) (char *csid); | ||||
| 	void (*reread_config) (void); | ||||
| 	void (*cluster_closedown) (void); | ||||
|  | ||||
| 	int (*get_cluster_name)(char *buf, int buflen); | ||||
|  | ||||
| 	int (*sync_lock) (const char *resource, int mode, int flags, int *lockid); | ||||
| 	int (*sync_unlock) (const char *resource, int lockid); | ||||
|  | ||||
| }; | ||||
|  | ||||
| #ifdef USE_GULM | ||||
| #  include "tcp-comms.h" | ||||
| struct cluster_ops *init_gulm_cluster(void); | ||||
| #define MAX_CSID_LEN 			GULM_MAX_CSID_LEN | ||||
| #define MAX_CLUSTER_MEMBER_NAME_LEN	GULM_MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_CMAN | ||||
| #  include <netinet/in.h> | ||||
| #  include "libcman.h" | ||||
| #  define CMAN_MAX_CSID_LEN 4 | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN CMAN_MAX_CSID_LEN | ||||
| #  endif | ||||
| #  undef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN | ||||
| #  define CMAN_MAX_CLUSTER_MESSAGE 1500 | ||||
| #  define CLUSTER_PORT_CLVMD 11 | ||||
| struct cluster_ops *init_cman_cluster(void); | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1009
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1009
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
|  | ||||
| /* DLM constant that clvmd uses as a generic NONBLOCK lock flag */ | ||||
| #define LKF_NOQUEUE 1 | ||||
|  | ||||
| extern int get_next_node_csid(void **context, char *csid); | ||||
| extern void add_down_node(char *csid); | ||||
| extern int gulm_fd(void); | ||||
| extern int get_ip_address(char *node, char *addr); | ||||
| extern void tcp_remove_client(char *csid); | ||||
| extern int alloc_client(int fd, char *csid, struct local_client **new_client); | ||||
|  | ||||
| void gulm_add_up_node(char *csid); | ||||
| int gulm_name_from_csid(char *csid, char *name); | ||||
							
								
								
									
										1919
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1919
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										121
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_H | ||||
| #define _CLVMD_H | ||||
|  | ||||
| #define CLVMD_MAJOR_VERSION 0 | ||||
| #define CLVMD_MINOR_VERSION 2 | ||||
| #define CLVMD_PATCH_VERSION 1 | ||||
|  | ||||
| /* Name of the cluster LVM admin lock */ | ||||
| #define ADMIN_LOCK_NAME "CLVMD_ADMIN" | ||||
|  | ||||
| /* Default time (in seconds) we will wait for all remote commands to execute | ||||
|    before declaring them dead */ | ||||
| #define DEFAULT_CMD_TIMEOUT 60 | ||||
|  | ||||
| /* One of these for each reply we get from command execution on a node */ | ||||
| struct node_reply { | ||||
| 	char node[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| 	char *replymsg; | ||||
| 	int status; | ||||
| 	struct node_reply *next; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * These exist for the use of local sockets only when we are | ||||
|  * collecting responses from all cluster nodes | ||||
|  */ | ||||
| struct localsock_bits { | ||||
| 	struct node_reply *replies; | ||||
| 	int num_replies; | ||||
| 	int expected_replies; | ||||
| 	time_t sent_time;	/* So we can check for timeouts */ | ||||
| 	int in_progress;	/* Only execute one cmd at a time per client */ | ||||
| 	int sent_out;		/* Flag to indicate that a command was sent | ||||
| 				   to remote nodes */ | ||||
| 	void *private;		/* Private area for command processor use */ | ||||
| 	void *cmd;		/* Whole command as passed down local socket */ | ||||
| 	int cmd_len;		/* Length of above */ | ||||
| 	int pipe;		/* Pipe to send PRE completion status down */ | ||||
| 	int finished;		/* Flag to tell subthread to exit */ | ||||
| 	int all_success;	/* Set to 0 if any node (or the pre_command) | ||||
| 				   failed */ | ||||
| 	struct local_client *pipe_client; | ||||
| 	pthread_t threadid; | ||||
| 	enum { PRE_COMMAND, POST_COMMAND, QUIT } state; | ||||
| 	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */ | ||||
| 	pthread_cond_t cond; | ||||
|  | ||||
| 	pthread_mutex_t reply_mutex;	/* Protect reply structure */ | ||||
| }; | ||||
|  | ||||
| /* Entries for PIPE clients */ | ||||
| struct pipe_bits { | ||||
| 	struct local_client *client;	/* Actual (localsock) client */ | ||||
| 	pthread_t threadid;		/* Our own copy of the thread id */ | ||||
| }; | ||||
|  | ||||
| /* Entries for Network socket clients */ | ||||
| struct netsock_bits { | ||||
| 	void *private; | ||||
| 	int flags; | ||||
| }; | ||||
|  | ||||
| typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len, | ||||
| 			      char *csid, struct local_client ** new_client); | ||||
|  | ||||
| /* One of these for each fd we are listening on */ | ||||
| struct local_client { | ||||
| 	int fd; | ||||
| 	enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS, | ||||
| 		    LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type; | ||||
| 	struct local_client *next; | ||||
| 	unsigned short xid; | ||||
| 	fd_callback_t callback; | ||||
| 	uint8_t removeme; | ||||
|  | ||||
| 	union { | ||||
| 		struct localsock_bits localsock; | ||||
| 		struct pipe_bits pipe; | ||||
| 		struct netsock_bits net; | ||||
| 	} bits; | ||||
| }; | ||||
|  | ||||
| #define DEBUGLOG(fmt, args...) debuglog(fmt, ## args); | ||||
|  | ||||
| #ifndef max | ||||
| #define max(a,b) ((a)>(b)?(a):(b)) | ||||
| #endif | ||||
|  | ||||
| /* The real command processor is in clvmd-command.c */ | ||||
| extern int do_command(struct local_client *client, struct clvm_header *msg, | ||||
| 		      int msglen, char **buf, int buflen, int *retlen); | ||||
|  | ||||
| /* Pre and post command routines are called only on the local node */ | ||||
| extern int do_pre_command(struct local_client *client); | ||||
| extern int do_post_command(struct local_client *client); | ||||
| extern void cmd_client_cleanup(struct local_client *client); | ||||
| extern int add_client(struct local_client *new_client); | ||||
|  | ||||
| extern void clvmd_cluster_init_completed(void); | ||||
| extern void process_message(struct local_client *client, char *buf, int len, char *csid); | ||||
| extern void debuglog(const char *fmt, ... ); | ||||
|  | ||||
| int sync_lock(const char *resource, int mode, int flags, int *lockid); | ||||
| int sync_unlock(const char *resource, int lockid); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										226
									
								
								daemons/clvmd/cnxman-socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								daemons/clvmd/cnxman-socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved. | ||||
| **  Copyright (C) 2004 Red Hat, Inc.  All rights reserved. | ||||
| ** | ||||
| **  This copyrighted material is made available to anyone wishing to use, | ||||
| **  modify, copy, or redistribute it subject to the terms and conditions | ||||
| **  of the GNU General Public License v.2. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* CMAN socket interface header, | ||||
|    may be include by user or kernel code */ | ||||
|  | ||||
| #ifndef __CNXMAN_SOCKET_H | ||||
| #define __CNXMAN_SOCKET_H | ||||
|  | ||||
| /* A currently unused number. TIPC also uses this number and you're unlikely | ||||
|    to be using both. | ||||
|  */ | ||||
| #define AF_CLUSTER 30 | ||||
| #define PF_CLUSTER AF_CLUSTER | ||||
|  | ||||
| /* Protocol(socket) types */ | ||||
| #define CLPROTO_MASTER 2 | ||||
| #define CLPROTO_CLIENT 3 | ||||
|  | ||||
| /* ioctls -- should register these properly */ | ||||
| #define SIOCCLUSTER_NOTIFY            _IOW('x', 0x01, int) | ||||
| #define SIOCCLUSTER_REMOVENOTIFY      _IO( 'x', 0x02) | ||||
| #define SIOCCLUSTER_GETMEMBERS        _IOR('x', 0x03, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SETEXPECTED_VOTES _IOW('x', 0x04, int) | ||||
| #define SIOCCLUSTER_ISQUORATE         _IO( 'x', 0x05) | ||||
| #define SIOCCLUSTER_ISLISTENING       _IOW('x', 0x06, struct cl_listen_request) | ||||
| #define SIOCCLUSTER_GETALLMEMBERS     _IOR('x', 0x07, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SET_VOTES         _IOW('x', 0x08, int) | ||||
| #define SIOCCLUSTER_GET_VERSION       _IOR('x', 0x09, struct cl_version) | ||||
| #define SIOCCLUSTER_SET_VERSION       _IOW('x', 0x0a, struct cl_version) | ||||
| #define SIOCCLUSTER_ISACTIVE          _IO( 'x', 0x0b) | ||||
| #define SIOCCLUSTER_KILLNODE          _IOW('x', 0x0c, int) | ||||
| #define SIOCCLUSTER_GET_JOINCOUNT     _IO( 'x', 0x0d) | ||||
| #define SIOCCLUSTER_SERVICE_REGISTER  _IOW('x', 0x0e, char) | ||||
| #define SIOCCLUSTER_SERVICE_UNREGISTER _IO('x', 0x0f) | ||||
| #define SIOCCLUSTER_SERVICE_JOIN      _IO( 'x', 0x10) | ||||
| #define SIOCCLUSTER_SERVICE_LEAVE     _IO( 'x', 0x20) | ||||
| #define SIOCCLUSTER_SERVICE_SETSIGNAL _IOW('x', 0x30, int) | ||||
| #define SIOCCLUSTER_SERVICE_STARTDONE _IOW('x', 0x40, unsigned int) | ||||
| #define SIOCCLUSTER_SERVICE_GETEVENT  _IOR('x', 0x50, struct cl_service_event) | ||||
| #define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_nodelist) | ||||
| #define SIOCCLUSTER_SERVICE_GLOBALID  _IOR('x', 0x70, uint32_t) | ||||
| #define SIOCCLUSTER_SERVICE_SETLEVEL  _IOR('x', 0x80, int) | ||||
| #define SIOCCLUSTER_GETNODE	      _IOWR('x', 0x90, struct cl_cluster_node) | ||||
| #define SIOCCLUSTER_BARRIER           _IOW('x', 0x0a0, struct cl_barrier_info) | ||||
|  | ||||
| /* These were setsockopts */ | ||||
| #define SIOCCLUSTER_PASS_SOCKET       _IOW('x', 0x0b0, struct cl_passed_sock) | ||||
| #define SIOCCLUSTER_SET_NODENAME      _IOW('x', 0x0b1, char *) | ||||
| #define SIOCCLUSTER_SET_NODEID        _IOW('x', 0x0b2, int) | ||||
| #define SIOCCLUSTER_JOIN_CLUSTER      _IOW('x', 0x0b3, struct cl_join_cluster_info) | ||||
| #define SIOCCLUSTER_LEAVE_CLUSTER     _IOW('x', 0x0b4, int) | ||||
|  | ||||
|  | ||||
| /* Maximum size of a cluster message */ | ||||
| #define CMAN_MAX_CLUSTER_MESSAGE          1500 | ||||
| #define CMAN_MAX_CLUSTER_MEMBER_NAME_LEN   255 | ||||
| #define MAX_BARRIER_NAME_LEN           33 | ||||
| #define MAX_SA_ADDR_LEN                12 | ||||
| #define MAX_CLUSTER_NAME_LEN           16 | ||||
|  | ||||
| /* Well-known cluster port numbers */ | ||||
| #define CLUSTER_PORT_MEMBERSHIP  1	/* Mustn't block during cluster | ||||
| 					 * transitions! */ | ||||
| #define CLUSTER_PORT_SERVICES    2 | ||||
| #define CLUSTER_PORT_SYSMAN      10	/* Remote execution daemon */ | ||||
| #define CLUSTER_PORT_CLVMD       11	/* Cluster LVM daemon */ | ||||
| #define CLUSTER_PORT_SLM         12	/* LVM SLM (simple lock manager) */ | ||||
|  | ||||
| /* Port numbers above this will be blocked when the cluster is inquorate or in | ||||
|  * transition */ | ||||
| #define HIGH_PROTECTED_PORT      9 | ||||
|  | ||||
| /* Reasons for leaving the cluster */ | ||||
| #define CLUSTER_LEAVEFLAG_DOWN     0	/* Normal shutdown */ | ||||
| #define CLUSTER_LEAVEFLAG_KILLED   1 | ||||
| #define CLUSTER_LEAVEFLAG_PANIC    2 | ||||
| #define CLUSTER_LEAVEFLAG_REMOVED  3	/* This one can reduce quorum */ | ||||
| #define CLUSTER_LEAVEFLAG_REJECTED 4	/* Not allowed into the cluster in the | ||||
| 					 * first place */ | ||||
| #define CLUSTER_LEAVEFLAG_INCONSISTENT 5	/* Our view of the cluster is | ||||
| 						 * in a minority */ | ||||
| #define CLUSTER_LEAVEFLAG_DEAD         6	/* Discovered to be dead */ | ||||
| #define CLUSTER_LEAVEFLAG_FORCE     0x10	/* Forced by command-line */ | ||||
|  | ||||
| /* OOB messages sent to a local socket */ | ||||
| #define CLUSTER_OOB_MSG_PORTCLOSED  1 | ||||
| #define CLUSTER_OOB_MSG_STATECHANGE 2 | ||||
| #define CLUSTER_OOB_MSG_SERVICEEVENT 3 | ||||
|  | ||||
| /* Sendmsg flags, these are above the normal sendmsg flags so they don't | ||||
|  * interfere */ | ||||
| #define MSG_NOACK     0x010000	/* Don't need an ACK for this message */ | ||||
| #define MSG_QUEUE     0x020000	/* Queue the message for sending later */ | ||||
| #define MSG_MULTICAST 0x080000	/* Message was sent to all nodes in the cluster | ||||
| 				 */ | ||||
| #define MSG_ALLINT    0x100000	/* Send out of all interfaces */ | ||||
| #define MSG_REPLYEXP  0x200000	/* Reply is expected */ | ||||
|  | ||||
| typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER, | ||||
| 	       NODESTATE_DEAD } nodestate_t; | ||||
|  | ||||
|  | ||||
| struct sockaddr_cl { | ||||
| 	unsigned short scl_family; | ||||
| 	unsigned char scl_flags; | ||||
| 	unsigned char scl_port; | ||||
| 	int           scl_nodeid; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * This is how we pass the multicast & receive sockets into kernel space. | ||||
|  */ | ||||
| struct cl_passed_sock { | ||||
| 	int fd;			/* FD of master socket to do multicast on */ | ||||
| 	int number;		/* Socket number, to match up recvonly & bcast | ||||
| 				 * sockets */ | ||||
|         int multicast;          /* Is it multicast or receive ? */ | ||||
| }; | ||||
|  | ||||
| /* Cluster configuration info passed when we join the cluster */ | ||||
| struct cl_join_cluster_info { | ||||
| 	unsigned char votes; | ||||
| 	unsigned int expected_votes; | ||||
| 	unsigned int two_node; | ||||
| 	unsigned int config_version; | ||||
|  | ||||
|         char cluster_name[17]; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* This is the structure, per node, returned from the membership ioctl */ | ||||
| struct cl_cluster_node { | ||||
| 	unsigned int size; | ||||
| 	unsigned int node_id; | ||||
| 	unsigned int us; | ||||
| 	unsigned int leave_reason; | ||||
| 	unsigned int incarnation; | ||||
| 	nodestate_t state; | ||||
| 	char name[CMAN_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| 	unsigned char votes; | ||||
| }; | ||||
|  | ||||
| /* The struct passed to the membership ioctls */ | ||||
| struct cl_cluster_nodelist { | ||||
|         uint32_t max_members; | ||||
|         struct cl_cluster_node *nodes; | ||||
| }; | ||||
|  | ||||
| /* Structure passed to SIOCCLUSTER_ISLISTENING */ | ||||
| struct cl_listen_request { | ||||
| 	unsigned char port; | ||||
|         int           nodeid; | ||||
| }; | ||||
|  | ||||
| /* A Cluster PORTCLOSED message - received by a local user as an OOB message */ | ||||
| struct cl_portclosed_oob { | ||||
| 	unsigned char cmd;	/* CLUSTER_OOB_MSG_PORTCLOSED */ | ||||
| 	unsigned char port; | ||||
| }; | ||||
|  | ||||
| /* Get all version numbers or set the config version */ | ||||
| struct cl_version { | ||||
| 	unsigned int major; | ||||
| 	unsigned int minor; | ||||
| 	unsigned int patch; | ||||
| 	unsigned int config; | ||||
| }; | ||||
|  | ||||
| /* structure passed to barrier ioctls */ | ||||
| struct cl_barrier_info { | ||||
| 	char cmd; | ||||
| 	char name[MAX_BARRIER_NAME_LEN]; | ||||
| 	unsigned int flags; | ||||
| 	unsigned long arg; | ||||
| }; | ||||
|  | ||||
| typedef enum { SERVICE_EVENT_STOP, SERVICE_EVENT_START, SERVICE_EVENT_FINISH, | ||||
| 		SERVICE_EVENT_LEAVEDONE } service_event_t; | ||||
|  | ||||
| typedef enum { SERVICE_START_FAILED, SERVICE_START_JOIN, SERVICE_START_LEAVE } | ||||
| 		service_start_t; | ||||
|  | ||||
| struct cl_service_event { | ||||
| 	service_event_t type; | ||||
| 	service_start_t start_type; | ||||
| 	unsigned int event_id; | ||||
| 	unsigned int last_stop; | ||||
| 	unsigned int last_start; | ||||
| 	unsigned int last_finish; | ||||
| 	unsigned int node_count; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Commands to the barrier ioctl */ | ||||
| #define BARRIER_IOCTL_REGISTER 1 | ||||
| #define BARRIER_IOCTL_CHANGE   2 | ||||
| #define BARRIER_IOCTL_DELETE   3 | ||||
| #define BARRIER_IOCTL_WAIT     4 | ||||
|  | ||||
| /* Attributes of a barrier - bitmask */ | ||||
| #define BARRIER_ATTR_AUTODELETE 1 | ||||
| #define BARRIER_ATTR_MULTISTEP  2 | ||||
| #define BARRIER_ATTR_MANUAL     4 | ||||
| #define BARRIER_ATTR_ENABLED    8 | ||||
| #define BARRIER_ATTR_CALLBACK  16 | ||||
|  | ||||
| /* Attribute setting commands */ | ||||
| #define BARRIER_SETATTR_AUTODELETE 1 | ||||
| #define BARRIER_SETATTR_MULTISTEP  2 | ||||
| #define BARRIER_SETATTR_ENABLED    3 | ||||
| #define BARRIER_SETATTR_NODES      4 | ||||
| #define BARRIER_SETATTR_CALLBACK   5 | ||||
| #define BARRIER_SETATTR_TIMEOUT    6 | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										602
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										602
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,602 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <syslog.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
| #include "list.h" | ||||
| #include "lvm-types.h" | ||||
| #include "libdlm.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| /* LVM2 headers */ | ||||
| #include "toolcontext.h" | ||||
| #include "log.h" | ||||
| #include "activate.h" | ||||
| #include "locking.h" | ||||
| #include "defaults.h" | ||||
|  | ||||
| static struct cmd_context *cmd = NULL; | ||||
| static struct dm_hash_table *lv_hash = NULL; | ||||
| static pthread_mutex_t lv_hash_lock; | ||||
| static char last_error[1024]; | ||||
|  | ||||
| struct lv_info { | ||||
| 	int lock_id; | ||||
| 	int lock_mode; | ||||
| }; | ||||
|  | ||||
| char *get_last_lvm_error() | ||||
| { | ||||
| 	return last_error; | ||||
| } | ||||
|  | ||||
| /* Return the mode a lock is currently held at (or -1 if not held) */ | ||||
| static int get_current_lock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (lvi) { | ||||
| 		return lvi->lock_mode; | ||||
| 	} else { | ||||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Called at shutdown to tidy the lockspace */ | ||||
| void unlock_all() | ||||
| { | ||||
| 	struct dm_hash_node *v; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	dm_hash_iterate(v, lv_hash) { | ||||
| 		struct lv_info *lvi = dm_hash_get_data(lv_hash, v); | ||||
|  | ||||
| 		sync_unlock(dm_hash_get_key(lv_hash, v), lvi->lock_id); | ||||
| 	} | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| } | ||||
|  | ||||
| /* Gets a real lock and keeps the info in the hash table */ | ||||
| int hold_lock(char *resource, int mode, int flags) | ||||
| { | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	flags &= LKF_NOQUEUE;	/* Only LKF_NOQUEUE is valid here */ | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (lvi) { | ||||
| 		/* Already exists - convert it */ | ||||
| 		status = | ||||
| 		    sync_lock(resource, mode, LKF_CONVERT | flags, | ||||
| 			      &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (!status) | ||||
| 			lvi->lock_mode = mode; | ||||
|  | ||||
| 		if (status) { | ||||
| 			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} | ||||
| 		errno = saved_errno; | ||||
| 	} else { | ||||
| 		lvi = malloc(sizeof(struct lv_info)); | ||||
| 		if (!lvi) | ||||
| 			return -1; | ||||
|  | ||||
| 		lvi->lock_mode = mode; | ||||
| 		status = sync_lock(resource, mode, flags, &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (status) { | ||||
| 			free(lvi); | ||||
| 			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} else { | ||||
| 		        pthread_mutex_lock(&lv_hash_lock); | ||||
| 			dm_hash_insert(lv_hash, resource, lvi); | ||||
| 			pthread_mutex_unlock(&lv_hash_lock); | ||||
| 		} | ||||
| 		errno = saved_errno; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Unlock and remove it from the hash table */ | ||||
| int hold_unlock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| 	if (!lvi) { | ||||
| 		DEBUGLOG("hold_unlock, lock not already held\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	status = sync_unlock(resource, lvi->lock_id); | ||||
| 	saved_errno = errno; | ||||
| 	if (!status) { | ||||
| 	    	pthread_mutex_lock(&lv_hash_lock); | ||||
| 		dm_hash_remove(lv_hash, resource); | ||||
| 		pthread_mutex_unlock(&lv_hash_lock); | ||||
| 		free(lvi); | ||||
| 	} else { | ||||
| 		DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status, | ||||
| 			 strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| 	errno = saved_errno; | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Watch the return codes here. | ||||
|    liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno. | ||||
|    libdlm API functions return 0 for success, -1 for failure and do set errno. | ||||
|    These functions here return 0 for success or >0 for failure (where the retcode is errno) | ||||
| */ | ||||
|  | ||||
| /* Activate LV exclusive or non-exclusive */ | ||||
| static int do_activate_lv(char *resource, unsigned char lock_flags, int mode) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
| 	int activate_lv; | ||||
| 	int exclusive = 0; | ||||
| 	struct lvinfo lvi; | ||||
|  | ||||
| 	/* Is it already open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == mode) { | ||||
| 		return 0;	/* Nothing to do */ | ||||
| 	} | ||||
|  | ||||
| 	/* Does the config file want us to activate this LV ? */ | ||||
| 	if (!lv_activation_filter(cmd, resource, &activate_lv)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (!activate_lv) | ||||
| 		return 0;	/* Success, we did nothing! */ | ||||
|  | ||||
| 	/* Do we need to activate exclusively? */ | ||||
| 	if ((activate_lv == 2) || (mode == LKM_EXMODE)) { | ||||
| 		exclusive = 1; | ||||
| 		mode = LKM_EXMODE; | ||||
| 	} | ||||
|  | ||||
| 	/* Try to get the lock if it's a clustered volume group */ | ||||
| 	if (lock_flags & LCK_CLUSTER_VG) { | ||||
| 		status = hold_lock(resource, mode, LKF_NOQUEUE); | ||||
| 		if (status) { | ||||
| 			/* Return an LVM-sensible error for this. | ||||
| 			 * Forcing EIO makes the upper level return this text | ||||
| 			 * rather than the strerror text for EAGAIN. | ||||
| 			 */ | ||||
| 			if (errno == EAGAIN) { | ||||
| 				sprintf(last_error, "Volume is busy on another node"); | ||||
| 				errno = EIO; | ||||
| 			} | ||||
| 			return errno; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* If it's suspended then resume it */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, &lvi, 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.suspended) | ||||
| 		if (!lv_resume(cmd, resource)) | ||||
| 			return EIO; | ||||
|  | ||||
| 	/* Now activate it */ | ||||
| 	if (!lv_activate(cmd, resource, exclusive)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Resume the LV if it was active */ | ||||
| static int do_resume_lv(char *resource) | ||||
| { | ||||
| 	int oldmode; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1) { | ||||
| 		DEBUGLOG("do_resume_lv, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_resume_if_active(cmd, resource)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Suspend the device if active */ | ||||
| static int do_suspend_lv(char *resource) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	struct lvinfo lvi; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1) { | ||||
| 		DEBUGLOG("do_suspend_lv, lock held at %d\n", oldmode); | ||||
| 		return 0; /* Not active, so it's OK */ | ||||
| 	} | ||||
|  | ||||
| 	/* Only suspend it if it exists */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, &lvi, 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.exists) { | ||||
| 		if (!lv_suspend_if_active(cmd, resource)) { | ||||
| 			return EIO; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_deactivate_lv(char *resource, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_deactivate_lock, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_deactivate(cmd, resource)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lock_flags & LCK_CLUSTER_VG) { | ||||
| 		status = hold_unlock(resource); | ||||
| 		if (status) | ||||
| 			return errno; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* This is the LOCK_LV part that happens on all nodes in the cluster - | ||||
|    it is responsible for the interaction with device-mapper and LVM */ | ||||
| int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	int status = 0; | ||||
|  | ||||
| 	DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n", | ||||
| 		 resource, command, lock_flags); | ||||
|  | ||||
| 	if (!cmd->config_valid || config_files_changed(cmd)) { | ||||
| 		/* Reinitialise various settings inc. logging, filters */ | ||||
| 		if (!refresh_toolcontext(cmd)) { | ||||
| 			log_error("Updated config file invalid. Aborting."); | ||||
| 			return EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (lock_flags & LCK_PARTIAL_MODE) | ||||
| 		init_partial(1); | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(1); | ||||
|  | ||||
| 	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE)) | ||||
| 		init_dmeventd_monitor(0); | ||||
|  | ||||
| 	switch (command) { | ||||
| 	case LCK_LV_EXCLUSIVE: | ||||
| 		status = do_activate_lv(resource, lock_flags, LKM_EXMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_SUSPEND: | ||||
| 		status = do_suspend_lv(resource); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_UNLOCK: | ||||
| 	case LCK_LV_RESUME:	/* if active */ | ||||
| 		status = do_resume_lv(resource); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_ACTIVATE: | ||||
| 		status = do_activate_lv(resource, lock_flags, LKM_CRMODE); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_DEACTIVATE: | ||||
| 		status = do_deactivate_lv(resource, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		DEBUGLOG("Invalid LV command 0x%x\n", command); | ||||
| 		status = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (lock_flags & LCK_PARTIAL_MODE) | ||||
| 		init_partial(0); | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(0); | ||||
|  | ||||
| 	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE)) | ||||
| 		init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR); | ||||
|  | ||||
| 	/* clean the pool for another command */ | ||||
| 	dm_pool_empty(cmd->mem); | ||||
|  | ||||
| 	DEBUGLOG("Command return is %d\n", status); | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */ | ||||
| int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the | ||||
| 	   lock out on this node (because we are the node modifying the metadata) | ||||
| 	   before suspending cluster-wide. | ||||
| 	 */ | ||||
| 	if (command == LCK_LV_SUSPEND) { | ||||
| 		DEBUGLOG("pre_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n", | ||||
| 			 resource, command, lock_flags); | ||||
|  | ||||
| 		if (hold_lock(resource, LKM_PWMODE, LKF_NOQUEUE)) | ||||
| 			return errno; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only AFTER the cluster-wide stuff above happens */ | ||||
| int post_lock_lv(unsigned char command, unsigned char lock_flags, | ||||
| 		 char *resource) | ||||
| { | ||||
| 	/* Opposite of above, done on resume after a metadata update */ | ||||
| 	if (command == LCK_LV_RESUME) { | ||||
| 		int oldmode; | ||||
|  | ||||
| 		DEBUGLOG | ||||
| 		    ("post_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n", | ||||
| 		     resource, command, lock_flags); | ||||
|  | ||||
| 		/* If the lock state is PW then restore it to what it was */ | ||||
| 		oldmode = get_current_lock(resource); | ||||
| 		if (oldmode == LKM_PWMODE) { | ||||
| 			struct lvinfo lvi; | ||||
|  | ||||
| 			if (!lv_info_by_lvid(cmd, resource, &lvi, 0)) | ||||
| 				return EIO; | ||||
|  | ||||
| 			if (lvi.exists) { | ||||
| 				if (hold_lock(resource, LKM_CRMODE, 0)) | ||||
| 					return errno; | ||||
| 			} else { | ||||
| 				if (hold_unlock(resource)) | ||||
| 					return errno; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Check if a VG is un use by LVM1 so we don't stomp on it */ | ||||
| int do_check_lvm1(char *vgname) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	status = check_lvm1_vg_inactive(cmd, vgname); | ||||
|  | ||||
| 	return status == 1 ? 0 : EBUSY; | ||||
| } | ||||
|  | ||||
| int do_refresh_cache() | ||||
| { | ||||
| 	DEBUGLOG("Refreshing context\n"); | ||||
| 	log_notice("Refreshing context"); | ||||
| 	return refresh_toolcontext(cmd)==1?0:-1; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Only called at gulm startup. Drop any leftover VG or P_orphan locks | ||||
|    that might be hanging around if we died for any reason | ||||
| */ | ||||
| static void drop_vg_locks() | ||||
| { | ||||
| 	char vg[128]; | ||||
| 	char line[255]; | ||||
| 	FILE *vgs = | ||||
| 	    popen | ||||
| 	    ("lvm pvs --nolocking --noheadings -o vg_name", "r"); | ||||
|  | ||||
| 	sync_unlock("P_orphans", LCK_EXCL); | ||||
|  | ||||
| 	if (!vgs) | ||||
| 		return; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), vgs)) { | ||||
| 		char *vgend; | ||||
| 		char *vgstart; | ||||
|  | ||||
| 		if (line[strlen(line)-1] == '\n') | ||||
| 			line[strlen(line)-1] = '\0'; | ||||
|  | ||||
| 		vgstart = line + strspn(line, " "); | ||||
| 		vgend = vgstart + strcspn(vgstart, " "); | ||||
| 		*vgend = '\0'; | ||||
|  | ||||
| 		if (strncmp(vgstart, "WARNING:", 8) == 0) | ||||
| 			continue; | ||||
|  | ||||
| 		sprintf(vg, "V_%s", vgstart); | ||||
| 		sync_unlock(vg, LCK_EXCL); | ||||
|  | ||||
| 	} | ||||
| 	if (fclose(vgs)) | ||||
| 		DEBUGLOG("vgs fclose failed: %s\n", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Ideally, clvmd should be started before any LVs are active | ||||
|  * but this may not be the case... | ||||
|  * I suppose this also comes in handy if clvmd crashes, not that it would! | ||||
|  */ | ||||
| static void *get_initial_state() | ||||
| { | ||||
| 	char lv[64], vg[64], flags[25], vg_flags[25]; | ||||
| 	char uuid[65]; | ||||
| 	char line[255]; | ||||
| 	FILE *lvs = | ||||
| 	    popen | ||||
| 	    ("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr", | ||||
| 	     "r"); | ||||
|  | ||||
| 	if (!lvs) | ||||
| 		return NULL; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), lvs)) { | ||||
| 	        if (sscanf(line, "%s %s %s %s\n", vg, lv, flags, vg_flags) == 4) { | ||||
|  | ||||
| 			/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */ | ||||
| 		        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */ | ||||
| 			    (flags[4] == 'a' || flags[4] == 's') &&	/* is it active or suspended? */ | ||||
| 			    vg_flags[5] == 'c') {			/* is it clustered ? */ | ||||
| 				/* Convert hyphen-separated UUIDs into one */ | ||||
| 				memcpy(&uuid[0], &vg[0], 6); | ||||
| 				memcpy(&uuid[6], &vg[7], 4); | ||||
| 				memcpy(&uuid[10], &vg[12], 4); | ||||
| 				memcpy(&uuid[14], &vg[17], 4); | ||||
| 				memcpy(&uuid[18], &vg[22], 4); | ||||
| 				memcpy(&uuid[22], &vg[27], 4); | ||||
| 				memcpy(&uuid[26], &vg[32], 6); | ||||
| 				memcpy(&uuid[32], &lv[0], 6); | ||||
| 				memcpy(&uuid[38], &lv[7], 4); | ||||
| 				memcpy(&uuid[42], &lv[12], 4); | ||||
| 				memcpy(&uuid[46], &lv[17], 4); | ||||
| 				memcpy(&uuid[50], &lv[22], 4); | ||||
| 				memcpy(&uuid[54], &lv[27], 4); | ||||
| 				memcpy(&uuid[58], &lv[32], 6); | ||||
| 				uuid[64] = '\0'; | ||||
|  | ||||
| 				DEBUGLOG("getting initial lock for %s\n", uuid); | ||||
| 				hold_lock(uuid, LKM_CRMODE, LKF_NOQUEUE); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (fclose(lvs)) | ||||
| 		DEBUGLOG("lvs fclose failed: %s\n", strerror(errno)); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static void lvm2_log_fn(int level, const char *file, int line, | ||||
| 			const char *message) | ||||
| { | ||||
| 	/* | ||||
| 	 * Ignore non-error messages, but store the latest one for returning  | ||||
| 	 * to the user. | ||||
| 	 */ | ||||
| 	if (level != _LOG_ERR && level != _LOG_FATAL) | ||||
| 		return; | ||||
|  | ||||
| 	strncpy(last_error, message, sizeof(last_error)); | ||||
| 	last_error[sizeof(last_error)-1] = '\0'; | ||||
| } | ||||
|  | ||||
| /* This checks some basic cluster-LVM configuration stuff */ | ||||
| static void check_config() | ||||
| { | ||||
| 	int locking_type; | ||||
|  | ||||
| 	locking_type = find_config_tree_int(cmd, "global/locking_type", 1); | ||||
|  | ||||
| 	if (locking_type == 3) /* compiled-in cluster support */ | ||||
| 		return; | ||||
|  | ||||
| 	if (locking_type == 2) { /* External library, check name */ | ||||
| 		const char *libname; | ||||
|  | ||||
| 		libname = find_config_tree_str(cmd, "global/locking_library", | ||||
| 					  ""); | ||||
| 		if (strstr(libname, "liblvm2clusterlock.so")) | ||||
| 			return; | ||||
|  | ||||
| 		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work."); | ||||
| 		return; | ||||
| 	} | ||||
| 	log_error("locking_type not set correctly in lvm.conf, cluster operations will not work."); | ||||
| } | ||||
|  | ||||
| void init_lvhash() | ||||
| { | ||||
| 	/* Create hash table for keeping LV locks & status */ | ||||
| 	lv_hash = dm_hash_create(100); | ||||
| 	pthread_mutex_init(&lv_hash_lock, NULL); | ||||
| } | ||||
|  | ||||
| /* Called to initialise the LVM context of the daemon */ | ||||
| int init_lvm(int using_gulm) | ||||
| { | ||||
| 	if (!(cmd = create_toolcontext(NULL, 0, 1))) { | ||||
| 		log_error("Failed to allocate command context"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */ | ||||
| 	init_syslog(LOG_DAEMON); | ||||
| 	init_debug(_LOG_ERR); | ||||
|  | ||||
| 	/* Check lvm.conf is setup for cluster-LVM */ | ||||
| 	check_config(); | ||||
|  | ||||
| 	/* Remove any non-LV locks that may have been left around */ | ||||
| 	if (using_gulm) | ||||
| 		drop_vg_locks(); | ||||
|  | ||||
| 	get_initial_state(); | ||||
|  | ||||
| 	/* Trap log messages so we can pass them back to the user */ | ||||
| 	init_log_fn(lvm2_log_fn); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										37
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Functions in lvm-functions.c */ | ||||
|  | ||||
| #ifndef _LVM_FUNCTIONS_H | ||||
| #define _LVM_FUNCTIONS_H | ||||
|  | ||||
| extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		       char *resource); | ||||
| extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		      char *resource); | ||||
| extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 			char *resource); | ||||
| extern int do_check_lvm1(char *vgname); | ||||
| extern int do_refresh_cache(void); | ||||
| extern int init_lvm(int using_gulm); | ||||
| extern void init_lvhash(void); | ||||
|  | ||||
| extern int hold_unlock(char *resource); | ||||
| extern int hold_lock(char *resource, int mode, int flags); | ||||
| extern void unlock_all(void); | ||||
| extern char *get_last_lvm_error(void); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										320
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,320 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Tell all clvmds in a cluster to refresh their toolcontext | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <libdevmapper.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "refresh_clvmd.h" | ||||
|  | ||||
| typedef struct lvm_response { | ||||
| 	char node[255]; | ||||
| 	char *response; | ||||
| 	int status; | ||||
| 	int len; | ||||
| } lvm_response_t; | ||||
|  | ||||
| /* | ||||
|  * This gets stuck at the start of memory we allocate so we | ||||
|  * can sanity-check it at deallocation time | ||||
|  */ | ||||
| #define LVM_SIGNATURE 0x434C564D | ||||
|  | ||||
| static int _clvmd_sock = -1; | ||||
|  | ||||
| /* Open connection to the Cluster Manager daemon */ | ||||
| static int _open_local_sock(void) | ||||
| { | ||||
| 	int local_socket; | ||||
| 	struct sockaddr_un sockaddr; | ||||
|  | ||||
| 	/* Open local socket */ | ||||
| 	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
| 		fprintf(stderr, "Local socket creation failed: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	memset(&sockaddr, 0, sizeof(sockaddr)); | ||||
| 	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME)); | ||||
|  | ||||
| 	sockaddr.sun_family = AF_UNIX; | ||||
|  | ||||
| 	if (connect(local_socket,(struct sockaddr *) &sockaddr, | ||||
| 		    sizeof(sockaddr))) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		fprintf(stderr, "connect() failed on local socket: %s\n", | ||||
| 			  strerror(errno)); | ||||
| 		if (close(local_socket)) | ||||
| 			return -1; | ||||
|  | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return local_socket; | ||||
| } | ||||
|  | ||||
| /* Send a request and return the status */ | ||||
| static int _send_request(char *inbuf, int inlen, char **retbuf) | ||||
| { | ||||
| 	char outbuf[PIPE_BUF]; | ||||
| 	struct clvm_header *outheader = (struct clvm_header *) outbuf; | ||||
| 	int len; | ||||
| 	int off; | ||||
| 	int buflen; | ||||
| 	int err; | ||||
|  | ||||
| 	/* Send it to CLVMD */ | ||||
|  rewrite: | ||||
| 	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) { | ||||
| 	        if (err == -1 && errno == EINTR) | ||||
| 		        goto rewrite; | ||||
| 		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the response */ | ||||
|  reread: | ||||
| 	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { | ||||
| 	        if (errno == EINTR) | ||||
| 		        goto reread; | ||||
| 		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (len == 0) { | ||||
| 		fprintf(stderr, "EOF reading CLVMD"); | ||||
| 		errno = ENOTCONN; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Allocate buffer */ | ||||
| 	buflen = len + outheader->arglen; | ||||
| 	*retbuf = dm_malloc(buflen); | ||||
| 	if (!*retbuf) { | ||||
| 		errno = ENOMEM; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Copy the header */ | ||||
| 	memcpy(*retbuf, outbuf, len); | ||||
| 	outheader = (struct clvm_header *) *retbuf; | ||||
|  | ||||
| 	/* Read the returned values */ | ||||
| 	off = 1;		/* we've already read the first byte */ | ||||
| 	while (off <= outheader->arglen && len > 0) { | ||||
| 		len = read(_clvmd_sock, outheader->args + off, | ||||
| 			   buflen - off - offsetof(struct clvm_header, args)); | ||||
| 		if (len > 0) | ||||
| 			off += len; | ||||
| 	} | ||||
|  | ||||
| 	/* Was it an error ? */ | ||||
| 	if (outheader->status != 0) { | ||||
| 		errno = outheader->status; | ||||
|  | ||||
| 		/* Only return an error here if there are no node-specific | ||||
| 		   errors present in the message that might have more detail */ | ||||
| 		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) { | ||||
| 			fprintf(stderr, "cluster request failed: %s\n", strerror(errno)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Build the structure header and parse-out wildcard node names */ | ||||
| static void _build_header(struct clvm_header *head, int cmd, const char *node, | ||||
| 			  int len) | ||||
| { | ||||
| 	head->cmd = cmd; | ||||
| 	head->status = 0; | ||||
| 	head->flags = 0; | ||||
| 	head->clientid = 0; | ||||
| 	head->arglen = len; | ||||
|  | ||||
| 	if (node) { | ||||
| 		/* | ||||
| 		 * Allow a couple of special node names: | ||||
| 		 * "*" for all nodes, | ||||
| 		 * "." for the local node only | ||||
| 		 */ | ||||
| 		if (strcmp(node, "*") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 		} else if (strcmp(node, ".") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 			head->flags = CLVMD_FLAG_LOCAL; | ||||
| 		} else | ||||
| 			strcpy(head->node, node); | ||||
| 	} else | ||||
| 		head->node[0] = '\0'; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Send a message to a(or all) node(s) in the cluster and wait for replies | ||||
|  */ | ||||
| static int _cluster_request(char cmd, const char *node, void *data, int len, | ||||
| 			   lvm_response_t ** response, int *num) | ||||
| { | ||||
| 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1]; | ||||
| 	char *inptr; | ||||
| 	char *retbuf = NULL; | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int num_responses = 0; | ||||
| 	struct clvm_header *head = (struct clvm_header *) outbuf; | ||||
| 	lvm_response_t *rarray; | ||||
|  | ||||
| 	*num = 0; | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		_clvmd_sock = _open_local_sock(); | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		return 0; | ||||
|  | ||||
| 	_build_header(head, cmd, node, len); | ||||
| 	memcpy(head->node + strlen(head->node) + 1, data, len); | ||||
|  | ||||
| 	status = _send_request(outbuf, sizeof(struct clvm_header) + | ||||
| 			      strlen(head->node) + len, &retbuf); | ||||
| 	if (!status) | ||||
| 		goto out; | ||||
|  | ||||
| 	/* Count the number of responses we got */ | ||||
| 	head = (struct clvm_header *) retbuf; | ||||
| 	inptr = head->args; | ||||
| 	while (inptr[0]) { | ||||
| 		num_responses++; | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		inptr += sizeof(int); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate response array. | ||||
| 	 * With an extra pair of INTs on the front to sanity | ||||
| 	 * check the pointer when we are given it back to free | ||||
| 	 */ | ||||
| 	*response = dm_malloc(sizeof(lvm_response_t) * num_responses + | ||||
| 			    sizeof(int) * 2); | ||||
| 	if (!*response) { | ||||
| 		errno = ENOMEM; | ||||
| 		status = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	rarray = *response; | ||||
|  | ||||
| 	/* Unpack the response into an lvm_response_t array */ | ||||
| 	inptr = head->args; | ||||
| 	i = 0; | ||||
| 	while (inptr[0]) { | ||||
| 		strcpy(rarray[i].node, inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
|  | ||||
| 		memcpy(&rarray[i].status, inptr, sizeof(int)); | ||||
| 		inptr += sizeof(int); | ||||
|  | ||||
| 		rarray[i].response = dm_malloc(strlen(inptr) + 1); | ||||
| 		if (rarray[i].response == NULL) { | ||||
| 			/* Free up everything else and return error */ | ||||
| 			int j; | ||||
| 			for (j = 0; j < i; j++) | ||||
| 				dm_free(rarray[i].response); | ||||
| 			free(*response); | ||||
| 			errno = ENOMEM; | ||||
| 			status = -1; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(rarray[i].response, inptr); | ||||
| 		rarray[i].len = strlen(inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		i++; | ||||
| 	} | ||||
| 	*num = num_responses; | ||||
| 	*response = rarray; | ||||
|  | ||||
|       out: | ||||
| 	if (retbuf) | ||||
| 		dm_free(retbuf); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Free reply array */ | ||||
| static int _cluster_free_request(lvm_response_t * response, int num) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num; i++) { | ||||
| 		dm_free(response[i].response); | ||||
| 	} | ||||
|  | ||||
| 	dm_free(response); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int refresh_clvmd() | ||||
| { | ||||
| 	int num_responses; | ||||
| 	char args[1]; // No args really. | ||||
| 	lvm_response_t *response; | ||||
| 	int saved_errno; | ||||
| 	int status; | ||||
| 	int i; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses); | ||||
|  | ||||
| 	/* If any nodes were down then display them and return an error */ | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status == EHOSTDOWN) { | ||||
| 			fprintf(stderr, "clvmd not running on node %s", | ||||
| 				  response[i].node); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} else if (response[i].status) { | ||||
| 			fprintf(stderr, "Error resetting node %s: %s", | ||||
| 				  response[i].node, | ||||
| 				  response[i].response[0] ? | ||||
| 				  	response[i].response : | ||||
| 				  	strerror(response[i].status)); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	saved_errno = errno; | ||||
| 	_cluster_free_request(response, num_responses); | ||||
| 	errno = saved_errno; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
							
								
								
									
										2
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| int refresh_clvmd(void); | ||||
|  | ||||
							
								
								
									
										371
									
								
								daemons/clvmd/system-lv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										371
									
								
								daemons/clvmd/system-lv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,371 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Routines dealing with the System LV */ | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <syslog.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stddef.h> | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <dirent.h> | ||||
| #include <errno.h> | ||||
| #include <mntent.h> | ||||
|  | ||||
| #include "libdlm.h" | ||||
| #include "log.h" | ||||
| #include "list.h" | ||||
| #include "locking.h" | ||||
| #include "system-lv.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #ifdef HAVE_CCS | ||||
| #include "ccs.h" | ||||
| #endif | ||||
|  | ||||
| #define SYSTEM_LV_FILESYSTEM "ext2" | ||||
| #define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX" | ||||
|  | ||||
| extern char *config_filename(void); | ||||
|  | ||||
| static char system_lv_name[PATH_MAX] = { '\0' }; | ||||
| static char mount_point[PATH_MAX] = { '\0' }; | ||||
| static int mounted = 0; | ||||
| static int mounted_rw = 0; | ||||
| static int lockid; | ||||
| static const char *lock_name = "CLVM_SYSTEM_LV"; | ||||
|  | ||||
| /* Look in /proc/mounts or (as a last resort) /etc/mtab to | ||||
|    see if the system-lv is mounted. If it is mounted and we | ||||
|    think it's not then abort because we don't have the right | ||||
|    lock status and we don't know what other processes are doing with it. | ||||
|  | ||||
|    Returns 1 for mounted, 0 for not mounted so it matches the condition | ||||
|    of the "mounted" static variable above. | ||||
| */ | ||||
| static int is_really_mounted(void) | ||||
| { | ||||
| 	FILE *mountfile; | ||||
| 	struct mntent *ment; | ||||
|  | ||||
| 	mountfile = setmntent("/proc/mounts", "r"); | ||||
| 	if (!mountfile) { | ||||
| 		mountfile = setmntent("/etc/mtab", "r"); | ||||
| 		if (!mountfile) { | ||||
| 			log_error("Unable to open /proc/mounts or /etc/mtab"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Look for system LV name in the file */ | ||||
| 	do { | ||||
| 		ment = getmntent(mountfile); | ||||
| 		if (ment) { | ||||
| 			if (strcmp(ment->mnt_fsname, system_lv_name) == 0) { | ||||
| 				endmntent(mountfile); | ||||
| 				return 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	while (ment); | ||||
|  | ||||
| 	endmntent(mountfile); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Get the system LV name from the config file */ | ||||
| static int find_system_lv(void) | ||||
| { | ||||
| 	if (system_lv_name[0] == '\0') { | ||||
| #ifdef HAVE_CCS | ||||
| 		int error; | ||||
| 		ccs_node_t *ctree; | ||||
|  | ||||
| 		/* Read the cluster config file */ | ||||
| 		/* Open the config file */ | ||||
| 		error = open_ccs_file(&ctree, "clvm.ccs"); | ||||
| 		if (error) { | ||||
| 			perror("reading config file"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(system_lv_name, find_ccs_str(ctree, | ||||
| 						    "cluster/systemlv", '/', | ||||
| 						    "/dev/vg/system_lv")); | ||||
|  | ||||
| 		/* Finished with config file */ | ||||
| 		close_ccs_file(ctree); | ||||
| #else | ||||
| 		if (getenv("CLVMD_SYSTEM_LV")) | ||||
| 			strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV")); | ||||
| 		else | ||||
| 			return -1; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	/* See if it has been mounted outside our control */ | ||||
| 	if (is_really_mounted() != mounted) { | ||||
| 		log_error | ||||
| 		    ("The system LV state has been mounted/umounted outside the control of clvmd\n" | ||||
| 		     "it cannot not be used for cluster communications until this is fixed.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* No prizes */ | ||||
| int system_lv_umount(void) | ||||
| { | ||||
| 	if (!mounted) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (umount(mount_point) < 0) { | ||||
| 		log_error("umount of system LV (%s) failed: %m\n", | ||||
| 			  system_lv_name); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sync_unlock(lock_name, lockid); | ||||
| 	mounted = 0; | ||||
|  | ||||
| 	/* Remove the mount point */ | ||||
| 	rmdir(mount_point); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int system_lv_mount(int readwrite) | ||||
| { | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
| 	int fd; | ||||
|  | ||||
| 	if (find_system_lv()) { | ||||
| 		errno = EBUSY; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Is it already mounted suitably? */ | ||||
| 	if (mounted) { | ||||
| 		if (!readwrite || (readwrite && mounted_rw)) { | ||||
| 			return 0; | ||||
| 		} else { | ||||
| 			/* Mounted RO and we need RW */ | ||||
| 			if (system_lv_umount() < 0) | ||||
| 				return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Randomize the mount point */ | ||||
| 	strcpy(mount_point, SYSTEM_LV_MOUNTPOINT); | ||||
| 	fd = mkstemp(mount_point); | ||||
| 	if (fd < 0) { | ||||
| 		log_error("mkstemp for system LV mount point failed: %m\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Race condition here but there's no mkstemp for directories */ | ||||
| 	close(fd); | ||||
| 	unlink(mount_point); | ||||
| 	mkdir(mount_point, 0600); | ||||
|  | ||||
| 	/* Make sure we have a system-lv lock */ | ||||
| 	status = | ||||
| 	    sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0, | ||||
| 		      &lockid); | ||||
| 	if (status < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Mount it */ | ||||
| 	if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM, | ||||
| 		  MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS | ||||
| 		  | (readwrite ? 0 : MS_RDONLY), NULL) < 0) { | ||||
| 		/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to | ||||
| 		   write to it we try to make a filesystem in it and retry the mount */ | ||||
| 		if (errno == EINVAL && readwrite) { | ||||
| 			char cmd[256]; | ||||
|  | ||||
| 			log_error("Attempting mkfs on system LV device %s\n", | ||||
| 				  system_lv_name); | ||||
| 			snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s", | ||||
| 				 SYSTEM_LV_FILESYSTEM, system_lv_name); | ||||
| 			system(cmd); | ||||
|  | ||||
| 			if (mount | ||||
| 			    (system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM, | ||||
| 			     MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | | ||||
| 			     MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY), | ||||
| 			     NULL) == 0) | ||||
| 				goto mounted; | ||||
| 		} | ||||
|  | ||||
| 		saved_errno = errno; | ||||
| 		log_error("mount of system LV (%s, %s, %s) failed: %m\n", | ||||
| 			  system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM); | ||||
| 		sync_unlock(lock_name, lockid); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|       mounted: | ||||
| /* Set the internal flags */ | ||||
| 	mounted = 1; | ||||
| 	mounted_rw = readwrite; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Erase *all* files in the root directory of the system LV. | ||||
|    This *MUST* be called with an appropriate lock held! | ||||
|    The LV is left mounted RW because it is assumed that the | ||||
|    caller wants to write something here after clearing some space */ | ||||
| int system_lv_eraseall(void) | ||||
| { | ||||
| 	DIR *dir; | ||||
| 	struct dirent *ent; | ||||
| 	char fname[PATH_MAX]; | ||||
|  | ||||
| 	/* Must be mounted R/W */ | ||||
| 	system_lv_mount(1); | ||||
|  | ||||
| 	dir = opendir(mount_point); | ||||
| 	if (!dir) | ||||
| 		return -1; | ||||
|  | ||||
| 	while ((ent = readdir(dir))) { | ||||
| 		struct stat st; | ||||
| 		snprintf(fname, sizeof(fname), "%s/%s", mount_point, | ||||
| 			 ent->d_name); | ||||
|  | ||||
| 		if (stat(fname, &st)) { | ||||
| 			if (S_ISREG(st.st_mode)) | ||||
| 				unlink(fname); | ||||
| 		} | ||||
| 	} | ||||
| 	closedir(dir); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* This is a "high-level" routine - it mounts the system LV, writes | ||||
|    the data into a file named after this node and then umounts the LV | ||||
|    again */ | ||||
| int system_lv_write_data(char *data, ssize_t len) | ||||
| { | ||||
| 	struct utsname nodeinfo; | ||||
| 	char fname[PATH_MAX]; | ||||
| 	int outfile; | ||||
| 	ssize_t thiswrite; | ||||
| 	ssize_t written; | ||||
|  | ||||
| 	if (system_lv_mount(1)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Build the file name we are goingto use. */ | ||||
| 	uname(&nodeinfo); | ||||
| 	snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename); | ||||
|  | ||||
| 	/* Open the file for output */ | ||||
| 	outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600); | ||||
| 	if (outfile < 0) { | ||||
| 		int saved_errno = errno; | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	written = 0; | ||||
| 	do { | ||||
| 		thiswrite = write(outfile, data + written, len - written); | ||||
| 		if (thiswrite > 0) | ||||
| 			written += thiswrite; | ||||
|  | ||||
| 	} while (written < len && thiswrite > 0); | ||||
|  | ||||
| 	close(outfile); | ||||
|  | ||||
| 	system_lv_umount(); | ||||
| 	return (thiswrite < 0) ? -1 : 0; | ||||
| } | ||||
|  | ||||
| /* This is a "high-level" routine - it mounts the system LV, reads | ||||
|    the data from a named file and then umounts the LV | ||||
|    again */ | ||||
| int system_lv_read_data(char *fname_base, char *data, ssize_t *len) | ||||
| { | ||||
| 	char fname[PATH_MAX]; | ||||
| 	int outfile; | ||||
| 	struct stat st; | ||||
| 	ssize_t filesize; | ||||
| 	ssize_t thisread; | ||||
| 	ssize_t readbytes; | ||||
|  | ||||
| 	if (system_lv_mount(0)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* Build the file name we are going to use. */ | ||||
| 	snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base); | ||||
|  | ||||
| 	/* Get the file size and stuff. Actually we only need the file size but | ||||
| 	   this will also check that the file exists */ | ||||
| 	if (stat(fname, &st) < 0) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		log_error("stat of file %s on system LV failed: %m\n", fname); | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	filesize = st.st_size; | ||||
|  | ||||
| 	outfile = open(fname, O_RDONLY); | ||||
| 	if (outfile < 0) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		log_error("open of file %s on system LV failed: %m\n", fname); | ||||
| 		system_lv_umount(); | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	readbytes = 0; | ||||
| 	do { | ||||
| 		thisread = | ||||
| 		    read(outfile, data + readbytes, filesize - readbytes); | ||||
| 		if (thisread > 0) | ||||
| 			readbytes += thisread; | ||||
|  | ||||
| 	} while (readbytes < filesize && thisread > 0); | ||||
|  | ||||
| 	close(outfile); | ||||
|  | ||||
| 	system_lv_umount(); | ||||
|  | ||||
| 	*len = readbytes; | ||||
| 	return (thisread < 0) ? -1 : 0; | ||||
| } | ||||
							
								
								
									
										30
									
								
								daemons/clvmd/system-lv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								daemons/clvmd/system-lv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVM_SYSTEM_LV_H | ||||
| #define _CLVM_SYSTEM_LV_H | ||||
|  | ||||
| /* Prototypes for System-LV functions */ | ||||
|  | ||||
| /* "low-level" functions */ | ||||
| extern int system_lv_umount(void); | ||||
| extern int system_lv_mount(int readwrite); | ||||
| extern int system_lv_eraseall(void); | ||||
|  | ||||
| /* "high-level" functions */ | ||||
| extern int system_lv_write_data(char *data, ssize_t len); | ||||
| extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										505
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,505 @@ | ||||
| /****************************************************************************** | ||||
| ******************************************************************************* | ||||
| ** | ||||
| **  Copyright (C) Sistina Software, Inc.  2002-2003  All rights reserved. | ||||
| **  Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
| ** | ||||
| ******************************************************************************* | ||||
| ******************************************************************************/ | ||||
|  | ||||
| /* This provides the inter-clvmd communications for a system without CMAN. | ||||
|    There is a listening TCP socket which accepts new connections in the | ||||
|    normal way. | ||||
|    It can also make outgoing connnections to the other clvmd nodes. | ||||
| */ | ||||
|  | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <syslog.h> | ||||
| #include <netdb.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "clvmd-gulm.h" | ||||
|  | ||||
| #define DEFAULT_TCP_PORT 21064 | ||||
|  | ||||
| static int listen_fd = -1; | ||||
| static int tcp_port; | ||||
| struct dm_hash_table *sock_hash; | ||||
|  | ||||
| static int get_our_ip_address(char *addr, int *family); | ||||
| static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client); | ||||
|  | ||||
| /* Called by init_cluster() to open up the listening socket */ | ||||
| int init_comms(unsigned short port) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|  | ||||
|     sock_hash = dm_hash_create(100); | ||||
|     tcp_port = port ? : DEFAULT_TCP_PORT; | ||||
|  | ||||
|     listen_fd = socket(AF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (listen_fd < 0) | ||||
|     { | ||||
| 	return -1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int one = 1; | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|     } | ||||
|  | ||||
|     memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) | ||||
|     { | ||||
| 	DEBUGLOG("Can't bind to port: %s\n", strerror(errno)); | ||||
| 	syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port); | ||||
| 	close(listen_fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     listen(listen_fd, 5); | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(listen_fd, F_SETFD, 1); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void tcp_remove_client(char *csid) | ||||
|  { | ||||
|     struct local_client *client; | ||||
|     DEBUGLOG("tcp_remove_client\n"); | ||||
|  | ||||
|     /* Don't actually close the socket here - that's the | ||||
|        job of clvmd.c whch will do the job when it notices the | ||||
|        other end has gone. We just need to remove the client(s) from | ||||
|        the hash table so we don't try to use it for sending any more */ | ||||
|     client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (client) | ||||
|     { | ||||
| 	dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	client->removeme = 1; | ||||
| 	close(client->fd); | ||||
|     } | ||||
|  | ||||
|     /* Look for a mangled one too */ | ||||
|     csid[0] ^= 0x80; | ||||
|  | ||||
|     client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (client) | ||||
|     { | ||||
| 	dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	client->removeme = 1; | ||||
| 	close(client->fd); | ||||
|     } | ||||
|  | ||||
|     /* Put it back as we found it */ | ||||
|     csid[0] ^= 0x80; | ||||
| } | ||||
|  | ||||
| int alloc_client(int fd, char *csid, struct local_client **new_client) | ||||
| { | ||||
|     struct local_client *client; | ||||
|  | ||||
|     DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid)); | ||||
|  | ||||
|     /* Create a local_client and return it */ | ||||
|     client = malloc(sizeof(struct local_client)); | ||||
|     if (!client) | ||||
|     { | ||||
| 	DEBUGLOG("malloc failed\n"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     memset(client, 0, sizeof(struct local_client)); | ||||
|     client->fd = fd; | ||||
|     client->type = CLUSTER_DATA_SOCK; | ||||
|     client->callback = read_from_tcpsock; | ||||
|     if (new_client) | ||||
| 	*new_client = client; | ||||
|  | ||||
|     /* Add to our list of node sockets */ | ||||
|     if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|     { | ||||
| 	DEBUGLOG("alloc_client mangling CSID for second connection\n"); | ||||
| 	/* This is a duplicate connection but we can't close it because | ||||
| 	   the other end may already have started sending. | ||||
| 	   So, we mangle the IP address and keep it, all sending will | ||||
| 	   go out of the main FD | ||||
| 	*/ | ||||
| 	csid[0] ^= 0x80; | ||||
| 	client->bits.net.flags = 1; /* indicate mangled CSID */ | ||||
|  | ||||
|         /* If it still exists then kill the connection as we should only | ||||
|            ever have one incoming connection from each node */ | ||||
|         if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|         { | ||||
| 	    DEBUGLOG("Multiple incoming connections from node\n"); | ||||
|             syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]); | ||||
|  | ||||
| 	    free(client); | ||||
|             errno = ECONNREFUSED; | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|     dm_hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int get_main_gulm_cluster_fd() | ||||
| { | ||||
|     return listen_fd; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Read on main comms (listen) socket, accept it */ | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, | ||||
| 			struct local_client **new_client) | ||||
| { | ||||
|     int newfd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t addrlen = sizeof(addr); | ||||
|     int status; | ||||
|     char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback\n"); | ||||
|     *new_client = NULL; | ||||
|     newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen); | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno); | ||||
|     if (!newfd) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "error in accept: %m"); | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; /* Don't return an error or clvmd will close the listening FD */ | ||||
|     } | ||||
|  | ||||
|     /* Check that the client is a member of the cluster | ||||
|        and reject if not. | ||||
|     */ | ||||
|     if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Got connect from non-cluster node %s\n", | ||||
| 	       print_csid((char *)&addr.sin6_addr)); | ||||
| 	DEBUGLOG("Got connect from non-cluster node %s\n", | ||||
| 		 print_csid((char *)&addr.sin6_addr)); | ||||
| 	close(newfd); | ||||
|  | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status); | ||||
| 	close(newfd); | ||||
| 	/* See above... */ | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|     DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client); | ||||
|     return newfd; | ||||
| } | ||||
|  | ||||
| /* Try to get at least 'len' bytes from the socket */ | ||||
| static int really_read(int fd, char *buf, int len) | ||||
| { | ||||
| 	int got, offset; | ||||
|  | ||||
| 	got = offset = 0; | ||||
|  | ||||
| 	do { | ||||
| 		got = read(fd, buf+offset, len-offset); | ||||
| 		DEBUGLOG("really_read. got %d bytes\n", got); | ||||
| 		offset += got; | ||||
| 	} while (got > 0 && offset < len); | ||||
|  | ||||
| 	if (got < 0) | ||||
| 		return got; | ||||
| 	else | ||||
| 		return offset; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t slen = sizeof(addr); | ||||
|     struct clvm_header *header = (struct clvm_header *)buf; | ||||
|     int status; | ||||
|     uint32_t arglen; | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock fd %d\n", client->fd); | ||||
|     *new_client = NULL; | ||||
|  | ||||
|     /* Get "csid" */ | ||||
|     getpeername(client->fd, (struct sockaddr *)&addr, &slen); | ||||
|     memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     /* Read just the header first, then get the rest if there is any. | ||||
|      * Stream sockets, sigh. | ||||
|      */ | ||||
|     status = really_read(client->fd, buf, sizeof(struct clvm_header)); | ||||
|     if (status > 0) | ||||
|     { | ||||
| 	    int status2; | ||||
|  | ||||
| 	    arglen = ntohl(header->arglen); | ||||
|  | ||||
| 	    /* Get the rest */ | ||||
| 	    if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE) | ||||
| 	    { | ||||
| 		    status2 = really_read(client->fd, buf+status, arglen); | ||||
| 		    if (status2 > 0) | ||||
| 			    status += status2; | ||||
| 		    else | ||||
| 			    status = status2; | ||||
| 	    } | ||||
|     } | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno); | ||||
|  | ||||
|     /* Remove it from the hash table if there's an error, clvmd will | ||||
|        remove the socket from its lists and free the client struct */ | ||||
|     if (status == 0 || | ||||
| 	(status < 0 && errno != EAGAIN && errno != EINTR)) | ||||
|     { | ||||
| 	char remcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	memcpy(remcsid, csid, GULM_MAX_CSID_LEN); | ||||
| 	close(client->fd); | ||||
|  | ||||
| 	/* If the csid was mangled, then make sure we remove the right entry */ | ||||
| 	if (client->bits.net.flags) | ||||
| 	    remcsid[0] ^= 0x80; | ||||
| 	dm_hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN); | ||||
|  | ||||
| 	/* Tell cluster manager layer */ | ||||
| 	add_down_node(remcsid); | ||||
|     } | ||||
|     else { | ||||
| 	    gulm_add_up_node(csid); | ||||
| 	    /* Send it back to clvmd */ | ||||
| 	    process_message(client, buf, status, csid); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| int gulm_connect_csid(char *csid, struct local_client **newclient) | ||||
| { | ||||
|     int fd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     int status; | ||||
|     int one = 1; | ||||
|  | ||||
|     DEBUGLOG("Connecting socket\n"); | ||||
|     fd = socket(PF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (fd < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Unable to create new socket: %m"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN); | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     DEBUGLOG("Connecting socket %d\n", fd); | ||||
|     if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) | ||||
|     { | ||||
| 	/* "Connection refused" is "normal" because clvmd may not yet be running | ||||
| 	 * on that node. | ||||
| 	 */ | ||||
| 	if (errno != ECONNREFUSED) | ||||
| 	{ | ||||
| 	    syslog(LOG_ERR, "Unable to connect to remote node: %m"); | ||||
| 	} | ||||
| 	DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno)); | ||||
| 	close(fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(fd, F_SETFD, 1); | ||||
|     setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|  | ||||
|     status = alloc_client(fd, csid, newclient); | ||||
|     if (status) | ||||
| 	close(fd); | ||||
|     else | ||||
| 	add_client(*newclient); | ||||
|  | ||||
|     /* If we can connect to it, it must be running a clvmd */ | ||||
|     gulm_add_up_node(csid); | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* Send a message to a known CSID */ | ||||
| static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const char *errtext) | ||||
| { | ||||
|     int status; | ||||
|     struct local_client *client; | ||||
|     char ourcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
|     assert(csid); | ||||
|  | ||||
|     DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen); | ||||
|  | ||||
|     /* Don't connect to ourself */ | ||||
|     get_our_gulm_csid(ourcsid); | ||||
|     if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0) | ||||
| 	return msglen; | ||||
|  | ||||
|     client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!client) | ||||
|     { | ||||
| 	status = gulm_connect_csid(csid, &client); | ||||
| 	if (status) | ||||
| 	    return -1; | ||||
|     } | ||||
|     DEBUGLOG("tcp_send_message, fd = %d\n", client->fd); | ||||
|  | ||||
|     return write(client->fd, buf, msglen); | ||||
| } | ||||
|  | ||||
|  | ||||
| int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext) | ||||
| { | ||||
|     int status=0; | ||||
|  | ||||
|     DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen); | ||||
|  | ||||
|     /* If csid is NULL then send to all known (not just connected) nodes */ | ||||
|     if (!csid) | ||||
|     { | ||||
| 	void *context = NULL; | ||||
| 	char loop_csid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	/* Loop round all gulm-known nodes */ | ||||
| 	while (get_next_node_csid(&context, loop_csid)) | ||||
| 	{ | ||||
| 	    status = tcp_send_message(buf, msglen, loop_csid, errtext); | ||||
| 	    if (status == 0 || | ||||
| 		(status < 0 && (errno == EAGAIN || errno == EINTR))) | ||||
| 		break; | ||||
| 	} | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  | ||||
| 	status = tcp_send_message(buf, msglen, csid, errtext); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* To get our own IP address we get the locally bound address of the | ||||
|    socket that's talking to GULM in the assumption(eek) that it will | ||||
|    be on the "right" network in a multi-homed system */ | ||||
| static int get_our_ip_address(char *addr, int *family) | ||||
| { | ||||
| 	struct utsname info; | ||||
|  | ||||
| 	uname(&info); | ||||
| 	get_ip_address(info.nodename, addr); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Public version of above for those that don't care what protocol | ||||
|    we're using */ | ||||
| void get_our_gulm_csid(char *csid) | ||||
| { | ||||
|     static char our_csid[GULM_MAX_CSID_LEN]; | ||||
|     static int got_csid = 0; | ||||
|  | ||||
|     if (!got_csid) | ||||
|     { | ||||
| 	int family; | ||||
|  | ||||
| 	memset(our_csid, 0, sizeof(our_csid)); | ||||
| 	if (get_our_ip_address(our_csid, &family)) | ||||
| 	{ | ||||
| 	    got_csid = 1; | ||||
| 	} | ||||
|     } | ||||
|     memcpy(csid, our_csid, GULM_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6) | ||||
| { | ||||
|    ip6->s6_addr32[0] = 0; | ||||
|    ip6->s6_addr32[1] = 0; | ||||
|    ip6->s6_addr32[2] = htonl(0xffff); | ||||
|    ip6->s6_addr32[3] = ip4->s_addr; | ||||
| } | ||||
|  | ||||
| /* Get someone else's IP address from DNS */ | ||||
| int get_ip_address(char *node, char *addr) | ||||
| { | ||||
|     struct hostent *he; | ||||
|  | ||||
|     memset(addr, 0, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     // TODO: what do we do about multi-homed hosts ??? | ||||
|     // CCSs ip_interfaces solved this but some bugger removed it. | ||||
|  | ||||
|     /* Try IPv6 first. The man page for gethostbyname implies that | ||||
|        it will lookup ip6 & ip4 names, but it seems not to */ | ||||
|     he = gethostbyname2(node, AF_INET6); | ||||
|     if (he) | ||||
|     { | ||||
| 	memcpy(addr, he->h_addr_list[0], | ||||
| 	       he->h_length); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	he = gethostbyname2(node, AF_INET); | ||||
| 	if (!he) | ||||
| 	    return -1; | ||||
| 	map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| char *print_csid(char *csid) | ||||
| { | ||||
|     static char buf[128]; | ||||
|     int *icsid = (int *)csid; | ||||
|  | ||||
|     sprintf(buf, "[%x.%x.%x.%x]", | ||||
| 	    icsid[0],icsid[1],icsid[2],icsid[3]); | ||||
|  | ||||
|     return buf; | ||||
| } | ||||
							
								
								
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #define GULM_MAX_CLUSTER_MESSAGE 1600 | ||||
| #define GULM_MAX_CSID_LEN sizeof(struct in6_addr) | ||||
| #define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128 | ||||
|  | ||||
| extern int init_comms(unsigned short); | ||||
| extern char *print_csid(char *); | ||||
| int get_main_gulm_cluster_fd(void); | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client); | ||||
| int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext); | ||||
| void get_our_gulm_csid(char *csid); | ||||
| int gulm_connect_csid(char *csid, struct local_client **newclient); | ||||
							
								
								
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/cmirrord/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| cmirrord | ||||
| @@ -1,43 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CPG_LIBS = @CPG_LIBS@ | ||||
| CPG_CFLAGS = @CPG_CFLAGS@ | ||||
|  | ||||
| SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c | ||||
|  | ||||
| TARGETS = cmirrord | ||||
|  | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) | ||||
| CFLOW_TARGET := $(TARGETS) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LMLIBS += $(CPG_LIBS) | ||||
| CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS) | ||||
| LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) | ||||
|  | ||||
| cmirrord: $(OBJECTS) | ||||
| 	$(SHOW) "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ | ||||
| 		$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS) | ||||
|  | ||||
| install_cluster: $(TARGETS) | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F) | ||||
|  | ||||
| install: install_cluster | ||||
| @@ -1,293 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <getopt.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| static volatile sig_atomic_t exit_now = 0; | ||||
| /* FIXME Review signal handling.  Should be volatile sig_atomic_t */ | ||||
| static sigset_t signal_mask; | ||||
| static volatile sig_atomic_t signal_received; | ||||
|  | ||||
| static void process_signals(void); | ||||
| static void daemonize(void); | ||||
| static void init_all(void); | ||||
| static void cleanup_all(void); | ||||
|  | ||||
| static void usage (FILE *dest) | ||||
| { | ||||
| 	fprintf (dest, "Usage: cmirrord [options]\n" | ||||
| 		 "   -f, --foreground    stay in the foreground, log to the terminal\n" | ||||
| 		 "   -h, --help          print this help\n"); | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	int foreground_mode = 0; | ||||
| 	static const struct option _long_options[] = { | ||||
| 		{ "foreground", no_argument, NULL, 'f' }, | ||||
| 		{ "help"      , no_argument, NULL, 'h' }, | ||||
| 		{ 0, 0, 0, 0 } | ||||
| 	}; | ||||
| 	int opt; | ||||
|  | ||||
| 	while ((opt = getopt_long (argc, argv, "fh", _long_options, NULL)) != -1) { | ||||
| 		switch (opt) { | ||||
| 		case 'f': | ||||
| 			foreground_mode = 1; | ||||
| 			break; | ||||
| 		case 'h': | ||||
| 			usage (stdout); | ||||
| 			exit (0); | ||||
| 		default: | ||||
| 			usage (stderr); | ||||
| 			exit (2); | ||||
| 		} | ||||
| 	} | ||||
| 	if (optind < argc) { | ||||
| 		usage (stderr); | ||||
| 		exit (2); | ||||
| 	} | ||||
|  | ||||
| 	if (!foreground_mode) | ||||
| 		daemonize(); | ||||
|  | ||||
| 	init_all(); | ||||
|  | ||||
| 	/* Parent can now exit, we're ready to handle requests */ | ||||
| 	if (!foreground_mode) | ||||
| 		kill(getppid(), SIGTERM); | ||||
|  | ||||
| 	LOG_PRINT("Starting cmirrord:"); | ||||
| 	LOG_PRINT(" Built: "__DATE__" "__TIME__"\n"); | ||||
| 	LOG_DBG(" Compiled with debugging."); | ||||
|  | ||||
| 	while (!exit_now) { | ||||
| 		links_monitor(); | ||||
|  | ||||
| 		links_issue_callbacks(); | ||||
|  | ||||
| 		process_signals(); | ||||
| 	} | ||||
| 	exit(EXIT_SUCCESS); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * parent_exit_handler: exit the parent | ||||
|  * @sig: the signal | ||||
|  * | ||||
|  */ | ||||
| static void parent_exit_handler(int sig __attribute__((unused))) | ||||
| { | ||||
| 	exit_now = 1; | ||||
| } | ||||
|  | ||||
| static void sig_handler(int sig) | ||||
| { | ||||
| 	/* FIXME Races - don't touch signal_mask here. */ | ||||
| 	sigaddset(&signal_mask, sig); | ||||
| 	signal_received = 1; | ||||
| } | ||||
|  | ||||
| static void process_signal(int sig){ | ||||
| 	int r = 0; | ||||
|  | ||||
| 	switch(sig) { | ||||
| 	case SIGINT: | ||||
| 	case SIGQUIT: | ||||
| 	case SIGTERM: | ||||
| 	case SIGHUP: | ||||
| 		r += log_status(); | ||||
| 		break; | ||||
| 	case SIGUSR1: | ||||
| 	case SIGUSR2: | ||||
| 		log_debug(); | ||||
| 		/*local_debug();*/ | ||||
| 		cluster_debug(); | ||||
| 		return; | ||||
| 	default: | ||||
| 		LOG_PRINT("Unknown signal received... ignoring"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!r) { | ||||
| 		LOG_DBG("No current cluster logs... safe to exit."); | ||||
| 		cleanup_all(); | ||||
| 		exit(EXIT_SUCCESS); | ||||
| 	} | ||||
|  | ||||
| 	LOG_ERROR("Cluster logs exist.  Refusing to exit."); | ||||
| } | ||||
|  | ||||
| static void process_signals(void) | ||||
| { | ||||
| 	int x; | ||||
|  | ||||
| 	if (!signal_received) | ||||
| 		return; | ||||
|  | ||||
| 	signal_received = 0; | ||||
|  | ||||
| 	for (x = 1; x < _NSIG; x++) { | ||||
| 		if (sigismember(&signal_mask, x)) { | ||||
| 			sigdelset(&signal_mask, x); | ||||
| 			process_signal(x); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void remove_lockfile(void) | ||||
| { | ||||
| 	if (unlink(CMIRRORD_PIDFILE)) | ||||
| 		LOG_ERROR("Unable to remove \"" CMIRRORD_PIDFILE "\" %s", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemonize | ||||
|  * | ||||
|  * Performs the steps necessary to become a daemon. | ||||
|  */ | ||||
| static void daemonize(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	int status; | ||||
| 	int devnull; | ||||
|  | ||||
| 	if ((devnull = open("/dev/null", O_RDWR)) == -1) { | ||||
| 		LOG_ERROR("Can't open /dev/null: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	signal(SIGTERM, &parent_exit_handler); | ||||
|  | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) { | ||||
| 		LOG_ERROR("Unable to fork()"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if (pid) { | ||||
| 		/* Parent waits here for child to get going */ | ||||
| 		while (!waitpid(pid, &status, WNOHANG) && !exit_now); | ||||
| 		if (exit_now) | ||||
| 			exit(EXIT_SUCCESS); | ||||
|  | ||||
| 		switch (WEXITSTATUS(status)) { | ||||
| 		case EXIT_LOCKFILE: | ||||
| 			LOG_ERROR("Failed to create lockfile"); | ||||
| 			LOG_ERROR("Process already running?"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SOCKET: | ||||
| 			LOG_ERROR("Unable to create netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_BIND: | ||||
| 			LOG_ERROR("Unable to bind to netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SETSOCKOPT: | ||||
| 			LOG_ERROR("Unable to setsockopt on netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_CLUSTER_CKPT_INIT: | ||||
| 			LOG_ERROR("Unable to initialize checkpoint service"); | ||||
| 			LOG_ERROR("Has the cluster infrastructure been started?"); | ||||
| 			break; | ||||
| 		case EXIT_FAILURE: | ||||
| 			LOG_ERROR("Failed to start: Generic error"); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Failed to start: Unknown error"); | ||||
| 			break; | ||||
| 		} | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	setsid(); | ||||
| 	if (chdir("/")) { | ||||
| 		LOG_ERROR("Failed to chdir /: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	umask(0); | ||||
|  | ||||
| 	if (close(0) || close(1) || close(2)) { | ||||
| 		LOG_ERROR("Failed to close terminal FDs"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if ((dup2(devnull, 0) < 0) || /* reopen stdin */ | ||||
| 	    (dup2(devnull, 1) < 0) || /* reopen stdout */ | ||||
| 	    (dup2(devnull, 2) < 0))   /* reopen stderr */ | ||||
| 		exit(EXIT_FAILURE); | ||||
|  | ||||
| 	if ((devnull > STDERR_FILENO) && close(devnull)) { | ||||
| 		LOG_ERROR("Failed to close descriptor %d: %s", | ||||
| 			  devnull, strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON); | ||||
| 	/* coverity[leaked_handle] devnull cannot leak here */ | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_all | ||||
|  * | ||||
|  * Initialize modules.  Exit on failure. | ||||
|  */ | ||||
| static void init_all(void) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG); | ||||
| 	if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0) | ||||
| 		exit(EXIT_LOCKFILE); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	atexit(remove_lockfile); | ||||
|  | ||||
| 	/* FIXME Replace with sigaction. (deprecated) */ | ||||
| 	signal(SIGINT, &sig_handler); | ||||
| 	signal(SIGQUIT, &sig_handler); | ||||
| 	signal(SIGTERM, &sig_handler); | ||||
| 	signal(SIGHUP, &sig_handler); | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	signal(SIGUSR1, &sig_handler); | ||||
| 	signal(SIGUSR2, &sig_handler); | ||||
| 	sigemptyset(&signal_mask); | ||||
| 	signal_received = 0; | ||||
|  | ||||
| 	if ((r = init_local()) || | ||||
| 	    (r = init_cluster())) { | ||||
| 		exit(r); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_all | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| static void cleanup_all(void) | ||||
| { | ||||
| 	cleanup_local(); | ||||
| 	cleanup_cluster(); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_CLUSTER_H | ||||
| #define _LVM_CLOG_CLUSTER_H | ||||
|  | ||||
| #include "libdm/libdevmapper.h" | ||||
| #include "libdm/misc/dm-log-userspace.h" | ||||
|  | ||||
| #define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */ | ||||
| #define DM_ULOG_CHECKPOINT_READY 21 | ||||
| #define DM_ULOG_MEMBER_JOIN      22 | ||||
|  | ||||
| /* | ||||
|  * There is other information in addition to what can | ||||
|  * be found in the dm_ulog_request structure that we | ||||
|  * need for processing.  'clog_request' is the wrapping | ||||
|  * structure we use to make the additional fields | ||||
|  * available. | ||||
|  */ | ||||
| struct clog_request { | ||||
| 	/* | ||||
| 	 * If we don't use a union, the structure size will | ||||
| 	 * vary between 32-bit and 64-bit machines.  So, we | ||||
| 	 * pack two 64-bit version numbers in there to force | ||||
| 	 * the size of the structure to be the same. | ||||
| 	 * | ||||
| 	 * The two version numbers also help us with endian | ||||
| 	 * issues.  The first is always little endian, while | ||||
| 	 * the second is in native format of the sending | ||||
| 	 * machine.  If the two are equal, there is no need | ||||
| 	 * to do endian conversions. | ||||
| 	 */ | ||||
| 	union version_u { | ||||
| 		uint64_t version[2]; /* LE version and native version */ | ||||
| 		struct dm_list list; | ||||
| 	} u; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'originator' is the machine from which the requests | ||||
| 	 * was made. | ||||
| 	 */ | ||||
| 	uint32_t originator; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'pit_server' is the "point-in-time" server for the | ||||
| 	 * request.  (I.e.  The machine that was the server at | ||||
| 	 * the time the request was issued - only important during | ||||
| 	 * startup. | ||||
| 	 */ | ||||
| 	uint32_t pit_server; | ||||
|  | ||||
| 	/* | ||||
| 	 * The request from the kernel that is being processed | ||||
| 	 */ | ||||
| 	struct dm_ulog_request u_rq; | ||||
| }; | ||||
|  | ||||
| int init_cluster(void); | ||||
| void cleanup_cluster(void); | ||||
| void cluster_debug(void); | ||||
|  | ||||
| int create_cluster_cpg(char *uuid, uint64_t luid); | ||||
| int destroy_cluster_cpg(char *uuid); | ||||
|  | ||||
| int cluster_send(struct clog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_CLUSTER_H */ | ||||
| @@ -1,33 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMMON_H | ||||
| #define _LVM_CLOG_COMMON_H | ||||
|  | ||||
| /* | ||||
|  * If there are problems when forking off to become a daemon, | ||||
|  * the child will exist with one of these codes.  This allows | ||||
|  * the parent to know the reason for the failure and print it | ||||
|  * to the launching terminal. | ||||
|  * | ||||
|  * #define EXIT_SUCCESS 0 (from stdlib.h) | ||||
|  * #define EXIT_FAILURE 1 (from stdlib.h) | ||||
|  */ | ||||
| #define EXIT_LOCKFILE              2 | ||||
| #define EXIT_KERNEL_SOCKET         3 /* Failed netlink socket create */ | ||||
| #define EXIT_KERNEL_BIND           4 | ||||
| #define EXIT_KERNEL_SETSOCKOPT     5 | ||||
| #define EXIT_CLUSTER_CKPT_INIT     6 /* Failed to init checkpoint */ | ||||
| #define EXIT_QUEUE_NOMEM           7 | ||||
|  | ||||
| #define DM_ULOG_REQUEST_SIZE 1024 | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMMON_H */ | ||||
| @@ -1,210 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "cluster.h" | ||||
| #include "compat.h" | ||||
| #include "lib/mm/xlate.h" | ||||
|  | ||||
| #include <errno.h> | ||||
|  | ||||
| /* | ||||
|  * Older versions of the log daemon communicate with different | ||||
|  * versions of the inter-machine communication structure, which | ||||
|  * varies in size and fields.  The older versions append the | ||||
|  * standard upstream version of the structure to every request. | ||||
|  * COMPAT_OFFSET is where the upstream structure starts. | ||||
|  */ | ||||
| #define COMPAT_OFFSET 256 | ||||
|  | ||||
| static void v5_data_endian_switch(struct clog_request *rq, int to_network __attribute__((unused))) | ||||
| { | ||||
| 	int i, end; | ||||
| 	int64_t *pi64; | ||||
| 	uint64_t *pu64; | ||||
| 	uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE; | ||||
|  | ||||
| 	if (rq->u_rq.request_type & DM_ULOG_RESPONSE) { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid response type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 			/* No outbound data */ | ||||
| 			break; | ||||
|  | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			pu64 = ((uint64_t *)rq->u_rq.data) + 1; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			return; | ||||
| 		} | ||||
| 	} else { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid request type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 			/* No incoming data */ | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 			end = rq->u_rq.data_size/sizeof(uint64_t); | ||||
|  | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			for (i = 0; i < end; i++) | ||||
| 				pu64[i] = xlate64(pu64[i]); | ||||
| 			break; | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			pi64 = ((int64_t *)rq->u_rq.data) + 1; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			exit(EXIT_FAILURE); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int v5_endian_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 1); | ||||
|  | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	/* FIXME: Remove this safety check */ | ||||
| 	if (rq->u.version[0] != xlate64(rq->u.version[1])) { | ||||
| 		LOG_ERROR("Programmer error:  version[0] must be LE"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Are we already running in the endian mode we send | ||||
| 	 * over the wire? | ||||
| 	 */ | ||||
| 	if (rq->u.version[0] == rq->u.version[1]) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = v5_endian_to_network(rq); | ||||
| 	if (r < 0) | ||||
| 		return r; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int v5_endian_from_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 0); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_from_network(void *data, size_t data_len) | ||||
| { | ||||
| 	uint64_t *vp = data; | ||||
| 	uint64_t version = xlate64(vp[0]); | ||||
| 	struct clog_request *rq = data; | ||||
|  | ||||
| 	switch (version) { | ||||
| 	case 5: /* Upstream */ | ||||
| 		if (version == vp[0]) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case 4: /* RHEL 5.[45] */ | ||||
| 	case 3: /* RHEL 5.3 */ | ||||
| 	case 2: /* RHEL 5.2 */ | ||||
| 		/* FIXME: still need to account for payload */ | ||||
| 		if (data_len < (COMPAT_OFFSET + sizeof(*rq))) | ||||
| 			return -ENOSPC; | ||||
|  | ||||
| 		rq = (struct clog_request *)((char *)data + COMPAT_OFFSET); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unable to process cluster message: " | ||||
| 			  "Incompatible version"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	v5_endian_from_network(rq); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMPAT_H | ||||
| #define _LVM_CLOG_COMPAT_H | ||||
|  | ||||
| /* | ||||
|  * The intermachine communication structure version are: | ||||
|  *	0: Unused | ||||
|  *	1: Never in the wild | ||||
|  *	2: RHEL 5.2 | ||||
|  *	3: RHEL 5.3 | ||||
|  *	4: RHEL 5.4, RHEL 5.5 | ||||
|  *	5: RHEL 6, Current Upstream Format | ||||
|  */ | ||||
| #define CLOG_TFR_VERSION 5 | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq); | ||||
| int clog_request_from_network(void *data, size_t data_len); | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMPAT_H */ | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,36 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_FUNCTIONS_H | ||||
| #define _LVM_CLOG_FUNCTIONS_H | ||||
|  | ||||
| #include "libdm/libdevmapper.h" | ||||
| #include "libdm/dm-tools/util.h" | ||||
| #include "libdm/misc/dm-log-userspace.h" | ||||
| #include "cluster.h" | ||||
|  | ||||
| #define LOG_RESUMED   1 | ||||
| #define LOG_SUSPENDED 2 | ||||
|  | ||||
| int local_resume(struct dm_ulog_request *rq); | ||||
| int cluster_postsuspend(char *, uint64_t); | ||||
|  | ||||
| int do_request(struct clog_request *rq, int server); | ||||
| int push_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char **buf, uint32_t debug_who); | ||||
| int pull_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char *buf, int size); | ||||
|  | ||||
| int log_get_state(struct dm_ulog_request *rq); | ||||
| int log_status(void); | ||||
| void log_debug(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_FUNCTIONS_H */ | ||||
| @@ -1,151 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "link_mon.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <poll.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| struct link_callback { | ||||
| 	int fd; | ||||
| 	const char *name; | ||||
| 	void *data; | ||||
| 	int (*callback)(void *data); | ||||
|  | ||||
| 	struct link_callback *next; | ||||
| }; | ||||
|  | ||||
| static unsigned used_pfds = 0; | ||||
| static unsigned free_pfds = 0; | ||||
| static struct pollfd *pfds = NULL; | ||||
| static struct link_callback *callbacks = NULL; | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			LOG_ERROR("links_register: Duplicate file descriptor"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lc = malloc(sizeof(*lc)); | ||||
| 	if (!lc) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	lc->fd = fd; | ||||
| 	lc->name = name; | ||||
| 	lc->data = data; | ||||
| 	lc->callback = callback; | ||||
|  | ||||
| 	if (!free_pfds) { | ||||
| 		struct pollfd *tmp; | ||||
| 		tmp = realloc(pfds, sizeof(struct pollfd) * ((used_pfds*2) + 1)); | ||||
| 		if (!tmp) { | ||||
| 			free(lc); | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
|  | ||||
| 		pfds = tmp; | ||||
| 		free_pfds = used_pfds + 1; | ||||
| 	} | ||||
|  | ||||
| 	free_pfds--; | ||||
| 	pfds[used_pfds].fd = fd; | ||||
| 	pfds[used_pfds].events = POLLIN; | ||||
| 	pfds[used_pfds].revents = 0; | ||||
| 	used_pfds++; | ||||
|  | ||||
| 	lc->next = callbacks; | ||||
| 	callbacks = lc; | ||||
| 	LOG_DBG("Adding %s/%d", lc->name, lc->fd); | ||||
| 	LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 		used_pfds, free_pfds); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_unregister(int fd) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *p, *c; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			/* entire struct is copied (overwritten) */ | ||||
| 			pfds[i] = pfds[used_pfds - 1]; | ||||
| 			used_pfds--; | ||||
| 			free_pfds++; | ||||
| 		} | ||||
|  | ||||
| 	for (p = NULL, c = callbacks; c; p = c, c = c->next) | ||||
| 		if (fd == c->fd) { | ||||
| 			LOG_DBG("Freeing up %s/%d", c->name, c->fd); | ||||
| 			LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 				used_pfds, free_pfds); | ||||
| 			if (p) | ||||
| 				p->next = c->next; | ||||
| 			else | ||||
| 				callbacks = c->next; | ||||
| 			free(c); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_monitor(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	int r; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		pfds[i].revents = 0; | ||||
| 	} | ||||
|  | ||||
| 	r = poll(pfds, used_pfds, -1); | ||||
| 	if (r <= 0) | ||||
| 		return r; | ||||
|  | ||||
| 	r = 0; | ||||
| 	/* FIXME: handle POLLHUP */ | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) { | ||||
| 			LOG_DBG("Data ready on %d", pfds[i].fd); | ||||
|  | ||||
| 			/* FIXME: Add this back return 1;*/ | ||||
| 			r++; | ||||
| 		} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int links_issue_callbacks(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) | ||||
| 			for (lc = callbacks; lc; lc = lc->next) | ||||
| 				if (pfds[i].fd == lc->fd) { | ||||
| 					LOG_DBG("Issuing callback on %s/%d", | ||||
| 						lc->name, lc->fd); | ||||
| 					lc->callback(lc->data); | ||||
| 					break; | ||||
| 				} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LINK_MON_H | ||||
| #define _LVM_CLOG_LINK_MON_H | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data); | ||||
| int links_unregister(int fd); | ||||
| int links_monitor(void); | ||||
| int links_issue_callbacks(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LINK_MON_H */ | ||||
| @@ -1,424 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <sys/socket.h> | ||||
| #include <linux/connector.h> | ||||
| #include <linux/netlink.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #ifndef CN_IDX_DM | ||||
| /* Kernel 2.6.31 is required to run this code */ | ||||
| #define CN_IDX_DM                       0x7     /* Device Mapper */ | ||||
| #define CN_VAL_DM_USERSPACE_LOG         0x1 | ||||
| #endif | ||||
|  | ||||
| static int cn_fd = -1;  /* Connector (netlink) socket fd */ | ||||
| static char recv_buf[2048]; | ||||
| static char send_buf[2048]; | ||||
|  | ||||
|  | ||||
| /* FIXME: merge this function with kernel_send_helper */ | ||||
| static int kernel_ack(uint32_t seq, int error) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh = (struct nlmsghdr *)send_buf; | ||||
| 	struct cn_msg *msg = NLMSG_DATA(nlh); | ||||
|  | ||||
| 	if (error < 0) { | ||||
| 		LOG_ERROR("Programmer error: error codes must be positive"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh->nlmsg_seq = 0; | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg->len = 0; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = seq; | ||||
| 	msg->ack = error; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * kernel_recv | ||||
|  * @rq: the newly allocated request from kernel | ||||
|  * | ||||
|  * Read requests from the kernel and allocate space for the new request. | ||||
|  * If there is no request from the kernel, *rq is NULL. | ||||
|  * | ||||
|  * This function is not thread safe due to returned stack pointer.  In fact, | ||||
|  * the returned pointer must not be in-use when this function is called again. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on error | ||||
|  */ | ||||
| static int kernel_recv(struct clog_request **rq) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	ssize_t len; | ||||
| 	char *foo; | ||||
| 	struct cn_msg *msg; | ||||
| 	struct dm_ulog_request *u_rq; | ||||
| 	struct nlmsghdr *nlmsg_h; | ||||
|  | ||||
| 	*rq = NULL; | ||||
| 	memset(recv_buf, 0, sizeof(recv_buf)); | ||||
|  | ||||
| 	len = recv(cn_fd, recv_buf, sizeof(recv_buf), 0); | ||||
| 	if (len < 0) { | ||||
| 		LOG_ERROR("Failed to recv message from kernel"); | ||||
| 		r = -errno; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	nlmsg_h = (struct nlmsghdr *)recv_buf; | ||||
| 	switch (nlmsg_h->nlmsg_type) { | ||||
| 	case NLMSG_ERROR: | ||||
| 		LOG_ERROR("Unable to recv message from kernel: NLMSG_ERROR"); | ||||
| 		r = -EBADE; | ||||
| 		goto fail; | ||||
| 	case NLMSG_DONE: | ||||
| 		msg = (struct cn_msg *)NLMSG_DATA((struct nlmsghdr *)recv_buf); | ||||
| 		len -= (ssize_t)sizeof(struct nlmsghdr); | ||||
|  | ||||
| 		if (len < (ssize_t)sizeof(struct cn_msg)) { | ||||
| 			LOG_ERROR("Incomplete request from kernel received"); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (msg->len > DM_ULOG_REQUEST_SIZE) { | ||||
| 			LOG_ERROR("Not enough space to receive kernel request (%d/%d)", | ||||
| 				  msg->len, DM_ULOG_REQUEST_SIZE); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (!msg->len) | ||||
| 			LOG_ERROR("Zero length message received"); | ||||
|  | ||||
| 		len -= (ssize_t)sizeof(struct cn_msg); | ||||
|  | ||||
| 		if (len < msg->len) | ||||
| 			LOG_ERROR("len = %zd, msg->len = %" PRIu16, len, msg->len); | ||||
|  | ||||
| 		msg->data[msg->len] = '\0'; /* Cleaner way to ensure this? */ | ||||
| 		u_rq = (struct dm_ulog_request *)msg->data; | ||||
|  | ||||
| 		if (!u_rq->request_type) { | ||||
| 			LOG_DBG("Bad transmission, requesting resend [%u]", | ||||
| 				msg->seq); | ||||
| 			r = -EAGAIN; | ||||
|  | ||||
| 			if (kernel_ack(msg->seq, EAGAIN)) { | ||||
| 				LOG_ERROR("Failed to NACK kernel transmission [%u]", | ||||
| 					  msg->seq); | ||||
| 				r = -EBADE; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Now we've got sizeof(struct cn_msg) + sizeof(struct nlmsghdr) | ||||
| 		 * worth of space that precede the request structure from the | ||||
| 		 * kernel.  Since that space isn't going to be used again, we | ||||
| 		 * can take it for our purposes; rather than allocating a whole | ||||
| 		 * new structure and doing a memcpy. | ||||
| 		 * | ||||
| 		 * We should really make sure 'clog_request' doesn't grow | ||||
| 		 * beyond what is available to us, but we need only check it | ||||
| 		 * once... perhaps at compile time? | ||||
| 		 */ | ||||
| 		foo = (char *)u_rq; | ||||
| 		foo -= (sizeof(struct clog_request) - sizeof(struct dm_ulog_request)); | ||||
| 		*rq = (struct clog_request *) foo; | ||||
|  | ||||
| 		/* Clear the wrapper container fields */ | ||||
| 		memset(*rq, 0, (size_t)((char *)u_rq - (char *)(*rq))); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unknown nlmsg_type"); | ||||
| 		r = -EBADE; | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	if (r) | ||||
| 		*rq = NULL; | ||||
|  | ||||
| 	return (r == -EAGAIN) ? 0 : r; | ||||
| } | ||||
|  | ||||
| static int kernel_send_helper(void *data, uint16_t out_size) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh; | ||||
| 	struct cn_msg *msg; | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh = (struct nlmsghdr *)send_buf; | ||||
| 	nlh->nlmsg_seq = 0;  /* FIXME: Is this used? */ | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(out_size + sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg = NLMSG_DATA(nlh); | ||||
| 	memcpy(msg->data, data, out_size); | ||||
| 	msg->len = out_size; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = 0; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(out_size + sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * do_local_work | ||||
|  * | ||||
|  * Any processing errors are placed in the 'rq' | ||||
|  * structure to be reported back to the kernel. | ||||
|  * It may be pointless for this function to | ||||
|  * return an int. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| static int do_local_work(void *data __attribute__((unused))) | ||||
| { | ||||
| 	int r; | ||||
| 	struct clog_request *rq; | ||||
| 	struct dm_ulog_request *u_rq = NULL; | ||||
|  | ||||
| 	r = kernel_recv(&rq); | ||||
| 	if (r) | ||||
| 		return r; | ||||
|  | ||||
| 	if (!rq) | ||||
| 		return 0; | ||||
|  | ||||
| 	u_rq = &rq->u_rq; | ||||
| 	LOG_DBG("[%s]  Request from kernel received: [%s/%u]", | ||||
| 		SHORT_UUID(u_rq->uuid), RQ_TYPE(u_rq->request_type), | ||||
| 		u_rq->seq); | ||||
| 	switch (u_rq->request_type) { | ||||
| 	case DM_ULOG_CTR: | ||||
| 	case DM_ULOG_DTR: | ||||
| 	case DM_ULOG_GET_REGION_SIZE: | ||||
| 	case DM_ULOG_IN_SYNC: | ||||
| 	case DM_ULOG_GET_SYNC_COUNT: | ||||
| 	case DM_ULOG_STATUS_TABLE: | ||||
| 	case DM_ULOG_PRESUSPEND: | ||||
| 		/* We do not specify ourselves as server here */ | ||||
| 		r = do_request(rq, 0); | ||||
| 		if (r) | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 		r = kernel_send(u_rq); | ||||
| 		if (r) | ||||
| 			LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 				  RQ_TYPE(u_rq->request_type)); | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_RESUME: | ||||
| 		/* | ||||
| 		 * Resume is a special case that requires a local | ||||
| 		 * component to join the CPG, and a cluster component | ||||
| 		 * to handle the request. | ||||
| 		 */ | ||||
| 		r = local_resume(u_rq); | ||||
| 		if (r) { | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 			r = kernel_send(u_rq); | ||||
| 			if (r) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* ELSE */ /* fall through */ | ||||
| 	case DM_ULOG_IS_CLEAN: | ||||
| 	case DM_ULOG_FLUSH: | ||||
| 	case DM_ULOG_MARK_REGION: | ||||
| 	case DM_ULOG_GET_RESYNC_WORK: | ||||
| 	case DM_ULOG_SET_REGION_SYNC: | ||||
| 	case DM_ULOG_STATUS_INFO: | ||||
| 	case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 	case DM_ULOG_POSTSUSPEND: | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			u_rq->data_size = 0; | ||||
| 			u_rq->error = r; | ||||
| 			if (kernel_send(u_rq)) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_CLEAR_REGION: | ||||
| 		r = kernel_ack(u_rq->seq, 0); | ||||
|  | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			/* | ||||
| 			 * FIXME: store error for delivery on flush | ||||
| 			 *        This would allow us to optimize MARK_REGION | ||||
| 			 *        too. | ||||
| 			 */ | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Invalid log request received (%u), ignoring.", | ||||
| 			  u_rq->request_type); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (r && !u_rq->error) | ||||
| 		u_rq->error = r; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * kernel_send | ||||
|  * @u_rq: result to pass back to kernel | ||||
|  * | ||||
|  * This function returns the u_rq structure | ||||
|  * (containing the results) to the kernel. | ||||
|  * It then frees the structure. | ||||
|  * | ||||
|  * WARNING: should the structure be freed if | ||||
|  * there is an error?  I vote 'yes'.  If the | ||||
|  * kernel doesn't get the response, it should | ||||
|  * resend the request. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| int kernel_send(struct dm_ulog_request *u_rq) | ||||
| { | ||||
| 	int r; | ||||
| 	uint16_t size; | ||||
|  | ||||
| 	if (!u_rq) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	size = (uint16_t)(sizeof(struct dm_ulog_request) + u_rq->data_size); | ||||
|  | ||||
| 	if (!u_rq->data_size && !u_rq->error) { | ||||
| 		/* An ACK is all that is needed */ | ||||
|  | ||||
| 		/* FIXME: add ACK code */ | ||||
| 	} else if (size > DM_ULOG_REQUEST_SIZE) { | ||||
| 		/* | ||||
| 		 * If we gotten here, we've already overrun | ||||
| 		 * our allotted space somewhere. | ||||
| 		 * | ||||
| 		 * We must do something, because the kernel | ||||
| 		 * is waiting for a response. | ||||
| 		 */ | ||||
| 		LOG_ERROR("Not enough space to respond to server"); | ||||
| 		u_rq->error = -ENOSPC; | ||||
| 		size = sizeof(struct dm_ulog_request); | ||||
| 	} | ||||
|  | ||||
| 	r = kernel_send_helper(u_rq, size); | ||||
| 	if (r) | ||||
| 		LOG_ERROR("Failed to send msg to kernel."); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_local | ||||
|  * | ||||
|  * Initialize kernel communication socket (netlink) | ||||
|  * | ||||
|  * Returns: 0 on success, values from common.h on failure | ||||
|  */ | ||||
| int init_local(void) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	unsigned opt; | ||||
| 	struct sockaddr_nl addr; | ||||
|  | ||||
| 	cn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||||
| 	if (cn_fd < 0) | ||||
| 		return EXIT_KERNEL_SOCKET; | ||||
|  | ||||
| 	/* memset to fix valgrind complaint */ | ||||
| 	memset(&addr, 0, sizeof(struct sockaddr_nl)); | ||||
|  | ||||
| 	addr.nl_family = AF_NETLINK; | ||||
| 	addr.nl_groups = CN_IDX_DM; | ||||
| 	addr.nl_pid = 0; | ||||
|  | ||||
| 	r = bind(cn_fd, (struct sockaddr *) &addr, sizeof(addr)); | ||||
| 	if (r < 0) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_BIND; | ||||
| 	} | ||||
|  | ||||
| 	opt = addr.nl_groups; | ||||
| 	r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt)); | ||||
| 	if (r) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_SETSOCKOPT; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	r = fcntl(cn_fd, F_SETFL, FNDELAY); | ||||
| 	*/ | ||||
|  | ||||
| 	links_register(cn_fd, "local", do_local_work, NULL); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_local | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| void cleanup_local(void) | ||||
| { | ||||
| 	links_unregister(cn_fd); | ||||
| 	if (cn_fd >= 0 && close(cn_fd)) | ||||
| 		LOG_ERROR("Failed to close socket: %s", | ||||
| 			  strerror(errno)); | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LOCAL_H | ||||
| #define _LVM_CLOG_LOCAL_H | ||||
|  | ||||
| int init_local(void); | ||||
| void cleanup_local(void); | ||||
|  | ||||
| int kernel_send(struct dm_ulog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOCAL_H */ | ||||
| @@ -1,57 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
|  | ||||
| const char * const __rq_types_off_by_one[] = { | ||||
| 	"DM_ULOG_CTR", | ||||
| 	"DM_ULOG_DTR", | ||||
| 	"DM_ULOG_PRESUSPEND", | ||||
| 	"DM_ULOG_POSTSUSPEND", | ||||
| 	"DM_ULOG_RESUME", | ||||
| 	"DM_ULOG_GET_REGION_SIZE", | ||||
| 	"DM_ULOG_IS_CLEAN", | ||||
| 	"DM_ULOG_IN_SYNC", | ||||
| 	"DM_ULOG_FLUSH", | ||||
| 	"DM_ULOG_MARK_REGION", | ||||
| 	"DM_ULOG_CLEAR_REGION", | ||||
| 	"DM_ULOG_GET_RESYNC_WORK", | ||||
| 	"DM_ULOG_SET_REGION_SYNC", | ||||
| 	"DM_ULOG_GET_SYNC_COUNT", | ||||
| 	"DM_ULOG_STATUS_INFO", | ||||
| 	"DM_ULOG_STATUS_TABLE", | ||||
| 	"DM_ULOG_IS_REMOTE_RECOVERING", | ||||
| 	NULL | ||||
| }; | ||||
|  | ||||
| int log_tabbing = 0; | ||||
| int log_is_open = 0; | ||||
|  | ||||
| /* | ||||
|  * Variables for various conditional logging | ||||
|  */ | ||||
| #ifdef MEMB | ||||
| int log_membership_change = 1; | ||||
| #else | ||||
| int log_membership_change = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef CKPT | ||||
| int log_checkpoint = 1; | ||||
| #else | ||||
| int log_checkpoint = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef RESEND | ||||
| int log_resend_requests = 1; | ||||
| #else | ||||
| int log_resend_requests = 0; | ||||
| #endif | ||||
| @@ -1,73 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CLOG_LOGGING_H | ||||
| #define _LVM_CLOG_LOGGING_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| /* SHORT_UUID - print last 8 chars of a string */ | ||||
| #define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x) | ||||
|  | ||||
| extern const char * const __rq_types_off_by_one[]; | ||||
| #define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1] | ||||
|  | ||||
| extern int log_tabbing; | ||||
| extern int log_is_open; | ||||
| extern int log_membership_change; | ||||
| extern int log_checkpoint; | ||||
| extern int log_resend_requests; | ||||
|  | ||||
| #define LOG_OPEN(ident, option, facility) do { \ | ||||
| 		openlog(ident, option, facility); \ | ||||
| 		log_is_open = 1;		  \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_CLOSE(void) do { \ | ||||
| 		log_is_open = 0; \ | ||||
| 		closelog();	 \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_OUTPUT(level, f, arg...) do {				\ | ||||
| 		int __i;						\ | ||||
| 		char __buffer[16];					\ | ||||
| 		FILE *fp = (level > LOG_NOTICE) ? stderr : stdout;	\ | ||||
| 		if (log_is_open) {					\ | ||||
| 			for (__i = 0; (__i < log_tabbing) && (__i < 15); __i++) \ | ||||
| 				__buffer[__i] = '\t';			\ | ||||
| 			__buffer[__i] = '\0';				\ | ||||
| 			syslog(level, "%s" f "\n", __buffer, ## arg);	\ | ||||
| 		} else {						\ | ||||
| 			for (__i = 0; __i < log_tabbing; __i++)		\ | ||||
| 				fprintf(fp, "\t");			\ | ||||
| 			fprintf(fp, f "\n", ## arg);			\ | ||||
| 		}							\ | ||||
| 	} while (0) | ||||
|  | ||||
|  | ||||
| #ifdef DEBUG | ||||
| #define LOG_DBG(f, arg...) LOG_OUTPUT(LOG_DEBUG, f, ## arg) | ||||
| #else /* DEBUG */ | ||||
| #define LOG_DBG(f, arg...) do {} while (0) | ||||
| #endif /* DEBUG */ | ||||
|  | ||||
| #define LOG_COND(__X, f, arg...) do {\ | ||||
| 		if (__X) { 	     \ | ||||
| 			LOG_OUTPUT(LOG_NOTICE, f, ## arg); \ | ||||
| 		} \ | ||||
| 	} while (0) | ||||
| #define LOG_PRINT(f, arg...) LOG_OUTPUT(LOG_NOTICE, f, ## arg) | ||||
| #define LOG_ERROR(f, arg...) LOG_OUTPUT(LOG_ERR, f, ## arg) | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOGGING_H */ | ||||
| @@ -1,4 +1,19 @@ | ||||
| init_fifos | ||||
| fini_fifos | ||||
| daemon_talk | ||||
| dm_event_get_version | ||||
| dm_event_handler_create | ||||
| dm_event_handler_destroy | ||||
| dm_event_handler_set_dso | ||||
| dm_event_handler_set_dev_name | ||||
| dm_event_handler_set_uuid | ||||
| dm_event_handler_set_major | ||||
| dm_event_handler_set_minor | ||||
| dm_event_handler_set_event_mask | ||||
| dm_event_handler_get_dso | ||||
| dm_event_handler_get_devname | ||||
| dm_event_handler_get_uuid | ||||
| dm_event_handler_get_major | ||||
| dm_event_handler_get_minor | ||||
| dm_event_handler_get_event_mask | ||||
| dm_event_register_handler | ||||
| dm_event_unregister_handler | ||||
| dm_event_get_registered_device | ||||
| dm_event_handler_set_timeout | ||||
| dm_event_handler_get_timeout | ||||
|   | ||||
							
								
								
									
										1
									
								
								daemons/dmeventd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								daemons/dmeventd/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| dmeventd | ||||
| @@ -1,5 +1,5 @@ | ||||
| # | ||||
| # Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2005 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| @@ -9,108 +9,75 @@ | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| abs_srcdir = @abs_srcdir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SOURCES = libdevmapper-event.c | ||||
| SOURCES2 = dmeventd.c | ||||
|  | ||||
| LIB_STATIC = libdevmapper-event.a | ||||
|  | ||||
| ifeq ("@LIB_SUFFIX@","dylib") | ||||
|   LIB_SHARED = libdevmapper-event.dylib | ||||
| else | ||||
|   LIB_SHARED = libdevmapper-event.so | ||||
| endif | ||||
|  | ||||
| TARGETS = dmeventd | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES) $(SOURCES2) \ | ||||
| 	plugins/lvm2/dmeventd_lvm.c \ | ||||
| 	plugins/mirror/dmeventd_mirror.c \ | ||||
| 	plugins/raid/dmeventd_raid.c \ | ||||
| 	plugins/snapshot/dmeventd_snapshot.c \ | ||||
| 	plugins/thin/dmeventd_thin.c \ | ||||
| 	plugins/vdo/dmeventd_vdo.c \ | ||||
| 	) | ||||
| CFLOW_TARGET := $(TARGETS) | ||||
| CLEAN_TARGETS = dmeventd.o | ||||
|  | ||||
| .PHONY: install_lib_dynamic install_lib_static install_include \ | ||||
| 	install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \ | ||||
| 	install_lib install_dmeventd | ||||
| include ../make.tmpl | ||||
|  | ||||
| INSTALL_DMEVENTD_TARGETS = install_dmeventd_dynamic | ||||
| INSTALL_LIB_TARGETS = install_lib_dynamic | ||||
|  | ||||
| LIB_NAME = libdevmapper-event | ||||
| ifeq ("@STATIC_LINK@", "yes") | ||||
|   LIB_STATIC = $(LIB_NAME).a | ||||
|   TARGETS += $(LIB_STATIC) dmeventd.static | ||||
|   INSTALL_DMEVENTD_TARGETS += install_dmeventd_static | ||||
|   INSTALL_LIB_TARGETS += install_lib_static | ||||
| endif | ||||
|  | ||||
| LIB_VERSION = $(LIB_VERSION_DM) | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIBS = $(PTHREAD_LIBS) -L$(interfacebuilddir) -ldevmapper | ||||
|  | ||||
| CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a | ||||
|  | ||||
| ifneq ($(MAKECMDGOALS),device-mapper) | ||||
|   SUBDIRS+=plugins | ||||
| endif | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h | ||||
| EXPORTED_FN_PREFIX = dm_event | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| all: device-mapper | ||||
| device-mapper: $(TARGETS) | ||||
| plugins.device-mapper: $(LIB_SHARED) | ||||
|  | ||||
| CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS) | ||||
| LDFLAGS += -ldl -ldevmapper -lpthread | ||||
| CLDFLAGS += -ldl -ldevmapper -lpthread | ||||
|  | ||||
| dmeventd: $(LIB_SHARED) dmeventd.o | ||||
| 	$(SHOW) "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \ | ||||
| 		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) | ||||
| 	$(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \ | ||||
| 	-L. -ldevmapper-event $(LIBS) -rdynamic | ||||
|  | ||||
| dmeventd.static: $(LIB_STATIC) dmeventd.o | ||||
| 	$(SHOW) "    [CC] $@" | ||||
| 	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_LDFLAGS) -static dmeventd.o \ | ||||
| 		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS) | ||||
| .PHONY: install_dynamic install_static install_include \ | ||||
| 	install_pkgconfig install_dmeventd | ||||
|  | ||||
| ifeq ("@PKGCONFIG@", "yes") | ||||
|   INSTALL_LIB_TARGETS += install_pkgconfig | ||||
| INSTALL_TYPE = install_dynamic | ||||
|  | ||||
| ifeq ("@STATIC_LINK@", "yes") | ||||
|   INSTALL_TYPE += install_static | ||||
| endif | ||||
|  | ||||
| install_include: $(srcdir)/libdevmapper-event.h | ||||
| 	$(SHOW) "    [INSTALL] $(<F)" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F) | ||||
| ifeq ("@PKGCONFIG@", "yes") | ||||
|   INSTALL_TYPE += install_pkgconfig | ||||
| endif | ||||
|  | ||||
| install_pkgconfig: libdevmapper-event.pc | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc | ||||
| install: $(INSTALL_TYPE) install_include install_dmeventd | ||||
|  | ||||
| install_lib_dynamic: install_lib_shared | ||||
| install_include: | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \ | ||||
| 		$(includedir)/libdevmapper-event.h | ||||
|  | ||||
| install_lib_static: $(LIB_STATIC) | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F) | ||||
| install_dynamic: libdevmapper-event.$(LIB_SUFFIX) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) | ||||
| 	$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \ | ||||
| 		$(libdir)/libdevmapper-event.$(LIB_SUFFIX) | ||||
|  | ||||
| install_lib: $(INSTALL_LIB_TARGETS) | ||||
| install_dmeventd: dmeventd | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$< | ||||
|  | ||||
| install_dmeventd_dynamic: dmeventd | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) | ||||
| install_pkgconfig: | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \ | ||||
| 		$(usrlibdir)/pkgconfig/devmapper-event.pc | ||||
|  | ||||
| install_dmeventd_static: dmeventd.static | ||||
| 	$(SHOW) "    [INSTALL] $<" | ||||
| 	$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F) | ||||
| install_static: libdevmapper-event.a | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/libdevmapper-event.a.$(LIB_VERSION) | ||||
| 	$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a | ||||
|  | ||||
| install_dmeventd: $(INSTALL_DMEVENTD_TARGETS) | ||||
| .PHONY: distclean_lib distclean | ||||
|  | ||||
| install: install_include install_lib install_dmeventd | ||||
| distclean_lib:  | ||||
| 	$(RM) libdevmapper-event.pc | ||||
|  | ||||
| install_device-mapper: install_include install_lib install_dmeventd | ||||
| distclean: distclean_lib | ||||
|  | ||||
| DISTCLEAN_TARGETS += libdevmapper-event.pc | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,24 +1,13 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #ifndef __DMEVENTD_DOT_H__ | ||||
| #define __DMEVENTD_DOT_H__ | ||||
|  | ||||
| /* FIXME This stuff must be configurable. */ | ||||
|  | ||||
| #define	DM_EVENT_FIFO_CLIENT	DEFAULT_DM_RUN_DIR "/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	DEFAULT_DM_RUN_DIR "/dmeventd-server" | ||||
| #define	DM_EVENT_DAEMON		"/sbin/dmeventd" | ||||
| #define DM_EVENT_LOCKFILE	"/var/lock/dmeventd" | ||||
| #define	DM_EVENT_FIFO_CLIENT	"/var/run/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	"/var/run/dmeventd-server" | ||||
| #define DM_EVENT_PIDFILE	"/var/run/dmeventd.pid" | ||||
|  | ||||
| #define DM_EVENT_DEFAULT_TIMEOUT 10 | ||||
|  | ||||
| @@ -32,9 +21,6 @@ enum dm_event_command { | ||||
| 	DM_EVENT_CMD_SET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_GET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_HELLO, | ||||
| 	DM_EVENT_CMD_DIE, | ||||
| 	DM_EVENT_CMD_GET_STATUS, | ||||
| 	DM_EVENT_CMD_GET_PARAMETERS, | ||||
| }; | ||||
|  | ||||
| /* Message passed between client and daemon. */ | ||||
| @@ -56,21 +42,11 @@ struct dm_event_fifos { | ||||
|  | ||||
| /*      EXIT_SUCCESS             0 -- stdlib.h */ | ||||
| /*      EXIT_FAILURE             1 -- stdlib.h */ | ||||
| /*      EXIT_LOCKFILE_INUSE      2 -- obsoleted */ | ||||
| #define EXIT_LOCKFILE_INUSE      2 | ||||
| #define EXIT_DESC_CLOSE_FAILURE  3 | ||||
| #define EXIT_DESC_OPEN_FAILURE   4 | ||||
| /*      EXIT_OPEN_PID_FAILURE    5 -- obsoleted */ | ||||
| #define EXIT_OPEN_PID_FAILURE    5 | ||||
| #define EXIT_FIFO_FAILURE        6 | ||||
| #define EXIT_CHDIR_FAILURE       7 | ||||
|  | ||||
| /* Implemented in libdevmapper-event.c, but not part of public API. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| int daemon_talk(struct dm_event_fifos *fifos, | ||||
| 		struct dm_event_daemon_message *msg, int cmd, | ||||
| 		const char *dso_name, const char *dev_name, | ||||
| 		unsigned evmask, uint32_t timeout); | ||||
| int init_fifos(struct dm_event_fifos *fifos); | ||||
| void fini_fifos(struct dm_event_fifos *fifos); | ||||
| int dm_event_get_version(struct dm_event_fifos *fifos, int *version); | ||||
|  | ||||
| #endif /* __DMEVENTD_DOT_H__ */ | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved. | ||||
|  * Copyright (C) 2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
| @@ -9,7 +9,7 @@ | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
| @@ -21,7 +21,6 @@ | ||||
| #ifndef LIB_DMEVENT_H | ||||
| #define LIB_DMEVENT_H | ||||
|  | ||||
| #include <stdarg.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* | ||||
| @@ -47,9 +46,7 @@ enum dm_event_mask { | ||||
| }; | ||||
|  | ||||
| #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK | ||||
| #define DM_EVENT_PROTOCOL_VERSION 2 | ||||
|  | ||||
| struct dm_task; | ||||
| struct dm_event_handler; | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void); | ||||
| @@ -58,17 +55,12 @@ void dm_event_handler_destroy(struct dm_event_handler *dmevh); | ||||
| /* | ||||
|  * Path of shared library to handle events. | ||||
|  * | ||||
|  * All of dmeventd, dso, device_name and uuid strings are duplicated so | ||||
|  * you do not need to keep the pointers valid after the call succeeds. | ||||
|  * They may return -ENOMEM though. | ||||
|  * All of dso, device_name and uuid strings are duplicated, you do not | ||||
|  * need to keep the pointers valid after the call succeeds. Thes may | ||||
|  * return -ENOMEM though. | ||||
|  */ | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path); | ||||
|  | ||||
| /* | ||||
|  * Path of dmeventd binary. | ||||
|  */ | ||||
| int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path); | ||||
|  | ||||
| /* | ||||
|  * Identify the device to monitor by exactly one of device_name, uuid or | ||||
|  * device number. String arguments are duplicated, see above. | ||||
| @@ -84,7 +76,6 @@ void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout); | ||||
| /* | ||||
|  * Specify mask for events to monitor. | ||||
|  */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask); | ||||
|  | ||||
| @@ -94,7 +85,6 @@ const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh); | ||||
| // FIXME  misuse of bitmask as enum | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* FIXME Review interface (what about this next thing?) */ | ||||
| @@ -106,28 +96,8 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next); | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh); | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* Set debug level for logging, and whether to log on stdout/stderr or syslog */ | ||||
| void dm_event_log_set(int debug_log_level, int use_syslog); | ||||
|  | ||||
| /* Log messages acroding to current debug level  */ | ||||
| __attribute__((format(printf, 6, 0))) | ||||
| void dm_event_log(const char *subsys, int level, const char *file, | ||||
| 		  int line, int dm_errno_or_class, | ||||
| 		  const char *format, va_list ap); | ||||
| /* Macro to route print_log do dm_event_log() */ | ||||
| #define DM_EVENT_LOG_FN(subsys) \ | ||||
| void print_log(int level, const char *file, int line, int dm_errno_or_class,\ | ||||
| 	       const char *format, ...)\ | ||||
| {\ | ||||
| 	va_list ap;\ | ||||
| 	va_start(ap, format);\ | ||||
| 	dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\ | ||||
| 	va_end(ap);\ | ||||
| } | ||||
|  | ||||
| /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for | ||||
|    detailed descriptions. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user); | ||||
| int register_device(const char *device_name, const char *uuid, int major, int minor, void **user); | ||||
| int unregister_device(const char *device_name, const char *uuid, int major, | ||||
|   | ||||
| @@ -5,6 +5,8 @@ includedir=@includedir@ | ||||
|  | ||||
| Name: devmapper-event | ||||
| Description: device-mapper event library | ||||
| Version: @DM_LIB_PATCHLEVEL@ | ||||
| Version: @DM_LIB_VERSION@ | ||||
| Requires: devmapper | ||||
| Cflags: -I${includedir} | ||||
| Libs: -L${libdir} -ldevmapper-event | ||||
| Libs.private: -lpthread -ldl | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| @@ -10,18 +10,13 @@ | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS += lvm2 snapshot raid thin mirror vdo | ||||
| SUBDIRS += mirror | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| snapshot: lvm2 | ||||
| mirror: lvm2 | ||||
| raid: lvm2 | ||||
| thin: lvm2 | ||||
| vdo: lvm2 | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| dmeventd_lvm2_init | ||||
| dmeventd_lvm2_exit | ||||
| dmeventd_lvm2_lock | ||||
| dmeventd_lvm2_unlock | ||||
| dmeventd_lvm2_pool | ||||
| dmeventd_lvm2_run | ||||
| dmeventd_lvm2_command | ||||
| @@ -1,30 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2010-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/tools | ||||
| LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@ | ||||
|  | ||||
| SOURCES = dmeventd_lvm.c | ||||
|  | ||||
| LIB_SHARED = libdevmapper-event-lvm2.$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_lib_shared | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,193 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "tools/lvm2cmd.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| /* | ||||
|  * register_device() is called first and performs initialisation. | ||||
|  * Only one device may be registered or unregistered at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
| static DM_LIST_INIT(_env_registry); | ||||
|  | ||||
| struct env_data { | ||||
| 	struct dm_list list; | ||||
| 	const char *cmd; | ||||
| 	const char *data; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("#lvm") | ||||
|  | ||||
| static void _lvm2_print_log(int level, const char *file, int line, | ||||
| 			    int dm_errno_or_class, const char *msg) | ||||
| { | ||||
| 	print_log(level, file, line, dm_errno_or_class, "%s", msg); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| void dmeventd_lvm2_lock(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_unlock(void) | ||||
| { | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_init(void) | ||||
| { | ||||
| 	int r = 0; | ||||
|  | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_lvm2_print_log); | ||||
|  | ||||
| 		if (!(_lvm_handle = lvm2_init_threaded())) | ||||
| 			goto out; | ||||
|  | ||||
| 		/* | ||||
| 		 * Need some space for allocations.  1024 should be more | ||||
| 		 * than enough for what we need (device mapper name splitting) | ||||
| 		 */ | ||||
| 		if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) { | ||||
| 			lvm2_exit(_lvm_handle); | ||||
| 			_lvm_handle = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		lvm2_disable_dmeventd_monitoring(_lvm_handle); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 		log_debug("lvm plugin initilized."); | ||||
| 	} | ||||
|  | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_exit(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		log_debug("lvm plugin shuting down."); | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		dm_list_init(&_env_registry); | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 		log_debug("lvm plugin exited."); | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| } | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void) | ||||
| { | ||||
| 	return _mem_pool; | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_run(const char *cmdline) | ||||
| { | ||||
| 	/* coverity[missing_lock] no locking for run part */ | ||||
| 	return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device) | ||||
| { | ||||
| 	static char _internal_prefix[] =  "_dmeventd_"; | ||||
| 	char *vg = NULL, *lv = NULL, *layer; | ||||
| 	int r; | ||||
| 	struct env_data *env_data; | ||||
| 	const char *env = NULL; | ||||
|  | ||||
| 	if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) { | ||||
| 		log_error("Unable to determine VG name from %s.", | ||||
| 			  device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* strip off the mirror component designations */ | ||||
| 	if ((layer = strstr(lv, "_mimagetmp")) || | ||||
| 	    (layer = strstr(lv, "_mlog"))) | ||||
| 		*layer = '\0'; | ||||
|  | ||||
| 	if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) { | ||||
| 		/* check if ENVVAR wasn't already resolved */ | ||||
| 		dm_list_iterate_items(env_data, &_env_registry) | ||||
| 			if (!strcmp(cmd, env_data->cmd)) { | ||||
| 				env = env_data->data; | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 		if (!env) { | ||||
| 			/* run lvm2 command to find out setting value */ | ||||
| 			dmeventd_lvm2_lock(); | ||||
| 			if (!dmeventd_lvm2_run(cmd) || | ||||
| 			    !(env = getenv(cmd))) { | ||||
| 				dmeventd_lvm2_unlock(); | ||||
| 				log_error("Unable to find configured command."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			/* output of internal command passed via env var */ | ||||
| 			env = dm_pool_strdup(_mem_pool, env); /* copy with lock */ | ||||
| 			dmeventd_lvm2_unlock(); | ||||
| 			if (!env || | ||||
| 			    !(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) || | ||||
| 			    !(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) { | ||||
| 				log_error("Unable to allocate env memory."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			env_data->data = env; | ||||
| 			/* add to ENVVAR registry */ | ||||
| 			dm_list_add(&_env_registry, &env_data->list); | ||||
| 		} | ||||
| 		cmd = env; | ||||
| 	} | ||||
|  | ||||
| 	r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv); | ||||
|  | ||||
| 	dm_pool_free(mem, vg); | ||||
|  | ||||
| 	if (r < 0) { | ||||
| 		log_error("Unable to form LVM command. (too long)."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Wrappers around liblvm2cmd functions for dmeventd plug-ins. | ||||
|  * | ||||
|  * liblvm2cmd is not thread-safe so the locking in this library helps dmeventd | ||||
|  * threads to co-operate in sharing a single instance. | ||||
|  * | ||||
|  * FIXME Either support this properly as a generic liblvm2cmd wrapper or make | ||||
|  * liblvm2cmd thread-safe so this can go away. | ||||
|  */ | ||||
|  | ||||
| #ifndef _DMEVENTD_LVMWRAP_H | ||||
| #define _DMEVENTD_LVMWRAP_H | ||||
|  | ||||
| struct dm_pool; | ||||
|  | ||||
| int dmeventd_lvm2_init(void); | ||||
| void dmeventd_lvm2_exit(void); | ||||
| int dmeventd_lvm2_run(const char *cmdline); | ||||
|  | ||||
| void dmeventd_lvm2_lock(void); | ||||
| void dmeventd_lvm2_unlock(void); | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void); | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device); | ||||
|  | ||||
| #define dmeventd_lvm2_run_with_lock(cmdline) \ | ||||
| 	({\ | ||||
| 		int rc;\ | ||||
| 		dmeventd_lvm2_lock();\ | ||||
| 		rc = dmeventd_lvm2_run(cmdline);\ | ||||
| 		dmeventd_lvm2_unlock();\ | ||||
| 		rc;\ | ||||
| 	}) | ||||
|  | ||||
| #define dmeventd_lvm2_init_with_pool(name, st) \ | ||||
| 	({\ | ||||
| 		struct dm_pool *mem;\ | ||||
| 		st = NULL;\ | ||||
| 		if (dmeventd_lvm2_init()) {\ | ||||
| 			if ((mem = dm_pool_create(name, 2048)) &&\ | ||||
| 			    (st = dm_pool_zalloc(mem, sizeof(*st))))\ | ||||
| 				st->mem = mem;\ | ||||
| 			else {\ | ||||
| 				if (mem)\ | ||||
| 					dm_pool_destroy(mem);\ | ||||
| 				dmeventd_lvm2_exit();\ | ||||
| 			}\ | ||||
| 		}\ | ||||
| 		st;\ | ||||
| 	}) | ||||
|  | ||||
| #define dmeventd_lvm2_exit_with_pool(pool) \ | ||||
| 	do {\ | ||||
| 		dm_pool_destroy(pool->mem);\ | ||||
| 		dmeventd_lvm2_exit();\ | ||||
| 	} while(0) | ||||
|  | ||||
| #endif /* _DMEVENTD_LVMWRAP_H */ | ||||
| @@ -1,8 +1,8 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2008-2014 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| @@ -10,23 +10,27 @@ | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
| INCLUDES += -I${top_srcdir}/tools | ||||
| CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd | ||||
|  | ||||
| SOURCES = dmeventd_mirror.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2mirror | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
| ifeq ("@LIB_SUFFIX@","dylib") | ||||
|   LIB_SHARED = libdevmapper-event-lvm2mirror.dylib | ||||
| else | ||||
|   LIB_SHARED = libdevmapper-event-lvm2mirror.so | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
| include $(top_srcdir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
| install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX) | ||||
| 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ | ||||
| 		$(libdir)/$<.$(LIB_VERSION) | ||||
| 	$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$< | ||||
|  | ||||
| install: install_lvm2 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved. | ||||
|  * Copyright (C) 2005 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
| @@ -9,203 +9,273 @@ | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "lib/activate/activate.h" | ||||
| #include "libdevmapper.h" | ||||
| #include "libdevmapper-event.h" | ||||
| #include "lvm2cmd.h" | ||||
|  | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <pthread.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* FIXME Missing openlog? */ | ||||
|  | ||||
| #define ME_IGNORE    0 | ||||
| #define ME_INSYNC    1 | ||||
| #define ME_FAILURE   2 | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	char cmd_lvconvert[512]; | ||||
| }; | ||||
| /* | ||||
|  * register_device() is called first and performs initialisation. | ||||
|  * Only one device may be registered or unregistered at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| DM_EVENT_LOG_FN("mirr") | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
|  | ||||
| static void _process_status_code(dm_status_mirror_health_t health, | ||||
| 				 uint32_t major, uint32_t minor, | ||||
| 				 const char *dev_type, int *r) | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| static int _get_mirror_event(char *params) | ||||
| { | ||||
| 	int i, r = ME_INSYNC; | ||||
| 	char **args = NULL; | ||||
| 	char *dev_status_str; | ||||
| 	char *log_status_str; | ||||
| 	char *sync_str; | ||||
| 	char *p = NULL; | ||||
| 	int log_argc, num_devs; | ||||
|  | ||||
| 	/* | ||||
| 	 *    A => Alive - No failures | ||||
| 	 *    D => Dead - A write failure occurred leaving mirror out-of-sync | ||||
| 	 *    F => Flush failed. | ||||
| 	 *    S => Sync - A sychronization failure occurred, mirror out-of-sync | ||||
| 	 *    R => Read - A read failure occurred, mirror data unaffected | ||||
| 	 *    U => Unclassified failure (bug) | ||||
| 	 */  | ||||
| 	switch (health) { | ||||
| 	case DM_STATUS_MIRROR_ALIVE: | ||||
| 		return; | ||||
| 	case DM_STATUS_MIRROR_FLUSH_FAILED: | ||||
| 		log_error("%s device %u:%u flush failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		*r = ME_FAILURE; | ||||
| 		break; | ||||
| 	case DM_STATUS_MIRROR_SYNC_FAILED: | ||||
| 		log_error("%s device %u:%u sync failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		break; | ||||
| 	case DM_STATUS_MIRROR_READ_FAILED: | ||||
| 		log_error("%s device %u:%u read failed.", | ||||
| 			  dev_type, major, minor); | ||||
| 		break; | ||||
| 	default: | ||||
| 		log_error("%s device %u:%u has failed (%c).", | ||||
| 			  dev_type, major, minor, (char)health); | ||||
| 		*r = ME_FAILURE; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 	 * dm core parms:	     0 409600 mirror | ||||
| 	 * Mirror core parms:	     2 253:4 253:5 400/400 | ||||
| 	 * New-style failure params: 1 AA | ||||
| 	 * New-style log params:     3 cluster 253:3 A | ||||
| 	 *			 or  3 disk 253:3 A | ||||
| 	 *			 or  1 core | ||||
| 	 */ | ||||
|  | ||||
| static int _get_mirror_event(struct dso_state *state, char *params) | ||||
| { | ||||
| 	int r = ME_INSYNC; | ||||
| 	unsigned i; | ||||
| 	struct dm_status_mirror *ms; | ||||
| 	/* number of devices */ | ||||
| 	if (!dm_split_words(params, 1, 0, &p)) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	if (!dm_get_status_mirror(state->mem, params, &ms)) { | ||||
| 		log_error("Unable to parse mirror status string."); | ||||
| 		return ME_IGNORE; | ||||
| 	} | ||||
| 	if (!(num_devs = atoi(p))) | ||||
| 		goto out_parse; | ||||
| 	p += strlen(p) + 1; | ||||
|  | ||||
| 	/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */ | ||||
| 	args = dm_malloc((num_devs + 7) * sizeof(char *)); | ||||
| 	if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	dev_status_str = args[2 + num_devs]; | ||||
| 	log_argc = atoi(args[3 + num_devs]); | ||||
| 	log_status_str = args[3 + num_devs + log_argc]; | ||||
| 	sync_str = args[num_devs]; | ||||
|  | ||||
| 	/* Check for bad mirror devices */ | ||||
| 	for (i = 0; i < ms->dev_count; ++i) | ||||
| 		_process_status_code(ms->devs[i].health, | ||||
| 				     ms->devs[i].major, ms->devs[i].minor, | ||||
| 				     i ? "Secondary mirror" : "Primary mirror", &r); | ||||
| 	for (i = 0; i < num_devs; i++) | ||||
| 		if (dev_status_str[i] == 'D') { | ||||
| 			syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]); | ||||
| 			r = ME_FAILURE; | ||||
| 		} | ||||
|  | ||||
| 	/* Check for bad disk log device */ | ||||
| 	for (i = 0; i < ms->log_count; ++i) | ||||
| 		_process_status_code(ms->logs[i].health, | ||||
| 				     ms->logs[i].major, ms->logs[i].minor, | ||||
| 				     "Log", &r); | ||||
|  | ||||
| 	/* Ignore if not in-sync */ | ||||
| 	if ((r == ME_INSYNC) && (ms->insync_regions != ms->total_regions)) | ||||
| 		r = ME_IGNORE; | ||||
|  | ||||
| 	dm_pool_free(state->mem, ms); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _remove_failed_devices(const char *cmd_lvconvert, const char *device) | ||||
| { | ||||
| 	/* if repair goes OK, report success even if lvscan has failed */ | ||||
| 	if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) { | ||||
| 		log_error("Repair of mirrored device %s failed.", device); | ||||
| 		return 0; | ||||
| 	if (log_argc > 1 && log_status_str[0] == 'D') { | ||||
| 		syslog(LOG_ERR, "Log device, %s, has failed.\n", | ||||
| 		       args[2 + num_devs + log_argc]); | ||||
| 		r = ME_FAILURE; | ||||
| 	} | ||||
|  | ||||
| 	log_info("Repair of mirrored device %s finished successfully.", device); | ||||
| 	if (r == ME_FAILURE) | ||||
| 		goto out; | ||||
|  | ||||
| 	return 1; | ||||
| 	p = strstr(sync_str, "/"); | ||||
| 	if (p) { | ||||
| 		p[0] = '\0'; | ||||
| 		if (strcmp(sync_str, p+1)) | ||||
| 			r = ME_IGNORE; | ||||
| 		p[0] = '/'; | ||||
| 	} else | ||||
| 		goto out_parse; | ||||
|  | ||||
| out: | ||||
| 	if (args) | ||||
| 		dm_free(args); | ||||
| 	return r; | ||||
| 	 | ||||
| out_parse: | ||||
| 	if (args) | ||||
| 		dm_free(args); | ||||
| 	syslog(LOG_ERR, "Unable to parse mirror status string."); | ||||
| 	return ME_IGNORE; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| static void _temporary_log_fn(int level, const char *file, | ||||
| 			      int line, const char *format) | ||||
| { | ||||
| 	if (!strncmp(format, "WARNING: ", 9) && (level < 5)) | ||||
| 		syslog(LOG_CRIT, "%s", format); | ||||
| 	else | ||||
| 		syslog(LOG_DEBUG, "%s", format); | ||||
| } | ||||
|  | ||||
| static int _remove_failed_devices(const char *device) | ||||
| { | ||||
| 	int r; | ||||
| #define CMD_SIZE 256	/* FIXME Use system restriction */ | ||||
| 	char cmd_str[CMD_SIZE]; | ||||
| 	char *vg = NULL, *lv = NULL, *layer = NULL; | ||||
|  | ||||
| 	if (strlen(device) > 200)  /* FIXME Use real restriction */ | ||||
| 		return -ENAMETOOLONG;	/* FIXME These return code distinctions are not used so remove them! */ | ||||
|  | ||||
| 	if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) { | ||||
| 		syslog(LOG_ERR, "Unable to determine VG name from %s", | ||||
| 		       device); | ||||
| 		return -ENOMEM;	/* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME Is any sanity-checking required on %s? */ | ||||
| 	if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) { | ||||
| 		/* this error should be caught above, but doesn't hurt to check again */ | ||||
| 		syslog(LOG_ERR, "Unable to form LVM command: Device name too long"); | ||||
| 		dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */ | ||||
| 		return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
| 	} | ||||
|  | ||||
| 	r = lvm2_run(_lvm_handle, cmd_str); | ||||
|  | ||||
| 	dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */ | ||||
| 	return (r == 1) ? 0 : -1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, enum dm_event_mask event, | ||||
| 		   void **unused __attribute((unused))) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	if (pthread_mutex_trylock(&_event_mutex)) { | ||||
| 		syslog(LOG_NOTICE, "Another thread is handling an event.  Waiting..."); | ||||
| 		pthread_mutex_lock(&_event_mutex); | ||||
| 	} | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			log_info("%s mapping lost.", device); | ||||
| 			syslog(LOG_INFO, "%s mapping lost.\n", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, TARGET_NAME_MIRROR)) { | ||||
| 			log_info("%s has unmirrored portion.", device); | ||||
| 		if (strcmp(target_type, "mirror")) { | ||||
| 			syslog(LOG_INFO, "%s has unmirrored portion.\n", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		switch(_get_mirror_event(state, params)) { | ||||
| 		switch(_get_mirror_event(params)) { | ||||
| 		case ME_INSYNC: | ||||
| 			/* FIXME: all we really know is that this | ||||
| 			   _part_ of the device is in sync | ||||
| 			   Also, this is not an error | ||||
| 			*/ | ||||
| 			log_notice("%s is now in-sync.", device); | ||||
| 			syslog(LOG_NOTICE, "%s is now in-sync\n", device); | ||||
| 			break; | ||||
| 		case ME_FAILURE: | ||||
| 			log_error("Device failure in %s.", device); | ||||
| 			if (!_remove_failed_devices(state->cmd_lvconvert, device)) | ||||
| 			syslog(LOG_ERR, "Device failure in %s\n", device); | ||||
| 			if (_remove_failed_devices(device)) | ||||
| 				/* FIXME Why are all the error return codes unused? Get rid of them? */ | ||||
| 				log_error("Failed to remove faulty devices in %s.", | ||||
| 					  device); | ||||
| 				syslog(LOG_ERR, "Failed to remove faulty devices in %s\n", | ||||
| 				       device); | ||||
| 			/* Should check before warning user that device is now linear | ||||
| 			else | ||||
| 				log_notice("%s is now a linear device.", | ||||
| 					   device); | ||||
| 				syslog(LOG_NOTICE, "%s is now a linear device.\n", | ||||
| 					device); | ||||
| 			*/ | ||||
| 			break; | ||||
| 		case ME_IGNORE: | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* FIXME Provide value then! */ | ||||
| 			log_warn("WARNING: %s received unknown event.", device); | ||||
| 			syslog(LOG_INFO, "Unknown event received.\n"); | ||||
| 		} | ||||
| 	} while (next); | ||||
|  | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| int register_device(const char *device, const char *uuid, int major, int minor, | ||||
| 		   void **unused __attribute((unused))) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("mirror_state", state)) | ||||
| 		goto_bad; | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
|         /* CANNOT use --config as this disables cached content */ | ||||
| 	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert), | ||||
| 				   "lvconvert --repair --use-policies", device)) | ||||
| 		goto_bad; | ||||
| 	syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device); | ||||
|  | ||||
| 	*user = state; | ||||
| 	/* | ||||
| 	 * Need some space for allocations.  1024 should be more | ||||
| 	 * than enough for what we need (device mapper name splitting) | ||||
| 	 */ | ||||
| 	if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) | ||||
| 		goto out; | ||||
|  | ||||
| 	log_info("Monitoring mirror device %s for events.", device); | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_temporary_log_fn); | ||||
| 		if (!(_lvm_handle = lvm2_init())) { | ||||
| 			dm_pool_destroy(_mem_pool); | ||||
| 			_mem_pool = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	log_error("Failed to monitor mirror %s.", device); | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return 0; | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| int unregister_device(const char *device, const char *uuid, int major, int minor, | ||||
| 		   void **unused __attribute((unused))) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring mirror device %s for events.", | ||||
| 		 device); | ||||
| 	syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n", | ||||
| 	       device); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|   | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
| LIBS += -ldevmapper-event-lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_raid.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2raid | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,189 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "lib/misc/lib.h" | ||||
| #include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h" | ||||
| #include "daemons/dmeventd/libdevmapper-event.h" | ||||
| #include "lib/config/defaults.h" | ||||
|  | ||||
| /* Hold enough elements for the mximum number of RAID images */ | ||||
| #define	RAID_DEVS_ELEMS	((DEFAULT_RAID_MAX_IMAGES + 63) / 64) | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	char cmd_lvconvert[512]; | ||||
| 	uint64_t raid_devs[RAID_DEVS_ELEMS]; | ||||
| 	int failed; | ||||
| 	int warned; | ||||
| }; | ||||
|  | ||||
| DM_EVENT_LOG_FN("raid") | ||||
|  | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
|  | ||||
| static int _process_raid_event(struct dso_state *state, char *params, const char *device) | ||||
| { | ||||
| 	struct dm_status_raid *status; | ||||
| 	const char *d; | ||||
| 	int dead = 0, r = 1; | ||||
| 	uint32_t dev; | ||||
|  | ||||
| 	if (!dm_get_status_raid(state->mem, params, &status)) { | ||||
| 		log_error("Failed to process status line for %s.", device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	d = status->dev_health; | ||||
| 	while ((d = strchr(d, 'D'))) { | ||||
| 		dev = (uint32_t)(d - status->dev_health); | ||||
|  | ||||
| 		if (!(state->raid_devs[dev / 64] & (UINT64_C(1) << (dev % 64)))) { | ||||
| 			state->raid_devs[dev / 64] |= (UINT64_C(1) << (dev % 64)); | ||||
| 			log_warn("WARNING: Device #%u of %s array, %s, has failed.", | ||||
| 				 dev, status->raid_type, device); | ||||
| 		} | ||||
|  | ||||
| 		d++; | ||||
| 		dead = 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * if we are converting from non-RAID to RAID (e.g. linear -> raid1) | ||||
| 	 * and too many original devices die, such that we cannot continue | ||||
| 	 * the "recover" operation, the sync action will go to "idle", the | ||||
| 	 * unsynced devs will remain at 'a', and the original devices will | ||||
| 	 * NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived. | ||||
| 	 * | ||||
| 	 * This is simply the way the kernel works... | ||||
| 	 */ | ||||
| 	if (!strcmp(status->sync_action, "idle") && | ||||
| 	    (status->dev_health[0] == 'a') && | ||||
| 	    (status->insync_regions < status->total_regions)) { | ||||
| 		log_error("Primary sources for new RAID, %s, have failed.", | ||||
| 			  device); | ||||
| 		dead = 1; /* run it through LVM repair */ | ||||
| 	} | ||||
|  | ||||
| 	if (dead) { | ||||
| 		/* | ||||
| 		 * Use the first event to run a repair ignoring any additional ones. | ||||
| 		 * | ||||
| 		 * We presume lvconvert to do pre-repair | ||||
| 		 * checks to avoid bloat in this plugin. | ||||
| 		 */ | ||||
| 		if (!state->warned && status->insync_regions < status->total_regions) { | ||||
| 			state->warned = 1; | ||||
| 			log_warn("WARNING: waiting for resynchronization to finish " | ||||
| 				 "before initiating repair on RAID device %s.", device); | ||||
| 			/* Fall through to allow lvconvert to run. */ | ||||
| 		} | ||||
|  | ||||
| 		if (state->failed) | ||||
| 			goto out; /* already reported */ | ||||
|  | ||||
| 		state->failed = 1; | ||||
|  | ||||
| 		/* if repair goes OK, report success even if lvscan has failed */ | ||||
| 		if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) { | ||||
| 			log_error("Repair of RAID device %s failed.", device); | ||||
| 			r = 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		state->failed = 0; | ||||
| 		if (status->insync_regions == status->total_regions) | ||||
| 			memset(&state->raid_devs, 0, sizeof(state->raid_devs)); | ||||
| 		log_info("%s array, %s, is %s in-sync.", | ||||
| 			 status->raid_type, device, | ||||
| 			 (status->insync_regions == status->total_regions) ? "now" : "not"); | ||||
| 	} | ||||
| out: | ||||
| 	dm_pool_free(state->mem, status); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			log_info("%s mapping lost.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, "raid")) { | ||||
| 			log_info("%s has non-raid portion.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!_process_raid_event(state, params, device)) | ||||
| 			log_error("Failed to process event for %s.", | ||||
| 				  device); | ||||
| 	} while (next); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **user) | ||||
| { | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init_with_pool("raid_state", state)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert), | ||||
| 				   "lvconvert --repair --use-policies", device)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	*user = state; | ||||
|  | ||||
| 	log_info("Monitoring RAID device %s for events.", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	log_error("Failed to monitor RAID %s.", device); | ||||
|  | ||||
| 	if (state) | ||||
| 		dmeventd_lvm2_exit_with_pool(state); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **user) | ||||
| { | ||||
| 	struct dso_state *state = *user; | ||||
|  | ||||
| 	dmeventd_lvm2_exit_with_pool(state); | ||||
| 	log_info("No longer monitoring RAID device %s for events.", | ||||
| 		 device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user