mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
Compare commits
629
Commits
main
...
releng/7.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57895cdc76 | ||
|
|
cff0c03ef7 | ||
|
|
bb602bfc7c | ||
|
|
a571840488 | ||
|
|
636b4dcc16 | ||
|
|
343d9769a6 | ||
|
|
17ce22e780 | ||
|
|
1258eef80a | ||
|
|
24b7af9d00 | ||
|
|
b1f3875d97 | ||
|
|
eaa7871ca9 | ||
|
|
526c7ad3a7 | ||
|
|
ba209d619d | ||
|
|
c305071382 | ||
|
|
273f2878cf | ||
|
|
d6b756fedf | ||
|
|
1a6175d504 | ||
|
|
e64896ab62 | ||
|
|
0170aa6bf2 | ||
|
|
b345cdf33f | ||
|
|
d766e68b5b | ||
|
|
981ef535d7 | ||
|
|
016bc70050 | ||
|
|
e06244ec03 | ||
|
|
765537c6f5 | ||
|
|
03b346e6fa | ||
|
|
ba492a05a0 | ||
|
|
b0884b996e | ||
|
|
fe2aa7693d | ||
|
|
72fd2dafeb | ||
|
|
52a42b6a92 | ||
|
|
9bb4915ac6 | ||
|
|
5d674ba13d | ||
|
|
a330834f3c | ||
|
|
397d753b08 | ||
|
|
b1e439e170 | ||
|
|
75cf92539f | ||
|
|
9fb0721520 | ||
|
|
eaaf37485b | ||
|
|
f37e77691e | ||
|
|
1347778aea | ||
|
|
5b20ea5899 | ||
|
|
fc148186da | ||
|
|
c5c7b65188 | ||
|
|
bbcc7dac08 | ||
|
|
ac9f2799f0 | ||
|
|
3546df733e | ||
|
|
8ba342d557 | ||
|
|
3125256ec6 | ||
|
|
517c2e2bb7 | ||
|
|
0f93896fb4 | ||
|
|
e1a6d0886b | ||
|
|
93d9a654b3 | ||
|
|
f9c2966924 | ||
|
|
355dc2b707 | ||
|
|
def6dd1073 | ||
|
|
b59b122423 | ||
|
|
07832de232 | ||
|
|
b1f6a82ffd | ||
|
|
9f934a7e5f | ||
|
|
e7b4df3955 | ||
|
|
57fdd6b658 | ||
|
|
9386f49e3e | ||
|
|
7e8d6fb1f3 | ||
|
|
406d294d7d | ||
|
|
c45b292880 | ||
|
|
2b0d8cb338 | ||
|
|
285d5a9d6a | ||
|
|
f0b5521fbb | ||
|
|
6682e365b1 | ||
|
|
c5f8c7522a | ||
|
|
00d99a8a27 | ||
|
|
4411d38642 | ||
|
|
a9a2a8643e | ||
|
|
d592bfdc47 | ||
|
|
77d3ed1b58 | ||
|
|
e9690482a4 | ||
|
|
f074d1d36f | ||
|
|
c642531635 | ||
|
|
ba92c33f87 | ||
|
|
797142b381 | ||
|
|
be7a7240c4 | ||
|
|
2bb3e6c220 | ||
|
|
9320c26dae | ||
|
|
8d34407042 | ||
|
|
a57f35aa34 | ||
|
|
fbfdb91277 | ||
|
|
eebe675427 | ||
|
|
dd8fad9331 | ||
|
|
39cb72a0ad | ||
|
|
a7f6626427 | ||
|
|
5063049acf | ||
|
|
524d43e266 | ||
|
|
d41b57e296 | ||
|
|
af1845a999 | ||
|
|
8f2d8624bd | ||
|
|
0438fc0b57 | ||
|
|
c8ee4e95ae | ||
|
|
fc78806aed | ||
|
|
2df5c59335 | ||
|
|
e5bc3ff47f | ||
|
|
263a670dd4 | ||
|
|
ba9c1d252c | ||
|
|
dec9ed20c8 | ||
|
|
d1d0d592d0 | ||
|
|
2044a6a462 | ||
|
|
f86934faa8 | ||
|
|
ec57f9e314 | ||
|
|
496f0a126b | ||
|
|
68c7ff1337 | ||
|
|
25a9a41ea9 | ||
|
|
ba668a1c0b | ||
|
|
53bc044a5d | ||
|
|
c1f1f5d49e | ||
|
|
dd38cd7054 | ||
|
|
b573f27291 | ||
|
|
ff94fecee5 | ||
|
|
39955554ac | ||
|
|
9399da327e | ||
|
|
b20de944bc | ||
|
|
5fd1b63742 | ||
|
|
ebad0ab421 | ||
|
|
b6b1755b57 | ||
|
|
376081cbeb | ||
|
|
f715124c6a | ||
|
|
6c55177060 | ||
|
|
d7b985d990 | ||
|
|
66efc31684 | ||
|
|
82b64d7b3b | ||
|
|
736af7c0d0 | ||
|
|
5bcb0d6f32 | ||
|
|
ffaeb38171 | ||
|
|
603ed752a9 | ||
|
|
782c339cc3 | ||
|
|
77d4e09ffb | ||
|
|
d95a02d264 | ||
|
|
a45ddb5079 | ||
|
|
c5c4528e84 | ||
|
|
06fd214a87 | ||
|
|
66f1289531 | ||
|
|
d9d4c110d6 | ||
|
|
d8ff91e4d0 | ||
|
|
181646a467 | ||
|
|
f38e825599 | ||
|
|
47cabd0773 | ||
|
|
ae29be00e1 | ||
|
|
adadd0aebe | ||
|
|
defc39cad7 | ||
|
|
e2e63530e0 | ||
|
|
3c12f2c559 | ||
|
|
d428bd79fe | ||
|
|
eac612218e | ||
|
|
23be48af29 | ||
|
|
e639d6a298 | ||
|
|
b9e8ce33bf | ||
|
|
8ed7efb349 | ||
|
|
50c731d76d | ||
|
|
00170154da | ||
|
|
13a8dfbcde | ||
|
|
4a68dc7fcc | ||
|
|
26cfc8a825 | ||
|
|
a70dcd4c90 | ||
|
|
f3b38a8f52 | ||
|
|
fa4cc34e04 | ||
|
|
8ddae67c7d | ||
|
|
23152f69a9 | ||
|
|
210c9941a4 | ||
|
|
8e02d0e34e | ||
|
|
d1214f7fa9 | ||
|
|
ca0202a548 | ||
|
|
0f36dbfe3d | ||
|
|
2eae01dcda | ||
|
|
48afcc4f66 | ||
|
|
2b72de12e7 | ||
|
|
5c1368a724 | ||
|
|
3dc9a55575 | ||
|
|
dc023ffd8f | ||
|
|
33e3033572 | ||
|
|
da65031984 | ||
|
|
d832e0e8ec | ||
|
|
ebcdb3dfdf | ||
|
|
fad8016856 | ||
|
|
ad237ab823 | ||
|
|
9961f423b2 | ||
|
|
9b49d7070c | ||
|
|
2555aae197 | ||
|
|
483a6b10be | ||
|
|
5d9cc9c840 | ||
|
|
b7550ae7c5 | ||
|
|
f6f1df19a8 | ||
|
|
ddc321ea83 | ||
|
|
27dc93d62a | ||
|
|
6b0086231a | ||
|
|
9f7625195f | ||
|
|
cc8cab3ea6 | ||
|
|
4d7ea11f18 | ||
|
|
2f7150eb7d | ||
|
|
0a2ccfca49 | ||
|
|
46725d7e98 | ||
|
|
de0deac6d1 | ||
|
|
830abbdcd0 | ||
|
|
43ebfcaebb | ||
|
|
88d01e1652 | ||
|
|
f197b674c8 | ||
|
|
9edf09d984 | ||
|
|
98f4ad8758 | ||
|
|
c624e58a52 | ||
|
|
2b6a405622 | ||
|
|
9b9edf29eb | ||
|
|
ee920b29e4 | ||
|
|
df328b80a4 | ||
|
|
8a127db5fb | ||
|
|
a17df66f73 | ||
|
|
d690d861c3 | ||
|
|
d695d61f3a | ||
|
|
e0ade83eb2 | ||
|
|
87466ff3c0 | ||
|
|
6ad5804dfa | ||
|
|
b85c778904 | ||
|
|
7d63e86312 | ||
|
|
07c239f3b8 | ||
|
|
3dd4c0540a | ||
|
|
d451c79512 | ||
|
|
42e3aac809 | ||
|
|
8d176865b8 | ||
|
|
5a75f72cbe | ||
|
|
2acdd5ba85 | ||
|
|
eb7309d73c | ||
|
|
d00e129312 | ||
|
|
b09ad44098 | ||
|
|
2d0c4f2e9c | ||
|
|
282efc867a | ||
|
|
5e5aac0b48 | ||
|
|
34ff01ab72 | ||
|
|
02c8f08473 | ||
|
|
5a466dbfe7 | ||
|
|
1fa75bf5b4 | ||
|
|
906c6141ea | ||
|
|
962e919636 | ||
|
|
f967770ba1 | ||
|
|
e1ae40edae | ||
|
|
55d4d32d14 | ||
|
|
bc06bb7574 | ||
|
|
82631e01b1 | ||
|
|
87385bb59a | ||
|
|
8c4e722f2c | ||
|
|
4026164992 | ||
|
|
724bc24618 | ||
|
|
406ba5f77d | ||
|
|
6d80dfcee4 | ||
|
|
2fe10c0994 | ||
|
|
5e10dd18c6 | ||
|
|
6c6becd398 | ||
|
|
2df37175be | ||
|
|
6a589c6a46 | ||
|
|
a3c4c4af76 | ||
|
|
6f61e79716 | ||
|
|
3ee5c17152 | ||
|
|
3e7c85ac90 | ||
|
|
0bbdfe5f8f | ||
|
|
a9203a9048 | ||
|
|
fec80518d1 | ||
|
|
f1e2fec476 | ||
|
|
acd6444a97 | ||
|
|
4a30332e8c | ||
|
|
95da346d28 | ||
|
|
5e98c79bff | ||
|
|
bc0e585d84 | ||
|
|
351626b1a3 | ||
|
|
276f367d58 | ||
|
|
ce57e3ce15 | ||
|
|
33b7747f90 | ||
|
|
ff2d9e41c6 | ||
|
|
fae91cdd6e | ||
|
|
17f3e5151e | ||
|
|
c27e674e3e | ||
|
|
1d5ed42e42 | ||
|
|
3db2bd5dd0 | ||
|
|
3ed7d7c408 | ||
|
|
a0dd3a4a26 | ||
|
|
c85c431742 | ||
|
|
22af6f832c | ||
|
|
216acdaa1a | ||
|
|
926f00db2e | ||
|
|
993a73f693 | ||
|
|
a66454e437 | ||
|
|
40f459ba13 | ||
|
|
79bebf6780 | ||
|
|
32f463a00d | ||
|
|
2463e28798 | ||
|
|
a0a70cee4e | ||
|
|
7d94ab0d2e | ||
|
|
317b869c4d | ||
|
|
fbe46d536d | ||
|
|
f52747efb1 | ||
|
|
074e5b657b | ||
|
|
d4188c1576 | ||
|
|
cb37077b69 | ||
|
|
507c62c1e0 | ||
|
|
87c5c6cf54 | ||
|
|
68511542cc | ||
|
|
a0c6c9893b | ||
|
|
943560d276 | ||
|
|
61a8731f19 | ||
|
|
4c2e9c55a9 | ||
|
|
3a3a146365 | ||
|
|
ee4fe8d52d | ||
|
|
177061dbad | ||
|
|
190aa7c4ce | ||
|
|
6d36b5c0b3 | ||
|
|
bbb346a6d1 | ||
|
|
5928852f5c | ||
|
|
002ba3a4a6 | ||
|
|
f78bd811dc | ||
|
|
83e6f06f3a | ||
|
|
6f8cb47796 | ||
|
|
2c6468d80b | ||
|
|
4f67ec757e | ||
|
|
2aa15316b8 | ||
|
|
7a6037bead | ||
|
|
213e43bd97 | ||
|
|
8402c765da | ||
|
|
18ddf4af54 | ||
|
|
c3e4db1a27 | ||
|
|
c33b25ca8f | ||
|
|
060b3829c9 | ||
|
|
c982f7ad54 | ||
|
|
041bb79bd6 | ||
|
|
e74431486a | ||
|
|
62d0ca8c7e | ||
|
|
e3b54a6dac | ||
|
|
233ca7d4ea | ||
|
|
063d5e83c3 | ||
|
|
2e3197fd89 | ||
|
|
0f7c1edf1f | ||
|
|
c4e3df83bd | ||
|
|
6181c1cdb9 | ||
|
|
21d6465ccb | ||
|
|
30ca9d8727 | ||
|
|
846cf29528 | ||
|
|
780c3a1b31 | ||
|
|
2c5aec2594 | ||
|
|
50e7e1c19d | ||
|
|
6646ffa721 | ||
|
|
8e114f600a | ||
|
|
4a219720a8 | ||
|
|
de9d96422c | ||
|
|
f3416a39c4 | ||
|
|
d621fa0dd5 | ||
|
|
e8e718520a | ||
|
|
95b7a65768 | ||
|
|
23cab32a73 | ||
|
|
c1a09e422a | ||
|
|
2e02c7ce5b | ||
|
|
8f5d91b32a | ||
|
|
6bde64f285 | ||
|
|
b6292775b7 | ||
|
|
3c6448617c | ||
|
|
4912167faa | ||
|
|
9b8ce42cf8 | ||
|
|
525c4e72ff | ||
|
|
635a8e7328 | ||
|
|
de1e3eafd1 | ||
|
|
607fabe1c0 | ||
|
|
b754501b83 | ||
|
|
e3c713a414 | ||
|
|
5ef14f40ee | ||
|
|
26beef6d6e | ||
|
|
06af448448 | ||
|
|
a1626fa4a1 | ||
|
|
2991ce874a | ||
|
|
4118d0240d | ||
|
|
924c8c36d5 | ||
|
|
15f9b1f123 | ||
|
|
e88eb1baa5 | ||
|
|
b51aa592da | ||
|
|
52e3426d88 | ||
|
|
717fbc2f39 | ||
|
|
5e971fe593 | ||
|
|
577dfe22ef | ||
|
|
04fe237f14 | ||
|
|
55930f85a7 | ||
|
|
8df1768750 | ||
|
|
fbc42229aa | ||
|
|
e7e238d972 | ||
|
|
00ecfdccbc | ||
|
|
0547dec6eb | ||
|
|
db153611b7 | ||
|
|
1f82297218 | ||
|
|
56a950fbee | ||
|
|
e5f3625c96 | ||
|
|
e47d2d582f | ||
|
|
8014a2c467 | ||
|
|
3db6ca3802 | ||
|
|
0b6b1fee2c | ||
|
|
a666c430f7 | ||
|
|
52e5bf08fd | ||
|
|
88afc19c45 | ||
|
|
7b500bb35a | ||
|
|
2a06ae2e2a | ||
|
|
2aa41ecdf6 | ||
|
|
c5e91c80cb | ||
|
|
65af6751d3 | ||
|
|
dc08335838 | ||
|
|
a0b4b29c22 | ||
|
|
bedbd38c88 | ||
|
|
bf8b1eeec1 | ||
|
|
c17e24ea93 | ||
|
|
574b6bd440 | ||
|
|
78815f1ceb | ||
|
|
7ceb827e8e | ||
|
|
9c0558c986 | ||
|
|
4df4f81cd9 | ||
|
|
3331e09fa8 | ||
|
|
a287efe2ad | ||
|
|
7b6884e083 | ||
|
|
c6af3fff67 | ||
|
|
dcf5bc078f | ||
|
|
53862ffce2 | ||
|
|
e7635ae3f4 | ||
|
|
1f2518e4d4 | ||
|
|
46a00dd234 | ||
|
|
c6c439d7b7 | ||
|
|
2388225b27 | ||
|
|
f0f863f474 | ||
|
|
7fe1156c2d | ||
|
|
95904116ba | ||
|
|
089de0b5e6 | ||
|
|
3b33cede20 | ||
|
|
10e83f309e | ||
|
|
cd6571c9e8 | ||
|
|
a1d03a63e2 | ||
|
|
8ceb270ef5 | ||
|
|
09b5d6225d | ||
|
|
415e83c5d1 | ||
|
|
11bd295874 | ||
|
|
5c20fec1ff | ||
|
|
ce2f6a4ab8 | ||
|
|
e875c72170 | ||
|
|
fa2f6df166 | ||
|
|
525807074b | ||
|
|
58ba392560 | ||
|
|
481583bfaa | ||
|
|
0510c1d5f5 | ||
|
|
17d9b280e6 | ||
|
|
03a23ac910 | ||
|
|
fd2876d496 | ||
|
|
b1a9d00078 | ||
|
|
df34168ccb | ||
|
|
5083ca8496 | ||
|
|
9c47c99dd9 | ||
|
|
a67be7b61b | ||
|
|
9731ff5b8b | ||
|
|
5cfd7b3725 | ||
|
|
639e377241 | ||
|
|
eb6c456843 | ||
|
|
00c1eba07e | ||
|
|
89ee7c98a7 | ||
|
|
d3679dba0a | ||
|
|
6d2bc17dc0 | ||
|
|
de78d995f2 | ||
|
|
07a35b6a86 | ||
|
|
267c460267 | ||
|
|
d4715a067f | ||
|
|
8dbc59062f | ||
|
|
b897500d32 | ||
|
|
c3d9d1849a | ||
|
|
09cbd642d1 | ||
|
|
4eb4dd7dfd | ||
|
|
2aaf75ceb0 | ||
|
|
d1325d6272 | ||
|
|
97bc3ec1d7 | ||
|
|
a96f115e93 | ||
|
|
81bb85457c | ||
|
|
3580f90556 | ||
|
|
d6cb10ee90 | ||
|
|
0c232a4b1c | ||
|
|
2345684755 | ||
|
|
a9eef3af45 | ||
|
|
6e71fbb4aa | ||
|
|
fb4f386b61 | ||
|
|
363c721c49 | ||
|
|
d19137594f | ||
|
|
15be235059 | ||
|
|
f398d9152c | ||
|
|
c5850c85e1 | ||
|
|
2e74d23f34 | ||
|
|
14aa857adf | ||
|
|
af72e05726 | ||
|
|
b0c8cb6a2c | ||
|
|
7665384130 | ||
|
|
5aaa6872b4 | ||
|
|
8c5d428ef5 | ||
|
|
3210dc64c8 | ||
|
|
2c43001f02 | ||
|
|
862f8e07f6 | ||
|
|
33b54e7fea | ||
|
|
a96060406a | ||
|
|
241b26dbe8 | ||
|
|
6fd7030bef | ||
|
|
4cf0e0f742 | ||
|
|
fc2cfccff7 | ||
|
|
95f108cdc8 | ||
|
|
b825780693 | ||
|
|
5a23c75a40 | ||
|
|
779c6ec3b7 | ||
|
|
710fd4c3a0 | ||
|
|
7a5ebe41f2 | ||
|
|
3525d10497 | ||
|
|
08ccf93b26 | ||
|
|
124ebb31f7 | ||
|
|
cfc3332c0a | ||
|
|
63a7bbd490 | ||
|
|
745b6d6f28 | ||
|
|
ede01361e9 | ||
|
|
b133fe6e30 | ||
|
|
db78be41af | ||
|
|
436febd5ff | ||
|
|
da52a855b5 | ||
|
|
d87b559201 | ||
|
|
2fc1a292ab | ||
|
|
eface3c948 | ||
|
|
dcef915314 | ||
|
|
9c6f2ad7c4 | ||
|
|
68c86e5b1a | ||
|
|
73c9a67c0b | ||
|
|
174a0511fa | ||
|
|
3988510d6b | ||
|
|
033c2efde7 | ||
|
|
95f402b600 | ||
|
|
384b018dfa | ||
|
|
c29f5a6e0a | ||
|
|
b0a9438374 | ||
|
|
0fbd434d7c | ||
|
|
9939260597 | ||
|
|
2eb2f49f44 | ||
|
|
c83c5beac6 | ||
|
|
a0dcb7d494 | ||
|
|
b612db5f80 | ||
|
|
c4266f447e | ||
|
|
2d21093e4d | ||
|
|
48585fcd37 | ||
|
|
8481c834c4 | ||
|
|
b6b43348db | ||
|
|
f343213c52 | ||
|
|
de5a2db811 | ||
|
|
e6a432eb18 | ||
|
|
7a14df136c | ||
|
|
49c0062cd5 | ||
|
|
6a7e4be847 | ||
|
|
69a7796c08 | ||
|
|
aa94e89899 | ||
|
|
c23470b57d | ||
|
|
87a2a78d20 | ||
|
|
2263ac7d16 | ||
|
|
a3bcc96162 | ||
|
|
942402992a | ||
|
|
40f365c7d2 | ||
|
|
7460f1fc2c | ||
|
|
4e77a33fe7 | ||
|
|
ae7d95e51d | ||
|
|
61327842cd | ||
|
|
2651587f54 | ||
|
|
2fb50104d4 | ||
|
|
0b4bef9bd3 | ||
|
|
ffda5de57b | ||
|
|
104e8616c5 | ||
|
|
b475eb93eb | ||
|
|
0cd44d1f56 | ||
|
|
efb96a3f45 | ||
|
|
1eb2ad1e4e | ||
|
|
50b5c77458 | ||
|
|
d535154f8c | ||
|
|
99d7b4efa0 | ||
|
|
c4d356d3b5 | ||
|
|
c58fe70a11 | ||
|
|
da03aa6abe | ||
|
|
f76b1ae6b0 | ||
|
|
5178882e40 | ||
|
|
bc812b1b5d | ||
|
|
704ebb3d12 | ||
|
|
3d805ce70e | ||
|
|
6754c88d9a | ||
|
|
26b811b837 | ||
|
|
9df46aa968 | ||
|
|
756cad44b8 | ||
|
|
905a294209 | ||
|
|
0c85abf74d | ||
|
|
f98d3e9ab6 | ||
|
|
40d9c42a65 | ||
|
|
83acd8b389 | ||
|
|
6f7e66a088 | ||
|
|
6a531c9cce | ||
|
|
5d4e8807e4 | ||
|
|
44fbb6baaa | ||
|
|
232e200f8f | ||
|
|
36e5e37f4b | ||
|
|
88fee42777 | ||
|
|
419d5e2694 | ||
|
|
fb687ff857 | ||
|
|
053dc5b664 | ||
|
|
57a376bd2a | ||
|
|
8d6a5b67d8 | ||
|
|
8ae8870710 | ||
|
|
fb1fe5636e | ||
|
|
860eb9060c | ||
|
|
f05f8b2c0a | ||
|
|
e97dd3a19c | ||
|
|
ea9db834af | ||
|
|
5ebdb7288b | ||
|
|
e5be0015b3 | ||
|
|
b63b29ce52 | ||
|
|
b87fe5d509 | ||
|
|
111ffdbefe | ||
|
|
0db15beb52 | ||
|
|
596c85c684 | ||
|
|
110c4497b3 | ||
|
|
48d7844109 | ||
|
|
4f2b812354 | ||
|
|
c634999a01 | ||
|
|
886d3dc28d | ||
|
|
7bd6fcaf56 | ||
|
|
b606aa9c81 | ||
|
|
367002cf4d | ||
|
|
0698aa3ad9 | ||
|
|
ab83b9eb20 | ||
|
|
3649fa51f5 | ||
|
|
a2c65d8ffe | ||
|
|
d617d42018 |
No files matched your search
@@ -4,7 +4,7 @@
|
||||
The compilation of software known as FreeBSD is distributed under the
|
||||
following terms:
|
||||
|
||||
Copyright (C) 1992-2007 The FreeBSD Project. All rights reserved.
|
||||
Copyright (C) 1992-2008 The FreeBSD Project. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -147,14 +147,14 @@ cleanworld:
|
||||
.if ${.CURDIR} == ${.OBJDIR} || ${.CURDIR}/obj == ${.OBJDIR}
|
||||
.if exists(${BW_CANONICALOBJDIR}/)
|
||||
-rm -rf ${BW_CANONICALOBJDIR}/*
|
||||
chflags -R 0 ${BW_CANONICALOBJDIR}
|
||||
-chflags -R 0 ${BW_CANONICALOBJDIR}
|
||||
rm -rf ${BW_CANONICALOBJDIR}/*
|
||||
.endif
|
||||
# To be safe in this case, fall back to a 'make cleandir'
|
||||
${_+_}@cd ${.CURDIR}; ${_MAKE} cleandir
|
||||
.else
|
||||
-rm -rf ${.OBJDIR}/*
|
||||
chflags -R 0 ${.OBJDIR}
|
||||
-chflags -R 0 ${.OBJDIR}
|
||||
rm -rf ${.OBJDIR}/*
|
||||
.endif
|
||||
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ CLEANDIR= cleandir
|
||||
.endif
|
||||
|
||||
CVS?= cvs
|
||||
CVSFLAGS?= -A -P -d -I!
|
||||
CVSFLAGS?= -r RELENG_7_0 -P -d -I!
|
||||
SUP?= /usr/bin/csup
|
||||
SUPFLAGS?= -g -L 2
|
||||
.if defined(SUPHOST)
|
||||
@@ -220,7 +220,7 @@ TMAKE= MAKEOBJDIRPREFIX=${OBJTREE} \
|
||||
# cross-tools stage
|
||||
XMAKE= TOOLS_PREFIX=${WORLDTMP} ${BMAKE} \
|
||||
TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \
|
||||
-DWITHOUT_FORTRAN -DWITHOUT_GDB
|
||||
-DWITHOUT_GDB
|
||||
|
||||
# world stage
|
||||
WMAKEENV= ${CROSSENV} \
|
||||
|
||||
+37
-3
@@ -14,11 +14,24 @@
|
||||
# The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last.
|
||||
#
|
||||
|
||||
# 20080126: oldcard.4 removal
|
||||
OLD_FILES+=usr/share/man/man4/card.4.gz
|
||||
OLD_FILES+=usr/share/man/man4/oldcard.4.gz
|
||||
# 20071207: Merged with fortunes-o.real
|
||||
OLD_FILES+=usr/share/games/fortune/fortunes2-o
|
||||
OLD_FILES+=usr/share/games/fortune/fortunes2-o.dat
|
||||
# 20071206: Disabled static versions of libkse by default
|
||||
.if ${DEFAULT_THREAD_LIB} != "libkse" && ${MK_LIBTHR} != "no"
|
||||
OLD_FILES+=usr/lib/libkse.a
|
||||
OLD_FILES+=usr/lib/libkse_p.a
|
||||
OLD_FILES+=usr/lib/libkse_pic.a
|
||||
.endif
|
||||
# 20070930: rename of cached to nscd
|
||||
OLD_FILES+=etc/cached.conf
|
||||
OLD_FILES+=etc/rc.d/cached
|
||||
OLD_FILES+=usr/sbin/cached
|
||||
OLD_FILES+=usr/share/man/man5/cached.conf.5
|
||||
OLD_FILES+=usr/share/man/man8/cached.8
|
||||
OLD_FILES+=usr/share/man/man5/cached.conf.5.gz
|
||||
OLD_FILES+=usr/share/man/man8/cached.8.gz
|
||||
# 20070807: removal of PowerPC specific header file.
|
||||
.if ${TARGET_ARCH} == "powerpc"
|
||||
OLD_FILES+=usr/include/machine/interruptvar.h
|
||||
@@ -579,11 +592,17 @@ OLD_FILES+=usr/share/man/man4/kame.4.gz
|
||||
# 20070201: remove libmytinfo link
|
||||
OLD_FILES+=usr/lib/libmytinfo.a
|
||||
OLD_FILES+=usr/lib/libmytinfo.so
|
||||
OLD_FILES+=usr/lib/libmytinfo_p.a
|
||||
OLD_FILES+=usr/lib/libmytinfo_p.a
|
||||
OLD_FILES+=usr/lib/libmytinfow.a
|
||||
OLD_FILES+=usr/lib/libmytinfow.so
|
||||
OLD_FILES+=usr/lib/libmytinfow_p.a
|
||||
.if ${TARGET_ARCH} == "amd64"
|
||||
OLD_FILES+=usr/lib32/libmytinfo.a
|
||||
OLD_FILES+=usr/lib32/libmytinfo.so
|
||||
OLD_FILES+=usr/lib32/libmytinfo_p.a
|
||||
OLD_FILES+=usr/lib32/libmytinfow.a
|
||||
OLD_FILES+=usr/lib32/libmytinfow.so
|
||||
OLD_FILES+=usr/lib32/libmytinfow_p.a
|
||||
.endif
|
||||
# 20070128: remove vnconfig
|
||||
OLD_FILES+=usr/sbin/vnconfig
|
||||
@@ -3946,6 +3965,21 @@ OLD_FILES+=usr/libdata/msdosfs/koi8u2dos
|
||||
# - usr/share/tmac/mm/locale
|
||||
# - usr/share/tmac/mm/se_locale
|
||||
# - var/yp/Makefile
|
||||
|
||||
# 20071120: shared library version bump
|
||||
OLD_LIBS+=usr/lib/libasn1.so.8
|
||||
OLD_LIBS+=usr/lib/libgssapi.so.8
|
||||
OLD_LIBS+=usr/lib/libgssapi_krb5.so.8
|
||||
OLD_LIBS+=usr/lib/libhdb.so.8
|
||||
OLD_LIBS+=usr/lib/libkadm5clnt.so.8
|
||||
OLD_LIBS+=usr/lib/libkadm5srv.so.8
|
||||
OLD_LIBS+=usr/lib/libkafs5.so.8
|
||||
OLD_LIBS+=usr/lib/libkrb5.so.8
|
||||
OLD_LIBS+=usr/lib/libobjc.so.2
|
||||
.if ${TARGET_ARCH} == "amd64"
|
||||
OLD_LIBS+=usr/lib32/libgssapi.so.8
|
||||
OLD_LIBS+=usr/lib32/libobjc.so.2
|
||||
.endif
|
||||
# 20070519: GCC 4.2
|
||||
OLD_LIBS+=usr/lib/libg2c.a
|
||||
OLD_LIBS+=usr/lib/libg2c.so
|
||||
|
||||
@@ -8,18 +8,101 @@ Items affecting the ports and packages system can be found in
|
||||
/usr/ports/UPDATING. Please read that file before running
|
||||
portupgrade.
|
||||
|
||||
NOTE TO PEOPLE WHO THINK THAT FreeBSD 7.x IS SLOW:
|
||||
FreeBSD 7.x has many debugging features turned on, in
|
||||
both the kernel and userland. These features attempt to detect
|
||||
incorrect use of system primitives, and encourage loud failure
|
||||
through extra sanity checking and fail stop semantics. They
|
||||
also substantially impact system performance. If you want to
|
||||
do performance measurement, benchmarking, and optimization,
|
||||
you'll want to turn them off. This includes various WITNESS-
|
||||
related kernel options, INVARIANTS, malloc debugging flags
|
||||
in userland, and various verbose features in the kernel. Many
|
||||
developers choose to disable these features on build machines
|
||||
to maximize performance.
|
||||
20090422: p12 FreeBSD-SA-09:07.libc, FreeBSD-SA-09:08.openssl
|
||||
Don't leak information via uninitialized space in db(3) records.
|
||||
[09:07]
|
||||
|
||||
Sanity-check string lengths in order to stop OpenSSL crashing
|
||||
when printing corrupt BMPString or UniversalString objects. [09:08]
|
||||
|
||||
20090323: p11 FreeBSD-SA-09:06.ktimer, FreeBSD-EN-09:01.kenv
|
||||
Correctly sanity-check timer IDs. [SA-09:06]
|
||||
|
||||
Limit the size of malloced buffer when dumping environment
|
||||
variables. [EN-09:01]
|
||||
|
||||
20090216: p10 FreeBSD-SA-09:05.telnetd
|
||||
Correctly scrub telnetd's environment.
|
||||
|
||||
20090113: p9 FreeBSD-SA-09:03.ntpd, FreeBSD-SA-09:04.bind
|
||||
Correct ntpd cryptographic signature bypass. [09:03]
|
||||
|
||||
Correct BIND DNSSEC incorrect checks for malformed
|
||||
signatures. [09:04]
|
||||
|
||||
20090107: p8 FreeBSD-SA-09:01.lukemftpd, FreeBSD-SA-09:02.openssl
|
||||
Prevent cross-site forgery attacks on lukemftpd(8) due to splitting
|
||||
long commands into multiple requests. [09:01]
|
||||
|
||||
Fix incorrect OpenSSL checks for malformed signatures. [09:02]
|
||||
|
||||
20081223: p7 FreeBSD-SA-08:12.ftpd, FreeBSD-SA-08:13.protosw
|
||||
Prevent cross-site forgery attacks on ftpd(8) due to splitting
|
||||
long commands into multiple requests. [08:12]
|
||||
|
||||
Avoid calling uninitialized function pointers in protocol switch
|
||||
code. [08:13]
|
||||
|
||||
20081124: p6 FreeBSD-SA-08:11.arc4random
|
||||
Make sure arc4random(9) is properly seeded when /etc/rc.d/initrandom
|
||||
returns.
|
||||
|
||||
20081002: p5 FreeBSD-SA-08:10.nd6
|
||||
Default to ignoring potentially evil IPv6 Neighbor Solicitation
|
||||
messages.
|
||||
|
||||
20080903: p4 FreeBSD-SA-08:07.amd64, FreeBSD-SA-08:08.nmount,
|
||||
FreeBSD-SA-08:09.icmp6
|
||||
Fix amd64 local privilege escalation. [08:07]
|
||||
Fix nmount(2) local privilege escalation. [08:08]
|
||||
Fix IPv6 remote kernel panics. [08:09]
|
||||
|
||||
20080713: p3 FreeBSD-SA-08:06.bind
|
||||
Improve randomization in BIND to prevent response spoofing.
|
||||
|
||||
20080619: p2 FreeBSD-EN-08:02.tcp
|
||||
Fix errors in the padding of TCP options.
|
||||
|
||||
20080416: p1 FreeBSD-SA-08:05.openssh
|
||||
Fix logic error in sshd(8) concerning the handling of failed
|
||||
attempts to bind ports for X11 forwarding.
|
||||
|
||||
20080226:
|
||||
FreeBSD 7.0-RELEASE
|
||||
|
||||
20080214: FreeBSD-SA-08:02.sendfile
|
||||
Fix sendfile(2) write-only file permission bypass.
|
||||
|
||||
20080114: FreeBSD-SA-08:01.pty, FreeBSD-SA-08:02.libc
|
||||
Fix issues which allow snooping on ptys. [08:01]
|
||||
Fix an off-by-one error in inet_network(3). [08:02]
|
||||
|
||||
20071126:
|
||||
The AT keyboard emulation of sunkbd(4) has been turned on
|
||||
by default. In order to make the special symbols of the Sun
|
||||
keyboards driven by sunkbd(4) work under X these now have
|
||||
to be configured the same way as Sun USB keyboards driven
|
||||
by ukbd(4) (which also does AT keyboard emulation), f.e.:
|
||||
|
||||
Option "XkbLayout" "us"
|
||||
Option "XkbRules" "xorg"
|
||||
Option "XkbSymbols" "pc(pc105)+sun_vndr/usb(sun_usb)+us"
|
||||
|
||||
20071028:
|
||||
It has been decided that it is desirable to provide ABI
|
||||
backwards compatibility to the FreeBSD 4/5/6 versions of the
|
||||
PCIOCGETCONF, PCIOCREAD and PCIOCWRITE IOCTLs, which was
|
||||
broken with the introduction of PCI domain support (see the
|
||||
20070930 entry). Unfortunately, this required the ABI of
|
||||
PCIOCGETCONF to be broken again in order to be able to
|
||||
provide backwards compatibility to the old version of that
|
||||
IOCTL. Thus consumers of PCIOCGETCONF have to be recompiled
|
||||
again. As for prominent ports this affects neither pciutils
|
||||
nor xorg-server this time, the hal port needs to be rebuilt
|
||||
however.
|
||||
|
||||
20071010:
|
||||
RELENG_7 branched.
|
||||
|
||||
20071009:
|
||||
Setting WITHOUT_LIBPTHREAD now means WITHOUT_LIBKSE and
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@
|
||||
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 9, 2002
|
||||
.Dd May 12, 2007
|
||||
.Dt MV 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
||||
+23
-9
@@ -74,6 +74,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ps.h"
|
||||
|
||||
#define _PATH_PTS "/dev/pts/"
|
||||
|
||||
#define W_SEP " \t" /* "Whitespace" list separators */
|
||||
#define T_SEP "," /* "Terminate-element" list separators */
|
||||
|
||||
@@ -705,9 +707,9 @@ addelem_pid(struct listinfo *inf, const char *elem)
|
||||
|
||||
/*-
|
||||
* The user can specify a device via one of three formats:
|
||||
* 1) fully qualified, e.g.: /dev/ttyp0 /dev/console
|
||||
* 2) missing "/dev", e.g.: ttyp0 console
|
||||
* 3) two-letters, e.g.: p0 co
|
||||
* 1) fully qualified, e.g.: /dev/ttyp0 /dev/console /dev/pts/0
|
||||
* 2) missing "/dev", e.g.: ttyp0 console pts/0
|
||||
* 3) two-letters, e.g.: p0 co 0
|
||||
* (matching letters that would be seen in the "TT" column)
|
||||
*/
|
||||
static int
|
||||
@@ -715,10 +717,11 @@ addelem_tty(struct listinfo *inf, const char *elem)
|
||||
{
|
||||
const char *ttypath;
|
||||
struct stat sb;
|
||||
char pathbuf[PATH_MAX], pathbuf2[PATH_MAX];
|
||||
char pathbuf[PATH_MAX], pathbuf2[PATH_MAX], pathbuf3[PATH_MAX];
|
||||
|
||||
ttypath = NULL;
|
||||
pathbuf2[0] = '\0';
|
||||
pathbuf3[0] = '\0';
|
||||
switch (*elem) {
|
||||
case '/':
|
||||
ttypath = elem;
|
||||
@@ -735,6 +738,8 @@ addelem_tty(struct listinfo *inf, const char *elem)
|
||||
ttypath = pathbuf;
|
||||
if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0)
|
||||
break;
|
||||
if (strncmp(pathbuf, _PATH_PTS, strlen(_PATH_PTS)) == 0)
|
||||
break;
|
||||
if (strcmp(pathbuf, _PATH_CONSOLE) == 0)
|
||||
break;
|
||||
/* Check to see if /dev/tty${elem} exists */
|
||||
@@ -745,21 +750,30 @@ addelem_tty(struct listinfo *inf, const char *elem)
|
||||
ttypath = NULL;
|
||||
break;
|
||||
}
|
||||
/* Check to see if /dev/pts/${elem} exists */
|
||||
strlcpy(pathbuf3, _PATH_PTS, sizeof(pathbuf3));
|
||||
strlcat(pathbuf3, elem, sizeof(pathbuf3));
|
||||
if (stat(pathbuf3, &sb) == 0 && S_ISCHR(sb.st_mode)) {
|
||||
/* No need to repeat stat() && S_ISCHR() checks */
|
||||
ttypath = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ttypath) {
|
||||
if (stat(ttypath, &sb) == -1) {
|
||||
if (pathbuf2[0] != '\0')
|
||||
warn("%s and %s", pathbuf2, ttypath);
|
||||
if (pathbuf3[0] != '\0')
|
||||
warn("%s, %s, and %s", pathbuf3, pathbuf2,
|
||||
ttypath);
|
||||
else
|
||||
warn("%s", ttypath);
|
||||
optfatal = 1;
|
||||
return (0);
|
||||
}
|
||||
if (!S_ISCHR(sb.st_mode)) {
|
||||
if (pathbuf2[0] != '\0')
|
||||
warnx("%s and %s: Not a terminal", pathbuf2,
|
||||
ttypath);
|
||||
if (pathbuf3[0] != '\0')
|
||||
warnx("%s, %s, and %s: Not a terminal",
|
||||
pathbuf3, pathbuf2, ttypath);
|
||||
else
|
||||
warnx("%s: Not a terminal", ttypath);
|
||||
optfatal = 1;
|
||||
|
||||
+382
-275
File diff suppressed because it is too large.
Load diff
@@ -1,8 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
BINDIR= /bin
|
||||
|
||||
PROG= uuidgen
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
@@ -1,80 +0,0 @@
|
||||
.\" Copyright (c) 2002 Marcel Moolenaar
|
||||
.\" 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 AUTHOR ``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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd September 7, 2005
|
||||
.Dt UUIDGEN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm uuidgen
|
||||
.Nd generate universally unique identifiers
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 1
|
||||
.Op Fl n Ar count
|
||||
.Op Fl o Ar filename
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility by default generates a single DCE version 1
|
||||
universally unique identifier (UUID),
|
||||
also known as a globally unique identifier (GUID).
|
||||
The UUID is written to stdout by default.
|
||||
The following options can be used to change the behaviour of
|
||||
.Nm :
|
||||
.Bl -tag -width indent
|
||||
.It Fl 1
|
||||
This option only has effect if multiple identifiers are to be generated and
|
||||
instructs
|
||||
.Nm
|
||||
to not generate them in batch, but one at a time.
|
||||
.It Fl n
|
||||
This option controls the number of identifiers generated.
|
||||
By default, multiple
|
||||
identifiers are generated in batch.
|
||||
.It Fl o
|
||||
Redirect output to
|
||||
.Ar filename
|
||||
instead of stdout.
|
||||
.El
|
||||
.Pp
|
||||
Batched generation yields a dense set of identifiers in such a way that there
|
||||
is no identifier that is larger than the smallest identifier in the set and
|
||||
smaller than the largest identifier in the set and that is not already in the
|
||||
set.
|
||||
.Pp
|
||||
When generating the identifiers one at a time, the identifiers will be close
|
||||
to each other, but operating system latency and processing time will be
|
||||
reflected in the distance between two successive identifiers.
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr uuidgen 2 ,
|
||||
.Xr uuid 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command first appeared in
|
||||
.Fx 5.0 .
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Marcel Moolenaar
|
||||
* 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 AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <uuid.h>
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "usage: uuidgen [-1] [-n count] [-o filename]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp;
|
||||
uuid_t *store, *uuid;
|
||||
char *p;
|
||||
int ch, count, i, iterate;
|
||||
|
||||
count = -1; /* no count yet */
|
||||
fp = stdout; /* default output file */
|
||||
iterate = 0; /* not one at a time */
|
||||
while ((ch = getopt(argc, argv, "1n:o:")) != -1)
|
||||
switch (ch) {
|
||||
case '1':
|
||||
iterate = 1;
|
||||
break;
|
||||
case 'n':
|
||||
if (count > 0)
|
||||
usage();
|
||||
count = strtol(optarg, &p, 10);
|
||||
if (*p != 0 || count < 1)
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
if (fp != stdout)
|
||||
errx(1, "multiple output files not allowed");
|
||||
fp = fopen(optarg, "w");
|
||||
if (fp == NULL)
|
||||
err(1, "fopen");
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc)
|
||||
usage();
|
||||
|
||||
if (count == -1)
|
||||
count = 1;
|
||||
|
||||
store = (uuid_t*)malloc(sizeof(uuid_t) * count);
|
||||
if (store == NULL)
|
||||
err(1, "malloc()");
|
||||
|
||||
if (!iterate) {
|
||||
/* Get them all in a single batch */
|
||||
if (uuidgen(store, count) != 0)
|
||||
err(1, "uuidgen()");
|
||||
} else {
|
||||
uuid = store;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (uuidgen(uuid++, 1) != 0)
|
||||
err(1, "uuidgen()");
|
||||
}
|
||||
}
|
||||
|
||||
uuid = store;
|
||||
while (count--) {
|
||||
uuid_to_string(uuid++, &p, NULL);
|
||||
fprintf(fp, "%s\n", p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
free(store);
|
||||
if (fp != stdout)
|
||||
fclose(fp);
|
||||
return (0);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_DEVID_H_
|
||||
#define _OPENSOLARIS_DEVID_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/disk.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct ddi_devid {
|
||||
char devid[DISK_IDENT_SIZE];
|
||||
} ddi_devid_t;
|
||||
|
||||
typedef struct devid_nmlist {
|
||||
char devname[MAXPATHLEN];
|
||||
dev_t dev;
|
||||
} devid_nmlist_t;
|
||||
|
||||
int devid_str_decode(char *devidstr, ddi_devid_t *retdevid,
|
||||
char **retminor_name);
|
||||
int devid_deviceid_to_nmlist(char *search_path, ddi_devid_t devid,
|
||||
char *minor_name, devid_nmlist_t **retlist);
|
||||
void devid_str_free(char *str);
|
||||
void devid_free(ddi_devid_t devid);
|
||||
void devid_free_nmlist(devid_nmlist_t *list);
|
||||
int devid_get(int fd, ddi_devid_t *retdevid);
|
||||
int devid_get_minor_name(int fd, char **retminor_name);
|
||||
char *devid_str_encode(ddi_devid_t devid, char *minor_name);
|
||||
|
||||
#endif /* !_OPENSOLARIS_DEVID_H_ */
|
||||
@@ -1,35 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_FSSHARE_H_
|
||||
#define _OPENSOLARIS_FSSHARE_H_
|
||||
|
||||
int fsshare(const char *, const char *, const char *);
|
||||
int fsunshare(const char *, const char *);
|
||||
|
||||
#endif /* !_OPENSOLARIS_FSSHARE_H_ */
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef _LIBINTL_H_
|
||||
#define _LIBINTL_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define textdomain(domain) 0
|
||||
#define gettext(...) (__VA_ARGS__)
|
||||
#define dgettext(domain, ...) (__VA_ARGS__)
|
||||
|
||||
#endif /* !_SOLARIS_H_ */
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _OPENSOLARIS_MNTTAB_H_
|
||||
#define _OPENSOLARIS_MNTTAB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <paths.h>
|
||||
|
||||
#define MNTTAB _PATH_DEVNULL
|
||||
#define MNT_LINE_MAX 1024
|
||||
|
||||
struct mnttab {
|
||||
char *mnt_special;
|
||||
char *mnt_mountp;
|
||||
char *mnt_fstype;
|
||||
char *mnt_mntopts;
|
||||
};
|
||||
|
||||
int getmntany(FILE *fd, struct mnttab *mgetp, struct mnttab *mrefp);
|
||||
|
||||
#endif /* !_OPENSOLARIS_MNTTAB_H_ */
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef _OPENSOLARIS_PRIV_H_
|
||||
#define _OPENSOLARIS_PRIV_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define PRIV_SYS_CONFIG 0
|
||||
|
||||
static __inline int
|
||||
priv_ineffect(priv)
|
||||
{
|
||||
|
||||
assert(priv == PRIV_SYS_CONFIG);
|
||||
return (geteuid() == 0);
|
||||
}
|
||||
|
||||
#endif /* !_OPENSOLARIS_PRIV_H_ */
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _SOLARIS_H_
|
||||
#define _SOLARIS_H_
|
||||
|
||||
#include <sys/ccompile.h>
|
||||
|
||||
#define dirent64 dirent
|
||||
|
||||
#endif /* !_SOLARIS_H_ */
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _ZONE_H_
|
||||
#define _ZONE_H_
|
||||
|
||||
#include <sys/zone.h>
|
||||
|
||||
#endif /* !_ZONE_H_ */
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Ricardo Correia. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <umem.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static umem_nofail_callback_t *nofail_cb = NULL;
|
||||
|
||||
struct umem_cache {
|
||||
umem_constructor_t *constructor;
|
||||
umem_destructor_t *destructor;
|
||||
void *callback_data;
|
||||
size_t bufsize;
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple stub for umem_alloc(). The callback isn't expected to return.
|
||||
*/
|
||||
void *umem_alloc(size_t size, int flags)
|
||||
{
|
||||
assert(flags == UMEM_DEFAULT || flags == UMEM_NOFAIL);
|
||||
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
void *ret = malloc(size);
|
||||
if(ret == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_zalloc().
|
||||
*/
|
||||
void *umem_zalloc(size_t size, int flags)
|
||||
{
|
||||
assert(flags == UMEM_DEFAULT || flags == UMEM_NOFAIL);
|
||||
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
void *ret = calloc(1, size);
|
||||
if(ret == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_free().
|
||||
*/
|
||||
void umem_free(void *buf, size_t size)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_nofail_callback().
|
||||
*/
|
||||
void umem_nofail_callback(umem_nofail_callback_t *callback)
|
||||
{
|
||||
nofail_cb = callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_create().
|
||||
*/
|
||||
umem_cache_t *umem_cache_create(char *debug_name, size_t bufsize, size_t align, umem_constructor_t *constructor, umem_destructor_t *destructor, umem_reclaim_t *reclaim, void *callback_data, void *source, int cflags)
|
||||
{
|
||||
assert(source == NULL);
|
||||
|
||||
umem_cache_t *cache = malloc(sizeof(umem_cache_t));
|
||||
if(cache == NULL)
|
||||
return NULL;
|
||||
|
||||
cache->constructor = constructor;
|
||||
cache->destructor = destructor;
|
||||
cache->callback_data = callback_data;
|
||||
cache->bufsize = bufsize;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_alloc(). The nofail callback isn't expected to return.
|
||||
*/
|
||||
void *umem_cache_alloc(umem_cache_t *cache, int flags)
|
||||
{
|
||||
void *buf = malloc(cache->bufsize);
|
||||
if(buf == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
if(cache->constructor != NULL) {
|
||||
if(cache->constructor(buf, cache->callback_data, flags) != 0) {
|
||||
free(buf);
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_free().
|
||||
*/
|
||||
void umem_cache_free(umem_cache_t *cache, void *buffer)
|
||||
{
|
||||
if(cache->destructor != NULL)
|
||||
cache->destructor(buffer, cache->callback_data);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_destroy().
|
||||
*/
|
||||
void umem_cache_destroy(umem_cache_t *cache)
|
||||
{
|
||||
free(cache);
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _UMEM_H
|
||||
#define _UMEM_H
|
||||
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UMEM_DEFAULT 0x0000 /* normal -- may fail */
|
||||
#define UMEM_NOFAIL 0x0100 /* Never fails -- may call exit(2) */
|
||||
|
||||
#define UMEM_FLAGS 0xffff /* all settable umem flags */
|
||||
|
||||
extern void *umem_alloc(size_t, int);
|
||||
extern void *umem_alloc_align(size_t, size_t, int);
|
||||
extern void *umem_zalloc(size_t, int);
|
||||
extern void umem_free(void *, size_t);
|
||||
extern void umem_free_align(void *, size_t);
|
||||
|
||||
/*
|
||||
* Flags for umem_cache_create()
|
||||
*/
|
||||
#define UMC_NOTOUCH 0x00010000
|
||||
#define UMC_NODEBUG 0x00020000
|
||||
#define UMC_NOMAGAZINE 0x00040000
|
||||
#define UMC_NOHASH 0x00080000
|
||||
|
||||
struct umem_cache; /* cache structure is opaque to umem clients */
|
||||
|
||||
typedef struct umem_cache umem_cache_t;
|
||||
typedef int umem_constructor_t(void *, void *, int);
|
||||
typedef void umem_destructor_t(void *, void *);
|
||||
typedef void umem_reclaim_t(void *);
|
||||
|
||||
typedef int umem_nofail_callback_t(void);
|
||||
#define UMEM_CALLBACK_RETRY 0
|
||||
#define UMEM_CALLBACK_EXIT(status) (0x100 | ((status) & 0xFF))
|
||||
|
||||
extern void umem_nofail_callback(umem_nofail_callback_t *);
|
||||
|
||||
extern umem_cache_t *umem_cache_create(char *, size_t,
|
||||
size_t, umem_constructor_t *, umem_destructor_t *, umem_reclaim_t *,
|
||||
void *, void *, int);
|
||||
extern void umem_cache_destroy(umem_cache_t *);
|
||||
|
||||
extern void *umem_cache_alloc(umem_cache_t *, int);
|
||||
extern void umem_cache_free(umem_cache_t *, void *);
|
||||
|
||||
extern void umem_reap(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _UMEM_H */
|
||||
@@ -1,119 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgeom.h>
|
||||
#include <devid.h>
|
||||
|
||||
int
|
||||
devid_str_decode(char *devidstr, ddi_devid_t *retdevid, char **retminor_name)
|
||||
{
|
||||
|
||||
if (strlcpy(retdevid->devid, devidstr, sizeof(retdevid->devid)) >=
|
||||
sizeof(retdevid->devid)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
*retminor_name = strdup("");
|
||||
if (*retminor_name == NULL);
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
devid_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name,
|
||||
devid_nmlist_t **retlist)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
char *dst;
|
||||
|
||||
if (g_get_name(devid.devid, path, sizeof(path)) == -1)
|
||||
return (errno);
|
||||
*retlist = malloc(sizeof(**retlist));
|
||||
if (*retlist == NULL)
|
||||
return (ENOMEM);
|
||||
if (strlcpy((*retlist)[0].devname, path,
|
||||
sizeof((*retlist)[0].devname)) >= sizeof((*retlist)[0].devname)) {
|
||||
free(*retlist);
|
||||
return (ENAMETOOLONG);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
devid_str_free(char *str)
|
||||
{
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
void
|
||||
devid_free(ddi_devid_t devid)
|
||||
{
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
void
|
||||
devid_free_nmlist(devid_nmlist_t *list)
|
||||
{
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
int
|
||||
devid_get(int fd, ddi_devid_t *retdevid)
|
||||
{
|
||||
|
||||
if (ioctl(fd, DIOCGIDENT, retdevid->devid) == -1)
|
||||
return (errno);
|
||||
if (retdevid->devid[0] == '\0')
|
||||
return (ENOENT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
devid_get_minor_name(int fd, char **retminor_name)
|
||||
{
|
||||
|
||||
*retminor_name = strdup("");
|
||||
if (*retminor_name == NULL)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
devid_str_encode(ddi_devid_t devid, char *minor_name)
|
||||
{
|
||||
|
||||
return (strdup(devid.devid));
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <assert.h>
|
||||
#include <pathnames.h> /* _PATH_MOUNTDPID */
|
||||
#include <fsshare.h>
|
||||
|
||||
#define FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
|
||||
#define OPTSSIZE 1024
|
||||
#define MAXLINESIZE (PATH_MAX + OPTSSIZE)
|
||||
|
||||
static void
|
||||
restart_mountd(void)
|
||||
{
|
||||
struct pidfh *pfh;
|
||||
pid_t mountdpid;
|
||||
|
||||
pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
|
||||
if (pfh != NULL) {
|
||||
/* Mountd is not running. */
|
||||
pidfile_remove(pfh);
|
||||
return;
|
||||
}
|
||||
if (errno != EEXIST) {
|
||||
/* Cannot open pidfile for some reason. */
|
||||
return;
|
||||
}
|
||||
/* We have mountd(8) PID in mountdpid varible. */
|
||||
kill(mountdpid, SIGHUP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one line from a file. Skip comments, empty lines and a line with a
|
||||
* mountpoint specified in the 'skip' argument.
|
||||
*/
|
||||
static char *
|
||||
getline(FILE *fd, const char *skip)
|
||||
{
|
||||
static char line[MAXLINESIZE];
|
||||
size_t len, skiplen;
|
||||
char *s, last;
|
||||
|
||||
if (skip != NULL)
|
||||
skiplen = strlen(skip);
|
||||
for (;;) {
|
||||
s = fgets(line, sizeof(line), fd);
|
||||
if (s == NULL)
|
||||
return (NULL);
|
||||
/* Skip empty lines and comments. */
|
||||
if (line[0] == '\n' || line[0] == '#')
|
||||
continue;
|
||||
len = strlen(line);
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
last = line[skiplen];
|
||||
/* Skip the given mountpoint. */
|
||||
if (skip != NULL && strncmp(skip, line, skiplen) == 0 &&
|
||||
(last == '\t' || last == ' ' || last == '\0')) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function translate options to a format acceptable by exports(5), eg.
|
||||
*
|
||||
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org 69.147.83.54
|
||||
*
|
||||
* Accepted input formats:
|
||||
*
|
||||
* ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,freefall.freebsd.org
|
||||
* ro network=192.168.0.0 mask=255.255.255.0 maproot=0 freefall.freebsd.org
|
||||
* -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,freefall.freebsd.org
|
||||
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org
|
||||
*
|
||||
* Recognized keywords:
|
||||
*
|
||||
* ro, maproot, mapall, mask, network, alldirs, public, webnfs, index, quiet
|
||||
*
|
||||
*/
|
||||
static const char *known_opts[] = { "ro", "maproot", "mapall", "mask",
|
||||
"network", "alldirs", "public", "webnfs", "index", "quiet", NULL };
|
||||
static char *
|
||||
translate_opts(const char *shareopts)
|
||||
{
|
||||
static char newopts[OPTSSIZE];
|
||||
char oldopts[OPTSSIZE];
|
||||
char *o, *s = NULL;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
|
||||
strlcpy(oldopts, shareopts, sizeof(oldopts));
|
||||
newopts[0] = '\0';
|
||||
s = oldopts;
|
||||
while ((o = strsep(&s, "-, ")) != NULL) {
|
||||
if (o[0] == '\0')
|
||||
continue;
|
||||
for (i = 0; known_opts[i] != NULL; i++) {
|
||||
len = strlen(known_opts[i]);
|
||||
if (strncmp(known_opts[i], o, len) == 0 &&
|
||||
(o[len] == '\0' || o[len] == '=')) {
|
||||
strlcat(newopts, "-", sizeof(newopts));
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(newopts, o, sizeof(newopts));
|
||||
strlcat(newopts, " ", sizeof(newopts));
|
||||
}
|
||||
return (newopts);
|
||||
}
|
||||
|
||||
static int
|
||||
fsshare_main(const char *file, const char *mountpoint, const char *shareopts,
|
||||
int share)
|
||||
{
|
||||
char tmpfile[PATH_MAX];
|
||||
char *line;
|
||||
FILE *newfd, *oldfd;
|
||||
int fd, error;
|
||||
|
||||
newfd = oldfd = NULL;
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
* Create temporary file in the same directory, so we can atomically
|
||||
* rename it.
|
||||
*/
|
||||
if (strlcpy(tmpfile, file, sizeof(tmpfile)) >= sizeof(tmpfile))
|
||||
return (ENAMETOOLONG);
|
||||
if (strlcat(tmpfile, ".XXXXXXXX", sizeof(tmpfile)) >= sizeof(tmpfile))
|
||||
return (ENAMETOOLONG);
|
||||
fd = mkstemp(tmpfile);
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
/*
|
||||
* File name is random, so we don't really need file lock now, but it
|
||||
* will be needed after rename(2).
|
||||
*/
|
||||
error = flock(fd, LOCK_EX);
|
||||
assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
|
||||
newfd = fdopen(fd, "r+");
|
||||
assert(newfd != NULL);
|
||||
/* Open old exports file. */
|
||||
oldfd = fopen(file, "r");
|
||||
if (oldfd == NULL) {
|
||||
if (share) {
|
||||
if (errno != ENOENT) {
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If there is no exports file, ignore the error. */
|
||||
if (errno == ENOENT)
|
||||
errno = 0;
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
error = flock(fileno(oldfd), LOCK_EX);
|
||||
assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/* Place big, fat warning at the begining of the file. */
|
||||
fprintf(newfd, "%s", FILE_HEADER);
|
||||
while (oldfd != NULL && (line = getline(oldfd, mountpoint)) != NULL)
|
||||
fprintf(newfd, "%s\n", line);
|
||||
if (oldfd != NULL && ferror(oldfd) != 0) {
|
||||
error = ferror(oldfd);
|
||||
goto out;
|
||||
}
|
||||
if (ferror(newfd) != 0) {
|
||||
error = ferror(newfd);
|
||||
goto out;
|
||||
}
|
||||
if (share) {
|
||||
fprintf(newfd, "%s\t%s\n", mountpoint,
|
||||
translate_opts(shareopts));
|
||||
}
|
||||
|
||||
out:
|
||||
if (error != 0)
|
||||
unlink(tmpfile);
|
||||
else {
|
||||
if (rename(tmpfile, file) == -1) {
|
||||
error = errno;
|
||||
unlink(tmpfile);
|
||||
} else {
|
||||
/*
|
||||
* Send SIGHUP to mountd, but unlock exports file later.
|
||||
*/
|
||||
restart_mountd();
|
||||
}
|
||||
}
|
||||
if (oldfd != NULL) {
|
||||
flock(fileno(oldfd), LOCK_UN);
|
||||
fclose(oldfd);
|
||||
}
|
||||
if (newfd != NULL) {
|
||||
flock(fileno(newfd), LOCK_UN);
|
||||
fclose(newfd);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the given mountpoint to the given exports file.
|
||||
*/
|
||||
int
|
||||
fsshare(const char *file, const char *mountpoint, const char *shareopts)
|
||||
{
|
||||
|
||||
return (fsshare_main(file, mountpoint, shareopts, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given mountpoint from the given exports file.
|
||||
*/
|
||||
int
|
||||
fsunshare(const char *file, const char *mountpoint)
|
||||
{
|
||||
|
||||
return (fsshare_main(file, mountpoint, NULL, 0));
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "@(#)mkdirp.c 1.15 06/01/04 SMI"
|
||||
|
||||
/*
|
||||
* Creates directory and it's parents if the parents do not
|
||||
* exist yet.
|
||||
*
|
||||
* Returns -1 if fails for reasons other than non-existing
|
||||
* parents.
|
||||
* Does NOT simplify pathnames with . or .. in them.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static char *simplify(const char *str);
|
||||
|
||||
int
|
||||
mkdirp(const char *d, mode_t mode)
|
||||
{
|
||||
char *endptr, *ptr, *slash, *str;
|
||||
|
||||
str = simplify(d);
|
||||
|
||||
/* If space couldn't be allocated for the simplified names, return. */
|
||||
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
|
||||
/* Try to make the directory */
|
||||
|
||||
if (mkdir(str, mode) == 0) {
|
||||
free(str);
|
||||
return (0);
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
endptr = strrchr(str, '\0');
|
||||
slash = strrchr(str, '/');
|
||||
|
||||
/* Search upward for the non-existing parent */
|
||||
|
||||
while (slash != NULL) {
|
||||
|
||||
ptr = slash;
|
||||
*ptr = '\0';
|
||||
|
||||
/* If reached an existing parent, break */
|
||||
|
||||
if (access(str, F_OK) == 0)
|
||||
break;
|
||||
|
||||
/* If non-existing parent */
|
||||
|
||||
else {
|
||||
slash = strrchr(str, '/');
|
||||
|
||||
/* If under / or current directory, make it. */
|
||||
|
||||
if (slash == NULL || slash == str) {
|
||||
if (mkdir(str, mode) != 0 && errno != EEXIST) {
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create directories starting from upmost non-existing parent */
|
||||
|
||||
while ((ptr = strchr(str, '\0')) != endptr) {
|
||||
*ptr = '/';
|
||||
if (mkdir(str, mode) != 0 && errno != EEXIST) {
|
||||
/*
|
||||
* If the mkdir fails because str already
|
||||
* exists (EEXIST), then str has the form
|
||||
* "existing-dir/..", and this is really
|
||||
* ok. (Remember, this loop is creating the
|
||||
* portion of the path that didn't exist)
|
||||
*/
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* simplify - given a pathname, simplify that path by removing
|
||||
* duplicate contiguous slashes.
|
||||
*
|
||||
* A simplified copy of the argument is returned to the
|
||||
* caller, or NULL is returned on error.
|
||||
*
|
||||
* The caller should handle error reporting based upon the
|
||||
* returned vlaue, and should free the returned value,
|
||||
* when appropriate.
|
||||
*/
|
||||
|
||||
static char *
|
||||
simplify(const char *str)
|
||||
{
|
||||
int i;
|
||||
size_t mbPathlen; /* length of multi-byte path */
|
||||
size_t wcPathlen; /* length of wide-character path */
|
||||
wchar_t *wptr; /* scratch pointer */
|
||||
wchar_t *wcPath; /* wide-character version of the path */
|
||||
char *mbPath; /* The copy fo the path to be returned */
|
||||
|
||||
/*
|
||||
* bail out if there is nothing there.
|
||||
*/
|
||||
|
||||
if (!str)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Get a copy of the argument.
|
||||
*/
|
||||
|
||||
if ((mbPath = strdup(str)) == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* convert the multi-byte version of the path to a
|
||||
* wide-character rendering, for doing our figuring.
|
||||
*/
|
||||
|
||||
mbPathlen = strlen(mbPath);
|
||||
|
||||
if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) {
|
||||
free(mbPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) {
|
||||
free(mbPath);
|
||||
free(wcPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove duplicate slashes first ("//../" -> "/")
|
||||
*/
|
||||
|
||||
for (wptr = wcPath, i = 0; i < wcPathlen; i++) {
|
||||
*wptr++ = wcPath[i];
|
||||
|
||||
if (wcPath[i] == '/') {
|
||||
i++;
|
||||
|
||||
while (wcPath[i] == '/') {
|
||||
i++;
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
*wptr = '\0';
|
||||
|
||||
/*
|
||||
* now convert back to the multi-byte format.
|
||||
*/
|
||||
|
||||
if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) {
|
||||
free(mbPath);
|
||||
free(wcPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
free(wcPath);
|
||||
return (mbPath);
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements Solaris compatible getmntany() and hasmntopt()
|
||||
* functions.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static char *
|
||||
mntopt(char **p)
|
||||
{
|
||||
char *cp = *p;
|
||||
char *retstr;
|
||||
|
||||
while (*cp && isspace(*cp))
|
||||
cp++;
|
||||
|
||||
retstr = cp;
|
||||
while (*cp && *cp != ',')
|
||||
cp++;
|
||||
|
||||
if (*cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
}
|
||||
|
||||
*p = cp;
|
||||
return (retstr);
|
||||
}
|
||||
|
||||
char *
|
||||
hasmntopt(struct mnttab *mnt, char *opt)
|
||||
{
|
||||
char tmpopts[MNT_LINE_MAX];
|
||||
char *f, *opts = tmpopts;
|
||||
|
||||
if (mnt->mnt_mntopts == NULL)
|
||||
return (NULL);
|
||||
(void) strcpy(opts, mnt->mnt_mntopts);
|
||||
f = mntopt(&opts);
|
||||
for (; *f; f = mntopt(&opts)) {
|
||||
if (strncmp(opt, f, strlen(opt)) == 0)
|
||||
return (f - tmpopts + mnt->mnt_mntopts);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
optadd(char *mntopts, size_t size, const char *opt)
|
||||
{
|
||||
|
||||
if (mntopts[0] != '\0')
|
||||
strlcat(mntopts, ",", size);
|
||||
strlcat(mntopts, opt, size);
|
||||
}
|
||||
|
||||
int
|
||||
getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
|
||||
{
|
||||
static struct statfs *sfs = NULL;
|
||||
static char mntopts[MNTMAXSTR];
|
||||
struct opt *o;
|
||||
long i, n, flags;
|
||||
|
||||
if (sfs != NULL) {
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
}
|
||||
mntopts[0] = '\0';
|
||||
|
||||
n = getfsstat(NULL, 0, MNT_NOWAIT);
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
n = sizeof(*sfs) * (n + 8);
|
||||
sfs = malloc(n);
|
||||
if (sfs == NULL)
|
||||
return (-1);
|
||||
n = getfsstat(sfs, n, MNT_WAIT);
|
||||
if (n == -1) {
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
if (mrefp->mnt_special != NULL &&
|
||||
strcmp(mrefp->mnt_special, sfs[i].f_mntfromname) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (mrefp->mnt_mountp != NULL &&
|
||||
strcmp(mrefp->mnt_mountp, sfs[i].f_mntonname) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (mrefp->mnt_fstype != NULL &&
|
||||
strcmp(mrefp->mnt_fstype, sfs[i].f_fstypename) != 0) {
|
||||
continue;
|
||||
}
|
||||
flags = sfs[i].f_flags;
|
||||
#define OPTADD(opt) optadd(mntopts, sizeof(mntopts), (opt))
|
||||
if (flags & MNT_RDONLY)
|
||||
OPTADD(MNTOPT_RO);
|
||||
else
|
||||
OPTADD(MNTOPT_RW);
|
||||
if (flags & MNT_NOSUID)
|
||||
OPTADD(MNTOPT_NOSUID);
|
||||
else
|
||||
OPTADD(MNTOPT_SETUID);
|
||||
if (flags & MNT_UPDATE)
|
||||
OPTADD(MNTOPT_REMOUNT);
|
||||
if (flags & MNT_NOATIME)
|
||||
OPTADD(MNTOPT_NOATIME);
|
||||
else
|
||||
OPTADD(MNTOPT_ATIME);
|
||||
OPTADD(MNTOPT_NOXATTR);
|
||||
if (flags & MNT_NOEXEC)
|
||||
OPTADD(MNTOPT_NOEXEC);
|
||||
else
|
||||
OPTADD(MNTOPT_EXEC);
|
||||
#undef OPTADD
|
||||
mgetp->mnt_special = sfs[i].f_mntfromname;
|
||||
mgetp->mnt_mountp = sfs[i].f_mntonname;
|
||||
mgetp->mnt_fstype = sfs[i].f_fstypename;
|
||||
mgetp->mnt_mntopts = mntopts;
|
||||
return (0);
|
||||
}
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
return (-1);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements Solaris compatible zmount() function.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void
|
||||
build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
|
||||
size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (*iovlen < 0)
|
||||
return;
|
||||
i = *iovlen;
|
||||
*iov = realloc(*iov, sizeof(**iov) * (i + 2));
|
||||
if (*iov == NULL) {
|
||||
*iovlen = -1;
|
||||
return;
|
||||
}
|
||||
(*iov)[i].iov_base = strdup(name);
|
||||
(*iov)[i].iov_len = strlen(name) + 1;
|
||||
i++;
|
||||
(*iov)[i].iov_base = val;
|
||||
if (len == (size_t)-1) {
|
||||
if (val != NULL)
|
||||
len = strlen(val) + 1;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
(*iov)[i].iov_len = (int)len;
|
||||
*iovlen = ++i;
|
||||
}
|
||||
|
||||
int
|
||||
zmount(const char *spec, const char *dir, int mflag, char *fstype,
|
||||
char *dataptr, int datalen, char *optptr, int optlen)
|
||||
{
|
||||
struct iovec *iov;
|
||||
char *optstr, *os, *p;
|
||||
int iovlen, rv;
|
||||
|
||||
assert(spec != NULL);
|
||||
assert(dir != NULL);
|
||||
assert(mflag == 0);
|
||||
assert(fstype != NULL);
|
||||
assert(strcmp(fstype, MNTTYPE_ZFS) == 0);
|
||||
assert(dataptr == NULL);
|
||||
assert(datalen == 0);
|
||||
assert(optptr != NULL);
|
||||
assert(optlen > 0);
|
||||
|
||||
optstr = strdup(optptr);
|
||||
assert(optptr != NULL);
|
||||
|
||||
iov = NULL;
|
||||
iovlen = 0;
|
||||
build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
|
||||
(size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "from", __DECONST(char *, spec), (size_t)-1);
|
||||
for (p = optstr; p != NULL; strsep(&p, ",/ "))
|
||||
build_iovec(&iov, &iovlen, p, NULL, (size_t)-1);
|
||||
rv = nmount(iov, iovlen, 0);
|
||||
free(optstr);
|
||||
return (rv);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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 AUTHORS 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 AUTHORS 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/zone.h>
|
||||
|
||||
int
|
||||
getzoneid(void)
|
||||
{
|
||||
size_t size;
|
||||
int jailid;
|
||||
|
||||
/* Information that we are in jail or not is enough for our needs. */
|
||||
size = sizeof(jailid);
|
||||
if (sysctlbyname("security.jail.jailed", &jailid, &size, NULL, 0) == -1)
|
||||
assert(!"No security.jail.jailed sysctl!");
|
||||
return (jailid);
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
Unless otherwise noted, all files in this distribution are released
|
||||
under the Common Development and Distribution License (CDDL).
|
||||
Exceptions are noted within the associated source files.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
|
||||
|
||||
1. Definitions.
|
||||
|
||||
1.1. "Contributor" means each individual or entity that creates
|
||||
or contributes to the creation of Modifications.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Original
|
||||
Software, prior Modifications used by a Contributor (if any),
|
||||
and the Modifications made by that particular Contributor.
|
||||
|
||||
1.3. "Covered Software" means (a) the Original Software, or (b)
|
||||
Modifications, or (c) the combination of files containing
|
||||
Original Software with files containing Modifications, in
|
||||
each case including portions thereof.
|
||||
|
||||
1.4. "Executable" means the Covered Software in any form other
|
||||
than Source Code.
|
||||
|
||||
1.5. "Initial Developer" means the individual or entity that first
|
||||
makes Original Software available under this License.
|
||||
|
||||
1.6. "Larger Work" means a work which combines Covered Software or
|
||||
portions thereof with code not governed by the terms of this
|
||||
License.
|
||||
|
||||
1.7. "License" means this document.
|
||||
|
||||
1.8. "Licensable" means having the right to grant, to the maximum
|
||||
extent possible, whether at the time of the initial grant or
|
||||
subsequently acquired, any and all of the rights conveyed
|
||||
herein.
|
||||
|
||||
1.9. "Modifications" means the Source Code and Executable form of
|
||||
any of the following:
|
||||
|
||||
A. Any file that results from an addition to, deletion from or
|
||||
modification of the contents of a file containing Original
|
||||
Software or previous Modifications;
|
||||
|
||||
B. Any new file that contains any part of the Original
|
||||
Software or previous Modifications; or
|
||||
|
||||
C. Any new file that is contributed or otherwise made
|
||||
available under the terms of this License.
|
||||
|
||||
1.10. "Original Software" means the Source Code and Executable
|
||||
form of computer software code that is originally released
|
||||
under this License.
|
||||
|
||||
1.11. "Patent Claims" means any patent claim(s), now owned or
|
||||
hereafter acquired, including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by
|
||||
grantor.
|
||||
|
||||
1.12. "Source Code" means (a) the common form of computer software
|
||||
code in which modifications are made and (b) associated
|
||||
documentation included in or with such code.
|
||||
|
||||
1.13. "You" (or "Your") means an individual or a legal entity
|
||||
exercising rights under, and complying with all of the terms
|
||||
of, this License. For legal entities, "You" includes any
|
||||
entity which controls, is controlled by, or is under common
|
||||
control with You. For purposes of this definition,
|
||||
"control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by
|
||||
contract or otherwise, or (b) ownership of more than fifty
|
||||
percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants.
|
||||
|
||||
2.1. The Initial Developer Grant.
|
||||
|
||||
Conditioned upon Your compliance with Section 3.1 below and
|
||||
subject to third party intellectual property claims, the Initial
|
||||
Developer hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Initial Developer, to use,
|
||||
reproduce, modify, display, perform, sublicense and
|
||||
distribute the Original Software (or portions thereof),
|
||||
with or without Modifications, and/or as part of a Larger
|
||||
Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using or
|
||||
selling of Original Software, to make, have made, use,
|
||||
practice, sell, and offer for sale, and/or otherwise
|
||||
dispose of the Original Software (or portions thereof).
|
||||
|
||||
(c) The licenses granted in Sections 2.1(a) and (b) are
|
||||
effective on the date Initial Developer first distributes
|
||||
or otherwise makes the Original Software available to a
|
||||
third party under the terms of this License.
|
||||
|
||||
(d) Notwithstanding Section 2.1(b) above, no patent license is
|
||||
granted: (1) for code that You delete from the Original
|
||||
Software, or (2) for infringements caused by: (i) the
|
||||
modification of the Original Software, or (ii) the
|
||||
combination of the Original Software with other software
|
||||
or devices.
|
||||
|
||||
2.2. Contributor Grant.
|
||||
|
||||
Conditioned upon Your compliance with Section 3.1 below and
|
||||
subject to third party intellectual property claims, each
|
||||
Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Contributor to use, reproduce,
|
||||
modify, display, perform, sublicense and distribute the
|
||||
Modifications created by such Contributor (or portions
|
||||
thereof), either on an unmodified basis, with other
|
||||
Modifications, as Covered Software and/or as part of a
|
||||
Larger Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using, or
|
||||
selling of Modifications made by that Contributor either
|
||||
alone and/or in combination with its Contributor Version
|
||||
(or portions of such combination), to make, use, sell,
|
||||
offer for sale, have made, and/or otherwise dispose of:
|
||||
(1) Modifications made by that Contributor (or portions
|
||||
thereof); and (2) the combination of Modifications made by
|
||||
that Contributor with its Contributor Version (or portions
|
||||
of such combination).
|
||||
|
||||
(c) The licenses granted in Sections 2.2(a) and 2.2(b) are
|
||||
effective on the date Contributor first distributes or
|
||||
otherwise makes the Modifications available to a third
|
||||
party.
|
||||
|
||||
(d) Notwithstanding Section 2.2(b) above, no patent license is
|
||||
granted: (1) for any code that Contributor has deleted
|
||||
from the Contributor Version; (2) for infringements caused
|
||||
by: (i) third party modifications of Contributor Version,
|
||||
or (ii) the combination of Modifications made by that
|
||||
Contributor with other software (except as part of the
|
||||
Contributor Version) or other devices; or (3) under Patent
|
||||
Claims infringed by Covered Software in the absence of
|
||||
Modifications made by that Contributor.
|
||||
|
||||
3. Distribution Obligations.
|
||||
|
||||
3.1. Availability of Source Code.
|
||||
|
||||
Any Covered Software that You distribute or otherwise make
|
||||
available in Executable form must also be made available in Source
|
||||
Code form and that Source Code form must be distributed only under
|
||||
the terms of this License. You must include a copy of this
|
||||
License with every copy of the Source Code form of the Covered
|
||||
Software You distribute or otherwise make available. You must
|
||||
inform recipients of any such Covered Software in Executable form
|
||||
as to how they can obtain such Covered Software in Source Code
|
||||
form in a reasonable manner on or through a medium customarily
|
||||
used for software exchange.
|
||||
|
||||
3.2. Modifications.
|
||||
|
||||
The Modifications that You create or to which You contribute are
|
||||
governed by the terms of this License. You represent that You
|
||||
believe Your Modifications are Your original creation(s) and/or
|
||||
You have sufficient rights to grant the rights conveyed by this
|
||||
License.
|
||||
|
||||
3.3. Required Notices.
|
||||
|
||||
You must include a notice in each of Your Modifications that
|
||||
identifies You as the Contributor of the Modification. You may
|
||||
not remove or alter any copyright, patent or trademark notices
|
||||
contained within the Covered Software, or any notices of licensing
|
||||
or any descriptive text giving attribution to any Contributor or
|
||||
the Initial Developer.
|
||||
|
||||
3.4. Application of Additional Terms.
|
||||
|
||||
You may not offer or impose any terms on any Covered Software in
|
||||
Source Code form that alters or restricts the applicable version
|
||||
of this License or the recipients' rights hereunder. You may
|
||||
choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of
|
||||
Covered Software. However, you may do so only on Your own behalf,
|
||||
and not on behalf of the Initial Developer or any Contributor.
|
||||
You must make it absolutely clear that any such warranty, support,
|
||||
indemnity or liability obligation is offered by You alone, and You
|
||||
hereby agree to indemnify the Initial Developer and every
|
||||
Contributor for any liability incurred by the Initial Developer or
|
||||
such Contributor as a result of warranty, support, indemnity or
|
||||
liability terms You offer.
|
||||
|
||||
3.5. Distribution of Executable Versions.
|
||||
|
||||
You may distribute the Executable form of the Covered Software
|
||||
under the terms of this License or under the terms of a license of
|
||||
Your choice, which may contain terms different from this License,
|
||||
provided that You are in compliance with the terms of this License
|
||||
and that the license for the Executable form does not attempt to
|
||||
limit or alter the recipient's rights in the Source Code form from
|
||||
the rights set forth in this License. If You distribute the
|
||||
Covered Software in Executable form under a different license, You
|
||||
must make it absolutely clear that any terms which differ from
|
||||
this License are offered by You alone, not by the Initial
|
||||
Developer or Contributor. You hereby agree to indemnify the
|
||||
Initial Developer and every Contributor for any liability incurred
|
||||
by the Initial Developer or such Contributor as a result of any
|
||||
such terms You offer.
|
||||
|
||||
3.6. Larger Works.
|
||||
|
||||
You may create a Larger Work by combining Covered Software with
|
||||
other code not governed by the terms of this License and
|
||||
distribute the Larger Work as a single product. In such a case,
|
||||
You must make sure the requirements of this License are fulfilled
|
||||
for the Covered Software.
|
||||
|
||||
4. Versions of the License.
|
||||
|
||||
4.1. New Versions.
|
||||
|
||||
Sun Microsystems, Inc. is the initial license steward and may
|
||||
publish revised and/or new versions of this License from time to
|
||||
time. Each version will be given a distinguishing version number.
|
||||
Except as provided in Section 4.3, no one other than the license
|
||||
steward has the right to modify this License.
|
||||
|
||||
4.2. Effect of New Versions.
|
||||
|
||||
You may always continue to use, distribute or otherwise make the
|
||||
Covered Software available under the terms of the version of the
|
||||
License under which You originally received the Covered Software.
|
||||
If the Initial Developer includes a notice in the Original
|
||||
Software prohibiting it from being distributed or otherwise made
|
||||
available under any subsequent version of the License, You must
|
||||
distribute and make the Covered Software available under the terms
|
||||
of the version of the License under which You originally received
|
||||
the Covered Software. Otherwise, You may also choose to use,
|
||||
distribute or otherwise make the Covered Software available under
|
||||
the terms of any subsequent version of the License published by
|
||||
the license steward.
|
||||
|
||||
4.3. Modified Versions.
|
||||
|
||||
When You are an Initial Developer and You want to create a new
|
||||
license for Your Original Software, You may create and use a
|
||||
modified version of this License if You: (a) rename the license
|
||||
and remove any references to the name of the license steward
|
||||
(except to note that the license differs from this License); and
|
||||
(b) otherwise make it clear that the license contains terms which
|
||||
differ from this License.
|
||||
|
||||
5. DISCLAIMER OF WARRANTY.
|
||||
|
||||
COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
|
||||
BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
|
||||
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
|
||||
SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
|
||||
PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||
PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
|
||||
COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
|
||||
INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
|
||||
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
|
||||
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
|
||||
ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
|
||||
DISCLAIMER.
|
||||
|
||||
6. TERMINATION.
|
||||
|
||||
6.1. This License and the rights granted hereunder will terminate
|
||||
automatically if You fail to comply with terms herein and fail to
|
||||
cure such breach within 30 days of becoming aware of the breach.
|
||||
Provisions which, by their nature, must remain in effect beyond
|
||||
the termination of this License shall survive.
|
||||
|
||||
6.2. If You assert a patent infringement claim (excluding
|
||||
declaratory judgment actions) against Initial Developer or a
|
||||
Contributor (the Initial Developer or Contributor against whom You
|
||||
assert such claim is referred to as "Participant") alleging that
|
||||
the Participant Software (meaning the Contributor Version where
|
||||
the Participant is a Contributor or the Original Software where
|
||||
the Participant is the Initial Developer) directly or indirectly
|
||||
infringes any patent, then any and all rights granted directly or
|
||||
indirectly to You by such Participant, the Initial Developer (if
|
||||
the Initial Developer is not the Participant) and all Contributors
|
||||
under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
|
||||
notice from Participant terminate prospectively and automatically
|
||||
at the expiration of such 60 day notice period, unless if within
|
||||
such 60 day period You withdraw Your claim with respect to the
|
||||
Participant Software against such Participant either unilaterally
|
||||
or pursuant to a written agreement with Participant.
|
||||
|
||||
6.3. In the event of termination under Sections 6.1 or 6.2 above,
|
||||
all end user licenses that have been validly granted by You or any
|
||||
distributor hereunder prior to termination (excluding licenses
|
||||
granted to You by any distributor) shall survive termination.
|
||||
|
||||
7. LIMITATION OF LIABILITY.
|
||||
|
||||
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
|
||||
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
|
||||
INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
|
||||
COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
|
||||
LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
|
||||
CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
|
||||
LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
|
||||
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
|
||||
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
|
||||
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
|
||||
INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
|
||||
APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
|
||||
NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
|
||||
APPLY TO YOU.
|
||||
|
||||
8. U.S. GOVERNMENT END USERS.
|
||||
|
||||
The Covered Software is a "commercial item," as that term is
|
||||
defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
|
||||
computer software" (as that term is defined at 48
|
||||
C.F.R. 252.227-7014(a)(1)) and "commercial computer software
|
||||
documentation" as such terms are used in 48 C.F.R. 12.212
|
||||
(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
|
||||
C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
|
||||
U.S. Government End Users acquire Covered Software with only those
|
||||
rights set forth herein. This U.S. Government Rights clause is in
|
||||
lieu of, and supersedes, any other FAR, DFAR, or other clause or
|
||||
provision that addresses Government rights in computer software
|
||||
under this License.
|
||||
|
||||
9. MISCELLANEOUS.
|
||||
|
||||
This License represents the complete agreement concerning subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. This License shall be governed
|
||||
by the law of the jurisdiction specified in a notice contained
|
||||
within the Original Software (except to the extent applicable law,
|
||||
if any, provides otherwise), excluding such jurisdiction's
|
||||
conflict-of-law provisions. Any litigation relating to this
|
||||
License shall be subject to the jurisdiction of the courts located
|
||||
in the jurisdiction and venue specified in a notice contained
|
||||
within the Original Software, with the losing party responsible
|
||||
for costs, including, without limitation, court costs and
|
||||
reasonable attorneys' fees and expenses. The application of the
|
||||
United Nations Convention on Contracts for the International Sale
|
||||
of Goods is expressly excluded. Any law or regulation which
|
||||
provides that the language of a contract shall be construed
|
||||
against the drafter shall not apply to this License. You agree
|
||||
that You alone are responsible for compliance with the United
|
||||
States export administration regulations (and the export control
|
||||
laws and regulation of any other countries) when You use,
|
||||
distribute or otherwise make available any Covered Software.
|
||||
|
||||
10. RESPONSIBILITY FOR CLAIMS.
|
||||
|
||||
As between Initial Developer and the Contributors, each party is
|
||||
responsible for claims and damages arising, directly or
|
||||
indirectly, out of its utilization of rights under this License
|
||||
and You agree to work with Initial Developer and Contributors to
|
||||
distribute such responsibility on an equitable basis. Nothing
|
||||
herein is intended or shall be deemed to constitute any admission
|
||||
of liability.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
|
||||
DISTRIBUTION LICENSE (CDDL)
|
||||
|
||||
For Covered Software in this distribution, this License shall
|
||||
be governed by the laws of the State of California (excluding
|
||||
conflict-of-law provisions).
|
||||
|
||||
Any litigation relating to this License shall be subject to the
|
||||
jurisdiction of the Federal Courts of the Northern District of
|
||||
California and the state courts of the State of California, with
|
||||
venue lying in Santa Clara County, California.
|
||||
@@ -1,93 +0,0 @@
|
||||
'\" te
|
||||
.\" CDDL HEADER START
|
||||
.\"
|
||||
.\" The contents of this file are subject to the terms of the
|
||||
.\" Common Development and Distribution License (the "License").
|
||||
.\" You may not use this file except in compliance with the License.
|
||||
.\"
|
||||
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
.\" or http://www.opensolaris.org/os/licensing.
|
||||
.\" See the License for the specific language governing permissions
|
||||
.\" and limitations under the License.
|
||||
.\"
|
||||
.\" When distributing Covered Code, include this CDDL HEADER in each
|
||||
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
.\" If applicable, add the following below this CDDL HEADER, with the
|
||||
.\" fields enclosed by brackets "[]" replaced with your own identifying
|
||||
.\" information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
.\"
|
||||
.\" CDDL HEADER END
|
||||
.\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
|
||||
.TH zdb 1M "31 Oct 2005" "SunOS 5.11" "System Administration Commands"
|
||||
.SH NAME
|
||||
zdb \- ZFS debugger
|
||||
.SH SYNOPSIS
|
||||
.LP
|
||||
.nf
|
||||
\fBzdb\fR \fIpool\fR
|
||||
.fi
|
||||
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
The \fBzdb\fR command is used by support engineers to diagnose failures and gather statistics. Since the \fBZFS\fR file system is always consistent on disk and is self-repairing, \fBzdb\fR should only be run under the direction by a support engineer.
|
||||
.LP
|
||||
If no arguments are specified, \fBzdb\fR, performs basic consistency checks on the pool and associated datasets, and report any problems detected.
|
||||
.LP
|
||||
Any options supported by this command are internal to Sun and subject to change at any time.
|
||||
.SH EXIT STATUS
|
||||
.LP
|
||||
The following exit values are returned:
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB0\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
The pool is consistent.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB1\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
An error was detected.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB2\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
Invalid command line options were specified.
|
||||
.RE
|
||||
|
||||
.SH ATTRIBUTES
|
||||
.LP
|
||||
See \fBattributes\fR(5) for descriptions of the following attributes:
|
||||
.sp
|
||||
|
||||
.sp
|
||||
.TS
|
||||
tab() box;
|
||||
cw(2.75i) |cw(2.75i)
|
||||
lw(2.75i) |lw(2.75i)
|
||||
.
|
||||
ATTRIBUTE TYPEATTRIBUTE VALUE
|
||||
_
|
||||
AvailabilitySUNWzfsu
|
||||
_
|
||||
Interface StabilityUnstable
|
||||
.TE
|
||||
|
||||
.SH SEE ALSO
|
||||
.LP
|
||||
\fBzfs\fR(1M), \fBzpool\fR(1M), \fBattributes\fR(5)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Print intent log header and statistics.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/zil.h>
|
||||
#include <sys/zil_impl.h>
|
||||
|
||||
extern uint8_t dump_opt[256];
|
||||
|
||||
static void
|
||||
print_log_bp(const blkptr_t *bp, const char *prefix)
|
||||
{
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
|
||||
sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
|
||||
(void) printf("%s%s\n", prefix, blkbuf);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
|
||||
{
|
||||
time_t crtime = lr->lr_crtime[0];
|
||||
char *name = (char *)(lr + 1);
|
||||
char *link = name + strlen(name) + 1;
|
||||
|
||||
if (txtype == TX_SYMLINK)
|
||||
(void) printf("\t\t\t%s -> %s\n", name, link);
|
||||
else
|
||||
(void) printf("\t\t\t%s\n", name);
|
||||
|
||||
(void) printf("\t\t\t%s", ctime(&crtime));
|
||||
(void) printf("\t\t\tdoid %llu, foid %llu, mode %llo\n",
|
||||
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_foid,
|
||||
(longlong_t)lr->lr_mode);
|
||||
(void) printf("\t\t\tuid %llu, gid %llu, gen %llu, rdev 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
|
||||
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tdoid %llu, name %s\n",
|
||||
(u_longlong_t)lr->lr_doid, (char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tdoid %llu, link_obj %llu, name %s\n",
|
||||
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
|
||||
(char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
|
||||
{
|
||||
char *snm = (char *)(lr + 1);
|
||||
char *tnm = snm + strlen(snm) + 1;
|
||||
|
||||
(void) printf("\t\t\tsdoid %llu, tdoid %llu\n",
|
||||
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
|
||||
(void) printf("\t\t\tsrc %s tgt %s\n", snm, tnm);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
|
||||
{
|
||||
char *data, *dlimit;
|
||||
blkptr_t *bp = &lr->lr_blkptr;
|
||||
char buf[SPA_MAXBLOCKSIZE];
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
int error;
|
||||
|
||||
(void) printf("\t\t\tfoid %llu, offset 0x%llx,"
|
||||
" length 0x%llx, blkoff 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blkoff);
|
||||
|
||||
if (verbose < 5)
|
||||
return;
|
||||
|
||||
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
||||
(void) printf("\t\t\thas blkptr, %s\n",
|
||||
bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
|
||||
"will claim" : "won't claim");
|
||||
print_log_bp(bp, "\t\t\t");
|
||||
if (bp->blk_birth == 0) {
|
||||
bzero(buf, sizeof (buf));
|
||||
} else {
|
||||
zbookmark_t zb;
|
||||
|
||||
ASSERT3U(bp->blk_cksum.zc_word[ZIL_ZC_OBJSET], ==,
|
||||
dmu_objset_id(zilog->zl_os));
|
||||
|
||||
zb.zb_objset = bp->blk_cksum.zc_word[ZIL_ZC_OBJSET];
|
||||
zb.zb_object = 0;
|
||||
zb.zb_level = -1;
|
||||
zb.zb_blkid = bp->blk_cksum.zc_word[ZIL_ZC_SEQ];
|
||||
|
||||
error = zio_wait(zio_read(NULL, zilog->zl_spa,
|
||||
bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
|
||||
ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
|
||||
if (error)
|
||||
return;
|
||||
}
|
||||
data = buf + lr->lr_blkoff;
|
||||
} else {
|
||||
data = (char *)(lr + 1);
|
||||
}
|
||||
|
||||
dlimit = data + MIN(lr->lr_length,
|
||||
(verbose < 6 ? 20 : SPA_MAXBLOCKSIZE));
|
||||
|
||||
(void) printf("\t\t\t");
|
||||
while (data < dlimit) {
|
||||
if (isprint(*data))
|
||||
(void) printf("%c ", *data);
|
||||
else
|
||||
(void) printf("%2X", *data);
|
||||
data++;
|
||||
}
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tfoid %llu, offset 0x%llx, length 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
|
||||
{
|
||||
time_t atime = (time_t)lr->lr_atime[0];
|
||||
time_t mtime = (time_t)lr->lr_mtime[0];
|
||||
|
||||
(void) printf("\t\t\tfoid %llu, mask 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
|
||||
|
||||
if (lr->lr_mask & AT_MODE) {
|
||||
(void) printf("\t\t\tAT_MODE %llo\n",
|
||||
(longlong_t)lr->lr_mode);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_UID) {
|
||||
(void) printf("\t\t\tAT_UID %llu\n",
|
||||
(u_longlong_t)lr->lr_uid);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_GID) {
|
||||
(void) printf("\t\t\tAT_GID %llu\n",
|
||||
(u_longlong_t)lr->lr_gid);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_SIZE) {
|
||||
(void) printf("\t\t\tAT_SIZE %llu\n",
|
||||
(u_longlong_t)lr->lr_size);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_ATIME) {
|
||||
(void) printf("\t\t\tAT_ATIME %llu.%09llu %s",
|
||||
(u_longlong_t)lr->lr_atime[0],
|
||||
(u_longlong_t)lr->lr_atime[1],
|
||||
ctime(&atime));
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_MTIME) {
|
||||
(void) printf("\t\t\tAT_MTIME %llu.%09llu %s",
|
||||
(u_longlong_t)lr->lr_mtime[0],
|
||||
(u_longlong_t)lr->lr_mtime[1],
|
||||
ctime(&mtime));
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tfoid %llu, aclcnt %llu\n",
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
|
||||
}
|
||||
|
||||
typedef void (*zil_prt_rec_func_t)();
|
||||
typedef struct zil_rec_info {
|
||||
zil_prt_rec_func_t zri_print;
|
||||
char *zri_name;
|
||||
uint64_t zri_count;
|
||||
} zil_rec_info_t;
|
||||
|
||||
static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
||||
{ NULL, "Total " },
|
||||
{ zil_prt_rec_create, "TX_CREATE " },
|
||||
{ zil_prt_rec_create, "TX_MKDIR " },
|
||||
{ zil_prt_rec_create, "TX_MKXATTR " },
|
||||
{ zil_prt_rec_create, "TX_SYMLINK " },
|
||||
{ zil_prt_rec_remove, "TX_REMOVE " },
|
||||
{ zil_prt_rec_remove, "TX_RMDIR " },
|
||||
{ zil_prt_rec_link, "TX_LINK " },
|
||||
{ zil_prt_rec_rename, "TX_RENAME " },
|
||||
{ zil_prt_rec_write, "TX_WRITE " },
|
||||
{ zil_prt_rec_truncate, "TX_TRUNCATE" },
|
||||
{ zil_prt_rec_setattr, "TX_SETATTR " },
|
||||
{ zil_prt_rec_acl, "TX_ACL " },
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
|
||||
{
|
||||
int txtype;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
txtype = lr->lrc_txtype;
|
||||
|
||||
ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
|
||||
ASSERT(lr->lrc_txg);
|
||||
|
||||
(void) printf("\t\t%s len %6llu, txg %llu, seq %llu\n",
|
||||
zil_rec_info[txtype].zri_name,
|
||||
(u_longlong_t)lr->lrc_reclen,
|
||||
(u_longlong_t)lr->lrc_txg,
|
||||
(u_longlong_t)lr->lrc_seq);
|
||||
|
||||
if (txtype && verbose >= 3)
|
||||
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
|
||||
|
||||
zil_rec_info[txtype].zri_count++;
|
||||
zil_rec_info[0].zri_count++;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
|
||||
{
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
char *claim;
|
||||
|
||||
if (verbose <= 3)
|
||||
return;
|
||||
|
||||
if (verbose >= 5) {
|
||||
(void) strcpy(blkbuf, ", ");
|
||||
sprintf_blkptr(blkbuf + strlen(blkbuf),
|
||||
BP_SPRINTF_LEN - strlen(blkbuf), bp);
|
||||
} else {
|
||||
blkbuf[0] = '\0';
|
||||
}
|
||||
|
||||
if (claim_txg != 0)
|
||||
claim = "already claimed";
|
||||
else if (bp->blk_birth >= spa_first_txg(zilog->zl_spa))
|
||||
claim = "will claim";
|
||||
else
|
||||
claim = "won't claim";
|
||||
|
||||
(void) printf("\tBlock seqno %llu, %s%s\n",
|
||||
(u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
print_log_stats(int verbose)
|
||||
{
|
||||
int i, w, p10;
|
||||
|
||||
if (verbose > 3)
|
||||
(void) printf("\n");
|
||||
|
||||
if (zil_rec_info[0].zri_count == 0)
|
||||
return;
|
||||
|
||||
for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10)
|
||||
w++;
|
||||
|
||||
for (i = 0; i < TX_MAX_TYPE; i++)
|
||||
if (zil_rec_info[i].zri_count || verbose >= 3)
|
||||
(void) printf("\t\t%s %*llu\n",
|
||||
zil_rec_info[i].zri_name, w,
|
||||
(u_longlong_t)zil_rec_info[i].zri_count);
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
dump_intent_log(zilog_t *zilog)
|
||||
{
|
||||
const zil_header_t *zh = zilog->zl_header;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
int i;
|
||||
|
||||
if (zh->zh_log.blk_birth == 0 || verbose < 2)
|
||||
return;
|
||||
|
||||
(void) printf("\n ZIL header: claim_txg %llu, seq %llu\n",
|
||||
(u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_replay_seq);
|
||||
|
||||
if (verbose >= 4)
|
||||
print_log_bp(&zh->zh_log, "\n\tfirst block: ");
|
||||
|
||||
for (i = 0; i < TX_MAX_TYPE; i++)
|
||||
zil_rec_info[i].zri_count = 0;
|
||||
|
||||
if (verbose >= 2) {
|
||||
(void) printf("\n");
|
||||
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
|
||||
zh->zh_claim_txg);
|
||||
print_log_stats(verbose);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,405 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zfs_util.h"
|
||||
#include "zfs_iter.h"
|
||||
|
||||
/*
|
||||
* This is a private interface used to gather up all the datasets specified on
|
||||
* the command line so that we can iterate over them in order.
|
||||
*
|
||||
* First, we iterate over all filesystems, gathering them together into an
|
||||
* AVL tree. We report errors for any explicitly specified datasets
|
||||
* that we couldn't open.
|
||||
*
|
||||
* When finished, we have an AVL tree of ZFS handles. We go through and execute
|
||||
* the provided callback for each one, passing whatever data the user supplied.
|
||||
*/
|
||||
|
||||
typedef struct zfs_node {
|
||||
zfs_handle_t *zn_handle;
|
||||
uu_avl_node_t zn_avlnode;
|
||||
} zfs_node_t;
|
||||
|
||||
typedef struct callback_data {
|
||||
uu_avl_t *cb_avl;
|
||||
int cb_recurse;
|
||||
zfs_type_t cb_types;
|
||||
zfs_sort_column_t *cb_sortcol;
|
||||
zfs_proplist_t **cb_proplist;
|
||||
} callback_data_t;
|
||||
|
||||
uu_avl_pool_t *avl_pool;
|
||||
|
||||
/*
|
||||
* Called for each dataset. If the object the object is of an appropriate type,
|
||||
* add it to the avl tree and recurse over any children as necessary.
|
||||
*/
|
||||
int
|
||||
zfs_callback(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
callback_data_t *cb = data;
|
||||
int dontclose = 0;
|
||||
|
||||
/*
|
||||
* If this object is of the appropriate type, add it to the AVL tree.
|
||||
*/
|
||||
if (zfs_get_type(zhp) & cb->cb_types) {
|
||||
uu_avl_index_t idx;
|
||||
zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));
|
||||
|
||||
node->zn_handle = zhp;
|
||||
uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
|
||||
if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
|
||||
&idx) == NULL) {
|
||||
if (cb->cb_proplist &&
|
||||
zfs_expand_proplist(zhp, cb->cb_proplist) != 0) {
|
||||
free(node);
|
||||
return (-1);
|
||||
}
|
||||
uu_avl_insert(cb->cb_avl, node, idx);
|
||||
dontclose = 1;
|
||||
} else {
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recurse if necessary.
|
||||
*/
|
||||
if (cb->cb_recurse && (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM ||
|
||||
(zfs_get_type(zhp) == ZFS_TYPE_VOLUME && (cb->cb_types &
|
||||
ZFS_TYPE_SNAPSHOT))))
|
||||
(void) zfs_iter_children(zhp, zfs_callback, data);
|
||||
|
||||
if (!dontclose)
|
||||
zfs_close(zhp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
|
||||
boolean_t reverse)
|
||||
{
|
||||
zfs_sort_column_t *col;
|
||||
zfs_prop_t prop;
|
||||
|
||||
if ((prop = zfs_name_to_prop(name)) == ZFS_PROP_INVAL &&
|
||||
!zfs_prop_user(name))
|
||||
return (-1);
|
||||
|
||||
col = safe_malloc(sizeof (zfs_sort_column_t));
|
||||
|
||||
col->sc_prop = prop;
|
||||
col->sc_reverse = reverse;
|
||||
if (prop == ZFS_PROP_INVAL) {
|
||||
col->sc_user_prop = safe_malloc(strlen(name) + 1);
|
||||
(void) strcpy(col->sc_user_prop, name);
|
||||
}
|
||||
|
||||
if (*sc == NULL) {
|
||||
col->sc_last = col;
|
||||
*sc = col;
|
||||
} else {
|
||||
(*sc)->sc_last->sc_next = col;
|
||||
(*sc)->sc_last = col;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
zfs_free_sort_columns(zfs_sort_column_t *sc)
|
||||
{
|
||||
zfs_sort_column_t *col;
|
||||
|
||||
while (sc != NULL) {
|
||||
col = sc->sc_next;
|
||||
free(sc->sc_user_prop);
|
||||
free(sc);
|
||||
sc = col;
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_compare(const void *larg, const void *rarg, void *unused)
|
||||
{
|
||||
zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
|
||||
zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
|
||||
const char *lname = zfs_get_name(l);
|
||||
const char *rname = zfs_get_name(r);
|
||||
char *lat, *rat;
|
||||
uint64_t lcreate, rcreate;
|
||||
int ret;
|
||||
|
||||
lat = (char *)strchr(lname, '@');
|
||||
rat = (char *)strchr(rname, '@');
|
||||
|
||||
if (lat != NULL)
|
||||
*lat = '\0';
|
||||
if (rat != NULL)
|
||||
*rat = '\0';
|
||||
|
||||
ret = strcmp(lname, rname);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* If we're comparing a dataset to one of its snapshots, we
|
||||
* always make the full dataset first.
|
||||
*/
|
||||
if (lat == NULL) {
|
||||
ret = -1;
|
||||
} else if (rat == NULL) {
|
||||
ret = 1;
|
||||
} else {
|
||||
/*
|
||||
* If we have two snapshots from the same dataset, then
|
||||
* we want to sort them according to creation time. We
|
||||
* use the hidden CREATETXG property to get an absolute
|
||||
* ordering of snapshots.
|
||||
*/
|
||||
lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
|
||||
rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
|
||||
|
||||
if (lcreate < rcreate)
|
||||
ret = -1;
|
||||
else if (lcreate > rcreate)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lat != NULL)
|
||||
*lat = '@';
|
||||
if (rat != NULL)
|
||||
*rat = '@';
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort datasets by specified columns.
|
||||
*
|
||||
* o Numeric types sort in ascending order.
|
||||
* o String types sort in alphabetical order.
|
||||
* o Types inappropriate for a row sort that row to the literal
|
||||
* bottom, regardless of the specified ordering.
|
||||
*
|
||||
* If no sort columns are specified, or two datasets compare equally
|
||||
* across all specified columns, they are sorted alphabetically by name
|
||||
* with snapshots grouped under their parents.
|
||||
*/
|
||||
static int
|
||||
zfs_sort(const void *larg, const void *rarg, void *data)
|
||||
{
|
||||
zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
|
||||
zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
|
||||
zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
|
||||
zfs_sort_column_t *psc;
|
||||
|
||||
for (psc = sc; psc != NULL; psc = psc->sc_next) {
|
||||
char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
|
||||
char *lstr, *rstr;
|
||||
uint64_t lnum, rnum;
|
||||
boolean_t lvalid, rvalid;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* We group the checks below the generic code. If 'lstr' and
|
||||
* 'rstr' are non-NULL, then we do a string based comparison.
|
||||
* Otherwise, we compare 'lnum' and 'rnum'.
|
||||
*/
|
||||
lstr = rstr = NULL;
|
||||
if (psc->sc_prop == ZFS_PROP_INVAL) {
|
||||
nvlist_t *luser, *ruser;
|
||||
nvlist_t *lval, *rval;
|
||||
|
||||
luser = zfs_get_user_props(l);
|
||||
ruser = zfs_get_user_props(r);
|
||||
|
||||
lvalid = (nvlist_lookup_nvlist(luser,
|
||||
psc->sc_user_prop, &lval) == 0);
|
||||
rvalid = (nvlist_lookup_nvlist(ruser,
|
||||
psc->sc_user_prop, &rval) == 0);
|
||||
|
||||
if (lvalid)
|
||||
verify(nvlist_lookup_string(lval,
|
||||
ZFS_PROP_VALUE, &lstr) == 0);
|
||||
if (rvalid)
|
||||
verify(nvlist_lookup_string(rval,
|
||||
ZFS_PROP_VALUE, &rstr) == 0);
|
||||
|
||||
} else if (zfs_prop_is_string(psc->sc_prop)) {
|
||||
lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
|
||||
sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
|
||||
rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
|
||||
sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
|
||||
|
||||
lstr = lbuf;
|
||||
rstr = rbuf;
|
||||
} else {
|
||||
lvalid = zfs_prop_valid_for_type(psc->sc_prop,
|
||||
zfs_get_type(l));
|
||||
rvalid = zfs_prop_valid_for_type(psc->sc_prop,
|
||||
zfs_get_type(r));
|
||||
|
||||
if (lvalid)
|
||||
(void) zfs_prop_get_numeric(l, psc->sc_prop,
|
||||
&lnum, NULL, NULL, 0);
|
||||
if (rvalid)
|
||||
(void) zfs_prop_get_numeric(r, psc->sc_prop,
|
||||
&rnum, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
if (!lvalid && !rvalid)
|
||||
continue;
|
||||
else if (!lvalid)
|
||||
return (1);
|
||||
else if (!rvalid)
|
||||
return (-1);
|
||||
|
||||
if (lstr)
|
||||
ret = strcmp(lstr, rstr);
|
||||
if (lnum < rnum)
|
||||
ret = -1;
|
||||
else if (lnum > rnum)
|
||||
ret = 1;
|
||||
|
||||
if (ret != 0) {
|
||||
if (psc->sc_reverse == B_TRUE)
|
||||
ret = (ret < 0) ? 1 : -1;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
return (zfs_compare(larg, rarg, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types,
|
||||
zfs_sort_column_t *sortcol, zfs_proplist_t **proplist, zfs_iter_f callback,
|
||||
void *data, boolean_t args_can_be_paths)
|
||||
{
|
||||
callback_data_t cb;
|
||||
int ret = 0;
|
||||
zfs_node_t *node;
|
||||
uu_avl_walk_t *walk;
|
||||
|
||||
avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
|
||||
offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
|
||||
|
||||
if (avl_pool == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cb.cb_sortcol = sortcol;
|
||||
cb.cb_recurse = recurse;
|
||||
cb.cb_proplist = proplist;
|
||||
cb.cb_types = types;
|
||||
if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
/*
|
||||
* If given no arguments, iterate over all datasets.
|
||||
*/
|
||||
cb.cb_recurse = 1;
|
||||
ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
|
||||
} else {
|
||||
int i;
|
||||
zfs_handle_t *zhp;
|
||||
zfs_type_t argtype;
|
||||
|
||||
/*
|
||||
* If we're recursive, then we always allow filesystems as
|
||||
* arguments. If we also are interested in snapshots, then we
|
||||
* can take volumes as well.
|
||||
*/
|
||||
argtype = types;
|
||||
if (recurse) {
|
||||
argtype |= ZFS_TYPE_FILESYSTEM;
|
||||
if (types & ZFS_TYPE_SNAPSHOT)
|
||||
argtype |= ZFS_TYPE_VOLUME;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (args_can_be_paths) {
|
||||
zhp = zfs_path_to_zhandle(g_zfs, argv[i],
|
||||
argtype);
|
||||
} else {
|
||||
zhp = zfs_open(g_zfs, argv[i], argtype);
|
||||
}
|
||||
if (zhp != NULL)
|
||||
ret |= zfs_callback(zhp, &cb);
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we've got our AVL tree full of zfs handles, so iterate
|
||||
* over each one and execute the real user callback.
|
||||
*/
|
||||
for (node = uu_avl_first(cb.cb_avl); node != NULL;
|
||||
node = uu_avl_next(cb.cb_avl, node))
|
||||
ret |= callback(node->zn_handle, data);
|
||||
|
||||
/*
|
||||
* Finally, clean up the AVL tree.
|
||||
*/
|
||||
if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((node = uu_avl_walk_next(walk)) != NULL) {
|
||||
uu_avl_remove(cb.cb_avl, node);
|
||||
zfs_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
|
||||
uu_avl_walk_end(walk);
|
||||
uu_avl_destroy(cb.cb_avl);
|
||||
uu_avl_pool_destroy(avl_pool);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef ZFS_ITER_H
|
||||
#define ZFS_ITER_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct zfs_sort_column {
|
||||
struct zfs_sort_column *sc_next;
|
||||
struct zfs_sort_column *sc_last;
|
||||
zfs_prop_t sc_prop;
|
||||
char *sc_user_prop;
|
||||
boolean_t sc_reverse;
|
||||
} zfs_sort_column_t;
|
||||
|
||||
int zfs_for_each(int, char **, boolean_t, zfs_type_t, zfs_sort_column_t *,
|
||||
zfs_proplist_t **, zfs_iter_f, void *, boolean_t);
|
||||
int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
|
||||
void zfs_free_sort_columns(zfs_sort_column_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZFS_ITER_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _ZFS_UTIL_H
|
||||
#define _ZFS_UTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void * safe_malloc(size_t size);
|
||||
libzfs_handle_t *g_zfs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZFS_UTIL_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <solaris.h>
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* Private interface for iterating over pools specified on the command line.
|
||||
* Most consumers will call for_each_pool, but in order to support iostat, we
|
||||
* allow fined grained control through the zpool_list_t interface.
|
||||
*/
|
||||
|
||||
typedef struct zpool_node {
|
||||
zpool_handle_t *zn_handle;
|
||||
uu_avl_node_t zn_avlnode;
|
||||
int zn_mark;
|
||||
} zpool_node_t;
|
||||
|
||||
struct zpool_list {
|
||||
boolean_t zl_findall;
|
||||
uu_avl_t *zl_avl;
|
||||
uu_avl_pool_t *zl_pool;
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zpool_compare(const void *larg, const void *rarg, void *unused)
|
||||
{
|
||||
zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
|
||||
zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
|
||||
const char *lname = zpool_get_name(l);
|
||||
const char *rname = zpool_get_name(r);
|
||||
|
||||
return (strcmp(lname, rname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for pool_list_get(). Adds the given pool to the AVL tree
|
||||
* of known pools.
|
||||
*/
|
||||
static int
|
||||
add_pool(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
zpool_list_t *zlp = data;
|
||||
zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
|
||||
uu_avl_index_t idx;
|
||||
|
||||
node->zn_handle = zhp;
|
||||
uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
|
||||
if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
|
||||
uu_avl_insert(zlp->zl_avl, node, idx);
|
||||
} else {
|
||||
zpool_close(zhp);
|
||||
free(node);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a list of pools based on the given arguments. If we're given no
|
||||
* arguments, then iterate over all pools in the system and add them to the AVL
|
||||
* tree. Otherwise, add only those pool explicitly specified on the command
|
||||
* line.
|
||||
*/
|
||||
zpool_list_t *
|
||||
pool_list_get(int argc, char **argv, zpool_proplist_t **proplist, int *err)
|
||||
{
|
||||
zpool_list_t *zlp;
|
||||
|
||||
zlp = safe_malloc(sizeof (zpool_list_t));
|
||||
|
||||
zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
|
||||
offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
|
||||
|
||||
if (zlp->zl_pool == NULL)
|
||||
zpool_no_memory();
|
||||
|
||||
if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
|
||||
UU_DEFAULT)) == NULL)
|
||||
zpool_no_memory();
|
||||
|
||||
if (argc == 0) {
|
||||
(void) zpool_iter(g_zfs, add_pool, zlp);
|
||||
zlp->zl_findall = B_TRUE;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
zpool_handle_t *zhp;
|
||||
|
||||
if ((zhp = zpool_open_canfail(g_zfs,
|
||||
argv[i])) != NULL && add_pool(zhp, zlp) == 0) {
|
||||
if (proplist &&
|
||||
zpool_expand_proplist(zhp, proplist) != 0)
|
||||
*err = B_TRUE;
|
||||
} else
|
||||
*err = B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return (zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for any new pools, adding them to the list. We only add pools when no
|
||||
* options were given on the command line. Otherwise, we keep the list fixed as
|
||||
* those that were explicitly specified.
|
||||
*/
|
||||
void
|
||||
pool_list_update(zpool_list_t *zlp)
|
||||
{
|
||||
if (zlp->zl_findall)
|
||||
(void) zpool_iter(g_zfs, add_pool, zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all pools in the list, executing the callback for each
|
||||
*/
|
||||
int
|
||||
pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
|
||||
void *data)
|
||||
{
|
||||
zpool_node_t *node, *next_node;
|
||||
int ret = 0;
|
||||
|
||||
for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
|
||||
next_node = uu_avl_next(zlp->zl_avl, node);
|
||||
if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
|
||||
unavail)
|
||||
ret |= func(node->zn_handle, data);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given pool from the list. When running iostat, we want to remove
|
||||
* those pools that no longer exist.
|
||||
*/
|
||||
void
|
||||
pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
|
||||
{
|
||||
zpool_node_t search, *node;
|
||||
|
||||
search.zn_handle = zhp;
|
||||
if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
|
||||
uu_avl_remove(zlp->zl_avl, node);
|
||||
zpool_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all the handles associated with this list.
|
||||
*/
|
||||
void
|
||||
pool_list_free(zpool_list_t *zlp)
|
||||
{
|
||||
uu_avl_walk_t *walk;
|
||||
zpool_node_t *node;
|
||||
|
||||
if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((node = uu_avl_walk_next(walk)) != NULL) {
|
||||
uu_avl_remove(zlp->zl_avl, node);
|
||||
zpool_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
|
||||
uu_avl_walk_end(walk);
|
||||
uu_avl_destroy(zlp->zl_avl);
|
||||
uu_avl_pool_destroy(zlp->zl_pool);
|
||||
|
||||
free(zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of elements in the pool list.
|
||||
*/
|
||||
int
|
||||
pool_list_count(zpool_list_t *zlp)
|
||||
{
|
||||
return (uu_avl_numnodes(zlp->zl_avl));
|
||||
}
|
||||
|
||||
/*
|
||||
* High level function which iterates over all pools given on the command line,
|
||||
* using the pool_list_* interfaces.
|
||||
*/
|
||||
int
|
||||
for_each_pool(int argc, char **argv, boolean_t unavail,
|
||||
zpool_proplist_t **proplist, zpool_iter_f func, void *data)
|
||||
{
|
||||
zpool_list_t *list;
|
||||
int ret = 0;
|
||||
|
||||
if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
|
||||
return (1);
|
||||
|
||||
if (pool_list_iter(list, unavail, func, data) != 0)
|
||||
ret = 1;
|
||||
|
||||
pool_list_free(list);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* Utility function to guarantee malloc() success.
|
||||
*/
|
||||
void *
|
||||
safe_malloc(size_t size)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if ((data = calloc(1, size)) == NULL) {
|
||||
(void) fprintf(stderr, "internal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as above, but for strdup()
|
||||
*/
|
||||
char *
|
||||
safe_strdup(const char *str)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if ((ret = strdup(str)) == NULL) {
|
||||
(void) fprintf(stderr, "internal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display an out of memory error message and abort the current program.
|
||||
*/
|
||||
void
|
||||
zpool_no_memory(void)
|
||||
{
|
||||
assert(errno == ENOMEM);
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef ZPOOL_UTIL_H
|
||||
#define ZPOOL_UTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libnvpair.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic utility functions
|
||||
*/
|
||||
void *safe_malloc(size_t);
|
||||
char *safe_strdup(const char *);
|
||||
void zpool_no_memory(void);
|
||||
|
||||
/*
|
||||
* Virtual device functions
|
||||
*/
|
||||
nvlist_t *make_root_vdev(nvlist_t *poolconfig, int force, int check_rep,
|
||||
boolean_t isreplace, int argc, char **argv);
|
||||
|
||||
/*
|
||||
* Pool list functions
|
||||
*/
|
||||
int for_each_pool(int, char **, boolean_t unavail, zpool_proplist_t **,
|
||||
zpool_iter_f, void *);
|
||||
|
||||
typedef struct zpool_list zpool_list_t;
|
||||
|
||||
zpool_list_t *pool_list_get(int, char **, zpool_proplist_t **, int *);
|
||||
void pool_list_update(zpool_list_t *);
|
||||
int pool_list_iter(zpool_list_t *, int unavail, zpool_iter_f, void *);
|
||||
void pool_list_free(zpool_list_t *);
|
||||
int pool_list_count(zpool_list_t *);
|
||||
void pool_list_remove(zpool_list_t *, zpool_handle_t *);
|
||||
|
||||
libzfs_handle_t *g_zfs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZPOOL_UTIL_H */
|
||||
@@ -1,883 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Functions to convert between a list of vdevs and an nvlist representing the
|
||||
* configuration. Each entry in the list can be one of:
|
||||
*
|
||||
* Device vdevs
|
||||
* disk=(path=..., devid=...)
|
||||
* file=(path=...)
|
||||
*
|
||||
* Group vdevs
|
||||
* raidz[1|2]=(...)
|
||||
* mirror=(...)
|
||||
*
|
||||
* Hot spares
|
||||
*
|
||||
* While the underlying implementation supports it, group vdevs cannot contain
|
||||
* other group vdevs. All userland verification of devices is contained within
|
||||
* this file. If successful, the nvlist returned can be passed directly to the
|
||||
* kernel; we've done as much verification as possible in userland.
|
||||
*
|
||||
* Hot spares are a special case, and passed down as an array of disk vdevs, at
|
||||
* the same level as the root of the vdev tree.
|
||||
*
|
||||
* The only function exported by this file is 'get_vdev_spec'. The function
|
||||
* performs several passes:
|
||||
*
|
||||
* 1. Construct the vdev specification. Performs syntax validation and
|
||||
* makes sure each device is valid.
|
||||
* 2. Check for devices in use. Using libdiskmgt, makes sure that no
|
||||
* devices are also in use. Some can be overridden using the 'force'
|
||||
* flag, others cannot.
|
||||
* 3. Check for replication errors if the 'force' flag is not specified.
|
||||
* validates that the replication level is consistent across the
|
||||
* entire pool.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <devid.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <libnvpair.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <paths.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <libgeom.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* For any given vdev specification, we can have multiple errors. The
|
||||
* vdev_error() function keeps track of whether we have seen an error yet, and
|
||||
* prints out a header if its the first error we've seen.
|
||||
*/
|
||||
boolean_t error_seen;
|
||||
boolean_t is_force;
|
||||
|
||||
/*PRINTFLIKE1*/
|
||||
static void
|
||||
vdev_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!error_seen) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev specification\n"));
|
||||
if (!is_force)
|
||||
(void) fprintf(stderr, gettext("use '-f' to override "
|
||||
"the following errors:\n"));
|
||||
else
|
||||
(void) fprintf(stderr, gettext("the following errors "
|
||||
"must be manually repaired:\n"));
|
||||
error_seen = B_TRUE;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void) vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a GEOM provider.
|
||||
*/
|
||||
static int
|
||||
check_provider(const char *name, boolean_t force, boolean_t isspare)
|
||||
{
|
||||
struct gmesh mesh;
|
||||
struct gclass *mp;
|
||||
struct ggeom *gp;
|
||||
struct gprovider *pp;
|
||||
int rv;
|
||||
|
||||
/* XXX: What to do with isspare? */
|
||||
|
||||
if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
name += sizeof(_PATH_DEV) - 1;
|
||||
|
||||
rv = geom_gettree(&mesh);
|
||||
assert(rv == 0);
|
||||
|
||||
pp = NULL;
|
||||
LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
|
||||
LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
|
||||
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
|
||||
if (strcmp(pp->lg_name, name) == 0)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
rv = -1;
|
||||
if (pp == NULL)
|
||||
vdev_error("no such provider %s\n", name);
|
||||
else {
|
||||
int acr, acw, ace;
|
||||
|
||||
VERIFY(sscanf(pp->lg_mode, "r%dw%de%d", &acr, &acw, &ace) == 3);
|
||||
if (acw == 0 && ace == 0)
|
||||
rv = 0;
|
||||
else
|
||||
vdev_error("%s is in use (%s)\n", name, pp->lg_mode);
|
||||
}
|
||||
geom_deletetree(&mesh);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
is_provider(const char *name)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = g_open(name, 0);
|
||||
if (fd >= 0) {
|
||||
g_close(fd);
|
||||
return (B_TRUE);
|
||||
}
|
||||
return (B_FALSE);
|
||||
|
||||
}
|
||||
/*
|
||||
* Create a leaf vdev. Determine if this is a GEOM provider.
|
||||
* Valid forms for a leaf vdev are:
|
||||
*
|
||||
* /dev/xxx Complete path to a GEOM provider
|
||||
* xxx Shorthand for /dev/xxx
|
||||
*/
|
||||
nvlist_t *
|
||||
make_leaf_vdev(const char *arg)
|
||||
{
|
||||
char ident[DISK_IDENT_SIZE], path[MAXPATHLEN];
|
||||
struct stat64 statbuf;
|
||||
nvlist_t *vdev = NULL;
|
||||
char *type = NULL;
|
||||
boolean_t wholedisk = B_FALSE;
|
||||
|
||||
if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
strlcpy(path, arg, sizeof (path));
|
||||
else
|
||||
snprintf(path, sizeof (path), "%s%s", _PATH_DEV, arg);
|
||||
|
||||
if (is_provider(path))
|
||||
type = VDEV_TYPE_DISK;
|
||||
else {
|
||||
(void) fprintf(stderr, gettext("cannot use '%s': must be a "
|
||||
"GEOM provider\n"), path);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, we have the complete device or file, and we know that it is
|
||||
* acceptable to use. Construct the nvlist to describe this vdev. All
|
||||
* vdevs have a 'path' element, and devices also have a 'devid' element.
|
||||
*/
|
||||
verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
|
||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
|
||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
||||
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
(uint64_t)B_FALSE) == 0);
|
||||
|
||||
/*
|
||||
* For a whole disk, defer getting its devid until after labeling it.
|
||||
*/
|
||||
if (1 || (S_ISBLK(statbuf.st_mode) && !wholedisk)) {
|
||||
/*
|
||||
* Get the devid for the device.
|
||||
*/
|
||||
int fd;
|
||||
ddi_devid_t devid;
|
||||
char *minor = NULL, *devid_str = NULL;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
(void) fprintf(stderr, gettext("cannot open '%s': "
|
||||
"%s\n"), path, strerror(errno));
|
||||
nvlist_free(vdev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (devid_get(fd, &devid) == 0) {
|
||||
if (devid_get_minor_name(fd, &minor) == 0 &&
|
||||
(devid_str = devid_str_encode(devid, minor)) !=
|
||||
NULL) {
|
||||
verify(nvlist_add_string(vdev,
|
||||
ZPOOL_CONFIG_DEVID, devid_str) == 0);
|
||||
}
|
||||
if (devid_str != NULL)
|
||||
devid_str_free(devid_str);
|
||||
if (minor != NULL)
|
||||
devid_str_free(minor);
|
||||
devid_free(devid);
|
||||
}
|
||||
|
||||
(void) close(fd);
|
||||
}
|
||||
|
||||
return (vdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through and verify the replication level of the pool is consistent.
|
||||
* Performs the following checks:
|
||||
*
|
||||
* For the new spec, verifies that devices in mirrors and raidz are the
|
||||
* same size.
|
||||
*
|
||||
* If the current configuration already has inconsistent replication
|
||||
* levels, ignore any other potential problems in the new spec.
|
||||
*
|
||||
* Otherwise, make sure that the current spec (if there is one) and the new
|
||||
* spec have consistent replication levels.
|
||||
*/
|
||||
typedef struct replication_level {
|
||||
char *zprl_type;
|
||||
uint64_t zprl_children;
|
||||
uint64_t zprl_parity;
|
||||
} replication_level_t;
|
||||
|
||||
/*
|
||||
* Given a list of toplevel vdevs, return the current replication level. If
|
||||
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
|
||||
* an error message will be displayed for each self-inconsistent vdev.
|
||||
*/
|
||||
replication_level_t *
|
||||
get_replication(nvlist_t *nvroot, boolean_t fatal)
|
||||
{
|
||||
nvlist_t **top;
|
||||
uint_t t, toplevels;
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
nvlist_t *nv;
|
||||
char *type;
|
||||
replication_level_t lastrep, rep, *ret;
|
||||
boolean_t dontreport;
|
||||
|
||||
ret = safe_malloc(sizeof (replication_level_t));
|
||||
|
||||
verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
|
||||
&top, &toplevels) == 0);
|
||||
|
||||
lastrep.zprl_type = NULL;
|
||||
for (t = 0; t < toplevels; t++) {
|
||||
nv = top[t];
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0) {
|
||||
/*
|
||||
* This is a 'file' or 'disk' vdev.
|
||||
*/
|
||||
rep.zprl_type = type;
|
||||
rep.zprl_children = 1;
|
||||
rep.zprl_parity = 0;
|
||||
} else {
|
||||
uint64_t vdev_size;
|
||||
|
||||
/*
|
||||
* This is a mirror or RAID-Z vdev. Go through and make
|
||||
* sure the contents are all the same (files vs. disks),
|
||||
* keeping track of the number of elements in the
|
||||
* process.
|
||||
*
|
||||
* We also check that the size of each vdev (if it can
|
||||
* be determined) is the same.
|
||||
*/
|
||||
rep.zprl_type = type;
|
||||
rep.zprl_children = 0;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||
verify(nvlist_lookup_uint64(nv,
|
||||
ZPOOL_CONFIG_NPARITY,
|
||||
&rep.zprl_parity) == 0);
|
||||
assert(rep.zprl_parity != 0);
|
||||
} else {
|
||||
rep.zprl_parity = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'dontreport' variable indicatest that we've
|
||||
* already reported an error for this spec, so don't
|
||||
* bother doing it again.
|
||||
*/
|
||||
type = NULL;
|
||||
dontreport = 0;
|
||||
vdev_size = -1ULL;
|
||||
for (c = 0; c < children; c++) {
|
||||
nvlist_t *cnv = child[c];
|
||||
char *path;
|
||||
struct stat64 statbuf;
|
||||
uint64_t size = -1ULL;
|
||||
char *childtype;
|
||||
int fd, err;
|
||||
|
||||
rep.zprl_children++;
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_TYPE, &childtype) == 0);
|
||||
|
||||
/*
|
||||
* If this is a a replacing or spare vdev, then
|
||||
* get the real first child of the vdev.
|
||||
*/
|
||||
if (strcmp(childtype,
|
||||
VDEV_TYPE_REPLACING) == 0 ||
|
||||
strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
|
||||
nvlist_t **rchild;
|
||||
uint_t rchildren;
|
||||
|
||||
verify(nvlist_lookup_nvlist_array(cnv,
|
||||
ZPOOL_CONFIG_CHILDREN, &rchild,
|
||||
&rchildren) == 0);
|
||||
assert(rchildren == 2);
|
||||
cnv = rchild[0];
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_TYPE,
|
||||
&childtype) == 0);
|
||||
}
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_PATH, &path) == 0);
|
||||
|
||||
/*
|
||||
* If we have a raidz/mirror that combines disks
|
||||
* with files, report it as an error.
|
||||
*/
|
||||
if (!dontreport && type != NULL &&
|
||||
strcmp(type, childtype) != 0) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication "
|
||||
"level: %s contains both "
|
||||
"files and devices\n"),
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
dontreport = B_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to stat(2), the value of 'st_size'
|
||||
* is undefined for block devices and character
|
||||
* devices. But there is no effective way to
|
||||
* determine the real size in userland.
|
||||
*
|
||||
* Instead, we'll take advantage of an
|
||||
* implementation detail of spec_size(). If the
|
||||
* device is currently open, then we (should)
|
||||
* return a valid size.
|
||||
*
|
||||
* If we still don't get a valid size (indicated
|
||||
* by a size of 0 or MAXOFFSET_T), then ignore
|
||||
* this device altogether.
|
||||
*/
|
||||
if ((fd = open(path, O_RDONLY)) >= 0) {
|
||||
err = fstat64(fd, &statbuf);
|
||||
(void) close(fd);
|
||||
} else {
|
||||
err = stat64(path, &statbuf);
|
||||
}
|
||||
|
||||
if (err != 0 || statbuf.st_size == 0)
|
||||
continue;
|
||||
|
||||
size = statbuf.st_size;
|
||||
|
||||
/*
|
||||
* Also check the size of each device. If they
|
||||
* differ, then report an error.
|
||||
*/
|
||||
if (!dontreport && vdev_size != -1ULL &&
|
||||
size != vdev_size) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"%s contains devices of "
|
||||
"different sizes\n"),
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
dontreport = B_TRUE;
|
||||
}
|
||||
|
||||
type = childtype;
|
||||
vdev_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have the replication of the last toplevel
|
||||
* vdev in 'rep'. Compare it to 'lastrep' to see if its
|
||||
* different.
|
||||
*/
|
||||
if (lastrep.zprl_type != NULL) {
|
||||
if (strcmp(lastrep.zprl_type, rep.zprl_type) != 0) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %s and %s vdevs are "
|
||||
"present\n"),
|
||||
lastrep.zprl_type, rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
} else if (lastrep.zprl_parity != rep.zprl_parity) {
|
||||
if (ret)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %llu and %llu device parity "
|
||||
"%s vdevs are present\n"),
|
||||
lastrep.zprl_parity,
|
||||
rep.zprl_parity,
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
} else if (lastrep.zprl_children != rep.zprl_children) {
|
||||
if (ret)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %llu-way and %llu-way %s "
|
||||
"vdevs are present\n"),
|
||||
lastrep.zprl_children,
|
||||
rep.zprl_children,
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
lastrep = rep;
|
||||
}
|
||||
|
||||
if (ret != NULL)
|
||||
*ret = rep;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the replication level of the vdev spec against the current pool. Calls
|
||||
* get_replication() to make sure the new spec is self-consistent. If the pool
|
||||
* has a consistent replication level, then we ignore any errors. Otherwise,
|
||||
* report any difference between the two.
|
||||
*/
|
||||
int
|
||||
check_replication(nvlist_t *config, nvlist_t *newroot)
|
||||
{
|
||||
replication_level_t *current = NULL, *new;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If we have a current pool configuration, check to see if it's
|
||||
* self-consistent. If not, simply return success.
|
||||
*/
|
||||
if (config != NULL) {
|
||||
nvlist_t *nvroot;
|
||||
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
if ((current = get_replication(nvroot, B_FALSE)) == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the replication level of the new vdev spec, reporting any
|
||||
* inconsistencies found.
|
||||
*/
|
||||
if ((new = get_replication(newroot, B_TRUE)) == NULL) {
|
||||
free(current);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the new vdev spec matches the replication level of
|
||||
* the current pool.
|
||||
*/
|
||||
ret = 0;
|
||||
if (current != NULL) {
|
||||
if (strcmp(current->zprl_type, new->zprl_type) != 0) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %s "
|
||||
"and new vdev is %s\n"),
|
||||
current->zprl_type, new->zprl_type);
|
||||
ret = -1;
|
||||
} else if (current->zprl_parity != new->zprl_parity) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %llu "
|
||||
"device parity and new vdev uses %llu\n"),
|
||||
current->zprl_parity, new->zprl_parity);
|
||||
ret = -1;
|
||||
} else if (current->zprl_children != new->zprl_children) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %llu-way "
|
||||
"%s and new vdev uses %llu-way %s\n"),
|
||||
current->zprl_children, current->zprl_type,
|
||||
new->zprl_children, new->zprl_type);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(new);
|
||||
if (current != NULL)
|
||||
free(current);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the given path is a hot spare within the given configuration.
|
||||
*/
|
||||
static boolean_t
|
||||
is_spare(nvlist_t *config, const char *path)
|
||||
{
|
||||
int fd;
|
||||
pool_state_t state;
|
||||
char *name = NULL;
|
||||
nvlist_t *label;
|
||||
uint64_t guid, spareguid;
|
||||
nvlist_t *nvroot;
|
||||
nvlist_t **spares;
|
||||
uint_t i, nspares;
|
||||
boolean_t inuse;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 ||
|
||||
!inuse ||
|
||||
state != POOL_STATE_SPARE ||
|
||||
zpool_read_label(fd, &label) != 0) {
|
||||
free(name);
|
||||
(void) close(fd);
|
||||
return (B_FALSE);
|
||||
}
|
||||
free(name);
|
||||
|
||||
(void) close(fd);
|
||||
verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0);
|
||||
nvlist_free(label);
|
||||
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||
&spares, &nspares) == 0) {
|
||||
for (i = 0; i < nspares; i++) {
|
||||
verify(nvlist_lookup_uint64(spares[i],
|
||||
ZPOOL_CONFIG_GUID, &spareguid) == 0);
|
||||
if (spareguid == guid)
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through and find any devices that are in use. We rely on libdiskmgt for
|
||||
* the majority of this task.
|
||||
*/
|
||||
int
|
||||
check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
|
||||
int isspare)
|
||||
{
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
char *type, *path;
|
||||
int ret;
|
||||
char buf[MAXPATHLEN];
|
||||
uint64_t wholedisk;
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0) {
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
|
||||
|
||||
/*
|
||||
* As a generic check, we look to see if this is a replace of a
|
||||
* hot spare within the same pool. If so, we allow it
|
||||
* regardless of what libdiskmgt or zpool_in_use() says.
|
||||
*/
|
||||
if (isreplacing) {
|
||||
(void) strlcpy(buf, path, sizeof (buf));
|
||||
if (is_spare(config, buf))
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
||||
ret = check_provider(path, force, isspare);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
if ((ret = check_in_use(config, child[c], force,
|
||||
isreplacing, B_FALSE)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
|
||||
&child, &children) == 0)
|
||||
for (c = 0; c < children; c++)
|
||||
if ((ret = check_in_use(config, child[c], force,
|
||||
isreplacing, B_TRUE)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char *
|
||||
is_grouping(const char *type, int *mindev)
|
||||
{
|
||||
if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 2;
|
||||
return (VDEV_TYPE_RAIDZ);
|
||||
}
|
||||
|
||||
if (strcmp(type, "raidz2") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 3;
|
||||
return (VDEV_TYPE_RAIDZ);
|
||||
}
|
||||
|
||||
if (strcmp(type, "mirror") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 2;
|
||||
return (VDEV_TYPE_MIRROR);
|
||||
}
|
||||
|
||||
if (strcmp(type, "spare") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 1;
|
||||
return (VDEV_TYPE_SPARE);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a syntactically valid vdev specification,
|
||||
* and ensure that all devices and files exist and can be opened.
|
||||
* Note: we don't bother freeing anything in the error paths
|
||||
* because the program is just going to exit anyway.
|
||||
*/
|
||||
nvlist_t *
|
||||
construct_spec(int argc, char **argv)
|
||||
{
|
||||
nvlist_t *nvroot, *nv, **top, **spares;
|
||||
int t, toplevels, mindev, nspares;
|
||||
const char *type;
|
||||
|
||||
top = NULL;
|
||||
toplevels = 0;
|
||||
spares = NULL;
|
||||
nspares = 0;
|
||||
|
||||
while (argc > 0) {
|
||||
nv = NULL;
|
||||
|
||||
/*
|
||||
* If it's a mirror or raidz, the subsequent arguments are
|
||||
* its leaves -- until we encounter the next mirror or raidz.
|
||||
*/
|
||||
if ((type = is_grouping(argv[0], &mindev)) != NULL) {
|
||||
nvlist_t **child = NULL;
|
||||
int c, children = 0;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
|
||||
spares != NULL) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: 'spare' can be "
|
||||
"specified only once\n"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; c++) {
|
||||
if (is_grouping(argv[c], NULL) != NULL)
|
||||
break;
|
||||
children++;
|
||||
child = realloc(child,
|
||||
children * sizeof (nvlist_t *));
|
||||
if (child == NULL)
|
||||
zpool_no_memory();
|
||||
if ((nv = make_leaf_vdev(argv[c])) == NULL)
|
||||
return (NULL);
|
||||
child[children - 1] = nv;
|
||||
}
|
||||
|
||||
if (children < mindev) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: %s requires at least %d "
|
||||
"devices\n"), argv[0], mindev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
argc -= c;
|
||||
argv += c;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
|
||||
spares = child;
|
||||
nspares = children;
|
||||
continue;
|
||||
} else {
|
||||
verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
|
||||
0) == 0);
|
||||
verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
|
||||
type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||
verify(nvlist_add_uint64(nv,
|
||||
ZPOOL_CONFIG_NPARITY,
|
||||
mindev - 1) == 0);
|
||||
}
|
||||
verify(nvlist_add_nvlist_array(nv,
|
||||
ZPOOL_CONFIG_CHILDREN, child,
|
||||
children) == 0);
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
nvlist_free(child[c]);
|
||||
free(child);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We have a device. Pass off to make_leaf_vdev() to
|
||||
* construct the appropriate nvlist describing the vdev.
|
||||
*/
|
||||
if ((nv = make_leaf_vdev(argv[0])) == NULL)
|
||||
return (NULL);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
toplevels++;
|
||||
top = realloc(top, toplevels * sizeof (nvlist_t *));
|
||||
if (top == NULL)
|
||||
zpool_no_memory();
|
||||
top[toplevels - 1] = nv;
|
||||
}
|
||||
|
||||
if (toplevels == 0 && nspares == 0) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: at least one toplevel vdev must be "
|
||||
"specified\n"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, create nvroot and add all top-level vdevs to it.
|
||||
*/
|
||||
verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
|
||||
verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
|
||||
VDEV_TYPE_ROOT) == 0);
|
||||
verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
|
||||
top, toplevels) == 0);
|
||||
if (nspares != 0)
|
||||
verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||
spares, nspares) == 0);
|
||||
|
||||
for (t = 0; t < toplevels; t++)
|
||||
nvlist_free(top[t]);
|
||||
for (t = 0; t < nspares; t++)
|
||||
nvlist_free(spares[t]);
|
||||
if (spares)
|
||||
free(spares);
|
||||
free(top);
|
||||
|
||||
return (nvroot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and validate the contents of the given vdev specification. This ensures
|
||||
* that the nvlist returned is well-formed, that all the devices exist, and that
|
||||
* they are not currently in use by any other known consumer. The 'poolconfig'
|
||||
* parameter is the current configuration of the pool when adding devices
|
||||
* existing pool, and is used to perform additional checks, such as changing the
|
||||
* replication level of the pool. It can be 'NULL' to indicate that this is a
|
||||
* new pool. The 'force' flag controls whether devices should be forcefully
|
||||
* added, even if they appear in use.
|
||||
*/
|
||||
nvlist_t *
|
||||
make_root_vdev(nvlist_t *poolconfig, int force, int check_rep,
|
||||
boolean_t isreplacing, int argc, char **argv)
|
||||
{
|
||||
nvlist_t *newroot;
|
||||
|
||||
is_force = force;
|
||||
|
||||
/*
|
||||
* Construct the vdev specification. If this is successful, we know
|
||||
* that we have a valid specification, and that all devices can be
|
||||
* opened.
|
||||
*/
|
||||
if ((newroot = construct_spec(argc, argv)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Validate each device to make sure that its not shared with another
|
||||
* subsystem. We do this even if 'force' is set, because there are some
|
||||
* uses (such as a dedicated dump device) that even '-f' cannot
|
||||
* override.
|
||||
*/
|
||||
if (check_in_use(poolconfig, newroot, force, isreplacing,
|
||||
B_FALSE) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the replication level of the given vdevs and report any errors
|
||||
* found. We include the existing pool spec, if any, as we need to
|
||||
* catch changes against the existing replication level.
|
||||
*/
|
||||
if (check_rep && check_replication(poolconfig, newroot) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (newroot);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/* Copyright (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _ASSERT_H
|
||||
#define _ASSERT_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6.1.4 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
extern void __assert_c99(const char *, const char *, int, const char *);
|
||||
#else
|
||||
extern void __assert(const char *, const char *, int);
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
extern void _assert();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ASSERT_H */
|
||||
|
||||
/*
|
||||
* Note that the ANSI C Standard requires all headers to be idempotent except
|
||||
* <assert.h> which is explicitly required not to be idempotent (section 4.1.2).
|
||||
* Therefore, it is by intent that the header guards (#ifndef _ASSERT_H) do
|
||||
* not span this entire file.
|
||||
*/
|
||||
|
||||
#undef assert
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define assert(EX) ((void)0)
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
#define assert(EX) (void)((EX) || \
|
||||
(__assert_c99(#EX, __FILE__, __LINE__, __func__), 0))
|
||||
#else
|
||||
#define assert(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
#define assert(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* NDEBUG */
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _ATOMIC_H
|
||||
#define _ATOMIC_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/atomic.h>
|
||||
|
||||
#endif /* _ATOMIC_H */
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Libintl is a library of advanced internationalization functions. */
|
||||
|
||||
#ifndef _LIBINTL_H
|
||||
#define _LIBINTL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/isa_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* wchar_t is a built-in type in standard C++ and as such is not
|
||||
* defined here when using standard C++. However, the GNU compiler
|
||||
* fixincludes utility nonetheless creates its own version of this
|
||||
* header for use by gcc and g++. In that version it adds a redundant
|
||||
* guard for __cplusplus. To avoid the creation of a gcc/g++ specific
|
||||
* header we need to include the following magic comment:
|
||||
*
|
||||
* we must use the C++ compiler's type
|
||||
*
|
||||
* The above comment should not be removed or changed until GNU
|
||||
* gcc/fixinc/inclhack.def is updated to bypass this header.
|
||||
*/
|
||||
#if !defined(__cplusplus) || (__cplusplus < 199711L && !defined(__GNUG__))
|
||||
#ifndef _WCHAR_T
|
||||
#define _WCHAR_T
|
||||
#if defined(_LP64)
|
||||
typedef int wchar_t;
|
||||
#else
|
||||
typedef long wchar_t;
|
||||
#endif
|
||||
#endif /* !_WCHAR_T */
|
||||
#endif /* !defined(__cplusplus) ... */
|
||||
|
||||
#define TEXTDOMAINMAX 256
|
||||
|
||||
#ifdef __STDC__
|
||||
extern char *dcgettext(const char *, const char *, const int);
|
||||
extern char *dgettext(const char *, const char *);
|
||||
extern char *gettext(const char *);
|
||||
extern char *textdomain(const char *);
|
||||
extern char *bindtextdomain(const char *, const char *);
|
||||
|
||||
/*
|
||||
* LI18NUX 2000 Globalization Specification Version 1.0
|
||||
* with Amendment 2
|
||||
*/
|
||||
extern char *dcngettext(const char *, const char *,
|
||||
const char *, unsigned long int, int);
|
||||
extern char *dngettext(const char *, const char *,
|
||||
const char *, unsigned long int);
|
||||
extern char *ngettext(const char *, const char *, unsigned long int);
|
||||
extern char *bind_textdomain_codeset(const char *, const char *);
|
||||
|
||||
/* Word handling functions --- requires dynamic linking */
|
||||
/* Warning: these are experimental and subject to change. */
|
||||
extern int wdinit(void);
|
||||
extern int wdchkind(wchar_t);
|
||||
extern int wdbindf(wchar_t, wchar_t, int);
|
||||
extern wchar_t *wddelim(wchar_t, wchar_t, int);
|
||||
extern wchar_t mcfiller(void);
|
||||
extern int mcwrap(void);
|
||||
|
||||
#else
|
||||
extern char *dcgettext();
|
||||
extern char *dgettext();
|
||||
extern char *gettext();
|
||||
extern char *textdomain();
|
||||
extern char *bindtextdomain();
|
||||
|
||||
/*
|
||||
* LI18NUX 2000 Globalization Specification Version 1.0
|
||||
* with Amendment 2
|
||||
*/
|
||||
extern char *dcngettext();
|
||||
extern char *dngettext();
|
||||
extern char *ngettext();
|
||||
extern char *bind_textdomain_codeset();
|
||||
|
||||
/* Word handling functions --- requires dynamic linking */
|
||||
/* Warning: these are experimental and subject to change. */
|
||||
extern int wdinit();
|
||||
extern int wdchkind();
|
||||
extern int wdbindf();
|
||||
extern wchar_t *wddelim();
|
||||
extern wchar_t mcfiller();
|
||||
extern int mcwrap();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBINTL_H */
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _STDIO_EXT_H
|
||||
#define _STDIO_EXT_H
|
||||
|
||||
#define enable_extended_FILE_stdio(x,y) (0)
|
||||
|
||||
#endif
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYNCH_H
|
||||
#define _SYNCH_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* synch.h:
|
||||
* definitions needed to use the thread synchronization interface
|
||||
*/
|
||||
|
||||
#ifndef _ASM
|
||||
#include <sys/machlock.h>
|
||||
#include <sys/time_impl.h>
|
||||
#include <sys/synch.h>
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ASM
|
||||
|
||||
/*
|
||||
* Semaphores
|
||||
*/
|
||||
typedef struct _sema {
|
||||
/* this structure must be the same as sem_t in <semaphore.h> */
|
||||
uint32_t count; /* semaphore count */
|
||||
uint16_t type;
|
||||
uint16_t magic;
|
||||
upad64_t pad1[3]; /* reserved for a mutex_t */
|
||||
upad64_t pad2[2]; /* reserved for a cond_t */
|
||||
} sema_t;
|
||||
|
||||
/*
|
||||
* POSIX.1c Note:
|
||||
* POSIX.1c requires that <pthread.h> define the structures pthread_mutex_t
|
||||
* and pthread_cond_t. These structures are identical to mutex_t (lwp_mutex_t)
|
||||
* and cond_t (lwp_cond_t) which are defined in <synch.h>. A nested included
|
||||
* of <synch.h> (to allow a "#typedef mutex_t pthread_mutex_t") would pull in
|
||||
* non-posix symbols/constants violating the namespace restrictions. Hence,
|
||||
* pthread_mutex_t/pthread_cond_t have been redefined in <pthread.h> (actually
|
||||
* in <sys/types.h>). Any modifications done to mutex_t/lwp_mutex_t or
|
||||
* cond_t/lwp_cond_t should also be done to pthread_mutex_t/pthread_cond_t.
|
||||
*/
|
||||
typedef lwp_mutex_t mutex_t;
|
||||
typedef lwp_cond_t cond_t;
|
||||
|
||||
/*
|
||||
* Readers/writer locks
|
||||
*
|
||||
* NOTE: The layout of this structure should be kept in sync with the layout
|
||||
* of the correponding structure of pthread_rwlock_t in sys/types.h.
|
||||
* Also, there is an identical structure for lwp_rwlock_t in <sys/synch.h>.
|
||||
* Because we have to deal with C++, we cannot redefine this one as that one.
|
||||
*/
|
||||
typedef struct _rwlock {
|
||||
int32_t readers; /* -1 == writer else # of readers */
|
||||
uint16_t type;
|
||||
uint16_t magic;
|
||||
mutex_t mutex; /* used to indicate ownership */
|
||||
cond_t readercv; /* unused */
|
||||
cond_t writercv; /* unused */
|
||||
} rwlock_t;
|
||||
|
||||
#ifdef __STDC__
|
||||
int _lwp_mutex_lock(lwp_mutex_t *);
|
||||
int _lwp_mutex_unlock(lwp_mutex_t *);
|
||||
int _lwp_mutex_trylock(lwp_mutex_t *);
|
||||
int _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
|
||||
int _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
|
||||
int _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
|
||||
int _lwp_cond_signal(lwp_cond_t *);
|
||||
int _lwp_cond_broadcast(lwp_cond_t *);
|
||||
int _lwp_sema_init(lwp_sema_t *, int);
|
||||
int _lwp_sema_wait(lwp_sema_t *);
|
||||
int _lwp_sema_trywait(lwp_sema_t *);
|
||||
int _lwp_sema_post(lwp_sema_t *);
|
||||
int cond_init(cond_t *, int, void *);
|
||||
int cond_destroy(cond_t *);
|
||||
int cond_wait(cond_t *, mutex_t *);
|
||||
int cond_timedwait(cond_t *, mutex_t *, const timespec_t *);
|
||||
int cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
|
||||
int cond_signal(cond_t *);
|
||||
int cond_broadcast(cond_t *);
|
||||
int mutex_init(mutex_t *, int, void *);
|
||||
int mutex_destroy(mutex_t *);
|
||||
int mutex_lock(mutex_t *);
|
||||
int mutex_trylock(mutex_t *);
|
||||
int mutex_unlock(mutex_t *);
|
||||
int rwlock_init(rwlock_t *, int, void *);
|
||||
int rwlock_destroy(rwlock_t *);
|
||||
int rw_rdlock(rwlock_t *);
|
||||
int rw_wrlock(rwlock_t *);
|
||||
int rw_unlock(rwlock_t *);
|
||||
int rw_tryrdlock(rwlock_t *);
|
||||
int rw_trywrlock(rwlock_t *);
|
||||
int sema_init(sema_t *, unsigned int, int, void *);
|
||||
int sema_destroy(sema_t *);
|
||||
int sema_wait(sema_t *);
|
||||
int sema_timedwait(sema_t *, const timespec_t *);
|
||||
int sema_reltimedwait(sema_t *, const timespec_t *);
|
||||
int sema_post(sema_t *);
|
||||
int sema_trywait(sema_t *);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
int _lwp_mutex_lock();
|
||||
int _lwp_mutex_unlock();
|
||||
int _lwp_mutex_trylock();
|
||||
int _lwp_cond_wait();
|
||||
int _lwp_cond_timedwait();
|
||||
int _lwp_cond_reltimedwait();
|
||||
int _lwp_cond_signal();
|
||||
int _lwp_cond_broadcast();
|
||||
int _lwp_sema_init();
|
||||
int _lwp_sema_wait();
|
||||
int _lwp_sema_trywait();
|
||||
int _lwp_sema_post();
|
||||
int cond_init();
|
||||
int cond_destroy();
|
||||
int cond_wait();
|
||||
int cond_timedwait();
|
||||
int cond_reltimedwait();
|
||||
int cond_signal();
|
||||
int cond_broadcast();
|
||||
int mutex_init();
|
||||
int mutex_destroy();
|
||||
int mutex_lock();
|
||||
int mutex_trylock();
|
||||
int mutex_unlock();
|
||||
int rwlock_init();
|
||||
int rwlock_destroy();
|
||||
int rw_rdlock();
|
||||
int rw_wrlock();
|
||||
int rw_unlock();
|
||||
int rw_tryrdlock();
|
||||
int rw_trywrlock();
|
||||
int sema_init();
|
||||
int sema_destroy();
|
||||
int sema_wait();
|
||||
int sema_timedwait();
|
||||
int sema_reltimedwait();
|
||||
int sema_post();
|
||||
int sema_trywait();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
/* "Magic numbers" tagging synchronization object types */
|
||||
#define MUTEX_MAGIC _MUTEX_MAGIC
|
||||
#define SEMA_MAGIC _SEMA_MAGIC
|
||||
#define COND_MAGIC _COND_MAGIC
|
||||
#define RWL_MAGIC _RWL_MAGIC
|
||||
|
||||
/*
|
||||
* POSIX.1c Note:
|
||||
* DEFAULTMUTEX is defined same as PTHREAD_MUTEX_INITIALIZER in <pthread.h>.
|
||||
* DEFAULTCV is defined same as PTHREAD_COND_INITIALIZER in <pthread.h>.
|
||||
* DEFAULTRWLOCK is defined same as PTHREAD_RWLOCK_INITIALIZER in <pthread.h>.
|
||||
* Any changes to these macros should be reflected in <pthread.h>
|
||||
*/
|
||||
#define DEFAULTMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define SHAREDMUTEX \
|
||||
{{0, 0, 0, {USYNC_PROCESS}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define RECURSIVEMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define ERRORCHECKMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_ERRORCHECK}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define RECURSIVE_ERRORCHECKMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE|LOCK_ERRORCHECK}, \
|
||||
MUTEX_MAGIC}, {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define DEFAULTCV \
|
||||
{{{0, 0, 0, 0}, USYNC_THREAD, COND_MAGIC}, 0}
|
||||
#define SHAREDCV \
|
||||
{{{0, 0, 0, 0}, USYNC_PROCESS, COND_MAGIC}, 0}
|
||||
#define DEFAULTSEMA \
|
||||
{0, USYNC_THREAD, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
|
||||
#define SHAREDSEMA \
|
||||
{0, USYNC_PROCESS, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
|
||||
#define DEFAULTRWLOCK \
|
||||
{0, USYNC_THREAD, RWL_MAGIC, DEFAULTMUTEX, DEFAULTCV, DEFAULTCV}
|
||||
#define SHAREDRWLOCK \
|
||||
{0, USYNC_PROCESS, RWL_MAGIC, SHAREDMUTEX, SHAREDCV, SHAREDCV}
|
||||
|
||||
/*
|
||||
* Tests on lock states.
|
||||
*/
|
||||
#define SEMA_HELD(x) _sema_held(x)
|
||||
#define RW_READ_HELD(x) _rw_read_held(x)
|
||||
#define RW_WRITE_HELD(x) _rw_write_held(x)
|
||||
#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_HELD(x))
|
||||
#define MUTEX_HELD(x) _mutex_held(x)
|
||||
|
||||
/*
|
||||
* The following definitions are for assertions which can be checked
|
||||
* statically by tools like lock_lint. You can also define your own
|
||||
* run-time test for each. If you don't, we define them to 1 so that
|
||||
* such assertions simply pass.
|
||||
*/
|
||||
#ifndef NO_LOCKS_HELD
|
||||
#define NO_LOCKS_HELD 1
|
||||
#endif
|
||||
#ifndef NO_COMPETING_THREADS
|
||||
#define NO_COMPETING_THREADS 1
|
||||
#endif
|
||||
|
||||
#ifndef _ASM
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
int _sema_held(sema_t *);
|
||||
int _rw_read_held(rwlock_t *);
|
||||
int _rw_write_held(rwlock_t *);
|
||||
int _mutex_held(mutex_t *);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
int _sema_held();
|
||||
int _rw_read_held();
|
||||
int _rw_write_held();
|
||||
int _mutex_held();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYNCH_H */
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _THREAD_H
|
||||
#define _THREAD_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Compatibility thread stuff needed for Solaris -> Linux port
|
||||
*/
|
||||
|
||||
typedef pthread_t thread_t;
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef pthread_cond_t cond_t;
|
||||
typedef pthread_rwlock_t rwlock_t;
|
||||
|
||||
#define USYNC_THREAD 0
|
||||
|
||||
#define thr_self() (unsigned long)pthread_self()
|
||||
#define thr_equal(a,b) pthread_equal(a,b)
|
||||
#define thr_join(t,d,s) pthread_join(t,s)
|
||||
#define thr_exit(r) pthread_exit(r)
|
||||
#define _mutex_init(l,f,a) pthread_mutex_init(l,NULL)
|
||||
#define _mutex_destroy(l) pthread_mutex_destroy(l)
|
||||
#define mutex_lock(l) pthread_mutex_lock(l)
|
||||
#define mutex_trylock(l) pthread_mutex_trylock(l)
|
||||
#define mutex_unlock(l) pthread_mutex_unlock(l)
|
||||
#define rwlock_init(l,f,a) pthread_rwlock_init(l,NULL)
|
||||
#define rwlock_destroy(l) pthread_rwlock_destroy(l)
|
||||
#define rw_rdlock(l) pthread_rwlock_rdlock(l)
|
||||
#define rw_wrlock(l) pthread_rwlock_wrlock(l)
|
||||
#define rw_tryrdlock(l) pthread_rwlock_tryrdlock(l)
|
||||
#define rw_trywrlock(l) pthread_rwlock_trywrlock(l)
|
||||
#define rw_unlock(l) pthread_rwlock_unlock(l)
|
||||
#define cond_init(l,f,a) pthread_cond_init(l,NULL)
|
||||
#define cond_destroy(l) pthread_cond_destroy(l)
|
||||
#define cond_wait(l,m) pthread_cond_wait(l,m)
|
||||
#define cond_signal(l) pthread_cond_signal(l)
|
||||
#define cond_broadcast(l) pthread_cond_broadcast(l)
|
||||
|
||||
#define THR_BOUND 0x00000001 /* = PTHREAD_SCOPE_SYSTEM */
|
||||
#define THR_NEW_LWP 0x00000002
|
||||
#define THR_DETACHED 0x00000040 /* = PTHREAD_CREATE_DETACHED */
|
||||
#define THR_SUSPENDED 0x00000080
|
||||
#define THR_DAEMON 0x00000100
|
||||
|
||||
static __inline int
|
||||
thr_create(void *stack_base, size_t stack_size, void *(*start_func) (void*),
|
||||
void *arg, long flags, thread_t *new_thread_ID)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(stack_base == NULL);
|
||||
assert(stack_size == 0);
|
||||
assert((flags & ~THR_BOUND & ~THR_DETACHED) == 0);
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
if(flags & THR_DETACHED)
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
/* This function ignores the THR_BOUND flag, since NPTL doesn't seem to support PTHREAD_SCOPE_PROCESS */
|
||||
|
||||
ret = pthread_create(new_thread_ID, &attr, start_func, arg);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* _THREAD_H */
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include "libnvpair.h"
|
||||
|
||||
/*
|
||||
* libnvpair - A tools library for manipulating <name, value> pairs.
|
||||
*
|
||||
* This library provides routines packing an unpacking nv pairs
|
||||
* for transporting data across process boundaries, transporting
|
||||
* between kernel and userland, and possibly saving onto disk files.
|
||||
*/
|
||||
|
||||
static void
|
||||
indent(FILE *fp, int depth)
|
||||
{
|
||||
while (depth-- > 0)
|
||||
(void) fprintf(fp, "\t");
|
||||
}
|
||||
|
||||
/*
|
||||
* nvlist_print - Prints elements in an event buffer
|
||||
*/
|
||||
static
|
||||
void
|
||||
nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
|
||||
{
|
||||
int i;
|
||||
char *name;
|
||||
uint_t nelem;
|
||||
nvpair_t *nvp;
|
||||
|
||||
if (nvl == NULL)
|
||||
return;
|
||||
|
||||
indent(fp, depth);
|
||||
(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
|
||||
|
||||
nvp = nvlist_next_nvpair(nvl, NULL);
|
||||
|
||||
while (nvp) {
|
||||
data_type_t type = nvpair_type(nvp);
|
||||
|
||||
indent(fp, depth);
|
||||
name = nvpair_name(nvp);
|
||||
(void) fprintf(fp, "\t%s =", name);
|
||||
nelem = 0;
|
||||
switch (type) {
|
||||
case DATA_TYPE_BOOLEAN: {
|
||||
(void) fprintf(fp, " 1");
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BOOLEAN_VALUE: {
|
||||
boolean_t val;
|
||||
(void) nvpair_value_boolean_value(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BYTE: {
|
||||
uchar_t val;
|
||||
(void) nvpair_value_byte(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%2.2x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT8: {
|
||||
int8_t val;
|
||||
(void) nvpair_value_int8(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT8: {
|
||||
uint8_t val;
|
||||
(void) nvpair_value_uint8(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT16: {
|
||||
int16_t val;
|
||||
(void) nvpair_value_int16(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT16: {
|
||||
uint16_t val;
|
||||
(void) nvpair_value_uint16(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT32: {
|
||||
int32_t val;
|
||||
(void) nvpair_value_int32(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT32: {
|
||||
uint32_t val;
|
||||
(void) nvpair_value_uint32(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT64: {
|
||||
int64_t val;
|
||||
(void) nvpair_value_int64(nvp, &val);
|
||||
(void) fprintf(fp, " %lld", (longlong_t)val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT64: {
|
||||
uint64_t val;
|
||||
(void) nvpair_value_uint64(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%llx", (u_longlong_t)val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_STRING: {
|
||||
char *val;
|
||||
(void) nvpair_value_string(nvp, &val);
|
||||
(void) fprintf(fp, " %s", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BOOLEAN_ARRAY: {
|
||||
boolean_t *val;
|
||||
(void) nvpair_value_boolean_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BYTE_ARRAY: {
|
||||
uchar_t *val;
|
||||
(void) nvpair_value_byte_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%2.2x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT8_ARRAY: {
|
||||
int8_t *val;
|
||||
(void) nvpair_value_int8_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT8_ARRAY: {
|
||||
uint8_t *val;
|
||||
(void) nvpair_value_uint8_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT16_ARRAY: {
|
||||
int16_t *val;
|
||||
(void) nvpair_value_int16_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT16_ARRAY: {
|
||||
uint16_t *val;
|
||||
(void) nvpair_value_uint16_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT32_ARRAY: {
|
||||
int32_t *val;
|
||||
(void) nvpair_value_int32_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT32_ARRAY: {
|
||||
uint32_t *val;
|
||||
(void) nvpair_value_uint32_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT64_ARRAY: {
|
||||
int64_t *val;
|
||||
(void) nvpair_value_int64_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %lld", (longlong_t)val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT64_ARRAY: {
|
||||
uint64_t *val;
|
||||
(void) nvpair_value_uint64_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%llx",
|
||||
(u_longlong_t)val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_STRING_ARRAY: {
|
||||
char **val;
|
||||
(void) nvpair_value_string_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %s", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_HRTIME: {
|
||||
hrtime_t val;
|
||||
(void) nvpair_value_hrtime(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%llx", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_NVLIST: {
|
||||
nvlist_t *val;
|
||||
(void) nvpair_value_nvlist(nvp, &val);
|
||||
(void) fprintf(fp, " (embedded nvlist)\n");
|
||||
nvlist_print_with_indent(fp, val, depth + 1);
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp, "(end %s)\n", name);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_NVLIST_ARRAY: {
|
||||
nvlist_t **val;
|
||||
(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
|
||||
(void) fprintf(fp, " (array of embedded nvlists)\n");
|
||||
for (i = 0; i < nelem; i++) {
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp,
|
||||
"(start %s[%d])\n", name, i);
|
||||
nvlist_print_with_indent(fp, val[i], depth + 1);
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp, "(end %s[%d])\n", name, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
(void) fprintf(fp, " unknown data type (%d)", type);
|
||||
break;
|
||||
}
|
||||
(void) fprintf(fp, "\n");
|
||||
nvp = nvlist_next_nvpair(nvl, nvp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvlist_print(FILE *fp, nvlist_t *nvl)
|
||||
{
|
||||
nvlist_print_with_indent(fp, nvl, 0);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBNVPAIR_H
|
||||
#define _LIBNVPAIR_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/nvpair.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void nvlist_print(FILE *, nvlist_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBNVPAIR_H */
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/nvpair.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void *
|
||||
nv_alloc_sys(nv_alloc_t *nva, size_t size)
|
||||
{
|
||||
return (malloc(size));
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
nv_free_sys(nv_alloc_t *nva, void *buf, size_t size)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
const nv_alloc_ops_t system_ops_def = {
|
||||
NULL, /* nv_ao_init() */
|
||||
NULL, /* nv_ao_fini() */
|
||||
nv_alloc_sys, /* nv_ao_alloc() */
|
||||
nv_free_sys, /* nv_ao_free() */
|
||||
NULL /* nv_ao_reset() */
|
||||
};
|
||||
|
||||
nv_alloc_t nv_alloc_nosleep_def = {
|
||||
&system_ops_def,
|
||||
NULL
|
||||
};
|
||||
|
||||
nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
|
||||
@@ -1,384 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUUTIL_H
|
||||
#define _LIBUUTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <solaris.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Standard flags codes.
|
||||
*/
|
||||
#define UU_DEFAULT 0
|
||||
|
||||
/*
|
||||
* Standard error codes.
|
||||
*/
|
||||
#define UU_ERROR_NONE 0 /* no error */
|
||||
#define UU_ERROR_INVALID_ARGUMENT 1 /* invalid argument */
|
||||
#define UU_ERROR_UNKNOWN_FLAG 2 /* passed flag invalid */
|
||||
#define UU_ERROR_NO_MEMORY 3 /* out of memory */
|
||||
#define UU_ERROR_CALLBACK_FAILED 4 /* callback-initiated error */
|
||||
#define UU_ERROR_NOT_SUPPORTED 5 /* operation not supported */
|
||||
#define UU_ERROR_EMPTY 6 /* no value provided */
|
||||
#define UU_ERROR_UNDERFLOW 7 /* value is too small */
|
||||
#define UU_ERROR_OVERFLOW 8 /* value is too value */
|
||||
#define UU_ERROR_INVALID_CHAR 9 /* value contains unexpected char */
|
||||
#define UU_ERROR_INVALID_DIGIT 10 /* value contains digit not in base */
|
||||
|
||||
#define UU_ERROR_SYSTEM 99 /* underlying system error */
|
||||
#define UU_ERROR_UNKNOWN 100 /* error status not known */
|
||||
|
||||
/*
|
||||
* Standard program exit codes.
|
||||
*/
|
||||
#define UU_EXIT_OK (*(uu_exit_ok()))
|
||||
#define UU_EXIT_FATAL (*(uu_exit_fatal()))
|
||||
#define UU_EXIT_USAGE (*(uu_exit_usage()))
|
||||
|
||||
/*
|
||||
* Exit status profiles.
|
||||
*/
|
||||
#define UU_PROFILE_DEFAULT 0
|
||||
#define UU_PROFILE_LAUNCHER 1
|
||||
|
||||
/*
|
||||
* Error reporting functions.
|
||||
*/
|
||||
uint32_t uu_error(void);
|
||||
const char *uu_strerror(uint32_t);
|
||||
|
||||
/*
|
||||
* Program notification functions.
|
||||
*/
|
||||
extern void uu_alt_exit(int);
|
||||
extern const char *uu_setpname(char *);
|
||||
extern const char *uu_getpname(void);
|
||||
/*PRINTFLIKE1*/
|
||||
extern void uu_warn(const char *, ...);
|
||||
extern void uu_vwarn(const char *, va_list);
|
||||
/*PRINTFLIKE1*/
|
||||
extern void uu_die(const char *, ...) __NORETURN;
|
||||
extern void uu_vdie(const char *, va_list) __NORETURN;
|
||||
/*PRINTFLIKE2*/
|
||||
extern void uu_xdie(int, const char *, ...) __NORETURN;
|
||||
extern void uu_vxdie(int, const char *, va_list) __NORETURN;
|
||||
|
||||
/*
|
||||
* Exit status functions (not to be used directly)
|
||||
*/
|
||||
extern int *uu_exit_ok(void);
|
||||
extern int *uu_exit_fatal(void);
|
||||
extern int *uu_exit_usage(void);
|
||||
|
||||
/*
|
||||
* string->number conversions
|
||||
*/
|
||||
extern int uu_strtoint(const char *, void *, size_t, int, int64_t, int64_t);
|
||||
extern int uu_strtouint(const char *, void *, size_t, int, uint64_t, uint64_t);
|
||||
|
||||
/*
|
||||
* Debug print facility functions.
|
||||
*/
|
||||
typedef struct uu_dprintf uu_dprintf_t;
|
||||
|
||||
typedef enum {
|
||||
UU_DPRINTF_SILENT,
|
||||
UU_DPRINTF_FATAL,
|
||||
UU_DPRINTF_WARNING,
|
||||
UU_DPRINTF_NOTICE,
|
||||
UU_DPRINTF_INFO,
|
||||
UU_DPRINTF_DEBUG
|
||||
} uu_dprintf_severity_t;
|
||||
|
||||
extern uu_dprintf_t *uu_dprintf_create(const char *, uu_dprintf_severity_t,
|
||||
uint_t);
|
||||
/*PRINTFLIKE3*/
|
||||
extern void uu_dprintf(uu_dprintf_t *, uu_dprintf_severity_t,
|
||||
const char *, ...);
|
||||
extern void uu_dprintf_destroy(uu_dprintf_t *);
|
||||
extern const char *uu_dprintf_getname(uu_dprintf_t *);
|
||||
|
||||
/*
|
||||
* Identifier test flags and function.
|
||||
*/
|
||||
#define UU_NAME_DOMAIN 0x1 /* allow SUNW, or com.sun, prefix */
|
||||
#define UU_NAME_PATH 0x2 /* allow '/'-delimited paths */
|
||||
|
||||
int uu_check_name(const char *, uint_t);
|
||||
|
||||
/*
|
||||
* File creation functions.
|
||||
*/
|
||||
extern int uu_open_tmp(const char *dir, uint_t uflags);
|
||||
|
||||
/*
|
||||
* Convenience functions.
|
||||
*/
|
||||
/*PRINTFLIKE1*/
|
||||
extern char *uu_msprintf(const char *format, ...);
|
||||
extern void *uu_zalloc(size_t);
|
||||
extern void uu_free(void *);
|
||||
|
||||
/*
|
||||
* Comparison function type definition.
|
||||
* Developers should be careful in their use of the _private argument. If you
|
||||
* break interface guarantees, you get undefined behavior.
|
||||
*/
|
||||
typedef int uu_compare_fn_t(const void *__left, const void *__right,
|
||||
void *__private);
|
||||
|
||||
/*
|
||||
* Walk variant flags.
|
||||
* A data structure need not provide support for all variants and
|
||||
* combinations. Refer to the appropriate documentation.
|
||||
*/
|
||||
#define UU_WALK_ROBUST 0x00000001 /* walk can survive removes */
|
||||
#define UU_WALK_REVERSE 0x00000002 /* reverse walk order */
|
||||
|
||||
#define UU_WALK_PREORDER 0x00000010 /* walk tree in pre-order */
|
||||
#define UU_WALK_POSTORDER 0x00000020 /* walk tree in post-order */
|
||||
|
||||
/*
|
||||
* Walk callback function return codes.
|
||||
*/
|
||||
#define UU_WALK_ERROR -1
|
||||
#define UU_WALK_NEXT 0
|
||||
#define UU_WALK_DONE 1
|
||||
|
||||
/*
|
||||
* Walk callback function type definition.
|
||||
*/
|
||||
typedef int uu_walk_fn_t(void *_elem, void *_private);
|
||||
|
||||
/*
|
||||
* lists: opaque structures
|
||||
*/
|
||||
typedef struct uu_list_pool uu_list_pool_t;
|
||||
typedef struct uu_list uu_list_t;
|
||||
|
||||
typedef struct uu_list_node {
|
||||
uintptr_t uln_opaque[2];
|
||||
} uu_list_node_t;
|
||||
|
||||
typedef struct uu_list_walk uu_list_walk_t;
|
||||
|
||||
typedef uintptr_t uu_list_index_t;
|
||||
|
||||
/*
|
||||
* lists: interface
|
||||
*
|
||||
* basic usage:
|
||||
* typedef struct foo {
|
||||
* ...
|
||||
* uu_list_node_t foo_node;
|
||||
* ...
|
||||
* } foo_t;
|
||||
*
|
||||
* static int
|
||||
* foo_compare(void *l_arg, void *r_arg, void *private)
|
||||
* {
|
||||
* foo_t *l = l_arg;
|
||||
* foo_t *r = r_arg;
|
||||
*
|
||||
* if (... l greater than r ...)
|
||||
* return (1);
|
||||
* if (... l less than r ...)
|
||||
* return (-1);
|
||||
* return (0);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* // at initialization time
|
||||
* foo_pool = uu_list_pool_create("foo_pool",
|
||||
* sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
|
||||
* debugging? 0 : UU_AVL_POOL_DEBUG);
|
||||
* ...
|
||||
*/
|
||||
uu_list_pool_t *uu_list_pool_create(const char *, size_t, size_t,
|
||||
uu_compare_fn_t *, uint32_t);
|
||||
#define UU_LIST_POOL_DEBUG 0x00000001
|
||||
|
||||
void uu_list_pool_destroy(uu_list_pool_t *);
|
||||
|
||||
/*
|
||||
* usage:
|
||||
*
|
||||
* foo_t *a;
|
||||
* a = malloc(sizeof(*a));
|
||||
* uu_list_node_init(a, &a->foo_list, pool);
|
||||
* ...
|
||||
* uu_list_node_fini(a, &a->foo_list, pool);
|
||||
* free(a);
|
||||
*/
|
||||
void uu_list_node_init(void *, uu_list_node_t *, uu_list_pool_t *);
|
||||
void uu_list_node_fini(void *, uu_list_node_t *, uu_list_pool_t *);
|
||||
|
||||
uu_list_t *uu_list_create(uu_list_pool_t *, void *_parent, uint32_t);
|
||||
#define UU_LIST_DEBUG 0x00000001
|
||||
#define UU_LIST_SORTED 0x00000002 /* list is sorted */
|
||||
|
||||
void uu_list_destroy(uu_list_t *); /* list must be empty */
|
||||
|
||||
size_t uu_list_numnodes(uu_list_t *);
|
||||
|
||||
void *uu_list_first(uu_list_t *);
|
||||
void *uu_list_last(uu_list_t *);
|
||||
|
||||
void *uu_list_next(uu_list_t *, void *);
|
||||
void *uu_list_prev(uu_list_t *, void *);
|
||||
|
||||
int uu_list_walk(uu_list_t *, uu_walk_fn_t *, void *, uint32_t);
|
||||
|
||||
uu_list_walk_t *uu_list_walk_start(uu_list_t *, uint32_t);
|
||||
void *uu_list_walk_next(uu_list_walk_t *);
|
||||
void uu_list_walk_end(uu_list_walk_t *);
|
||||
|
||||
void *uu_list_find(uu_list_t *, void *, void *, uu_list_index_t *);
|
||||
void uu_list_insert(uu_list_t *, void *, uu_list_index_t);
|
||||
|
||||
void *uu_list_nearest_next(uu_list_t *, uu_list_index_t);
|
||||
void *uu_list_nearest_prev(uu_list_t *, uu_list_index_t);
|
||||
|
||||
void *uu_list_teardown(uu_list_t *, void **);
|
||||
|
||||
void uu_list_remove(uu_list_t *, void *);
|
||||
|
||||
/*
|
||||
* lists: interfaces for non-sorted lists only
|
||||
*/
|
||||
int uu_list_insert_before(uu_list_t *, void *_target, void *_elem);
|
||||
int uu_list_insert_after(uu_list_t *, void *_target, void *_elem);
|
||||
|
||||
/*
|
||||
* avl trees: opaque structures
|
||||
*/
|
||||
typedef struct uu_avl_pool uu_avl_pool_t;
|
||||
typedef struct uu_avl uu_avl_t;
|
||||
|
||||
typedef struct uu_avl_node {
|
||||
#ifdef _LP64
|
||||
uintptr_t uan_opaque[3];
|
||||
#else
|
||||
uintptr_t uan_opaque[4];
|
||||
#endif
|
||||
} uu_avl_node_t;
|
||||
|
||||
typedef struct uu_avl_walk uu_avl_walk_t;
|
||||
|
||||
typedef uintptr_t uu_avl_index_t;
|
||||
|
||||
/*
|
||||
* avl trees: interface
|
||||
*
|
||||
* basic usage:
|
||||
* typedef struct foo {
|
||||
* ...
|
||||
* uu_avl_node_t foo_node;
|
||||
* ...
|
||||
* } foo_t;
|
||||
*
|
||||
* static int
|
||||
* foo_compare(void *l_arg, void *r_arg, void *private)
|
||||
* {
|
||||
* foo_t *l = l_arg;
|
||||
* foo_t *r = r_arg;
|
||||
*
|
||||
* if (... l greater than r ...)
|
||||
* return (1);
|
||||
* if (... l less than r ...)
|
||||
* return (-1);
|
||||
* return (0);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* // at initialization time
|
||||
* foo_pool = uu_avl_pool_create("foo_pool",
|
||||
* sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
|
||||
* debugging? 0 : UU_AVL_POOL_DEBUG);
|
||||
* ...
|
||||
*/
|
||||
uu_avl_pool_t *uu_avl_pool_create(const char *, size_t, size_t,
|
||||
uu_compare_fn_t *, uint32_t);
|
||||
#define UU_AVL_POOL_DEBUG 0x00000001
|
||||
|
||||
void uu_avl_pool_destroy(uu_avl_pool_t *);
|
||||
|
||||
/*
|
||||
* usage:
|
||||
*
|
||||
* foo_t *a;
|
||||
* a = malloc(sizeof(*a));
|
||||
* uu_avl_node_init(a, &a->foo_avl, pool);
|
||||
* ...
|
||||
* uu_avl_node_fini(a, &a->foo_avl, pool);
|
||||
* free(a);
|
||||
*/
|
||||
void uu_avl_node_init(void *, uu_avl_node_t *, uu_avl_pool_t *);
|
||||
void uu_avl_node_fini(void *, uu_avl_node_t *, uu_avl_pool_t *);
|
||||
|
||||
uu_avl_t *uu_avl_create(uu_avl_pool_t *, void *_parent, uint32_t);
|
||||
#define UU_AVL_DEBUG 0x00000001
|
||||
|
||||
void uu_avl_destroy(uu_avl_t *); /* list must be empty */
|
||||
|
||||
size_t uu_avl_numnodes(uu_avl_t *);
|
||||
|
||||
void *uu_avl_first(uu_avl_t *);
|
||||
void *uu_avl_last(uu_avl_t *);
|
||||
|
||||
void *uu_avl_next(uu_avl_t *, void *);
|
||||
void *uu_avl_prev(uu_avl_t *, void *);
|
||||
|
||||
int uu_avl_walk(uu_avl_t *, uu_walk_fn_t *, void *, uint32_t);
|
||||
|
||||
uu_avl_walk_t *uu_avl_walk_start(uu_avl_t *, uint32_t);
|
||||
void *uu_avl_walk_next(uu_avl_walk_t *);
|
||||
void uu_avl_walk_end(uu_avl_walk_t *);
|
||||
|
||||
void *uu_avl_find(uu_avl_t *, void *, void *, uu_avl_index_t *);
|
||||
void uu_avl_insert(uu_avl_t *, void *, uu_avl_index_t);
|
||||
|
||||
void *uu_avl_nearest_next(uu_avl_t *, uu_avl_index_t);
|
||||
void *uu_avl_nearest_prev(uu_avl_t *, uu_avl_index_t);
|
||||
|
||||
void *uu_avl_teardown(uu_avl_t *, void **);
|
||||
|
||||
void uu_avl_remove(uu_avl_t *, void *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBUUTIL_H */
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUUTIL_COMMON_H
|
||||
#define _LIBUUTIL_COMMON_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <solaris.h>
|
||||
|
||||
/*
|
||||
* We don't bind to the internal libc interfaces if this is a
|
||||
* native build.
|
||||
*/
|
||||
#ifndef NATIVE_BUILD
|
||||
#include "c_synonyms.h"
|
||||
#endif
|
||||
|
||||
#include <libuutil.h>
|
||||
#include <libuutil_impl.h>
|
||||
|
||||
#endif /* _LIBUUTIL_COMMON_H */
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUUTIL_IMPL_H
|
||||
#define _LIBUUTIL_IMPL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libuutil.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/avl_impl.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void uu_set_error(uint_t);
|
||||
#pragma rarely_called(uu_set_error)
|
||||
|
||||
/*PRINTFLIKE1*/
|
||||
void uu_panic(const char *format, ...);
|
||||
#pragma rarely_called(uu_panic)
|
||||
|
||||
struct uu_dprintf {
|
||||
char *uud_name;
|
||||
uu_dprintf_severity_t uud_severity;
|
||||
uint_t uud_flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* For debugging purposes, libuutil keeps around linked lists of all uu_lists
|
||||
* and uu_avls, along with pointers to their parents. These can cause false
|
||||
* negatives when looking for memory leaks, so we encode the pointers by
|
||||
* storing them with swapped endianness; this is not perfect, but it's about
|
||||
* the best we can do without wasting a lot of space.
|
||||
*/
|
||||
#ifdef _LP64
|
||||
#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr))
|
||||
#else
|
||||
#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr))
|
||||
#endif
|
||||
|
||||
#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr))
|
||||
|
||||
/*
|
||||
* uu_list structures
|
||||
*/
|
||||
typedef struct uu_list_node_impl {
|
||||
struct uu_list_node_impl *uln_next;
|
||||
struct uu_list_node_impl *uln_prev;
|
||||
} uu_list_node_impl_t;
|
||||
|
||||
struct uu_list_walk {
|
||||
uu_list_walk_t *ulw_next;
|
||||
uu_list_walk_t *ulw_prev;
|
||||
|
||||
uu_list_t *ulw_list;
|
||||
int8_t ulw_dir;
|
||||
uint8_t ulw_robust;
|
||||
uu_list_node_impl_t *ulw_next_result;
|
||||
};
|
||||
|
||||
struct uu_list {
|
||||
uintptr_t ul_next_enc;
|
||||
uintptr_t ul_prev_enc;
|
||||
|
||||
uu_list_pool_t *ul_pool;
|
||||
uintptr_t ul_parent_enc; /* encoded parent pointer */
|
||||
size_t ul_offset;
|
||||
size_t ul_numnodes;
|
||||
uint8_t ul_debug;
|
||||
uint8_t ul_sorted;
|
||||
uint8_t ul_index; /* mark for uu_list_index_ts */
|
||||
|
||||
uu_list_node_impl_t ul_null_node;
|
||||
uu_list_walk_t ul_null_walk; /* for robust walkers */
|
||||
};
|
||||
|
||||
#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr))
|
||||
|
||||
#define UU_LIST_POOL_MAXNAME 64
|
||||
|
||||
struct uu_list_pool {
|
||||
uu_list_pool_t *ulp_next;
|
||||
uu_list_pool_t *ulp_prev;
|
||||
|
||||
char ulp_name[UU_LIST_POOL_MAXNAME];
|
||||
size_t ulp_nodeoffset;
|
||||
size_t ulp_objsize;
|
||||
uu_compare_fn_t *ulp_cmp;
|
||||
uint8_t ulp_debug;
|
||||
uint8_t ulp_last_index;
|
||||
pthread_mutex_t ulp_lock; /* protects null_list */
|
||||
uu_list_t ulp_null_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* uu_avl structures
|
||||
*/
|
||||
typedef struct avl_node uu_avl_node_impl_t;
|
||||
|
||||
struct uu_avl_walk {
|
||||
uu_avl_walk_t *uaw_next;
|
||||
uu_avl_walk_t *uaw_prev;
|
||||
|
||||
uu_avl_t *uaw_avl;
|
||||
void *uaw_next_result;
|
||||
int8_t uaw_dir;
|
||||
uint8_t uaw_robust;
|
||||
};
|
||||
|
||||
struct uu_avl {
|
||||
uintptr_t ua_next_enc;
|
||||
uintptr_t ua_prev_enc;
|
||||
|
||||
uu_avl_pool_t *ua_pool;
|
||||
uintptr_t ua_parent_enc;
|
||||
uint8_t ua_debug;
|
||||
uint8_t ua_index; /* mark for uu_avl_index_ts */
|
||||
|
||||
struct avl_tree ua_tree;
|
||||
uu_avl_walk_t ua_null_walk;
|
||||
};
|
||||
|
||||
#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x))
|
||||
|
||||
#define UU_AVL_POOL_MAXNAME 64
|
||||
|
||||
struct uu_avl_pool {
|
||||
uu_avl_pool_t *uap_next;
|
||||
uu_avl_pool_t *uap_prev;
|
||||
|
||||
char uap_name[UU_AVL_POOL_MAXNAME];
|
||||
size_t uap_nodeoffset;
|
||||
size_t uap_objsize;
|
||||
uu_compare_fn_t *uap_cmp;
|
||||
uint8_t uap_debug;
|
||||
uint8_t uap_last_index;
|
||||
pthread_mutex_t uap_lock; /* protects null_avl */
|
||||
uu_avl_t uap_null_avl;
|
||||
};
|
||||
|
||||
/*
|
||||
* atfork() handlers
|
||||
*/
|
||||
void uu_avl_lockup(void);
|
||||
void uu_avl_release(void);
|
||||
|
||||
void uu_list_lockup(void);
|
||||
void uu_list_release(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBUUTIL_IMPL_H */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *
|
||||
uu_zalloc(size_t n)
|
||||
{
|
||||
void *p = malloc(n);
|
||||
|
||||
if (p == NULL) {
|
||||
uu_set_error(UU_ERROR_SYSTEM);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
(void) memset(p, 0, n);
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
uu_free(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
char *
|
||||
uu_msprintf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char attic[1];
|
||||
uint_t M, m;
|
||||
char *b;
|
||||
|
||||
va_start(args, format);
|
||||
M = vsnprintf(attic, 1, format, args);
|
||||
va_end(args);
|
||||
|
||||
for (;;) {
|
||||
m = M;
|
||||
if ((b = uu_zalloc(m + 1)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
va_start(args, format);
|
||||
M = vsnprintf(b, m + 1, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (M == m)
|
||||
break; /* sizes match */
|
||||
|
||||
uu_free(b);
|
||||
}
|
||||
|
||||
return (b);
|
||||
}
|
||||
@@ -1,567 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/avl.h>
|
||||
|
||||
static uu_avl_pool_t uu_null_apool = { &uu_null_apool, &uu_null_apool };
|
||||
static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* The index mark change on every insert and delete, to catch stale
|
||||
* references.
|
||||
*
|
||||
* We leave the low bit alone, since the avl code uses it.
|
||||
*/
|
||||
#define INDEX_MAX (sizeof (uintptr_t) - 2)
|
||||
#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX)
|
||||
|
||||
#define INDEX_DECODE(i) ((i) & ~INDEX_MAX)
|
||||
#define INDEX_ENCODE(p, n) (((n) & ~INDEX_MAX) | (p)->ua_index)
|
||||
#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ua_index)
|
||||
#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
|
||||
|
||||
/*
|
||||
* When an element is inactive (not in a tree), we keep a marked pointer to
|
||||
* its containing pool in its first word, and a NULL pointer in its second.
|
||||
*
|
||||
* On insert, we use these to verify that it comes from the correct pool.
|
||||
*/
|
||||
#define NODE_ARRAY(p, n) ((uintptr_t *)((uintptr_t)(n) + \
|
||||
(pp)->uap_nodeoffset))
|
||||
|
||||
#define POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1))
|
||||
|
||||
#define DEAD_MARKER 0xc4
|
||||
|
||||
uu_avl_pool_t *
|
||||
uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
|
||||
uu_compare_fn_t *compare_func, uint32_t flags)
|
||||
{
|
||||
uu_avl_pool_t *pp, *next, *prev;
|
||||
|
||||
if (name == NULL ||
|
||||
uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
|
||||
nodeoffset + sizeof (uu_avl_node_t) > objsize ||
|
||||
compare_func == NULL) {
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (flags & ~UU_AVL_POOL_DEBUG) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pp = uu_zalloc(sizeof (uu_avl_pool_t));
|
||||
if (pp == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
(void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name));
|
||||
pp->uap_nodeoffset = nodeoffset;
|
||||
pp->uap_objsize = objsize;
|
||||
pp->uap_cmp = compare_func;
|
||||
if (flags & UU_AVL_POOL_DEBUG)
|
||||
pp->uap_debug = 1;
|
||||
pp->uap_last_index = 0;
|
||||
|
||||
(void) pthread_mutex_init(&pp->uap_lock, NULL);
|
||||
|
||||
pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
|
||||
pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
|
||||
|
||||
(void) pthread_mutex_lock(&uu_apool_list_lock);
|
||||
pp->uap_next = next = &uu_null_apool;
|
||||
pp->uap_prev = prev = next->uap_prev;
|
||||
next->uap_prev = pp;
|
||||
prev->uap_next = pp;
|
||||
(void) pthread_mutex_unlock(&uu_apool_list_lock);
|
||||
|
||||
return (pp);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_pool_destroy(uu_avl_pool_t *pp)
|
||||
{
|
||||
if (pp->uap_debug) {
|
||||
if (pp->uap_null_avl.ua_next_enc !=
|
||||
UU_PTR_ENCODE(&pp->uap_null_avl) ||
|
||||
pp->uap_null_avl.ua_prev_enc !=
|
||||
UU_PTR_ENCODE(&pp->uap_null_avl)) {
|
||||
uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
|
||||
"outstanding avls, or is corrupt.\n",
|
||||
sizeof (pp->uap_name), pp->uap_name, pp);
|
||||
}
|
||||
}
|
||||
(void) pthread_mutex_lock(&uu_apool_list_lock);
|
||||
pp->uap_next->uap_prev = pp->uap_prev;
|
||||
pp->uap_prev->uap_next = pp->uap_next;
|
||||
(void) pthread_mutex_unlock(&uu_apool_list_lock);
|
||||
pp->uap_prev = NULL;
|
||||
pp->uap_next = NULL;
|
||||
uu_free(pp);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
|
||||
{
|
||||
uintptr_t *na = (uintptr_t *)np;
|
||||
|
||||
if (pp->uap_debug) {
|
||||
uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
|
||||
if (offset + sizeof (*np) > pp->uap_objsize) {
|
||||
uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
|
||||
"offset %ld doesn't fit in object (size %ld)\n",
|
||||
base, np, pp, pp->uap_name, offset,
|
||||
pp->uap_objsize);
|
||||
}
|
||||
if (offset != pp->uap_nodeoffset) {
|
||||
uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
|
||||
"offset %ld doesn't match pool's offset (%ld)\n",
|
||||
base, np, pp, pp->uap_name, offset,
|
||||
pp->uap_objsize);
|
||||
}
|
||||
}
|
||||
|
||||
na[0] = POOL_TO_MARKER(pp);
|
||||
na[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
|
||||
{
|
||||
uintptr_t *na = (uintptr_t *)np;
|
||||
|
||||
if (pp->uap_debug) {
|
||||
if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) {
|
||||
uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
|
||||
"node already finied\n",
|
||||
base, np, pp, pp->uap_name);
|
||||
}
|
||||
if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) {
|
||||
uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
|
||||
"node corrupt, in tree, or in different pool\n",
|
||||
base, np, pp, pp->uap_name);
|
||||
}
|
||||
}
|
||||
|
||||
na[0] = DEAD_MARKER;
|
||||
na[1] = DEAD_MARKER;
|
||||
na[2] = DEAD_MARKER;
|
||||
}
|
||||
|
||||
struct uu_avl_node_compare_info {
|
||||
uu_compare_fn_t *ac_compare;
|
||||
void *ac_private;
|
||||
void *ac_right;
|
||||
void *ac_found;
|
||||
};
|
||||
|
||||
static int
|
||||
uu_avl_node_compare(const void *l, const void *r)
|
||||
{
|
||||
struct uu_avl_node_compare_info *info =
|
||||
(struct uu_avl_node_compare_info *)l;
|
||||
|
||||
int res = info->ac_compare(r, info->ac_right, info->ac_private);
|
||||
|
||||
if (res == 0) {
|
||||
if (info->ac_found == NULL)
|
||||
info->ac_found = (void *)r;
|
||||
return (-1);
|
||||
}
|
||||
if (res < 0)
|
||||
return (1);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
uu_avl_t *
|
||||
uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
|
||||
{
|
||||
uu_avl_t *ap, *next, *prev;
|
||||
|
||||
if (flags & ~UU_AVL_DEBUG) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ap = uu_zalloc(sizeof (*ap));
|
||||
if (ap == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ap->ua_pool = pp;
|
||||
ap->ua_parent_enc = UU_PTR_ENCODE(parent);
|
||||
ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
|
||||
ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
|
||||
|
||||
avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize,
|
||||
pp->uap_nodeoffset);
|
||||
|
||||
ap->ua_null_walk.uaw_next = &ap->ua_null_walk;
|
||||
ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
|
||||
|
||||
(void) pthread_mutex_lock(&pp->uap_lock);
|
||||
next = &pp->uap_null_avl;
|
||||
prev = UU_PTR_DECODE(next->ua_prev_enc);
|
||||
ap->ua_next_enc = UU_PTR_ENCODE(next);
|
||||
ap->ua_prev_enc = UU_PTR_ENCODE(prev);
|
||||
next->ua_prev_enc = UU_PTR_ENCODE(ap);
|
||||
prev->ua_next_enc = UU_PTR_ENCODE(ap);
|
||||
(void) pthread_mutex_unlock(&pp->uap_lock);
|
||||
|
||||
return (ap);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_destroy(uu_avl_t *ap)
|
||||
{
|
||||
uu_avl_pool_t *pp = ap->ua_pool;
|
||||
|
||||
if (ap->ua_debug) {
|
||||
if (avl_numnodes(&ap->ua_tree) != 0) {
|
||||
uu_panic("uu_avl_destroy(%p): tree not empty\n", ap);
|
||||
}
|
||||
if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk ||
|
||||
ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) {
|
||||
uu_panic("uu_avl_destroy(%p): outstanding walkers\n",
|
||||
ap);
|
||||
}
|
||||
}
|
||||
(void) pthread_mutex_lock(&pp->uap_lock);
|
||||
UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
|
||||
UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
|
||||
(void) pthread_mutex_unlock(&pp->uap_lock);
|
||||
ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
|
||||
ap->ua_next_enc = UU_PTR_ENCODE(NULL);
|
||||
|
||||
ap->ua_pool = NULL;
|
||||
avl_destroy(&ap->ua_tree);
|
||||
|
||||
uu_free(ap);
|
||||
}
|
||||
|
||||
size_t
|
||||
uu_avl_numnodes(uu_avl_t *ap)
|
||||
{
|
||||
return (avl_numnodes(&ap->ua_tree));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_first(uu_avl_t *ap)
|
||||
{
|
||||
return (avl_first(&ap->ua_tree));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_last(uu_avl_t *ap)
|
||||
{
|
||||
return (avl_last(&ap->ua_tree));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_next(uu_avl_t *ap, void *node)
|
||||
{
|
||||
return (AVL_NEXT(&ap->ua_tree, node));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_prev(uu_avl_t *ap, void *node)
|
||||
{
|
||||
return (AVL_PREV(&ap->ua_tree, node));
|
||||
}
|
||||
|
||||
static void
|
||||
_avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags)
|
||||
{
|
||||
uu_avl_walk_t *next, *prev;
|
||||
|
||||
int robust = (flags & UU_WALK_ROBUST);
|
||||
int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
|
||||
|
||||
(void) memset(wp, 0, sizeof (*wp));
|
||||
wp->uaw_avl = ap;
|
||||
wp->uaw_robust = robust;
|
||||
wp->uaw_dir = direction;
|
||||
|
||||
if (direction > 0)
|
||||
wp->uaw_next_result = avl_first(&ap->ua_tree);
|
||||
else
|
||||
wp->uaw_next_result = avl_last(&ap->ua_tree);
|
||||
|
||||
if (ap->ua_debug || robust) {
|
||||
wp->uaw_next = next = &ap->ua_null_walk;
|
||||
wp->uaw_prev = prev = next->uaw_prev;
|
||||
next->uaw_prev = wp;
|
||||
prev->uaw_next = wp;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
_avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap)
|
||||
{
|
||||
void *np = wp->uaw_next_result;
|
||||
|
||||
avl_tree_t *t = &ap->ua_tree;
|
||||
|
||||
if (np == NULL)
|
||||
return (NULL);
|
||||
|
||||
wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) :
|
||||
AVL_PREV(t, np);
|
||||
|
||||
return (np);
|
||||
}
|
||||
|
||||
static void
|
||||
_avl_walk_fini(uu_avl_walk_t *wp)
|
||||
{
|
||||
if (wp->uaw_next != NULL) {
|
||||
wp->uaw_next->uaw_prev = wp->uaw_prev;
|
||||
wp->uaw_prev->uaw_next = wp->uaw_next;
|
||||
wp->uaw_next = NULL;
|
||||
wp->uaw_prev = NULL;
|
||||
}
|
||||
wp->uaw_avl = NULL;
|
||||
wp->uaw_next_result = NULL;
|
||||
}
|
||||
|
||||
uu_avl_walk_t *
|
||||
uu_avl_walk_start(uu_avl_t *ap, uint32_t flags)
|
||||
{
|
||||
uu_avl_walk_t *wp;
|
||||
|
||||
if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
wp = uu_zalloc(sizeof (*wp));
|
||||
if (wp == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
_avl_walk_init(wp, ap, flags);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_walk_next(uu_avl_walk_t *wp)
|
||||
{
|
||||
return (_avl_walk_advance(wp, wp->uaw_avl));
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_walk_end(uu_avl_walk_t *wp)
|
||||
{
|
||||
_avl_walk_fini(wp);
|
||||
uu_free(wp);
|
||||
}
|
||||
|
||||
int
|
||||
uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags)
|
||||
{
|
||||
void *e;
|
||||
uu_avl_walk_t my_walk;
|
||||
|
||||
int status = UU_WALK_NEXT;
|
||||
|
||||
if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
_avl_walk_init(&my_walk, ap, flags);
|
||||
while (status == UU_WALK_NEXT &&
|
||||
(e = _avl_walk_advance(&my_walk, ap)) != NULL)
|
||||
status = (*func)(e, private);
|
||||
_avl_walk_fini(&my_walk);
|
||||
|
||||
if (status >= 0)
|
||||
return (0);
|
||||
uu_set_error(UU_ERROR_CALLBACK_FAILED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_remove(uu_avl_t *ap, void *elem)
|
||||
{
|
||||
uu_avl_walk_t *wp;
|
||||
uu_avl_pool_t *pp = ap->ua_pool;
|
||||
uintptr_t *na = NODE_ARRAY(pp, elem);
|
||||
|
||||
if (ap->ua_debug) {
|
||||
/*
|
||||
* invalidate outstanding uu_avl_index_ts.
|
||||
*/
|
||||
ap->ua_index = INDEX_NEXT(ap->ua_index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Robust walkers most be advanced, if we are removing the node
|
||||
* they are currently using. In debug mode, non-robust walkers
|
||||
* are also on the walker list.
|
||||
*/
|
||||
for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk;
|
||||
wp = wp->uaw_next) {
|
||||
if (wp->uaw_robust) {
|
||||
if (elem == wp->uaw_next_result)
|
||||
(void) _avl_walk_advance(wp, ap);
|
||||
} else if (wp->uaw_next_result != NULL) {
|
||||
uu_panic("uu_avl_remove(%p, %p): active non-robust "
|
||||
"walker\n", ap, elem);
|
||||
}
|
||||
}
|
||||
|
||||
avl_remove(&ap->ua_tree, elem);
|
||||
|
||||
na[0] = POOL_TO_MARKER(pp);
|
||||
na[1] = 0;
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_teardown(uu_avl_t *ap, void **cookie)
|
||||
{
|
||||
void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
|
||||
|
||||
if (elem != NULL) {
|
||||
uu_avl_pool_t *pp = ap->ua_pool;
|
||||
uintptr_t *na = NODE_ARRAY(pp, elem);
|
||||
|
||||
na[0] = POOL_TO_MARKER(pp);
|
||||
na[1] = 0;
|
||||
}
|
||||
return (elem);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out)
|
||||
{
|
||||
struct uu_avl_node_compare_info info;
|
||||
void *result;
|
||||
|
||||
info.ac_compare = ap->ua_pool->uap_cmp;
|
||||
info.ac_private = private;
|
||||
info.ac_right = elem;
|
||||
info.ac_found = NULL;
|
||||
|
||||
result = avl_find(&ap->ua_tree, &info, out);
|
||||
if (out != NULL)
|
||||
*out = INDEX_ENCODE(ap, *out);
|
||||
|
||||
if (ap->ua_debug && result != NULL)
|
||||
uu_panic("uu_avl_find: internal error: avl_find succeeded\n");
|
||||
|
||||
return (info.ac_found);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx)
|
||||
{
|
||||
if (ap->ua_debug) {
|
||||
uu_avl_pool_t *pp = ap->ua_pool;
|
||||
uintptr_t *na = NODE_ARRAY(pp, elem);
|
||||
|
||||
if (na[1] != 0)
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): node already "
|
||||
"in tree, or corrupt\n",
|
||||
ap, elem, idx);
|
||||
if (na[0] == 0)
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): node not "
|
||||
"initialized\n",
|
||||
ap, elem, idx);
|
||||
if (na[0] != POOL_TO_MARKER(pp))
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): node from "
|
||||
"other pool, or corrupt\n",
|
||||
ap, elem, idx);
|
||||
|
||||
if (!INDEX_VALID(ap, idx))
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
|
||||
ap, elem, idx,
|
||||
INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
|
||||
/*
|
||||
* invalidate outstanding uu_avl_index_ts.
|
||||
*/
|
||||
ap->ua_index = INDEX_NEXT(ap->ua_index);
|
||||
}
|
||||
avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx)
|
||||
{
|
||||
if (ap->ua_debug && !INDEX_VALID(ap, idx))
|
||||
uu_panic("uu_avl_nearest_next(%p, %p): %s\n",
|
||||
ap, idx, INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx)
|
||||
{
|
||||
if (ap->ua_debug && !INDEX_VALID(ap, idx))
|
||||
uu_panic("uu_avl_nearest_prev(%p, %p): %s\n",
|
||||
ap, idx, INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE));
|
||||
}
|
||||
|
||||
/*
|
||||
* called from uu_lockup() and uu_release(), as part of our fork1()-safety.
|
||||
*/
|
||||
void
|
||||
uu_avl_lockup(void)
|
||||
{
|
||||
uu_avl_pool_t *pp;
|
||||
|
||||
(void) pthread_mutex_lock(&uu_apool_list_lock);
|
||||
for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
|
||||
pp = pp->uap_next)
|
||||
(void) pthread_mutex_lock(&pp->uap_lock);
|
||||
}
|
||||
|
||||
void
|
||||
uu_avl_release(void)
|
||||
{
|
||||
uu_avl_pool_t *pp;
|
||||
|
||||
for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
|
||||
pp = pp->uap_next)
|
||||
(void) pthread_mutex_unlock(&pp->uap_lock);
|
||||
(void) pthread_mutex_unlock(&uu_apool_list_lock);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define FACILITY_FMT "%s (%s): "
|
||||
|
||||
#if !defined(TEXT_DOMAIN)
|
||||
#define TEXT_DOMAIN "SYS_TEST"
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
strseverity(uu_dprintf_severity_t severity)
|
||||
{
|
||||
switch (severity) {
|
||||
case UU_DPRINTF_SILENT:
|
||||
return (dgettext(TEXT_DOMAIN, "silent"));
|
||||
case UU_DPRINTF_FATAL:
|
||||
return (dgettext(TEXT_DOMAIN, "FATAL"));
|
||||
case UU_DPRINTF_WARNING:
|
||||
return (dgettext(TEXT_DOMAIN, "WARNING"));
|
||||
case UU_DPRINTF_NOTICE:
|
||||
return (dgettext(TEXT_DOMAIN, "note"));
|
||||
case UU_DPRINTF_INFO:
|
||||
return (dgettext(TEXT_DOMAIN, "info"));
|
||||
case UU_DPRINTF_DEBUG:
|
||||
return (dgettext(TEXT_DOMAIN, "debug"));
|
||||
default:
|
||||
return (dgettext(TEXT_DOMAIN, "unspecified"));
|
||||
}
|
||||
}
|
||||
|
||||
uu_dprintf_t *
|
||||
uu_dprintf_create(const char *name, uu_dprintf_severity_t severity,
|
||||
uint_t flags)
|
||||
{
|
||||
uu_dprintf_t *D;
|
||||
|
||||
if (uu_check_name(name, UU_NAME_DOMAIN) == -1) {
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (name != NULL) {
|
||||
D->uud_name = strdup(name);
|
||||
if (D->uud_name == NULL) {
|
||||
uu_free(D);
|
||||
return (NULL);
|
||||
}
|
||||
} else {
|
||||
D->uud_name = NULL;
|
||||
}
|
||||
|
||||
D->uud_severity = severity;
|
||||
D->uud_flags = flags;
|
||||
|
||||
return (D);
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
void
|
||||
uu_dprintf(uu_dprintf_t *D, uu_dprintf_severity_t severity,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
|
||||
/* XXX Assert that severity is not UU_DPRINTF_SILENT. */
|
||||
|
||||
if (severity > D->uud_severity)
|
||||
return;
|
||||
|
||||
(void) fprintf(stderr, FACILITY_FMT, D->uud_name,
|
||||
strseverity(severity));
|
||||
|
||||
va_start(alist, format);
|
||||
(void) vfprintf(stderr, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
void
|
||||
uu_dprintf_destroy(uu_dprintf_t *D)
|
||||
{
|
||||
if (D->uud_name)
|
||||
free(D->uud_name);
|
||||
|
||||
uu_free(D);
|
||||
}
|
||||
|
||||
const char *
|
||||
uu_dprintf_getname(uu_dprintf_t *D)
|
||||
{
|
||||
return (D->uud_name);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* We require names of the form:
|
||||
* [provider,]identifier[/[provider,]identifier]...
|
||||
*
|
||||
* Where provider is either a stock symbol (SUNW) or a java-style reversed
|
||||
* domain name (com.sun).
|
||||
*
|
||||
* Both providers and identifiers must start with a letter, and may
|
||||
* only contain alphanumerics, dashes, and underlines. Providers
|
||||
* may also contain periods.
|
||||
*
|
||||
* Note that we do _not_ use the macros in <ctype.h>, since they are affected
|
||||
* by the current locale settings.
|
||||
*/
|
||||
|
||||
#define IS_ALPHA(c) \
|
||||
(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
|
||||
#define IS_DIGIT(c) \
|
||||
((c) >= '0' && (c) <= '9')
|
||||
|
||||
static int
|
||||
is_valid_ident(const char *s, const char *e, int allowdot)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (s >= e)
|
||||
return (0); /* name is empty */
|
||||
|
||||
c = *s++;
|
||||
if (!IS_ALPHA(c))
|
||||
return (0); /* does not start with letter */
|
||||
|
||||
while (s < e && (c = *s++) != 0) {
|
||||
if (IS_ALPHA(c) || IS_DIGIT(c) || c == '-' || c == '_' ||
|
||||
(allowdot && c == '.'))
|
||||
continue;
|
||||
return (0); /* invalid character */
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
is_valid_component(const char *b, const char *e, uint_t flags)
|
||||
{
|
||||
char *sp;
|
||||
|
||||
if (flags & UU_NAME_DOMAIN) {
|
||||
sp = strchr(b, ',');
|
||||
if (sp != NULL && sp < e) {
|
||||
if (!is_valid_ident(b, sp, 1))
|
||||
return (0);
|
||||
b = sp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (is_valid_ident(b, e, 0));
|
||||
}
|
||||
|
||||
int
|
||||
uu_check_name(const char *name, uint_t flags)
|
||||
{
|
||||
const char *end = name + strlen(name);
|
||||
const char *p;
|
||||
|
||||
if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!(flags & UU_NAME_PATH)) {
|
||||
if (!is_valid_component(name, end, flags))
|
||||
goto bad;
|
||||
return (0);
|
||||
}
|
||||
|
||||
while ((p = strchr(name, '/')) != NULL) {
|
||||
if (!is_valid_component(name, p - 1, flags))
|
||||
goto bad;
|
||||
name = p + 1;
|
||||
}
|
||||
if (!is_valid_component(name, end, flags))
|
||||
goto bad;
|
||||
|
||||
return (0);
|
||||
|
||||
bad:
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (-1);
|
||||
}
|
||||
@@ -1,711 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ELEM_TO_NODE(lp, e) \
|
||||
((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
|
||||
|
||||
#define NODE_TO_ELEM(lp, n) \
|
||||
((void *)((uintptr_t)(n) - (lp)->ul_offset))
|
||||
|
||||
/*
|
||||
* uu_list_index_ts define a location for insertion. They are simply a
|
||||
* pointer to the object after the insertion point. We store a mark
|
||||
* in the low-bits of the index, to help prevent mistakes.
|
||||
*
|
||||
* When debugging, the index mark changes on every insert and delete, to
|
||||
* catch stale references.
|
||||
*/
|
||||
#define INDEX_MAX (sizeof (uintptr_t) - 1)
|
||||
#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
|
||||
|
||||
#define INDEX_TO_NODE(i) ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
|
||||
#define NODE_TO_INDEX(p, n) (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
|
||||
#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ul_index)
|
||||
#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
|
||||
|
||||
#define POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
|
||||
|
||||
static uu_list_pool_t uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
|
||||
static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
uu_list_pool_t *
|
||||
uu_list_pool_create(const char *name, size_t objsize,
|
||||
size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
|
||||
{
|
||||
uu_list_pool_t *pp, *next, *prev;
|
||||
|
||||
if (name == NULL ||
|
||||
uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
|
||||
nodeoffset + sizeof (uu_list_node_t) > objsize) {
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (flags & ~UU_LIST_POOL_DEBUG) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pp = uu_zalloc(sizeof (uu_list_pool_t));
|
||||
if (pp == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
(void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
|
||||
pp->ulp_nodeoffset = nodeoffset;
|
||||
pp->ulp_objsize = objsize;
|
||||
pp->ulp_cmp = compare_func;
|
||||
if (flags & UU_LIST_POOL_DEBUG)
|
||||
pp->ulp_debug = 1;
|
||||
pp->ulp_last_index = 0;
|
||||
|
||||
(void) pthread_mutex_init(&pp->ulp_lock, NULL);
|
||||
|
||||
pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
|
||||
pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
|
||||
|
||||
(void) pthread_mutex_lock(&uu_lpool_list_lock);
|
||||
pp->ulp_next = next = &uu_null_lpool;
|
||||
pp->ulp_prev = prev = next->ulp_prev;
|
||||
next->ulp_prev = pp;
|
||||
prev->ulp_next = pp;
|
||||
(void) pthread_mutex_unlock(&uu_lpool_list_lock);
|
||||
|
||||
return (pp);
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_pool_destroy(uu_list_pool_t *pp)
|
||||
{
|
||||
if (pp->ulp_debug) {
|
||||
if (pp->ulp_null_list.ul_next_enc !=
|
||||
UU_PTR_ENCODE(&pp->ulp_null_list) ||
|
||||
pp->ulp_null_list.ul_prev_enc !=
|
||||
UU_PTR_ENCODE(&pp->ulp_null_list)) {
|
||||
uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
|
||||
"outstanding lists, or is corrupt.\n",
|
||||
sizeof (pp->ulp_name), pp->ulp_name, pp);
|
||||
}
|
||||
}
|
||||
(void) pthread_mutex_lock(&uu_lpool_list_lock);
|
||||
pp->ulp_next->ulp_prev = pp->ulp_prev;
|
||||
pp->ulp_prev->ulp_next = pp->ulp_next;
|
||||
(void) pthread_mutex_unlock(&uu_lpool_list_lock);
|
||||
pp->ulp_prev = NULL;
|
||||
pp->ulp_next = NULL;
|
||||
uu_free(pp);
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
|
||||
{
|
||||
uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
|
||||
|
||||
if (pp->ulp_debug) {
|
||||
uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
|
||||
if (offset + sizeof (*np) > pp->ulp_objsize) {
|
||||
uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
|
||||
"offset %ld doesn't fit in object (size %ld)\n",
|
||||
base, np, pp, pp->ulp_name, offset,
|
||||
pp->ulp_objsize);
|
||||
}
|
||||
if (offset != pp->ulp_nodeoffset) {
|
||||
uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
|
||||
"offset %ld doesn't match pool's offset (%ld)\n",
|
||||
base, np, pp, pp->ulp_name, offset,
|
||||
pp->ulp_objsize);
|
||||
}
|
||||
}
|
||||
np->uln_next = POOL_TO_MARKER(pp);
|
||||
np->uln_prev = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
|
||||
{
|
||||
uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
|
||||
|
||||
if (pp->ulp_debug) {
|
||||
if (np->uln_next == NULL &&
|
||||
np->uln_prev == NULL) {
|
||||
uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
|
||||
"node already finied\n",
|
||||
base, np_arg, pp, pp->ulp_name);
|
||||
}
|
||||
if (np->uln_next != POOL_TO_MARKER(pp) ||
|
||||
np->uln_prev != NULL) {
|
||||
uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
|
||||
"node corrupt or on list\n",
|
||||
base, np_arg, pp, pp->ulp_name);
|
||||
}
|
||||
}
|
||||
np->uln_next = NULL;
|
||||
np->uln_prev = NULL;
|
||||
}
|
||||
|
||||
uu_list_t *
|
||||
uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
|
||||
{
|
||||
uu_list_t *lp, *next, *prev;
|
||||
|
||||
if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
|
||||
if (pp->ulp_debug)
|
||||
uu_panic("uu_list_create(%p, ...): requested "
|
||||
"UU_LIST_SORTED, but pool has no comparison func\n",
|
||||
pp);
|
||||
uu_set_error(UU_ERROR_NOT_SUPPORTED);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
lp = uu_zalloc(sizeof (*lp));
|
||||
if (lp == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
lp->ul_pool = pp;
|
||||
lp->ul_parent_enc = UU_PTR_ENCODE(parent);
|
||||
lp->ul_offset = pp->ulp_nodeoffset;
|
||||
lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
|
||||
lp->ul_sorted = (flags & UU_LIST_SORTED);
|
||||
lp->ul_numnodes = 0;
|
||||
lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
|
||||
|
||||
lp->ul_null_node.uln_next = &lp->ul_null_node;
|
||||
lp->ul_null_node.uln_prev = &lp->ul_null_node;
|
||||
|
||||
lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
|
||||
lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
|
||||
|
||||
(void) pthread_mutex_lock(&pp->ulp_lock);
|
||||
next = &pp->ulp_null_list;
|
||||
prev = UU_PTR_DECODE(next->ul_prev_enc);
|
||||
lp->ul_next_enc = UU_PTR_ENCODE(next);
|
||||
lp->ul_prev_enc = UU_PTR_ENCODE(prev);
|
||||
next->ul_prev_enc = UU_PTR_ENCODE(lp);
|
||||
prev->ul_next_enc = UU_PTR_ENCODE(lp);
|
||||
(void) pthread_mutex_unlock(&pp->ulp_lock);
|
||||
|
||||
return (lp);
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_destroy(uu_list_t *lp)
|
||||
{
|
||||
uu_list_pool_t *pp = lp->ul_pool;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
|
||||
lp->ul_null_node.uln_prev != &lp->ul_null_node) {
|
||||
uu_panic("uu_list_destroy(%p): list not empty\n",
|
||||
lp);
|
||||
}
|
||||
if (lp->ul_numnodes != 0) {
|
||||
uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
|
||||
"but list is empty\n", lp);
|
||||
}
|
||||
if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
|
||||
lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
|
||||
uu_panic("uu_list_destroy(%p): outstanding walkers\n",
|
||||
lp);
|
||||
}
|
||||
}
|
||||
|
||||
(void) pthread_mutex_lock(&pp->ulp_lock);
|
||||
UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
|
||||
UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
|
||||
(void) pthread_mutex_unlock(&pp->ulp_lock);
|
||||
lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
|
||||
lp->ul_next_enc = UU_PTR_ENCODE(NULL);
|
||||
lp->ul_pool = NULL;
|
||||
uu_free(lp);
|
||||
}
|
||||
|
||||
static void
|
||||
list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
|
||||
uu_list_node_impl_t *next)
|
||||
{
|
||||
if (lp->ul_debug) {
|
||||
if (next->uln_prev != prev || prev->uln_next != next)
|
||||
uu_panic("insert(%p): internal error: %p and %p not "
|
||||
"neighbors\n", lp, next, prev);
|
||||
|
||||
if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
|
||||
np->uln_prev != NULL) {
|
||||
uu_panic("insert(%p): elem %p node %p corrupt, "
|
||||
"not initialized, or already in a list.\n",
|
||||
lp, NODE_TO_ELEM(lp, np), np);
|
||||
}
|
||||
/*
|
||||
* invalidate outstanding uu_list_index_ts.
|
||||
*/
|
||||
lp->ul_index = INDEX_NEXT(lp->ul_index);
|
||||
}
|
||||
np->uln_next = next;
|
||||
np->uln_prev = prev;
|
||||
next->uln_prev = np;
|
||||
prev->uln_next = np;
|
||||
|
||||
lp->ul_numnodes++;
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
|
||||
{
|
||||
uu_list_node_impl_t *np;
|
||||
|
||||
np = INDEX_TO_NODE(idx);
|
||||
if (np == NULL)
|
||||
np = &lp->ul_null_node;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (!INDEX_VALID(lp, idx))
|
||||
uu_panic("uu_list_insert(%p, %p, %p): %s\n",
|
||||
lp, elem, idx,
|
||||
INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
|
||||
"index\n", lp, elem, idx);
|
||||
}
|
||||
|
||||
list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
|
||||
{
|
||||
int sorted = lp->ul_sorted;
|
||||
uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
|
||||
uu_list_node_impl_t *np;
|
||||
|
||||
if (func == NULL) {
|
||||
if (out != NULL)
|
||||
*out = 0;
|
||||
uu_set_error(UU_ERROR_NOT_SUPPORTED);
|
||||
return (NULL);
|
||||
}
|
||||
for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
|
||||
np = np->uln_next) {
|
||||
void *ep = NODE_TO_ELEM(lp, np);
|
||||
int cmp = func(ep, elem, private);
|
||||
if (cmp == 0) {
|
||||
if (out != NULL)
|
||||
*out = NODE_TO_INDEX(lp, np);
|
||||
return (ep);
|
||||
}
|
||||
if (sorted && cmp > 0) {
|
||||
if (out != NULL)
|
||||
*out = NODE_TO_INDEX(lp, np);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
if (out != NULL)
|
||||
*out = NODE_TO_INDEX(lp, 0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
|
||||
{
|
||||
uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
|
||||
|
||||
if (np == NULL)
|
||||
np = &lp->ul_null_node;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (!INDEX_VALID(lp, idx))
|
||||
uu_panic("uu_list_nearest_next(%p, %p): %s\n",
|
||||
lp, idx, INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
|
||||
"index\n", lp, idx);
|
||||
}
|
||||
|
||||
if (np == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
else
|
||||
return (NODE_TO_ELEM(lp, np));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
|
||||
{
|
||||
uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
|
||||
|
||||
if (np == NULL)
|
||||
np = &lp->ul_null_node;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (!INDEX_VALID(lp, idx))
|
||||
uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
|
||||
lp, idx, INDEX_CHECK(idx)? "outdated index" :
|
||||
"invalid index");
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
|
||||
"index\n", lp, idx);
|
||||
}
|
||||
|
||||
if ((np = np->uln_prev) == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
else
|
||||
return (NODE_TO_ELEM(lp, np));
|
||||
}
|
||||
|
||||
static void
|
||||
list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
|
||||
{
|
||||
uu_list_walk_t *next, *prev;
|
||||
|
||||
int robust = (flags & UU_WALK_ROBUST);
|
||||
int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
|
||||
|
||||
(void) memset(wp, 0, sizeof (*wp));
|
||||
wp->ulw_list = lp;
|
||||
wp->ulw_robust = robust;
|
||||
wp->ulw_dir = direction;
|
||||
if (direction > 0)
|
||||
wp->ulw_next_result = lp->ul_null_node.uln_next;
|
||||
else
|
||||
wp->ulw_next_result = lp->ul_null_node.uln_prev;
|
||||
|
||||
if (lp->ul_debug || robust) {
|
||||
wp->ulw_next = next = &lp->ul_null_walk;
|
||||
wp->ulw_prev = prev = next->ulw_prev;
|
||||
next->ulw_prev = wp;
|
||||
prev->ulw_next = wp;
|
||||
}
|
||||
}
|
||||
|
||||
static uu_list_node_impl_t *
|
||||
list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
|
||||
{
|
||||
uu_list_node_impl_t *np = wp->ulw_next_result;
|
||||
uu_list_node_impl_t *next;
|
||||
|
||||
if (np == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
|
||||
next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
|
||||
|
||||
wp->ulw_next_result = next;
|
||||
return (np);
|
||||
}
|
||||
|
||||
static void
|
||||
list_walk_fini(uu_list_walk_t *wp)
|
||||
{
|
||||
/* GLXXX debugging? */
|
||||
if (wp->ulw_next != NULL) {
|
||||
wp->ulw_next->ulw_prev = wp->ulw_prev;
|
||||
wp->ulw_prev->ulw_next = wp->ulw_next;
|
||||
wp->ulw_next = NULL;
|
||||
wp->ulw_prev = NULL;
|
||||
}
|
||||
wp->ulw_list = NULL;
|
||||
wp->ulw_next_result = NULL;
|
||||
}
|
||||
|
||||
uu_list_walk_t *
|
||||
uu_list_walk_start(uu_list_t *lp, uint32_t flags)
|
||||
{
|
||||
uu_list_walk_t *wp;
|
||||
|
||||
if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
wp = uu_zalloc(sizeof (*wp));
|
||||
if (wp == NULL) {
|
||||
uu_set_error(UU_ERROR_NO_MEMORY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
list_walk_init(wp, lp, flags);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_walk_next(uu_list_walk_t *wp)
|
||||
{
|
||||
uu_list_t *lp = wp->ulw_list;
|
||||
uu_list_node_impl_t *np = list_walk_advance(wp, lp);
|
||||
|
||||
if (np == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (NODE_TO_ELEM(lp, np));
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_walk_end(uu_list_walk_t *wp)
|
||||
{
|
||||
list_walk_fini(wp);
|
||||
uu_free(wp);
|
||||
}
|
||||
|
||||
int
|
||||
uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
|
||||
{
|
||||
uu_list_node_impl_t *np;
|
||||
|
||||
int status = UU_WALK_NEXT;
|
||||
|
||||
int robust = (flags & UU_WALK_ROBUST);
|
||||
int reverse = (flags & UU_WALK_REVERSE);
|
||||
|
||||
if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
|
||||
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (lp->ul_debug || robust) {
|
||||
uu_list_walk_t my_walk;
|
||||
void *e;
|
||||
|
||||
list_walk_init(&my_walk, lp, flags);
|
||||
while (status == UU_WALK_NEXT &&
|
||||
(e = uu_list_walk_next(&my_walk)) != NULL)
|
||||
status = (*func)(e, private);
|
||||
list_walk_fini(&my_walk);
|
||||
} else {
|
||||
if (!reverse) {
|
||||
for (np = lp->ul_null_node.uln_next;
|
||||
status == UU_WALK_NEXT && np != &lp->ul_null_node;
|
||||
np = np->uln_next) {
|
||||
status = (*func)(NODE_TO_ELEM(lp, np), private);
|
||||
}
|
||||
} else {
|
||||
for (np = lp->ul_null_node.uln_prev;
|
||||
status == UU_WALK_NEXT && np != &lp->ul_null_node;
|
||||
np = np->uln_prev) {
|
||||
status = (*func)(NODE_TO_ELEM(lp, np), private);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status >= 0)
|
||||
return (0);
|
||||
uu_set_error(UU_ERROR_CALLBACK_FAILED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_remove(uu_list_t *lp, void *elem)
|
||||
{
|
||||
uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
|
||||
uu_list_walk_t *wp;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_remove(%p, %p): elem not on list\n",
|
||||
lp, elem);
|
||||
/*
|
||||
* invalidate outstanding uu_list_index_ts.
|
||||
*/
|
||||
lp->ul_index = INDEX_NEXT(lp->ul_index);
|
||||
}
|
||||
|
||||
/*
|
||||
* robust walkers must be advanced. In debug mode, non-robust
|
||||
* walkers are also on the list. If there are any, it's an error.
|
||||
*/
|
||||
for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
|
||||
wp = wp->ulw_next) {
|
||||
if (wp->ulw_robust) {
|
||||
if (np == wp->ulw_next_result)
|
||||
(void) list_walk_advance(wp, lp);
|
||||
} else if (wp->ulw_next_result != NULL) {
|
||||
uu_panic("uu_list_remove(%p, %p): active non-robust "
|
||||
"walker\n", lp, elem);
|
||||
}
|
||||
}
|
||||
|
||||
np->uln_next->uln_prev = np->uln_prev;
|
||||
np->uln_prev->uln_next = np->uln_next;
|
||||
|
||||
lp->ul_numnodes--;
|
||||
|
||||
np->uln_next = POOL_TO_MARKER(lp->ul_pool);
|
||||
np->uln_prev = NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_teardown(uu_list_t *lp, void **cookie)
|
||||
{
|
||||
void *ep;
|
||||
|
||||
/*
|
||||
* XXX: disable list modification until list is empty
|
||||
*/
|
||||
if (lp->ul_debug && *cookie != NULL)
|
||||
uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n", lp,
|
||||
cookie);
|
||||
|
||||
ep = uu_list_first(lp);
|
||||
if (ep)
|
||||
uu_list_remove(lp, ep);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
int
|
||||
uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
|
||||
{
|
||||
uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
|
||||
|
||||
if (target == NULL)
|
||||
np = &lp->ul_null_node;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
|
||||
"not currently on a list\n",
|
||||
lp, target, elem, target);
|
||||
}
|
||||
if (lp->ul_sorted) {
|
||||
if (lp->ul_debug)
|
||||
uu_panic("uu_list_insert_before(%p, ...): list is "
|
||||
"UU_LIST_SORTED\n", lp);
|
||||
uu_set_error(UU_ERROR_NOT_SUPPORTED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
|
||||
{
|
||||
uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
|
||||
|
||||
if (target == NULL)
|
||||
np = &lp->ul_null_node;
|
||||
|
||||
if (lp->ul_debug) {
|
||||
if (np->uln_prev == NULL)
|
||||
uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
|
||||
"not currently on a list\n",
|
||||
lp, target, elem, target);
|
||||
}
|
||||
if (lp->ul_sorted) {
|
||||
if (lp->ul_debug)
|
||||
uu_panic("uu_list_insert_after(%p, ...): list is "
|
||||
"UU_LIST_SORTED\n", lp);
|
||||
uu_set_error(UU_ERROR_NOT_SUPPORTED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t
|
||||
uu_list_numnodes(uu_list_t *lp)
|
||||
{
|
||||
return (lp->ul_numnodes);
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_first(uu_list_t *lp)
|
||||
{
|
||||
uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
|
||||
if (n == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
return (NODE_TO_ELEM(lp, n));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_last(uu_list_t *lp)
|
||||
{
|
||||
uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
|
||||
if (n == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
return (NODE_TO_ELEM(lp, n));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_next(uu_list_t *lp, void *elem)
|
||||
{
|
||||
uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
|
||||
|
||||
n = n->uln_next;
|
||||
if (n == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
return (NODE_TO_ELEM(lp, n));
|
||||
}
|
||||
|
||||
void *
|
||||
uu_list_prev(uu_list_t *lp, void *elem)
|
||||
{
|
||||
uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
|
||||
|
||||
n = n->uln_prev;
|
||||
if (n == &lp->ul_null_node)
|
||||
return (NULL);
|
||||
return (NODE_TO_ELEM(lp, n));
|
||||
}
|
||||
|
||||
/*
|
||||
* called from uu_lockup() and uu_release(), as part of our fork1()-safety.
|
||||
*/
|
||||
void
|
||||
uu_list_lockup(void)
|
||||
{
|
||||
uu_list_pool_t *pp;
|
||||
|
||||
(void) pthread_mutex_lock(&uu_lpool_list_lock);
|
||||
for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
|
||||
pp = pp->ulp_next)
|
||||
(void) pthread_mutex_lock(&pp->ulp_lock);
|
||||
}
|
||||
|
||||
void
|
||||
uu_list_release(void)
|
||||
{
|
||||
uu_list_pool_t *pp;
|
||||
|
||||
for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
|
||||
pp = pp->ulp_next)
|
||||
(void) pthread_mutex_unlock(&pp->ulp_lock);
|
||||
(void) pthread_mutex_unlock(&uu_lpool_list_lock);
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/debug.h>
|
||||
#include <thread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(TEXT_DOMAIN)
|
||||
#define TEXT_DOMAIN "SYS_TEST"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
|
||||
* is here to enable the building of a native version of
|
||||
* libuutil.so when the build machine has not yet been upgraded
|
||||
* to a version of libc that provides pthread_key_create_once_np().
|
||||
* It should all be deleted when solaris_nevada ships.
|
||||
* The code is not MT-safe in a relaxed memory model.
|
||||
*/
|
||||
|
||||
#if defined(PTHREAD_ONCE_KEY_NP)
|
||||
static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
|
||||
#else /* PTHREAD_ONCE_KEY_NP */
|
||||
static pthread_key_t uu_error_key = 0;
|
||||
static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif /* PTHREAD_ONCE_KEY_NP */
|
||||
|
||||
static int uu_error_key_setup = 0;
|
||||
|
||||
static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* LINTED static unused */
|
||||
static const char *uu_panic_format;
|
||||
/* LINTED static unused */
|
||||
static va_list uu_panic_args;
|
||||
static pthread_t uu_panic_thread;
|
||||
|
||||
static uint32_t _uu_main_error;
|
||||
|
||||
void
|
||||
uu_set_error(uint_t code)
|
||||
{
|
||||
|
||||
#if defined(PTHREAD_ONCE_KEY_NP)
|
||||
if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
|
||||
uu_error_key_setup = -1;
|
||||
else
|
||||
uu_error_key_setup = 1;
|
||||
#else /* PTHREAD_ONCE_KEY_NP */
|
||||
if (uu_error_key_setup == 0) {
|
||||
(void) pthread_mutex_lock(&uu_key_lock);
|
||||
if (uu_error_key_setup == 0) {
|
||||
if (pthread_key_create(&uu_error_key, NULL) != 0)
|
||||
uu_error_key_setup = -1;
|
||||
else
|
||||
uu_error_key_setup = 1;
|
||||
}
|
||||
(void) pthread_mutex_unlock(&uu_key_lock);
|
||||
}
|
||||
#endif /* PTHREAD_ONCE_KEY_NP */
|
||||
if (uu_error_key_setup > 0)
|
||||
(void) pthread_setspecific(uu_error_key,
|
||||
(void *)(uintptr_t)code);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uu_error(void)
|
||||
{
|
||||
|
||||
if (uu_error_key_setup < 0) /* can't happen? */
|
||||
return (UU_ERROR_UNKNOWN);
|
||||
|
||||
/*
|
||||
* Because UU_ERROR_NONE == 0, if uu_set_error() was
|
||||
* never called, then this will return UU_ERROR_NONE:
|
||||
*/
|
||||
return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
|
||||
}
|
||||
|
||||
const char *
|
||||
uu_strerror(uint32_t code)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
switch (code) {
|
||||
case UU_ERROR_NONE:
|
||||
str = dgettext(TEXT_DOMAIN, "No error");
|
||||
break;
|
||||
|
||||
case UU_ERROR_INVALID_ARGUMENT:
|
||||
str = dgettext(TEXT_DOMAIN, "Invalid argument");
|
||||
break;
|
||||
|
||||
case UU_ERROR_UNKNOWN_FLAG:
|
||||
str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
|
||||
break;
|
||||
|
||||
case UU_ERROR_NO_MEMORY:
|
||||
str = dgettext(TEXT_DOMAIN, "Out of memory");
|
||||
break;
|
||||
|
||||
case UU_ERROR_CALLBACK_FAILED:
|
||||
str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
|
||||
break;
|
||||
|
||||
case UU_ERROR_NOT_SUPPORTED:
|
||||
str = dgettext(TEXT_DOMAIN, "Operation not supported");
|
||||
break;
|
||||
|
||||
case UU_ERROR_EMPTY:
|
||||
str = dgettext(TEXT_DOMAIN, "No value provided");
|
||||
break;
|
||||
|
||||
case UU_ERROR_UNDERFLOW:
|
||||
str = dgettext(TEXT_DOMAIN, "Value too small");
|
||||
break;
|
||||
|
||||
case UU_ERROR_OVERFLOW:
|
||||
str = dgettext(TEXT_DOMAIN, "Value too large");
|
||||
break;
|
||||
|
||||
case UU_ERROR_INVALID_CHAR:
|
||||
str = dgettext(TEXT_DOMAIN,
|
||||
"Value contains unexpected character");
|
||||
break;
|
||||
|
||||
case UU_ERROR_INVALID_DIGIT:
|
||||
str = dgettext(TEXT_DOMAIN,
|
||||
"Value contains digit not in base");
|
||||
break;
|
||||
|
||||
case UU_ERROR_SYSTEM:
|
||||
str = dgettext(TEXT_DOMAIN, "Underlying system error");
|
||||
break;
|
||||
|
||||
case UU_ERROR_UNKNOWN:
|
||||
str = dgettext(TEXT_DOMAIN, "Error status not known");
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = ESRCH;
|
||||
str = NULL;
|
||||
break;
|
||||
}
|
||||
return (str);
|
||||
}
|
||||
|
||||
void
|
||||
uu_panic(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
(void) pthread_mutex_lock(&uu_panic_lock);
|
||||
if (uu_panic_thread == 0) {
|
||||
uu_panic_thread = pthread_self();
|
||||
uu_panic_format = format;
|
||||
va_copy(uu_panic_args, args);
|
||||
}
|
||||
(void) pthread_mutex_unlock(&uu_panic_lock);
|
||||
|
||||
(void) vfprintf(stderr, format, args);
|
||||
|
||||
if (uu_panic_thread == pthread_self())
|
||||
abort();
|
||||
else
|
||||
for (;;)
|
||||
(void) pause();
|
||||
}
|
||||
|
||||
int
|
||||
assfail(const char *astring, const char *file, int line)
|
||||
{
|
||||
__assert(astring, file, line);
|
||||
/*NOTREACHED*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
uu_lockup(void)
|
||||
{
|
||||
(void) pthread_mutex_lock(&uu_panic_lock);
|
||||
#if !defined(PTHREAD_ONCE_KEY_NP)
|
||||
(void) pthread_mutex_lock(&uu_key_lock);
|
||||
#endif
|
||||
uu_avl_lockup();
|
||||
uu_list_lockup();
|
||||
}
|
||||
|
||||
static void
|
||||
uu_release(void)
|
||||
{
|
||||
(void) pthread_mutex_unlock(&uu_panic_lock);
|
||||
#if !defined(PTHREAD_ONCE_KEY_NP)
|
||||
(void) pthread_mutex_unlock(&uu_key_lock);
|
||||
#endif
|
||||
uu_avl_release();
|
||||
uu_list_release();
|
||||
}
|
||||
|
||||
static void
|
||||
uu_release_child(void)
|
||||
{
|
||||
uu_panic_format = NULL;
|
||||
uu_panic_thread = 0;
|
||||
|
||||
uu_release();
|
||||
}
|
||||
|
||||
#pragma init(uu_init)
|
||||
static void
|
||||
uu_init(void)
|
||||
{
|
||||
(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _LP64
|
||||
#define TMPPATHFMT "%s/uu%ld"
|
||||
#else /* _LP64 */
|
||||
#define TMPPATHFMT "%s/uu%lld"
|
||||
#endif /* _LP64 */
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
uu_open_tmp(const char *dir, uint_t uflags)
|
||||
{
|
||||
int f;
|
||||
char *fname = uu_zalloc(PATH_MAX);
|
||||
|
||||
if (fname == NULL)
|
||||
return (-1);
|
||||
|
||||
for (;;) {
|
||||
(void) snprintf(fname, PATH_MAX, "%s/uu%lld", dir, gethrtime());
|
||||
|
||||
f = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600);
|
||||
|
||||
if (f >= 0 || errno != EEXIST)
|
||||
break;
|
||||
}
|
||||
|
||||
if (f >= 0)
|
||||
(void) unlink(fname);
|
||||
|
||||
uu_free(fname);
|
||||
|
||||
return (f);
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char PNAME_FMT[] = "%s: ";
|
||||
static const char ERRNO_FMT[] = ": %s\n";
|
||||
|
||||
static const char *pname;
|
||||
|
||||
static void
|
||||
uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
|
||||
|
||||
int uu_exit_ok_value = EXIT_SUCCESS;
|
||||
int uu_exit_fatal_value = EXIT_FAILURE;
|
||||
int uu_exit_usage_value = 2;
|
||||
|
||||
int *
|
||||
uu_exit_ok(void)
|
||||
{
|
||||
return (&uu_exit_ok_value);
|
||||
}
|
||||
|
||||
int *
|
||||
uu_exit_fatal(void)
|
||||
{
|
||||
return (&uu_exit_fatal_value);
|
||||
}
|
||||
|
||||
int *
|
||||
uu_exit_usage(void)
|
||||
{
|
||||
return (&uu_exit_usage_value);
|
||||
}
|
||||
|
||||
void
|
||||
uu_alt_exit(int profile)
|
||||
{
|
||||
switch (profile) {
|
||||
case UU_PROFILE_DEFAULT:
|
||||
uu_exit_ok_value = EXIT_SUCCESS;
|
||||
uu_exit_fatal_value = EXIT_FAILURE;
|
||||
uu_exit_usage_value = 2;
|
||||
break;
|
||||
case UU_PROFILE_LAUNCHER:
|
||||
uu_exit_ok_value = EXIT_SUCCESS;
|
||||
uu_exit_fatal_value = 124;
|
||||
uu_exit_usage_value = 125;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
uu_warn_internal(int err, const char *format, va_list alist)
|
||||
{
|
||||
if (pname != NULL)
|
||||
(void) fprintf(stderr, PNAME_FMT, pname);
|
||||
|
||||
(void) vfprintf(stderr, format, alist);
|
||||
|
||||
if (strrchr(format, '\n') == NULL)
|
||||
(void) fprintf(stderr, ERRNO_FMT, strerror(err));
|
||||
}
|
||||
|
||||
void
|
||||
uu_vwarn(const char *format, va_list alist)
|
||||
{
|
||||
uu_warn_internal(errno, format, alist);
|
||||
}
|
||||
|
||||
/*PRINTFLIKE1*/
|
||||
void
|
||||
uu_warn(const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
va_start(alist, format);
|
||||
uu_warn_internal(errno, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
static void
|
||||
uu_die_internal(int status, const char *format, va_list alist)
|
||||
{
|
||||
uu_warn_internal(errno, format, alist);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (!issetugid()) {
|
||||
cp = getenv("UU_DIE_ABORTS");
|
||||
if (cp != NULL && *cp != '\0')
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
uu_vdie(const char *format, va_list alist)
|
||||
{
|
||||
uu_die_internal(UU_EXIT_FATAL, format, alist);
|
||||
}
|
||||
|
||||
/*PRINTFLIKE1*/
|
||||
void
|
||||
uu_die(const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
va_start(alist, format);
|
||||
uu_die_internal(UU_EXIT_FATAL, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
void
|
||||
uu_vxdie(int status, const char *format, va_list alist)
|
||||
{
|
||||
uu_die_internal(status, format, alist);
|
||||
}
|
||||
|
||||
/*PRINTFLIKE2*/
|
||||
void
|
||||
uu_xdie(int status, const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
va_start(alist, format);
|
||||
uu_die_internal(status, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
const char *
|
||||
uu_setpname(char *arg0)
|
||||
{
|
||||
/*
|
||||
* Having a NULL argv[0], while uncommon, is possible. It
|
||||
* makes more sense to handle this event in uu_setpname rather
|
||||
* than in each of its consumers.
|
||||
*/
|
||||
if (arg0 == NULL) {
|
||||
pname = "unknown_command";
|
||||
return (pname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against '/' at end of command invocation.
|
||||
*/
|
||||
for (;;) {
|
||||
char *p = strrchr(arg0, '/');
|
||||
if (p == NULL) {
|
||||
pname = arg0;
|
||||
break;
|
||||
} else {
|
||||
if (*(p + 1) == '\0') {
|
||||
*p = '\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
pname = p + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (pname);
|
||||
}
|
||||
|
||||
const char *
|
||||
uu_getpname(void)
|
||||
{
|
||||
return (pname);
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include "libuutil_common.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_BASE 36
|
||||
|
||||
#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
|
||||
|
||||
#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
|
||||
((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
|
||||
|
||||
static int
|
||||
strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char *)s_arg;
|
||||
|
||||
uint64_t val = 0;
|
||||
uint64_t multmax;
|
||||
|
||||
unsigned c, i;
|
||||
|
||||
int neg = 0;
|
||||
|
||||
int bad_digit = 0;
|
||||
int bad_char = 0;
|
||||
int overflow = 0;
|
||||
|
||||
if (s == NULL || base == 1 || base > MAX_BASE) {
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while ((c = *s) != 0 && isspace(c))
|
||||
s++;
|
||||
|
||||
switch (c) {
|
||||
case '-':
|
||||
if (!sign)
|
||||
overflow = 1; /* becomes underflow below */
|
||||
neg = 1;
|
||||
/*FALLTHRU*/
|
||||
case '+':
|
||||
c = *++s;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\0') {
|
||||
uu_set_error(UU_ERROR_EMPTY);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (base == 0) {
|
||||
if (c != '0')
|
||||
base = 10;
|
||||
else if (s[1] == 'x' || s[1] == 'X')
|
||||
base = 16;
|
||||
else
|
||||
base = 8;
|
||||
}
|
||||
|
||||
if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X'))
|
||||
c = *(s += 2);
|
||||
|
||||
if ((val = CTOI(c)) >= base) {
|
||||
if (IS_DIGIT(c))
|
||||
bad_digit = 1;
|
||||
else
|
||||
bad_char = 1;
|
||||
val = 0;
|
||||
}
|
||||
|
||||
multmax = (uint64_t)UINT64_MAX / (uint64_t)base;
|
||||
|
||||
for (c = *++s; c != '\0'; c = *++s) {
|
||||
if ((i = CTOI(c)) >= base) {
|
||||
if (isspace(c))
|
||||
break;
|
||||
if (IS_DIGIT(c))
|
||||
bad_digit = 1;
|
||||
else
|
||||
bad_char = 1;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (val > multmax)
|
||||
overflow = 1;
|
||||
|
||||
val *= base;
|
||||
if ((uint64_t)UINT64_MAX - val < (uint64_t)i)
|
||||
overflow = 1;
|
||||
|
||||
val += i;
|
||||
}
|
||||
|
||||
while ((c = *s) != 0) {
|
||||
if (!isspace(c))
|
||||
bad_char = 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
if (neg) {
|
||||
if (val > -(uint64_t)INT64_MIN)
|
||||
overflow = 1;
|
||||
} else {
|
||||
if (val > INT64_MAX)
|
||||
overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (neg)
|
||||
val = -val;
|
||||
|
||||
if (bad_char | bad_digit | overflow) {
|
||||
if (bad_char)
|
||||
uu_set_error(UU_ERROR_INVALID_CHAR);
|
||||
else if (bad_digit)
|
||||
uu_set_error(UU_ERROR_INVALID_DIGIT);
|
||||
else if (overflow) {
|
||||
if (neg)
|
||||
uu_set_error(UU_ERROR_UNDERFLOW);
|
||||
else
|
||||
uu_set_error(UU_ERROR_OVERFLOW);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*out = val;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uu_strtoint(const char *s, void *v, size_t sz, int base,
|
||||
int64_t min, int64_t max)
|
||||
{
|
||||
uint64_t val_u;
|
||||
int64_t val;
|
||||
|
||||
if (min > max)
|
||||
goto bad_argument;
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
if (max > INT8_MAX || min < INT8_MIN)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 2:
|
||||
if (max > INT16_MAX || min < INT16_MIN)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 4:
|
||||
if (max > INT32_MAX || min < INT32_MIN)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 8:
|
||||
if (max > INT64_MAX || min < INT64_MIN)
|
||||
goto bad_argument;
|
||||
break;
|
||||
default:
|
||||
goto bad_argument;
|
||||
}
|
||||
|
||||
if (min == 0 && max == 0) {
|
||||
min = -(1ULL << (8 * sz - 1));
|
||||
max = (1ULL << (8 * sz - 1)) - 1;
|
||||
}
|
||||
|
||||
if (strtoint(s, &val_u, base, 1) == -1)
|
||||
return (-1);
|
||||
|
||||
val = (int64_t)val_u;
|
||||
|
||||
if (val < min) {
|
||||
uu_set_error(UU_ERROR_UNDERFLOW);
|
||||
return (-1);
|
||||
} else if (val > max) {
|
||||
uu_set_error(UU_ERROR_OVERFLOW);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
*(int8_t *)v = val;
|
||||
return (0);
|
||||
case 2:
|
||||
*(int16_t *)v = val;
|
||||
return (0);
|
||||
case 4:
|
||||
*(int32_t *)v = val;
|
||||
return (0);
|
||||
case 8:
|
||||
*(int64_t *)v = val;
|
||||
return (0);
|
||||
default:
|
||||
break; /* fall through to bad_argument */
|
||||
}
|
||||
|
||||
bad_argument:
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
uu_strtouint(const char *s, void *v, size_t sz, int base,
|
||||
uint64_t min, uint64_t max)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
if (min > max)
|
||||
goto bad_argument;
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
if (max > UINT8_MAX)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 2:
|
||||
if (max > UINT16_MAX)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 4:
|
||||
if (max > UINT32_MAX)
|
||||
goto bad_argument;
|
||||
break;
|
||||
case 8:
|
||||
if (max > UINT64_MAX)
|
||||
goto bad_argument;
|
||||
break;
|
||||
default:
|
||||
goto bad_argument;
|
||||
}
|
||||
|
||||
if (min == 0 && max == 0) {
|
||||
/* we have to be careful, since << can overflow */
|
||||
max = (1ULL << (8 * sz - 1)) * 2 - 1;
|
||||
}
|
||||
|
||||
if (strtoint(s, &val, base, 0) == -1)
|
||||
return (-1);
|
||||
|
||||
if (val < min) {
|
||||
uu_set_error(UU_ERROR_UNDERFLOW);
|
||||
return (-1);
|
||||
} else if (val > max) {
|
||||
uu_set_error(UU_ERROR_OVERFLOW);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
*(uint8_t *)v = val;
|
||||
return (0);
|
||||
case 2:
|
||||
*(uint16_t *)v = val;
|
||||
return (0);
|
||||
case 4:
|
||||
*(uint32_t *)v = val;
|
||||
return (0);
|
||||
case 8:
|
||||
*(uint64_t *)v = val;
|
||||
return (0);
|
||||
default:
|
||||
break; /* shouldn't happen, fall through */
|
||||
}
|
||||
|
||||
bad_argument:
|
||||
uu_set_error(UU_ERROR_INVALID_ARGUMENT);
|
||||
return (-1);
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_H
|
||||
#define _LIBZFS_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <assert.h>
|
||||
#include <libnvpair.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/varargs.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Miscellaneous ZFS constants
|
||||
*/
|
||||
#define ZFS_MAXNAMELEN MAXNAMELEN
|
||||
#define ZPOOL_MAXNAMELEN MAXNAMELEN
|
||||
#define ZFS_MAXPROPLEN MAXPATHLEN
|
||||
|
||||
/*
|
||||
* libzfs errors
|
||||
*/
|
||||
enum {
|
||||
EZFS_NOMEM = 2000, /* out of memory */
|
||||
EZFS_BADPROP, /* invalid property value */
|
||||
EZFS_PROPREADONLY, /* cannot set readonly property */
|
||||
EZFS_PROPTYPE, /* property does not apply to dataset type */
|
||||
EZFS_PROPNONINHERIT, /* property is not inheritable */
|
||||
EZFS_PROPSPACE, /* bad quota or reservation */
|
||||
EZFS_BADTYPE, /* dataset is not of appropriate type */
|
||||
EZFS_BUSY, /* pool or dataset is busy */
|
||||
EZFS_EXISTS, /* pool or dataset already exists */
|
||||
EZFS_NOENT, /* no such pool or dataset */
|
||||
EZFS_BADSTREAM, /* bad backup stream */
|
||||
EZFS_DSREADONLY, /* dataset is readonly */
|
||||
EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
|
||||
EZFS_VOLHASDATA, /* volume already contains data */
|
||||
EZFS_INVALIDNAME, /* invalid dataset name */
|
||||
EZFS_BADRESTORE, /* unable to restore to destination */
|
||||
EZFS_BADBACKUP, /* backup failed */
|
||||
EZFS_BADTARGET, /* bad attach/detach/replace target */
|
||||
EZFS_NODEVICE, /* no such device in pool */
|
||||
EZFS_BADDEV, /* invalid device to add */
|
||||
EZFS_NOREPLICAS, /* no valid replicas */
|
||||
EZFS_RESILVERING, /* currently resilvering */
|
||||
EZFS_BADVERSION, /* unsupported version */
|
||||
EZFS_POOLUNAVAIL, /* pool is currently unavailable */
|
||||
EZFS_DEVOVERFLOW, /* too many devices in one vdev */
|
||||
EZFS_BADPATH, /* must be an absolute path */
|
||||
EZFS_CROSSTARGET, /* rename or clone across pool or dataset */
|
||||
EZFS_ZONED, /* used improperly in local zone */
|
||||
EZFS_MOUNTFAILED, /* failed to mount dataset */
|
||||
EZFS_UMOUNTFAILED, /* failed to unmount dataset */
|
||||
EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
|
||||
EZFS_SHARENFSFAILED, /* share(1M) failed */
|
||||
EZFS_DEVLINKS, /* failed to create zvol links */
|
||||
EZFS_PERM, /* permission denied */
|
||||
EZFS_NOSPC, /* out of space */
|
||||
EZFS_IO, /* I/O error */
|
||||
EZFS_INTR, /* signal received */
|
||||
EZFS_ISSPARE, /* device is a hot spare */
|
||||
EZFS_INVALCONFIG, /* invalid vdev configuration */
|
||||
EZFS_RECURSIVE, /* recursive dependency */
|
||||
EZFS_NOHISTORY, /* no history object */
|
||||
EZFS_UNSHAREISCSIFAILED, /* iscsitgtd failed request to unshare */
|
||||
EZFS_SHAREISCSIFAILED, /* iscsitgtd failed request to share */
|
||||
EZFS_POOLPROPS, /* couldn't retrieve pool props */
|
||||
EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
|
||||
EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
|
||||
EZFS_NAMETOOLONG, /* dataset name is too long */
|
||||
EZFS_UNKNOWN
|
||||
};
|
||||
|
||||
/*
|
||||
* Basic handle types
|
||||
*/
|
||||
typedef struct zfs_handle zfs_handle_t;
|
||||
typedef struct zpool_handle zpool_handle_t;
|
||||
typedef struct libzfs_handle libzfs_handle_t;
|
||||
|
||||
/*
|
||||
* Library initialization
|
||||
*/
|
||||
extern libzfs_handle_t *libzfs_init(void);
|
||||
extern void libzfs_fini(libzfs_handle_t *);
|
||||
|
||||
extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
|
||||
extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
|
||||
|
||||
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
|
||||
|
||||
extern int libzfs_errno(libzfs_handle_t *);
|
||||
extern const char *libzfs_error_action(libzfs_handle_t *);
|
||||
extern const char *libzfs_error_description(libzfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Basic handle functions
|
||||
*/
|
||||
extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
|
||||
extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
|
||||
extern void zpool_close(zpool_handle_t *);
|
||||
extern const char *zpool_get_name(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_guid(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_space_used(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_space_total(zpool_handle_t *);
|
||||
extern int zpool_get_root(zpool_handle_t *, char *, size_t);
|
||||
extern int zpool_get_state(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_version(zpool_handle_t *);
|
||||
|
||||
/*
|
||||
* Iterate over all active pools in the system.
|
||||
*/
|
||||
typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
|
||||
extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
|
||||
|
||||
/*
|
||||
* Functions to create and destroy pools
|
||||
*/
|
||||
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
||||
const char *);
|
||||
extern int zpool_destroy(zpool_handle_t *);
|
||||
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
||||
|
||||
/*
|
||||
* Functions to manipulate pool and vdev state
|
||||
*/
|
||||
extern int zpool_scrub(zpool_handle_t *, pool_scrub_type_t);
|
||||
|
||||
extern int zpool_vdev_online(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_offline(zpool_handle_t *, const char *, int);
|
||||
extern int zpool_vdev_attach(zpool_handle_t *, const char *, const char *,
|
||||
nvlist_t *, int);
|
||||
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
|
||||
extern int zpool_clear(zpool_handle_t *, const char *);
|
||||
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *);
|
||||
|
||||
/*
|
||||
* Functions to manage pool properties
|
||||
*/
|
||||
extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
|
||||
extern int zpool_get_prop(zpool_handle_t *, zfs_prop_t, char *,
|
||||
size_t proplen, zfs_source_t *);
|
||||
extern const char *zpool_prop_to_name(zpool_prop_t);
|
||||
extern const char *zpool_prop_values(zpool_prop_t);
|
||||
|
||||
/*
|
||||
* Pool health statistics.
|
||||
*/
|
||||
typedef enum {
|
||||
/*
|
||||
* The following correspond to faults as defined in the (fault.fs.zfs.*)
|
||||
* event namespace. Each is associated with a corresponding message ID.
|
||||
*/
|
||||
ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */
|
||||
ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */
|
||||
ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */
|
||||
ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */
|
||||
ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */
|
||||
ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */
|
||||
ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */
|
||||
ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */
|
||||
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
|
||||
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
|
||||
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
|
||||
|
||||
/*
|
||||
* The following are not faults per se, but still an error possibly
|
||||
* requiring administrative attention. There is no corresponding
|
||||
* message ID.
|
||||
*/
|
||||
ZPOOL_STATUS_VERSION_OLDER, /* older on-disk version */
|
||||
ZPOOL_STATUS_RESILVERING, /* device being resilvered */
|
||||
ZPOOL_STATUS_OFFLINE_DEV, /* device online */
|
||||
|
||||
/*
|
||||
* Finally, the following indicates a healthy pool.
|
||||
*/
|
||||
ZPOOL_STATUS_OK
|
||||
} zpool_status_t;
|
||||
|
||||
extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
|
||||
extern zpool_status_t zpool_import_status(nvlist_t *, char **);
|
||||
|
||||
/*
|
||||
* Statistics and configuration functions.
|
||||
*/
|
||||
extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
|
||||
extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
|
||||
extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
|
||||
|
||||
/*
|
||||
* Import and export functions
|
||||
*/
|
||||
extern int zpool_export(zpool_handle_t *);
|
||||
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
|
||||
const char *);
|
||||
|
||||
/*
|
||||
* Search for pools to import
|
||||
*/
|
||||
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
|
||||
|
||||
/*
|
||||
* Miscellaneous pool functions
|
||||
*/
|
||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
|
||||
extern int zpool_upgrade(zpool_handle_t *);
|
||||
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
||||
extern void zpool_log_history(libzfs_handle_t *, int, char **, const char *,
|
||||
boolean_t, boolean_t);
|
||||
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
* Basic handle manipulations. These functions do not create or destroy the
|
||||
* underlying datasets, only the references to them.
|
||||
*/
|
||||
extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
|
||||
extern void zfs_close(zfs_handle_t *);
|
||||
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
|
||||
extern const char *zfs_get_name(const zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Property management functions. Some functions are shared with the kernel,
|
||||
* and are found in sys/fs/zfs.h.
|
||||
*/
|
||||
extern const char *zfs_prop_to_name(zfs_prop_t);
|
||||
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
|
||||
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
|
||||
zfs_source_t *, char *, size_t, boolean_t);
|
||||
extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
|
||||
zfs_source_t *, char *, size_t);
|
||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||
extern const char *zfs_prop_get_string(zfs_handle_t *, zfs_prop_t);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *);
|
||||
extern const char *zfs_prop_values(zfs_prop_t);
|
||||
extern int zfs_prop_valid_for_type(zfs_prop_t, int);
|
||||
extern const char *zfs_prop_default_string(zfs_prop_t prop);
|
||||
extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
|
||||
extern int zfs_prop_is_string(zfs_prop_t prop);
|
||||
extern const char *zfs_prop_column_name(zfs_prop_t);
|
||||
extern boolean_t zfs_prop_align_right(zfs_prop_t);
|
||||
extern void nicebool(int value, char *buf, size_t buflen);
|
||||
|
||||
typedef struct zfs_proplist {
|
||||
zfs_prop_t pl_prop;
|
||||
char *pl_user_prop;
|
||||
struct zfs_proplist *pl_next;
|
||||
boolean_t pl_all;
|
||||
size_t pl_width;
|
||||
boolean_t pl_fixed;
|
||||
} zfs_proplist_t;
|
||||
|
||||
typedef zfs_proplist_t zpool_proplist_t;
|
||||
|
||||
extern int zfs_get_proplist(libzfs_handle_t *, char *, zfs_proplist_t **);
|
||||
extern int zpool_get_proplist(libzfs_handle_t *, char *, zpool_proplist_t **);
|
||||
extern int zfs_expand_proplist(zfs_handle_t *, zfs_proplist_t **);
|
||||
extern int zpool_expand_proplist(zpool_handle_t *, zpool_proplist_t **);
|
||||
extern void zfs_free_proplist(zfs_proplist_t *);
|
||||
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
|
||||
|
||||
#define ZFS_MOUNTPOINT_NONE "none"
|
||||
#define ZFS_MOUNTPOINT_LEGACY "legacy"
|
||||
|
||||
/*
|
||||
* Functions for printing properties from zfs/zpool
|
||||
*/
|
||||
typedef struct libzfs_get_cbdata {
|
||||
int cb_sources;
|
||||
int cb_columns[4];
|
||||
int cb_colwidths[5];
|
||||
boolean_t cb_scripted;
|
||||
boolean_t cb_literal;
|
||||
boolean_t cb_first;
|
||||
zfs_proplist_t *cb_proplist;
|
||||
} libzfs_get_cbdata_t;
|
||||
|
||||
void libzfs_print_one_property(const char *, libzfs_get_cbdata_t *,
|
||||
const char *, const char *, zfs_source_t, const char *);
|
||||
|
||||
#define GET_COL_NAME 1
|
||||
#define GET_COL_PROPERTY 2
|
||||
#define GET_COL_VALUE 3
|
||||
#define GET_COL_SOURCE 4
|
||||
|
||||
/*
|
||||
* Iterator functions.
|
||||
*/
|
||||
typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
|
||||
extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
|
||||
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
|
||||
|
||||
/*
|
||||
* Functions to create and destroy datasets.
|
||||
*/
|
||||
extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
|
||||
nvlist_t *);
|
||||
extern int zfs_destroy(zfs_handle_t *);
|
||||
extern int zfs_destroy_snaps(zfs_handle_t *, char *);
|
||||
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t);
|
||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, int);
|
||||
extern int zfs_rename(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_send(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_receive(libzfs_handle_t *, const char *, int, int, int,
|
||||
boolean_t, int);
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Miscellaneous functions.
|
||||
*/
|
||||
extern const char *zfs_type_to_name(zfs_type_t);
|
||||
extern void zfs_refresh_properties(zfs_handle_t *);
|
||||
extern int zfs_name_valid(const char *, zfs_type_t);
|
||||
extern int zfs_disable(zfs_handle_t *);
|
||||
extern int zfs_enable(zfs_handle_t *);
|
||||
extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
|
||||
|
||||
/*
|
||||
* Mount support functions.
|
||||
*/
|
||||
extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
|
||||
extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
|
||||
extern int zfs_mount(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_unmount(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_unmountall(zfs_handle_t *, int);
|
||||
|
||||
/*
|
||||
* Share support functions.
|
||||
*/
|
||||
extern boolean_t zfs_is_shared(zfs_handle_t *);
|
||||
extern int zfs_share(zfs_handle_t *);
|
||||
extern int zfs_unshare(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Protocol-specifc share support functions.
|
||||
*/
|
||||
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
|
||||
extern int zfs_share_nfs(zfs_handle_t *);
|
||||
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
|
||||
extern int zfs_unshareall_nfs(zfs_handle_t *);
|
||||
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
|
||||
extern int zfs_share_iscsi(zfs_handle_t *);
|
||||
extern int zfs_unshare_iscsi(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* FreeBSD-specific jail support function.
|
||||
*/
|
||||
extern int zfs_jail(zfs_handle_t *, int, int);
|
||||
|
||||
/*
|
||||
* When dealing with nvlists, verify() is extremely useful
|
||||
*/
|
||||
#ifndef verify
|
||||
#ifdef NDEBUG
|
||||
#define verify(EX) ((void)(EX))
|
||||
#else
|
||||
#define verify(EX) assert(EX)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Utility function to convert a number to a human-readable form.
|
||||
*/
|
||||
extern void zfs_nicenum(uint64_t, char *, size_t);
|
||||
extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
|
||||
|
||||
/*
|
||||
* Pool destroy special. Remove the device information without destroying
|
||||
* the underlying dataset.
|
||||
*/
|
||||
extern int zfs_remove_link(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Given a device or file, determine if it is part of a pool.
|
||||
*/
|
||||
extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
|
||||
boolean_t *);
|
||||
|
||||
/*
|
||||
* ftyp special. Read the label from a given device.
|
||||
*/
|
||||
extern int zpool_read_label(int, nvlist_t **);
|
||||
|
||||
/*
|
||||
* Create and remove zvol /dev links.
|
||||
*/
|
||||
extern int zpool_create_zvol_links(zpool_handle_t *);
|
||||
extern int zpool_remove_zvol_links(zpool_handle_t *);
|
||||
|
||||
/*
|
||||
* Enable and disable datasets within a pool by mounting/unmounting and
|
||||
* sharing/unsharing them.
|
||||
*/
|
||||
extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
|
||||
extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern int zmount(const char *, const char *, int, char *, char *, int, char *,
|
||||
int);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBZFS_H */
|
||||
@@ -1,599 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <zone.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
/*
|
||||
* Structure to keep track of dataset state. Before changing the 'sharenfs' or
|
||||
* 'mountpoint' property, we record whether the filesystem was previously
|
||||
* mounted/shared. This prior state dictates whether we remount/reshare the
|
||||
* dataset after the property has been changed.
|
||||
*
|
||||
* The interface consists of the following sequence of functions:
|
||||
*
|
||||
* changelist_gather()
|
||||
* changelist_prefix()
|
||||
* < change property >
|
||||
* changelist_postfix()
|
||||
* changelist_free()
|
||||
*
|
||||
* Other interfaces:
|
||||
*
|
||||
* changelist_remove() - remove a node from a gathered list
|
||||
* changelist_rename() - renames all datasets appropriately when doing a rename
|
||||
* changelist_unshare() - unshares all the nodes in a given changelist
|
||||
* changelist_haszonedchild() - check if there is any child exported to
|
||||
* a local zone
|
||||
*/
|
||||
typedef struct prop_changenode {
|
||||
zfs_handle_t *cn_handle;
|
||||
int cn_shared;
|
||||
int cn_mounted;
|
||||
int cn_zoned;
|
||||
uu_list_node_t cn_listnode;
|
||||
} prop_changenode_t;
|
||||
|
||||
struct prop_changelist {
|
||||
zfs_prop_t cl_prop;
|
||||
zfs_prop_t cl_realprop;
|
||||
uu_list_pool_t *cl_pool;
|
||||
uu_list_t *cl_list;
|
||||
boolean_t cl_waslegacy;
|
||||
boolean_t cl_allchildren;
|
||||
boolean_t cl_alldependents;
|
||||
int cl_flags;
|
||||
boolean_t cl_haszonedchild;
|
||||
boolean_t cl_sorted;
|
||||
};
|
||||
|
||||
/*
|
||||
* If the property is 'mountpoint', go through and unmount filesystems as
|
||||
* necessary. We don't do the same for 'sharenfs', because we can just re-share
|
||||
* with different options without interrupting service.
|
||||
*/
|
||||
int
|
||||
changelist_prefix(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
int ret = 0;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT)
|
||||
return (0);
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
/*
|
||||
* If we are in the global zone, but this dataset is exported
|
||||
* to a local zone, do nothing.
|
||||
*/
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
continue;
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
switch (clp->cl_realprop) {
|
||||
case ZFS_PROP_NAME:
|
||||
/*
|
||||
* If this was a rename, unshare the zvol, and
|
||||
* remove the /dev/zvol links.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
|
||||
if (zvol_remove_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0)
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
case ZFS_PROP_VOLSIZE:
|
||||
/*
|
||||
* If this was a change to the volume size, we
|
||||
* need to unshare and reshare the volume.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
break;
|
||||
}
|
||||
} else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
|
||||
* reshare the filesystems as necessary. In changelist_gather() we recorded
|
||||
* whether the filesystem was previously shared or mounted. The action we take
|
||||
* depends on the previous state, and whether the value was previously 'legacy'.
|
||||
* For non-legacy properties, we only remount/reshare the filesystem if it was
|
||||
* previously mounted/shared. Otherwise, we always remount/reshare the
|
||||
* filesystem.
|
||||
*/
|
||||
int
|
||||
changelist_postfix(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* If we're changing the mountpoint, attempt to destroy the underlying
|
||||
* mountpoint. All other datasets will have inherited from this dataset
|
||||
* (in which case their mountpoints exist in the filesystem in the new
|
||||
* location), or have explicit mountpoints set (in which case they won't
|
||||
* be in the changelist).
|
||||
*/
|
||||
if ((cn = uu_list_last(clp->cl_list)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
|
||||
remove_mountpoint(cn->cn_handle);
|
||||
|
||||
/*
|
||||
* We walk the datasets in reverse, because we want to mount any parent
|
||||
* datasets before mounting the children.
|
||||
*/
|
||||
for (cn = uu_list_last(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_prev(clp->cl_list, cn)) {
|
||||
/*
|
||||
* If we are in the global zone, but this dataset is exported
|
||||
* to a local zone, do nothing.
|
||||
*/
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
continue;
|
||||
|
||||
zfs_refresh_properties(cn->cn_handle);
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
/*
|
||||
* If we're doing a rename, recreate the /dev/zvol
|
||||
* links.
|
||||
*/
|
||||
if (clp->cl_realprop == ZFS_PROP_NAME &&
|
||||
zvol_create_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0) {
|
||||
ret = -1;
|
||||
} else if (cn->cn_shared ||
|
||||
clp->cl_prop == ZFS_PROP_SHAREISCSI) {
|
||||
if (zfs_prop_get(cn->cn_handle,
|
||||
ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0,
|
||||
B_FALSE) == 0 &&
|
||||
strcmp(shareopts, "off") == 0) {
|
||||
ret = zfs_unshare_iscsi(cn->cn_handle);
|
||||
} else {
|
||||
ret = zfs_share_iscsi(cn->cn_handle);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((clp->cl_waslegacy || cn->cn_mounted) &&
|
||||
!zfs_is_mounted(cn->cn_handle, NULL) &&
|
||||
zfs_mount(cn->cn_handle, NULL, 0) != 0)
|
||||
ret = -1;
|
||||
|
||||
/*
|
||||
* We always re-share even if the filesystem is currently
|
||||
* shared, so that we can adopt any new options.
|
||||
*/
|
||||
if (cn->cn_shared ||
|
||||
(clp->cl_prop == ZFS_PROP_SHARENFS && clp->cl_waslegacy)) {
|
||||
if (zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
|
||||
shareopts, sizeof (shareopts), NULL, NULL, 0,
|
||||
B_FALSE) == 0 && strcmp(shareopts, "off") == 0) {
|
||||
ret = zfs_unshare_nfs(cn->cn_handle, NULL);
|
||||
} else {
|
||||
ret = zfs_share_nfs(cn->cn_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this "dataset" a child of "parent"?
|
||||
*/
|
||||
static boolean_t
|
||||
isa_child_of(const char *dataset, const char *parent)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(parent);
|
||||
|
||||
if (strncmp(dataset, parent, len) == 0 &&
|
||||
(dataset[len] == '@' || dataset[len] == '/' ||
|
||||
dataset[len] == '\0'))
|
||||
return (B_TRUE);
|
||||
else
|
||||
return (B_FALSE);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If we rename a filesystem, child filesystem handles are no longer valid
|
||||
* since we identify each dataset by its name in the ZFS namespace. As a
|
||||
* result, we have to go through and fix up all the names appropriately. We
|
||||
* could do this automatically if libzfs kept track of all open handles, but
|
||||
* this is a lot less work.
|
||||
*/
|
||||
void
|
||||
changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
char newname[ZFS_MAXNAMELEN];
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
/*
|
||||
* Do not rename a clone that's not in the source hierarchy.
|
||||
*/
|
||||
if (!isa_child_of(cn->cn_handle->zfs_name, src))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Destroy the previous mountpoint if needed.
|
||||
*/
|
||||
remove_mountpoint(cn->cn_handle);
|
||||
|
||||
(void) strlcpy(newname, dst, sizeof (newname));
|
||||
(void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));
|
||||
|
||||
(void) strlcpy(cn->cn_handle->zfs_name, newname,
|
||||
sizeof (cn->cn_handle->zfs_name));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a gathered changelist for the 'sharenfs' property, unshare all the
|
||||
* datasets in the list.
|
||||
*/
|
||||
int
|
||||
changelist_unshare(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
int ret = 0;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_SHARENFS)
|
||||
return (0);
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there is any child exported to a local zone in a given changelist.
|
||||
* This information has already been recorded while gathering the changelist
|
||||
* via changelist_gather().
|
||||
*/
|
||||
int
|
||||
changelist_haszonedchild(prop_changelist_t *clp)
|
||||
{
|
||||
return (clp->cl_haszonedchild);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a node from a gathered list.
|
||||
*/
|
||||
void
|
||||
changelist_remove(zfs_handle_t *zhp, prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
|
||||
if (strcmp(cn->cn_handle->zfs_name, zhp->zfs_name) == 0) {
|
||||
uu_list_remove(clp->cl_list, cn);
|
||||
zfs_close(cn->cn_handle);
|
||||
free(cn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Release any memory associated with a changelist.
|
||||
*/
|
||||
void
|
||||
changelist_free(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
void *cookie;
|
||||
|
||||
if (clp->cl_list) {
|
||||
cookie = NULL;
|
||||
while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
|
||||
zfs_close(cn->cn_handle);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
uu_list_destroy(clp->cl_list);
|
||||
}
|
||||
if (clp->cl_pool)
|
||||
uu_list_pool_destroy(clp->cl_pool);
|
||||
|
||||
free(clp);
|
||||
}
|
||||
|
||||
static int
|
||||
change_one(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
prop_changelist_t *clp = data;
|
||||
char property[ZFS_MAXPROPLEN];
|
||||
char where[64];
|
||||
prop_changenode_t *cn;
|
||||
zfs_source_t sourcetype;
|
||||
|
||||
/*
|
||||
* We only want to unmount/unshare those filesystems that may inherit
|
||||
* from the target filesystem. If we find any filesystem with a
|
||||
* locally set mountpoint, we ignore any children since changing the
|
||||
* property will not affect them. If this is a rename, we iterate
|
||||
* over all children regardless, since we need them unmounted in
|
||||
* order to do the rename. Also, if this is a volume and we're doing
|
||||
* a rename, then always add it to the changelist.
|
||||
*/
|
||||
|
||||
if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
|
||||
zfs_prop_get(zhp, clp->cl_prop, property,
|
||||
sizeof (property), &sourcetype, where, sizeof (where),
|
||||
B_FALSE) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (clp->cl_alldependents || clp->cl_allchildren ||
|
||||
sourcetype == ZFS_SRC_DEFAULT || sourcetype == ZFS_SRC_INHERITED) {
|
||||
if ((cn = zfs_alloc(zfs_get_handle(zhp),
|
||||
sizeof (prop_changenode_t))) == NULL) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
cn->cn_handle = zhp;
|
||||
cn->cn_mounted = zfs_is_mounted(zhp, NULL);
|
||||
cn->cn_shared = zfs_is_shared(zhp);
|
||||
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
|
||||
|
||||
/* Indicate if any child is exported to a local zone. */
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
clp->cl_haszonedchild = B_TRUE;
|
||||
|
||||
uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
|
||||
|
||||
if (clp->cl_sorted) {
|
||||
uu_list_index_t idx;
|
||||
|
||||
(void) uu_list_find(clp->cl_list, cn, NULL,
|
||||
&idx);
|
||||
uu_list_insert(clp->cl_list, cn, idx);
|
||||
} else {
|
||||
ASSERT(!clp->cl_alldependents);
|
||||
verify(uu_list_insert_before(clp->cl_list,
|
||||
uu_list_first(clp->cl_list), cn) == 0);
|
||||
}
|
||||
|
||||
if (!clp->cl_alldependents)
|
||||
return (zfs_iter_children(zhp, change_one, data));
|
||||
} else {
|
||||
zfs_close(zhp);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
compare_mountpoints(const void *a, const void *b, void *unused)
|
||||
{
|
||||
const prop_changenode_t *ca = a;
|
||||
const prop_changenode_t *cb = b;
|
||||
|
||||
char mounta[MAXPATHLEN];
|
||||
char mountb[MAXPATHLEN];
|
||||
|
||||
boolean_t hasmounta, hasmountb;
|
||||
|
||||
/*
|
||||
* When unsharing or unmounting filesystems, we need to do it in
|
||||
* mountpoint order. This allows the user to have a mountpoint
|
||||
* hierarchy that is different from the dataset hierarchy, and still
|
||||
* allow it to be changed. However, if either dataset doesn't have a
|
||||
* mountpoint (because it is a volume or a snapshot), we place it at the
|
||||
* end of the list, because it doesn't affect our change at all.
|
||||
*/
|
||||
hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
|
||||
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
|
||||
hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
|
||||
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
|
||||
|
||||
if (!hasmounta && hasmountb)
|
||||
return (-1);
|
||||
else if (hasmounta && !hasmountb)
|
||||
return (1);
|
||||
else if (!hasmounta && !hasmountb)
|
||||
return (0);
|
||||
else
|
||||
return (strcmp(mountb, mounta));
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a ZFS handle and a property, construct a complete list of datasets
|
||||
* that need to be modified as part of this process. For anything but the
|
||||
* 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
|
||||
* Otherwise, we iterate over all children and look for any datasets that
|
||||
* inherit the property. For each such dataset, we add it to the list and
|
||||
* mark whether it was shared beforehand.
|
||||
*/
|
||||
prop_changelist_t *
|
||||
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
prop_changenode_t *cn;
|
||||
zfs_handle_t *temp;
|
||||
char property[ZFS_MAXPROPLEN];
|
||||
uu_compare_fn_t *compare = NULL;
|
||||
|
||||
if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* For mountpoint-related tasks, we want to sort everything by
|
||||
* mountpoint, so that we mount and unmount them in the appropriate
|
||||
* order, regardless of their position in the hierarchy.
|
||||
*/
|
||||
if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
|
||||
prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
|
||||
compare = compare_mountpoints;
|
||||
clp->cl_sorted = B_TRUE;
|
||||
}
|
||||
|
||||
clp->cl_pool = uu_list_pool_create("changelist_pool",
|
||||
sizeof (prop_changenode_t),
|
||||
offsetof(prop_changenode_t, cn_listnode),
|
||||
compare, 0);
|
||||
if (clp->cl_pool == NULL) {
|
||||
assert(uu_error() == UU_ERROR_NO_MEMORY);
|
||||
(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
clp->cl_list = uu_list_create(clp->cl_pool, NULL,
|
||||
clp->cl_sorted ? UU_LIST_SORTED : 0);
|
||||
clp->cl_flags = flags;
|
||||
|
||||
if (clp->cl_list == NULL) {
|
||||
assert(uu_error() == UU_ERROR_NO_MEMORY);
|
||||
(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a rename or the 'zoned' property, we pretend we're
|
||||
* changing the mountpoint and flag it so we can catch all children in
|
||||
* change_one().
|
||||
*
|
||||
* Flag cl_alldependents to catch all children plus the dependents
|
||||
* (clones) that are not in the hierarchy.
|
||||
*/
|
||||
if (prop == ZFS_PROP_NAME) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
clp->cl_alldependents = B_TRUE;
|
||||
} else if (prop == ZFS_PROP_ZONED) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
clp->cl_allchildren = B_TRUE;
|
||||
} else if (prop == ZFS_PROP_CANMOUNT) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
} else if (prop == ZFS_PROP_VOLSIZE) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
} else {
|
||||
clp->cl_prop = prop;
|
||||
}
|
||||
clp->cl_realprop = prop;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
|
||||
clp->cl_prop != ZFS_PROP_SHARENFS &&
|
||||
clp->cl_prop != ZFS_PROP_SHAREISCSI)
|
||||
return (clp);
|
||||
|
||||
if (clp->cl_alldependents) {
|
||||
if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
} else if (zfs_iter_children(zhp, change_one, clp) != 0) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to re-open ourselves because we auto-close all the handles
|
||||
* and can't tell the difference.
|
||||
*/
|
||||
if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
|
||||
ZFS_TYPE_ANY)) == NULL) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Always add ourself to the list. We add ourselves to the end so that
|
||||
* we're the last to be unmounted.
|
||||
*/
|
||||
if ((cn = zfs_alloc(zhp->zfs_hdl,
|
||||
sizeof (prop_changenode_t))) == NULL) {
|
||||
zfs_close(temp);
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
cn->cn_handle = temp;
|
||||
cn->cn_mounted = zfs_is_mounted(temp, NULL);
|
||||
cn->cn_shared = zfs_is_shared(temp);
|
||||
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
|
||||
|
||||
uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
|
||||
if (clp->cl_sorted) {
|
||||
uu_list_index_t idx;
|
||||
(void) uu_list_find(clp->cl_list, cn, NULL, &idx);
|
||||
uu_list_insert(clp->cl_list, cn, idx);
|
||||
} else {
|
||||
verify(uu_list_insert_after(clp->cl_list,
|
||||
uu_list_last(clp->cl_list), cn) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property was previously 'legacy' or 'none', record this fact,
|
||||
* as the behavior of changelist_postfix() will be different.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, prop, property, sizeof (property),
|
||||
NULL, NULL, 0, B_FALSE) == 0 &&
|
||||
(strcmp(property, "legacy") == 0 || strcmp(property, "none") == 0 ||
|
||||
strcmp(property, "off") == 0))
|
||||
clp->cl_waslegacy = B_TRUE;
|
||||
|
||||
return (clp);
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* The pool configuration repository is stored in /etc/zfs/zpool.cache as a
|
||||
* single packed nvlist. While it would be nice to just read in this
|
||||
* file from userland, this wouldn't work from a local zone. So we have to have
|
||||
* a zpool ioctl to return the complete configuration for all pools. In the
|
||||
* global zone, this will be identical to reading the file and unpacking it in
|
||||
* userland.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
typedef struct config_node {
|
||||
char *cn_name;
|
||||
nvlist_t *cn_config;
|
||||
uu_avl_node_t cn_avl;
|
||||
} config_node_t;
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
config_node_compare(const void *a, const void *b, void *unused)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const config_node_t *ca = (config_node_t *)a;
|
||||
const config_node_t *cb = (config_node_t *)b;
|
||||
|
||||
ret = strcmp(ca->cn_name, cb->cn_name);
|
||||
|
||||
if (ret < 0)
|
||||
return (-1);
|
||||
else if (ret > 0)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
namespace_clear(libzfs_handle_t *hdl)
|
||||
{
|
||||
if (hdl->libzfs_ns_avl) {
|
||||
config_node_t *cn;
|
||||
void *cookie = NULL;
|
||||
|
||||
while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
|
||||
&cookie)) != NULL) {
|
||||
nvlist_free(cn->cn_config);
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
uu_avl_destroy(hdl->libzfs_ns_avl);
|
||||
hdl->libzfs_ns_avl = NULL;
|
||||
}
|
||||
|
||||
if (hdl->libzfs_ns_avlpool) {
|
||||
uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
|
||||
hdl->libzfs_ns_avlpool = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the pool namespace, or re-loads it if the cache has changed.
|
||||
*/
|
||||
static int
|
||||
namespace_reload(libzfs_handle_t *hdl)
|
||||
{
|
||||
nvlist_t *config;
|
||||
config_node_t *cn;
|
||||
nvpair_t *elem;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
void *cookie;
|
||||
|
||||
if (hdl->libzfs_ns_gen == 0) {
|
||||
/*
|
||||
* This is the first time we've accessed the configuration
|
||||
* cache. Initialize the AVL tree and then fall through to the
|
||||
* common code.
|
||||
*/
|
||||
if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
|
||||
sizeof (config_node_t),
|
||||
offsetof(config_node_t, cn_avl),
|
||||
config_node_compare, UU_DEFAULT)) == NULL)
|
||||
return (no_memory(hdl));
|
||||
|
||||
if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
|
||||
NULL, UU_DEFAULT)) == NULL)
|
||||
return (no_memory(hdl));
|
||||
}
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
|
||||
for (;;) {
|
||||
zc.zc_cookie = hdl->libzfs_ns_gen;
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
|
||||
switch (errno) {
|
||||
case EEXIST:
|
||||
/*
|
||||
* The namespace hasn't changed.
|
||||
*/
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (0);
|
||||
|
||||
case ENOMEM:
|
||||
if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (zfs_standard_error(hdl, errno,
|
||||
dgettext(TEXT_DOMAIN, "failed to read "
|
||||
"pool configuration")));
|
||||
}
|
||||
} else {
|
||||
hdl->libzfs_ns_gen = zc.zc_cookie;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
/*
|
||||
* Clear out any existing configuration information.
|
||||
*/
|
||||
cookie = NULL;
|
||||
while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
|
||||
nvlist_free(cn->cn_config);
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
elem = NULL;
|
||||
while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
|
||||
nvlist_t *child;
|
||||
uu_avl_index_t where;
|
||||
|
||||
if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
|
||||
nvlist_free(config);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((cn->cn_name = zfs_strdup(hdl,
|
||||
nvpair_name(elem))) == NULL) {
|
||||
free(cn);
|
||||
nvlist_free(config);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
verify(nvpair_value_nvlist(elem, &child) == 0);
|
||||
if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
nvlist_free(config);
|
||||
return (no_memory(hdl));
|
||||
}
|
||||
verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
|
||||
== NULL);
|
||||
|
||||
uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
|
||||
}
|
||||
|
||||
nvlist_free(config);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the configuration for the given pool. The configuration is a nvlist
|
||||
* describing the vdevs, as well as the statistics associated with each one.
|
||||
*/
|
||||
nvlist_t *
|
||||
zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
|
||||
{
|
||||
if (oldconfig)
|
||||
*oldconfig = zhp->zpool_old_config;
|
||||
return (zhp->zpool_config);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the vdev statistics associated with the given pool. This is used in
|
||||
* iostat to show configuration changes and determine the delta from the last
|
||||
* time the function was called. This function can fail, in case the pool has
|
||||
* been destroyed.
|
||||
*/
|
||||
int
|
||||
zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int error;
|
||||
nvlist_t *config;
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
|
||||
*missing = B_FALSE;
|
||||
(void) strcpy(zc.zc_name, zhp->zpool_name);
|
||||
|
||||
if (zhp->zpool_config_size == 0)
|
||||
zhp->zpool_config_size = 1 << 16;
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
|
||||
return (-1);
|
||||
|
||||
for (;;) {
|
||||
if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
|
||||
&zc) == 0) {
|
||||
/*
|
||||
* The real error is returned in the zc_cookie field.
|
||||
*/
|
||||
error = zc.zc_cookie;
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == ENOMEM) {
|
||||
if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
zcmd_free_nvlists(&zc);
|
||||
if (errno == ENOENT || errno == EINVAL)
|
||||
*missing = B_TRUE;
|
||||
zhp->zpool_state = POOL_STATE_UNAVAIL;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
zhp->zpool_config_size = zc.zc_nvlist_dst_size;
|
||||
|
||||
if (zhp->zpool_config != NULL) {
|
||||
uint64_t oldtxg, newtxg;
|
||||
|
||||
verify(nvlist_lookup_uint64(zhp->zpool_config,
|
||||
ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
|
||||
verify(nvlist_lookup_uint64(config,
|
||||
ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
|
||||
|
||||
if (zhp->zpool_old_config != NULL)
|
||||
nvlist_free(zhp->zpool_old_config);
|
||||
|
||||
if (oldtxg != newtxg) {
|
||||
nvlist_free(zhp->zpool_config);
|
||||
zhp->zpool_old_config = NULL;
|
||||
} else {
|
||||
zhp->zpool_old_config = zhp->zpool_config;
|
||||
}
|
||||
}
|
||||
|
||||
zhp->zpool_config = config;
|
||||
if (error)
|
||||
zhp->zpool_state = POOL_STATE_UNAVAIL;
|
||||
else
|
||||
zhp->zpool_state = POOL_STATE_ACTIVE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all pools in the system.
|
||||
*/
|
||||
int
|
||||
zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
|
||||
{
|
||||
config_node_t *cn;
|
||||
zpool_handle_t *zhp;
|
||||
int ret;
|
||||
|
||||
if (namespace_reload(hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||
|
||||
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0)
|
||||
return (-1);
|
||||
|
||||
if (zhp == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(zhp, data)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over root datasets, calling the given function for each. The zfs
|
||||
* handle passed each time must be explicitly closed by the callback.
|
||||
*/
|
||||
int
|
||||
zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
|
||||
{
|
||||
config_node_t *cn;
|
||||
zfs_handle_t *zhp;
|
||||
int ret;
|
||||
|
||||
if (namespace_reload(hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||
|
||||
if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(zhp, data)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,646 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Iterate over all children of the current object. This includes the normal
|
||||
* dataset hierarchy, but also arbitrary hierarchies due to clones. We want to
|
||||
* walk all datasets in the pool, and construct a directed graph of the form:
|
||||
*
|
||||
* home
|
||||
* |
|
||||
* +----+----+
|
||||
* | |
|
||||
* v v ws
|
||||
* bar baz |
|
||||
* | |
|
||||
* v v
|
||||
* @yesterday ----> foo
|
||||
*
|
||||
* In order to construct this graph, we have to walk every dataset in the pool,
|
||||
* because the clone parent is stored as a property of the child, not the
|
||||
* parent. The parent only keeps track of the number of clones.
|
||||
*
|
||||
* In the normal case (without clones) this would be rather expensive. To avoid
|
||||
* unnecessary computation, we first try a walk of the subtree hierarchy
|
||||
* starting from the initial node. At each dataset, we construct a node in the
|
||||
* graph and an edge leading from its parent. If we don't see any snapshots
|
||||
* with a non-zero clone count, then we are finished.
|
||||
*
|
||||
* If we do find a cloned snapshot, then we finish the walk of the current
|
||||
* subtree, but indicate that we need to do a complete walk. We then perform a
|
||||
* global walk of all datasets, avoiding the subtree we already processed.
|
||||
*
|
||||
* At the end of this, we'll end up with a directed graph of all relevant (and
|
||||
* possible some irrelevant) datasets in the system. We need to both find our
|
||||
* limiting subgraph and determine a safe ordering in which to destroy the
|
||||
* datasets. We do a topological ordering of our graph starting at our target
|
||||
* dataset, and then walk the results in reverse.
|
||||
*
|
||||
* It's possible for the graph to have cycles if, for example, the user renames
|
||||
* a clone to be the parent of its origin snapshot. The user can request to
|
||||
* generate an error in this case, or ignore the cycle and continue.
|
||||
*
|
||||
* When removing datasets, we want to destroy the snapshots in chronological
|
||||
* order (because this is the most efficient method). In order to accomplish
|
||||
* this, we store the creation transaction group with each vertex and keep each
|
||||
* vertex's edges sorted according to this value. The topological sort will
|
||||
* automatically walk the snapshots in the correct order.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
#include "zfs_namecheck.h"
|
||||
|
||||
#define MIN_EDGECOUNT 4
|
||||
|
||||
/*
|
||||
* Vertex structure. Indexed by dataset name, this structure maintains a list
|
||||
* of edges to other vertices.
|
||||
*/
|
||||
struct zfs_edge;
|
||||
typedef struct zfs_vertex {
|
||||
char zv_dataset[ZFS_MAXNAMELEN];
|
||||
struct zfs_vertex *zv_next;
|
||||
int zv_visited;
|
||||
uint64_t zv_txg;
|
||||
struct zfs_edge **zv_edges;
|
||||
int zv_edgecount;
|
||||
int zv_edgealloc;
|
||||
} zfs_vertex_t;
|
||||
|
||||
enum {
|
||||
VISIT_SEEN = 1,
|
||||
VISIT_SORT_PRE,
|
||||
VISIT_SORT_POST
|
||||
};
|
||||
|
||||
/*
|
||||
* Edge structure. Simply maintains a pointer to the destination vertex. There
|
||||
* is no need to store the source vertex, since we only use edges in the context
|
||||
* of the source vertex.
|
||||
*/
|
||||
typedef struct zfs_edge {
|
||||
zfs_vertex_t *ze_dest;
|
||||
struct zfs_edge *ze_next;
|
||||
} zfs_edge_t;
|
||||
|
||||
#define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */
|
||||
|
||||
/*
|
||||
* Graph structure. Vertices are maintained in a hash indexed by dataset name.
|
||||
*/
|
||||
typedef struct zfs_graph {
|
||||
zfs_vertex_t **zg_hash;
|
||||
size_t zg_size;
|
||||
size_t zg_nvertex;
|
||||
} zfs_graph_t;
|
||||
|
||||
/*
|
||||
* Allocate a new edge pointing to the target vertex.
|
||||
*/
|
||||
static zfs_edge_t *
|
||||
zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
|
||||
|
||||
if (zep == NULL)
|
||||
return (NULL);
|
||||
|
||||
zep->ze_dest = dest;
|
||||
|
||||
return (zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an edge.
|
||||
*/
|
||||
static void
|
||||
zfs_edge_destroy(zfs_edge_t *zep)
|
||||
{
|
||||
free(zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new vertex with the given name.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
|
||||
|
||||
if (zvp == NULL)
|
||||
return (NULL);
|
||||
|
||||
assert(strlen(dataset) < ZFS_MAXNAMELEN);
|
||||
|
||||
(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
|
||||
|
||||
if ((zvp->zv_edges = zfs_alloc(hdl,
|
||||
MIN_EDGECOUNT * sizeof (void *))) == NULL) {
|
||||
free(zvp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
zvp->zv_edgealloc = MIN_EDGECOUNT;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a vertex. Frees up any associated edges.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_destroy(zfs_vertex_t *zvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < zvp->zv_edgecount; i++)
|
||||
zfs_edge_destroy(zvp->zv_edges[i]);
|
||||
|
||||
free(zvp->zv_edges);
|
||||
free(zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a vertex, add an edge to the destination vertex.
|
||||
*/
|
||||
static int
|
||||
zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
|
||||
zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_edge_create(hdl, dest);
|
||||
|
||||
if (zep == NULL)
|
||||
return (-1);
|
||||
|
||||
if (zvp->zv_edgecount == zvp->zv_edgealloc) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
|
||||
zvp->zv_edgealloc * sizeof (void *),
|
||||
zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
|
||||
zvp->zv_edges = ptr;
|
||||
zvp->zv_edgealloc *= 2;
|
||||
}
|
||||
|
||||
zvp->zv_edges[zvp->zv_edgecount++] = zep;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_edge_compare(const void *a, const void *b)
|
||||
{
|
||||
const zfs_edge_t *ea = *((zfs_edge_t **)a);
|
||||
const zfs_edge_t *eb = *((zfs_edge_t **)b);
|
||||
|
||||
if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
|
||||
return (-1);
|
||||
if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the given vertex edges according to the creation txg of each vertex.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_sort_edges(zfs_vertex_t *zvp)
|
||||
{
|
||||
if (zvp->zv_edgecount == 0)
|
||||
return;
|
||||
|
||||
qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
|
||||
zfs_edge_compare);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a new graph object. We allow the size to be specified as a
|
||||
* parameter so in the future we can size the hash according to the number of
|
||||
* datasets in the pool.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
zfs_graph_create(libzfs_handle_t *hdl, size_t size)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
|
||||
|
||||
if (zgp == NULL)
|
||||
return (NULL);
|
||||
|
||||
zgp->zg_size = size;
|
||||
if ((zgp->zg_hash = zfs_alloc(hdl,
|
||||
size * sizeof (zfs_vertex_t *))) == NULL) {
|
||||
free(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a graph object. We have to iterate over all the hash chains,
|
||||
* destroying each vertex in the process.
|
||||
*/
|
||||
static void
|
||||
zfs_graph_destroy(zfs_graph_t *zgp)
|
||||
{
|
||||
int i;
|
||||
zfs_vertex_t *current, *next;
|
||||
|
||||
for (i = 0; i < zgp->zg_size; i++) {
|
||||
current = zgp->zg_hash[i];
|
||||
while (current != NULL) {
|
||||
next = current->zv_next;
|
||||
zfs_vertex_destroy(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(zgp->zg_hash);
|
||||
free(zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Graph hash function. Classic bernstein k=33 hash function, taken from
|
||||
* usr/src/cmd/sgs/tools/common/strhash.c
|
||||
*/
|
||||
static size_t
|
||||
zfs_graph_hash(zfs_graph_t *zgp, const char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++) != 0)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return (hash % zgp->zg_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a dataset name, finds the associated vertex, creating it if necessary.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
|
||||
uint64_t txg)
|
||||
{
|
||||
size_t idx = zfs_graph_hash(zgp, dataset);
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
|
||||
if (strcmp(zvp->zv_dataset, dataset) == 0) {
|
||||
if (zvp->zv_txg == 0)
|
||||
zvp->zv_txg = txg;
|
||||
return (zvp);
|
||||
}
|
||||
}
|
||||
|
||||
if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
zvp->zv_next = zgp->zg_hash[idx];
|
||||
zvp->zv_txg = txg;
|
||||
zgp->zg_hash[idx] = zvp;
|
||||
zgp->zg_nvertex++;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given two dataset names, create an edge between them. For the source vertex,
|
||||
* mark 'zv_visited' to indicate that we have seen this vertex, and not simply
|
||||
* created it as a destination of another edge. If 'dest' is NULL, then this
|
||||
* is an individual vertex (i.e. the starting vertex), so don't add an edge.
|
||||
*/
|
||||
static int
|
||||
zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
|
||||
const char *dest, uint64_t txg)
|
||||
{
|
||||
zfs_vertex_t *svp, *dvp;
|
||||
|
||||
if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
|
||||
return (-1);
|
||||
svp->zv_visited = VISIT_SEEN;
|
||||
if (dest != NULL) {
|
||||
dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
|
||||
if (dvp == NULL)
|
||||
return (-1);
|
||||
if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children of the given dataset, adding any vertices as
|
||||
* necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an
|
||||
* error, or 1 otherwise. This is a simple recursive algorithm - the ZFS
|
||||
* namespace typically is very flat. We manually invoke the necessary ioctl()
|
||||
* calls to avoid the overhead and additional semantics of zfs_open().
|
||||
*/
|
||||
static int
|
||||
iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = 0, err;
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
/*
|
||||
* Look up the source vertex, and avoid it if we've seen it before.
|
||||
*/
|
||||
zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
|
||||
if (zvp == NULL)
|
||||
return (-1);
|
||||
if (zvp->zv_visited == VISIT_SEEN)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* We check the clone parent here instead of within the loop, so that if
|
||||
* the root dataset has been promoted from a clone, we find its parent
|
||||
* appropriately.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0 &&
|
||||
zc.zc_objset_stats.dds_clone_of[0] != '\0') {
|
||||
if (zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of,
|
||||
zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
|
||||
/*
|
||||
* Ignore private dataset names.
|
||||
*/
|
||||
if (dataset_name_hidden(zc.zc_name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Iterate over all children
|
||||
*/
|
||||
err = iterate_children(hdl, zgp, zc.zc_name);
|
||||
if (err == -1)
|
||||
return (-1);
|
||||
else if (err == 1)
|
||||
ret = 1;
|
||||
|
||||
/*
|
||||
* Indicate if we found a dataset with a non-zero clone count.
|
||||
*/
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate over all snapshots.
|
||||
*/
|
||||
bzero(&zc, sizeof (zc));
|
||||
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Indicate if we found a dataset with a non-zero clone count.
|
||||
*/
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
zvp->zv_visited = VISIT_SEEN;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a complete graph of all necessary vertices. First, we iterate over
|
||||
* only our object's children. If we don't find any cloned snapshots, then we
|
||||
* simple return that. Otherwise, we have to start at the pool root and iterate
|
||||
* over all datasets.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
construct_graph(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE);
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
if (zgp == NULL)
|
||||
return (zgp);
|
||||
|
||||
/*
|
||||
* We need to explicitly check whether this dataset has clones or not,
|
||||
* since iterate_children() only checks the children.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
(void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc);
|
||||
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0 ||
|
||||
(ret = iterate_children(hdl, zgp, dataset)) != 0) {
|
||||
/*
|
||||
* Determine pool name and try again.
|
||||
*/
|
||||
char *pool, *slash;
|
||||
|
||||
if ((slash = strchr(dataset, '/')) != NULL ||
|
||||
(slash = strchr(dataset, '@')) != NULL) {
|
||||
pool = zfs_alloc(hdl, slash - dataset + 1);
|
||||
if (pool == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
(void) strncpy(pool, dataset, slash - dataset);
|
||||
pool[slash - dataset] = '\0';
|
||||
|
||||
if (iterate_children(hdl, zgp, pool) == -1 ||
|
||||
zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
|
||||
free(pool);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
free(pool);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a graph, do a recursive topological sort into the given array. This is
|
||||
* really just a depth first search, so that the deepest nodes appear first.
|
||||
* hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
|
||||
*/
|
||||
static int
|
||||
topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
|
||||
size_t *idx, zfs_vertex_t *zgv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
|
||||
/*
|
||||
* If we've already seen this vertex as part of our depth-first
|
||||
* search, then we have a cyclic dependency, and we must return
|
||||
* an error.
|
||||
*/
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"recursive dependency at '%s'"),
|
||||
zgv->zv_dataset);
|
||||
return (zfs_error(hdl, EZFS_RECURSIVE,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot determine dependent datasets")));
|
||||
} else if (zgv->zv_visited >= VISIT_SORT_PRE) {
|
||||
/*
|
||||
* If we've already processed this as part of the topological
|
||||
* sort, then don't bother doing so again.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
zgv->zv_visited = VISIT_SORT_PRE;
|
||||
|
||||
/* avoid doing a search if we don't have to */
|
||||
zfs_vertex_sort_edges(zgv);
|
||||
for (i = 0; i < zgv->zv_edgecount; i++) {
|
||||
if (topo_sort(hdl, allowrecursion, result, idx,
|
||||
zgv->zv_edges[i]->ze_dest) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* we may have visited this in the course of the above */
|
||||
if (zgv->zv_visited == VISIT_SORT_POST)
|
||||
return (0);
|
||||
|
||||
if ((result[*idx] = zfs_alloc(hdl,
|
||||
strlen(zgv->zv_dataset) + 1)) == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) strcpy(result[*idx], zgv->zv_dataset);
|
||||
*idx += 1;
|
||||
zgv->zv_visited = VISIT_SORT_POST;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The only public interface for this file. Do the dirty work of constructing a
|
||||
* child list for the given object. Construct the graph, do the toplogical
|
||||
* sort, and then return the array of strings to the caller.
|
||||
*
|
||||
* The 'allowrecursion' parameter controls behavior when cycles are found. If
|
||||
* it is set, the the cycle is ignored and the results returned as if the cycle
|
||||
* did not exist. If it is not set, then the routine will generate an error if
|
||||
* a cycle is found.
|
||||
*/
|
||||
int
|
||||
get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
|
||||
const char *dataset, char ***result, size_t *count)
|
||||
{
|
||||
zfs_graph_t *zgp;
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
if ((zgp = construct_graph(hdl, dataset)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if ((*result = zfs_alloc(hdl,
|
||||
zgp->zg_nvertex * sizeof (char *))) == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get rid of the last entry, which is our starting vertex and not
|
||||
* strictly a dependent.
|
||||
*/
|
||||
assert(*count > 0);
|
||||
free((*result)[*count - 1]);
|
||||
(*count)--;
|
||||
|
||||
zfs_graph_destroy(zgp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBFS_IMPL_H
|
||||
#define _LIBFS_IMPL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_acl.h>
|
||||
#include <sys/nvpair.h>
|
||||
|
||||
#include <libuutil.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct libzfs_handle {
|
||||
int libzfs_error;
|
||||
int libzfs_fd;
|
||||
FILE *libzfs_mnttab;
|
||||
FILE *libzfs_sharetab;
|
||||
uu_avl_pool_t *libzfs_ns_avlpool;
|
||||
uu_avl_t *libzfs_ns_avl;
|
||||
uint64_t libzfs_ns_gen;
|
||||
int libzfs_desc_active;
|
||||
char libzfs_action[1024];
|
||||
char libzfs_desc[1024];
|
||||
int libzfs_printerr;
|
||||
};
|
||||
|
||||
struct zfs_handle {
|
||||
libzfs_handle_t *zfs_hdl;
|
||||
char zfs_name[ZFS_MAXNAMELEN];
|
||||
zfs_type_t zfs_type; /* type including snapshot */
|
||||
zfs_type_t zfs_head_type; /* type excluding snapshot */
|
||||
dmu_objset_stats_t zfs_dmustats;
|
||||
nvlist_t *zfs_props;
|
||||
nvlist_t *zfs_user_props;
|
||||
boolean_t zfs_mntcheck;
|
||||
char *zfs_mntopts;
|
||||
char zfs_root[MAXPATHLEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* This is different from checking zfs_type, because it will also catch
|
||||
* snapshots of volumes.
|
||||
*/
|
||||
#define ZFS_IS_VOLUME(zhp) ((zhp)->zfs_head_type == ZFS_TYPE_VOLUME)
|
||||
|
||||
struct zpool_handle {
|
||||
libzfs_handle_t *zpool_hdl;
|
||||
char zpool_name[ZPOOL_MAXNAMELEN];
|
||||
int zpool_state;
|
||||
size_t zpool_config_size;
|
||||
nvlist_t *zpool_config;
|
||||
nvlist_t *zpool_old_config;
|
||||
nvlist_t *zpool_props;
|
||||
};
|
||||
|
||||
int zfs_error(libzfs_handle_t *, int, const char *);
|
||||
int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
|
||||
void *zfs_alloc(libzfs_handle_t *, size_t);
|
||||
void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
|
||||
char *zfs_strdup(libzfs_handle_t *, const char *);
|
||||
int no_memory(libzfs_handle_t *);
|
||||
|
||||
int zfs_standard_error(libzfs_handle_t *, int, const char *);
|
||||
int zfs_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
int zpool_standard_error(libzfs_handle_t *, int, const char *);
|
||||
int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
|
||||
int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
|
||||
size_t *);
|
||||
|
||||
int zfs_expand_proplist_common(libzfs_handle_t *, zfs_proplist_t **,
|
||||
zfs_type_t);
|
||||
int zfs_get_proplist_common(libzfs_handle_t *, char *, zfs_proplist_t **,
|
||||
zfs_type_t);
|
||||
zfs_prop_t zfs_prop_iter_common(zfs_prop_f, void *, zfs_type_t, boolean_t);
|
||||
zfs_prop_t zfs_name_to_prop_common(const char *, zfs_type_t);
|
||||
|
||||
nvlist_t *zfs_validate_properties(libzfs_handle_t *, zfs_type_t, char *,
|
||||
nvlist_t *, uint64_t, zfs_handle_t *zhp, const char *errbuf);
|
||||
|
||||
typedef struct prop_changelist prop_changelist_t;
|
||||
|
||||
int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
|
||||
int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *, size_t *);
|
||||
int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
|
||||
int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
|
||||
void zcmd_free_nvlists(zfs_cmd_t *);
|
||||
|
||||
int changelist_prefix(prop_changelist_t *);
|
||||
int changelist_postfix(prop_changelist_t *);
|
||||
void changelist_rename(prop_changelist_t *, const char *, const char *);
|
||||
void changelist_remove(zfs_handle_t *, prop_changelist_t *);
|
||||
void changelist_free(prop_changelist_t *);
|
||||
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
|
||||
int changelist_unshare(prop_changelist_t *);
|
||||
int changelist_haszonedchild(prop_changelist_t *);
|
||||
|
||||
void remove_mountpoint(zfs_handle_t *);
|
||||
|
||||
zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
|
||||
|
||||
int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
|
||||
|
||||
int zvol_create_link(libzfs_handle_t *, const char *);
|
||||
int zvol_remove_link(libzfs_handle_t *, const char *);
|
||||
int zpool_iter_zvol(zpool_handle_t *, int (*)(const char *, void *), void *);
|
||||
|
||||
void namespace_clear(libzfs_handle_t *);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
|
||||
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
|
||||
* error is returned zc_nvlist_dst_size won't be updated.
|
||||
*/
|
||||
static __inline int
|
||||
zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc)
|
||||
{
|
||||
size_t oldsize;
|
||||
int ret;
|
||||
|
||||
oldsize = zc->zc_nvlist_dst_size;
|
||||
ret = ioctl(fd, cmd, zc);
|
||||
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
|
||||
ret = -1;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#define ioctl(fd, cmd, zc) zcmd_ioctl((fd), (cmd), (zc))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBFS_IMPL_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,986 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Routines to manage ZFS mounts. We separate all the nasty routines that have
|
||||
* to deal with the OS. The following functions are the main entry points --
|
||||
* they are used by mount and unmount and when changing a filesystem's
|
||||
* mountpoint.
|
||||
*
|
||||
* zfs_is_mounted()
|
||||
* zfs_mount()
|
||||
* zfs_unmount()
|
||||
* zfs_unmountall()
|
||||
*
|
||||
* This file also contains the functions used to manage sharing filesystems via
|
||||
* NFS and iSCSI:
|
||||
*
|
||||
* zfs_is_shared()
|
||||
* zfs_share()
|
||||
* zfs_unshare()
|
||||
*
|
||||
* zfs_is_shared_nfs()
|
||||
* zfs_share_nfs()
|
||||
* zfs_unshare_nfs()
|
||||
* zfs_unshareall_nfs()
|
||||
* zfs_is_shared_iscsi()
|
||||
* zfs_share_iscsi()
|
||||
* zfs_unshare_iscsi()
|
||||
*
|
||||
* The following functions are available for pool consumers, and will
|
||||
* mount/unmount and share/unshare all datasets within pool:
|
||||
*
|
||||
* zpool_enable_datasets()
|
||||
* zpool_disable_datasets()
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <zone.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
static int (*iscsitgt_zfs_share)(const char *);
|
||||
static int (*iscsitgt_zfs_unshare)(const char *);
|
||||
static int (*iscsitgt_zfs_is_shared)(const char *);
|
||||
|
||||
#pragma init(zfs_iscsi_init)
|
||||
static void
|
||||
zfs_iscsi_init(void)
|
||||
{
|
||||
void *libiscsitgt;
|
||||
|
||||
if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
|
||||
RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
|
||||
(iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_share")) == NULL ||
|
||||
(iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_unshare")) == NULL ||
|
||||
(iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_is_shared")) == NULL) {
|
||||
iscsitgt_zfs_share = NULL;
|
||||
iscsitgt_zfs_unshare = NULL;
|
||||
iscsitgt_zfs_is_shared = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the sharetab for the given mountpoint, returning true if it is found.
|
||||
*/
|
||||
static boolean_t
|
||||
is_shared(libzfs_handle_t *hdl, const char *mountpoint)
|
||||
{
|
||||
char buf[MAXPATHLEN], *tab;
|
||||
|
||||
if (hdl->libzfs_sharetab == NULL)
|
||||
return (0);
|
||||
|
||||
(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
|
||||
|
||||
while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
|
||||
|
||||
/* the mountpoint is the first entry on each line */
|
||||
if ((tab = strchr(buf, '\t')) != NULL) {
|
||||
*tab = '\0';
|
||||
if (strcmp(buf, mountpoint) == 0)
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Returns true if the specified directory is empty. If we can't open the
|
||||
* directory at all, return true so that the mount can fail with a more
|
||||
* informative error message.
|
||||
*/
|
||||
static boolean_t
|
||||
dir_is_empty(const char *dirname)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent64 *dp;
|
||||
|
||||
if ((dirp = opendir(dirname)) == NULL)
|
||||
return (B_TRUE);
|
||||
|
||||
while ((dp = readdir64(dirp)) != NULL) {
|
||||
|
||||
if (strcmp(dp->d_name, ".") == 0 ||
|
||||
strcmp(dp->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
(void) closedir(dirp);
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
(void) closedir(dirp);
|
||||
return (B_TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Checks to see if the mount is active. If the filesystem is mounted, we fill
|
||||
* in 'where' with the current mountpoint, and return 1. Otherwise, we return
|
||||
* 0.
|
||||
*/
|
||||
boolean_t
|
||||
is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/*
|
||||
* Search for the entry in /etc/mnttab. We don't bother getting the
|
||||
* mountpoint, as we can just search for the special device. This will
|
||||
* also let us find mounts when the mountpoint is 'legacy'.
|
||||
*/
|
||||
search.mnt_special = (char *)special;
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
|
||||
rewind(zfs_hdl->libzfs_mnttab);
|
||||
if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (where != NULL)
|
||||
*where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_mounted(zfs_handle_t *zhp, char **where)
|
||||
{
|
||||
return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the given dataset is mountable, false otherwise. Returns the
|
||||
* mountpoint in 'buf'.
|
||||
*/
|
||||
static boolean_t
|
||||
zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
|
||||
zfs_source_t *source)
|
||||
{
|
||||
char sourceloc[ZFS_MAXNAMELEN];
|
||||
zfs_source_t sourcetype;
|
||||
|
||||
if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
|
||||
return (B_FALSE);
|
||||
|
||||
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
|
||||
&sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
|
||||
|
||||
if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
|
||||
strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT))
|
||||
return (B_FALSE);
|
||||
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
|
||||
getzoneid() == GLOBAL_ZONEID)
|
||||
return (B_FALSE);
|
||||
|
||||
if (source)
|
||||
*source = sourcetype;
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
|
||||
{
|
||||
struct stat buf;
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
char mntopts[MNT_LINE_MAX];
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
if (options == NULL)
|
||||
mntopts[0] = '\0';
|
||||
else
|
||||
(void) strlcpy(mntopts, options, sizeof (mntopts));
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
return (0);
|
||||
|
||||
/* Create the directory if it doesn't already exist */
|
||||
if (lstat(mountpoint, &buf) != 0) {
|
||||
if (mkdirp(mountpoint, 0755) != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"failed to create mountpoint"));
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
|
||||
mountpoint));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* FreeBSD: overlay mounts are not checked. */
|
||||
/*
|
||||
* Determine if the mountpoint is empty. If so, refuse to perform the
|
||||
* mount. We don't perform this check if MS_OVERLAY is specified, which
|
||||
* would defeat the point. We also avoid this check if 'remount' is
|
||||
* specified.
|
||||
*/
|
||||
if ((flags & MS_OVERLAY) == 0 &&
|
||||
strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
|
||||
!dir_is_empty(mountpoint)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"directory is not empty"));
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* perform the mount */
|
||||
if (zmount(zfs_get_name(zhp), mountpoint, flags,
|
||||
MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
|
||||
/*
|
||||
* Generic errors are nasty, but there are just way too many
|
||||
* from mount(), and they're well-understood. We pick a few
|
||||
* common ones to improve upon.
|
||||
*/
|
||||
if (errno == EBUSY)
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"mountpoint or dataset is busy"));
|
||||
else
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
|
||||
zhp->zfs_name));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount a single filesystem.
|
||||
*/
|
||||
static int
|
||||
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
|
||||
{
|
||||
if (unmount(mountpoint, flags) != 0) {
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
|
||||
mountpoint));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/* check to see if need to unmount the filesystem */
|
||||
search.mnt_special = zhp->zfs_name;
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
rewind(zhp->zfs_hdl->libzfs_mnttab);
|
||||
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
|
||||
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
|
||||
|
||||
if (mountpoint == NULL)
|
||||
mountpoint = entry.mnt_mountp;
|
||||
|
||||
/*
|
||||
* Unshare and unmount the filesystem
|
||||
*/
|
||||
if (zfs_unshare_nfs(zhp, mountpoint) != 0 ||
|
||||
unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount this filesystem and any children inheriting the mountpoint property.
|
||||
* To do this, just act like we're changing the mountpoint property, but don't
|
||||
* remount the filesystems afterwards.
|
||||
*/
|
||||
int
|
||||
zfs_unmountall(zfs_handle_t *zhp, int flags)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
int ret;
|
||||
|
||||
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
|
||||
if (clp == NULL)
|
||||
return (-1);
|
||||
|
||||
ret = changelist_prefix(clp);
|
||||
changelist_free(clp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_shared(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_is_shared_iscsi(zhp));
|
||||
|
||||
return (zfs_is_shared_nfs(zhp, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_share(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_share_iscsi(zhp));
|
||||
|
||||
return (zfs_share_nfs(zhp));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_unshare(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_unshare_iscsi(zhp));
|
||||
|
||||
return (zfs_unshare_nfs(zhp, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the filesystem is currently shared.
|
||||
*/
|
||||
boolean_t
|
||||
zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
|
||||
{
|
||||
char *mountpoint;
|
||||
|
||||
if (!zfs_is_mounted(zhp, &mountpoint))
|
||||
return (B_FALSE);
|
||||
|
||||
if (is_shared(zhp->zfs_hdl, mountpoint)) {
|
||||
if (where != NULL)
|
||||
*where = mountpoint;
|
||||
else
|
||||
free(mountpoint);
|
||||
return (B_TRUE);
|
||||
} else {
|
||||
free(mountpoint);
|
||||
return (B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Share the given filesystem according to the options in 'sharenfs'. We rely
|
||||
* on share(1M) to the dirty work for us.
|
||||
*/
|
||||
int
|
||||
zfs_share_nfs(zfs_handle_t *zhp)
|
||||
{
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
char buf[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Return success if there are no share options.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
|
||||
NULL, NULL, 0, B_FALSE) != 0 ||
|
||||
strcmp(shareopts, "off") == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the 'zoned' property is set, then zfs_is_mountable() will have
|
||||
* already bailed out if we are in the global zone. But local
|
||||
* zones cannot be NFS servers, so we ignore it for local zones as well.
|
||||
*/
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
|
||||
return (0);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
{
|
||||
int error;
|
||||
|
||||
if (strcmp(shareopts, "on") == 0)
|
||||
error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
|
||||
else
|
||||
error = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
|
||||
if (error != 0) {
|
||||
zfs_error_aux(hdl, "%s", strerror(error));
|
||||
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp));
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Invoke the share(1M) command. We always do this, even if it's
|
||||
* currently shared, as the options may have changed.
|
||||
*/
|
||||
if (strcmp(shareopts, "on") == 0)
|
||||
(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
|
||||
"-F nfs \"%s\" 2>&1", mountpoint);
|
||||
else
|
||||
(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
|
||||
"-F nfs -o \"%s\" \"%s\" 2>&1", shareopts,
|
||||
mountpoint);
|
||||
|
||||
if ((fp = popen(buf, "r")) == NULL)
|
||||
return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp)));
|
||||
|
||||
/*
|
||||
* share(1M) should only produce output if there is some kind
|
||||
* of error. All output begins with "share_nfs: ", so we trim
|
||||
* this off to get to the real error.
|
||||
*/
|
||||
if (fgets(buf, sizeof (buf), fp) != NULL) {
|
||||
char *colon = strchr(buf, ':');
|
||||
|
||||
while (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
if (colon != NULL)
|
||||
zfs_error_aux(hdl, colon + 2);
|
||||
|
||||
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp));
|
||||
|
||||
verify(pclose(fp) != 0);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
verify(pclose(fp) == 0);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare a filesystem by mountpoint.
|
||||
*/
|
||||
static int
|
||||
unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
{
|
||||
int error;
|
||||
|
||||
error = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
|
||||
if (error != 0) {
|
||||
zfs_error_aux(hdl, "%s", strerror(error));
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) snprintf(buf, sizeof (buf),
|
||||
"/usr/sbin/unshare \"%s\" 2>&1",
|
||||
mountpoint);
|
||||
|
||||
if ((fp = popen(buf, "r")) == NULL)
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
|
||||
/*
|
||||
* unshare(1M) should only produce output if there is
|
||||
* some kind of error. All output begins with "unshare
|
||||
* nfs: ", so we trim this off to get to the real error.
|
||||
*/
|
||||
if (fgets(buf, sizeof (buf), fp) != NULL) {
|
||||
char *colon = strchr(buf, ':');
|
||||
|
||||
while (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
if (colon != NULL)
|
||||
zfs_error_aux(hdl, colon + 2);
|
||||
|
||||
verify(pclose(fp) != 0);
|
||||
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
}
|
||||
|
||||
verify(pclose(fp) == 0);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/* check to see if need to unmount the filesystem */
|
||||
search.mnt_special = (char *)zfs_get_name(zhp);
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
rewind(zhp->zfs_hdl->libzfs_mnttab);
|
||||
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
|
||||
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
|
||||
|
||||
if (mountpoint == NULL)
|
||||
mountpoint = entry.mnt_mountp;
|
||||
|
||||
if (is_shared(zhp->zfs_hdl, mountpoint) &&
|
||||
unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as zfs_unmountall(), but for NFS unshares.
|
||||
*/
|
||||
int
|
||||
zfs_unshareall_nfs(zfs_handle_t *zhp)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
int ret;
|
||||
|
||||
clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
|
||||
if (clp == NULL)
|
||||
return (-1);
|
||||
|
||||
ret = changelist_unshare(clp);
|
||||
changelist_free(clp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the mountpoint associated with the current dataset, if necessary.
|
||||
* We only remove the underlying directory if:
|
||||
*
|
||||
* - The mountpoint is not 'none' or 'legacy'
|
||||
* - The mountpoint is non-empty
|
||||
* - The mountpoint is the default or inherited
|
||||
* - The 'zoned' property is set, or we're in a local zone
|
||||
*
|
||||
* Any other directories we leave alone.
|
||||
*/
|
||||
void
|
||||
remove_mountpoint(zfs_handle_t *zhp)
|
||||
{
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
zfs_source_t source;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
|
||||
&source))
|
||||
return;
|
||||
|
||||
if (source == ZFS_SRC_DEFAULT ||
|
||||
source == ZFS_SRC_INHERITED) {
|
||||
/*
|
||||
* Try to remove the directory, silently ignoring any errors.
|
||||
* The filesystem may have since been removed or moved around,
|
||||
* and this error isn't really useful to the administrator in
|
||||
* any way.
|
||||
*/
|
||||
(void) rmdir(mountpoint);
|
||||
}
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_shared_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
return (iscsitgt_zfs_is_shared != NULL &&
|
||||
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_share_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
const char *dataset = zhp->zfs_name;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/*
|
||||
* Return success if there are no share options.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
|
||||
strcmp(shareopts, "off") == 0)
|
||||
return (0);
|
||||
|
||||
/* We don't support iSCSI on FreeBSD yet. */
|
||||
#ifdef TODO
|
||||
if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0)
|
||||
return (zfs_error_fmt(hdl, EZFS_SHAREISCSIFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_unshare_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
const char *dataset = zfs_get_name(zhp);
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/* We don't support iSCSI on FreeBSD yet. */
|
||||
#ifdef TODO
|
||||
/*
|
||||
* Return if the volume is not shared
|
||||
*/
|
||||
if (!zfs_is_shared_iscsi(zhp))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If this fails with ENODEV it indicates that zvol wasn't shared so
|
||||
* we should return success in that case.
|
||||
*/
|
||||
if (iscsitgt_zfs_unshare == NULL ||
|
||||
(iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV))
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct mount_cbdata {
|
||||
zfs_handle_t **cb_datasets;
|
||||
int cb_used;
|
||||
int cb_alloc;
|
||||
} mount_cbdata_t;
|
||||
|
||||
static int
|
||||
mount_cb(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
mount_cbdata_t *cbp = data;
|
||||
|
||||
if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cbp->cb_alloc == cbp->cb_used) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(zhp->zfs_hdl,
|
||||
cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
|
||||
cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
cbp->cb_datasets = ptr;
|
||||
|
||||
cbp->cb_alloc *= 2;
|
||||
}
|
||||
|
||||
cbp->cb_datasets[cbp->cb_used++] = zhp;
|
||||
|
||||
return (zfs_iter_children(zhp, mount_cb, cbp));
|
||||
}
|
||||
|
||||
static int
|
||||
dataset_cmp(const void *a, const void *b)
|
||||
{
|
||||
zfs_handle_t **za = (zfs_handle_t **)a;
|
||||
zfs_handle_t **zb = (zfs_handle_t **)b;
|
||||
char mounta[MAXPATHLEN];
|
||||
char mountb[MAXPATHLEN];
|
||||
boolean_t gota, gotb;
|
||||
|
||||
if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
|
||||
verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
|
||||
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
|
||||
if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
|
||||
verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
|
||||
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
|
||||
|
||||
if (gota && gotb)
|
||||
return (strcmp(mounta, mountb));
|
||||
|
||||
if (gota)
|
||||
return (-1);
|
||||
if (gotb)
|
||||
return (1);
|
||||
|
||||
return (strcmp(zfs_get_name(a), zfs_get_name(b)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount and share all datasets within the given pool. This assumes that no
|
||||
* datasets within the pool are currently mounted. Because users can create
|
||||
* complicated nested hierarchies of mountpoints, we first gather all the
|
||||
* datasets and mountpoints within the pool, and sort them by mountpoint. Once
|
||||
* we have the list of all filesystems, we iterate over them in order and mount
|
||||
* and/or share each one.
|
||||
*/
|
||||
#pragma weak zpool_mount_datasets = zpool_enable_datasets
|
||||
int
|
||||
zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
|
||||
{
|
||||
mount_cbdata_t cb = { 0 };
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
zfs_handle_t *zfsp;
|
||||
int i, ret = -1;
|
||||
|
||||
/*
|
||||
* Gather all datasets within the pool.
|
||||
*/
|
||||
if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
cb.cb_alloc = 4;
|
||||
|
||||
if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL)
|
||||
goto out;
|
||||
|
||||
cb.cb_datasets[0] = zfsp;
|
||||
cb.cb_used = 1;
|
||||
|
||||
if (zfs_iter_children(zfsp, mount_cb, &cb) != 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Sort the datasets by mountpoint.
|
||||
*/
|
||||
qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp);
|
||||
|
||||
/*
|
||||
* And mount all the datasets.
|
||||
*/
|
||||
ret = 0;
|
||||
for (i = 0; i < cb.cb_used; i++) {
|
||||
if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 ||
|
||||
zfs_share(cb.cb_datasets[i]) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < cb.cb_used; i++)
|
||||
zfs_close(cb.cb_datasets[i]);
|
||||
free(cb.cb_datasets);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
zvol_cb(const char *dataset, void *data)
|
||||
{
|
||||
libzfs_handle_t *hdl = data;
|
||||
zfs_handle_t *zhp;
|
||||
|
||||
/*
|
||||
* Ignore snapshots and ignore failures from non-existant datasets.
|
||||
*/
|
||||
if (strchr(dataset, '@') != NULL ||
|
||||
(zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
|
||||
return (0);
|
||||
|
||||
(void) zfs_unshare_iscsi(zhp);
|
||||
|
||||
zfs_close(zhp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mountpoint_compare(const void *a, const void *b)
|
||||
{
|
||||
const char *mounta = *((char **)a);
|
||||
const char *mountb = *((char **)b);
|
||||
|
||||
return (strcmp(mountb, mounta));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare and unmount all datasets within the given pool. We don't want to
|
||||
* rely on traversing the DSL to discover the filesystems within the pool,
|
||||
* because this may be expensive (if not all of them are mounted), and can fail
|
||||
* arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
|
||||
* gather all the filesystems that are currently mounted.
|
||||
*/
|
||||
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
|
||||
int
|
||||
zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
|
||||
{
|
||||
int used, alloc;
|
||||
struct statfs *sfs;
|
||||
size_t namelen;
|
||||
char **mountpoints = NULL;
|
||||
zfs_handle_t **datasets = NULL;
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
int i, j, n;
|
||||
int ret = -1;
|
||||
int flags = (force ? MS_FORCE : 0);
|
||||
|
||||
/*
|
||||
* First unshare all zvols.
|
||||
*/
|
||||
if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
namelen = strlen(zhp->zpool_name);
|
||||
|
||||
used = alloc = 0;
|
||||
if ((n = getmntinfo(&sfs, MNT_WAIT)) == 0) {
|
||||
fprintf(stderr, "getmntinfo(): %s\n", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
/*
|
||||
* Ignore non-ZFS entries.
|
||||
*/
|
||||
if (strcmp(sfs[j].f_fstypename, MNTTYPE_ZFS) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ignore filesystems not within this pool.
|
||||
*/
|
||||
if (strncmp(sfs[j].f_mntfromname, zhp->zpool_name, namelen) != 0 ||
|
||||
(sfs[j].f_mntfromname[namelen] != '/' &&
|
||||
sfs[j].f_mntfromname[namelen] != '\0'))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* At this point we've found a filesystem within our pool. Add
|
||||
* it to our growing list.
|
||||
*/
|
||||
if (used == alloc) {
|
||||
if (alloc == 0) {
|
||||
if ((mountpoints = zfs_alloc(hdl,
|
||||
8 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
|
||||
if ((datasets = zfs_alloc(hdl,
|
||||
8 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
|
||||
alloc = 8;
|
||||
} else {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, mountpoints,
|
||||
alloc * sizeof (void *),
|
||||
alloc * 2 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
mountpoints = ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, datasets,
|
||||
alloc * sizeof (void *),
|
||||
alloc * 2 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
datasets = ptr;
|
||||
|
||||
alloc *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mountpoints[used] = zfs_strdup(hdl,
|
||||
sfs[j].f_mntonname)) == NULL)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* This is allowed to fail, in case there is some I/O error. It
|
||||
* is only used to determine if we need to remove the underlying
|
||||
* mountpoint, so failure is not fatal.
|
||||
*/
|
||||
datasets[used] = make_dataset_handle(hdl, sfs[j].f_mntfromname);
|
||||
|
||||
used++;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have the entire list of filesystems, so sort it by
|
||||
* mountpoint.
|
||||
*/
|
||||
qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
|
||||
|
||||
/*
|
||||
* Walk through and first unshare everything.
|
||||
*/
|
||||
for (i = 0; i < used; i++) {
|
||||
if (is_shared(hdl, mountpoints[i]) &&
|
||||
unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now unmount everything, removing the underlying directories as
|
||||
* appropriate.
|
||||
*/
|
||||
for (i = 0; i < used; i++) {
|
||||
if (unmount_one(hdl, mountpoints[i], flags) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < used; i++) {
|
||||
if (datasets[i])
|
||||
remove_mountpoint(datasets[i]);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
for (i = 0; i < used; i++) {
|
||||
if (datasets[i])
|
||||
zfs_close(datasets[i]);
|
||||
free(mountpoints[i]);
|
||||
}
|
||||
free(datasets);
|
||||
free(mountpoints);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,303 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* This file contains the functions which analyze the status of a pool. This
|
||||
* include both the status of an active pool, as well as the status exported
|
||||
* pools. Returns one of the ZPOOL_STATUS_* defines describing the status of
|
||||
* the pool. This status is independent (to a certain degree) from the state of
|
||||
* the pool. A pool's state descsribes only whether or not it is capable of
|
||||
* providing the necessary fault tolerance for data. The status describes the
|
||||
* overall status of devices. A pool that is online can still have a device
|
||||
* that is experiencing errors.
|
||||
*
|
||||
* Only a subset of the possible faults can be detected using 'zpool status',
|
||||
* and not all possible errors correspond to a FMA message ID. The explanation
|
||||
* is left up to the caller, depending on whether it is a live pool or an
|
||||
* import.
|
||||
*/
|
||||
|
||||
#include <libzfs.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
/*
|
||||
* Message ID table. This must be kep in sync with the ZPOOL_STATUS_* defines
|
||||
* in libzfs.h. Note that there are some status results which go past the end
|
||||
* of this table, and hence have no associated message ID.
|
||||
*/
|
||||
static char *zfs_msgid_table[] = {
|
||||
"ZFS-8000-14",
|
||||
"ZFS-8000-2Q",
|
||||
"ZFS-8000-3C",
|
||||
"ZFS-8000-4J",
|
||||
"ZFS-8000-5E",
|
||||
"ZFS-8000-6X",
|
||||
"ZFS-8000-72",
|
||||
"ZFS-8000-8A",
|
||||
"ZFS-8000-9P",
|
||||
"ZFS-8000-A5",
|
||||
"ZFS-8000-EY"
|
||||
};
|
||||
|
||||
/*
|
||||
* If the pool is active, a certain class of static errors is overridden by the
|
||||
* faults as analayzed by FMA. These faults have separate knowledge articles,
|
||||
* and the article referred to by 'zpool status' must match that indicated by
|
||||
* the syslog error message. We override missing data as well as corrupt pool.
|
||||
*/
|
||||
static char *zfs_msgid_table_active[] = {
|
||||
"ZFS-8000-14",
|
||||
"ZFS-8000-D3", /* overridden */
|
||||
"ZFS-8000-D3", /* overridden */
|
||||
"ZFS-8000-4J",
|
||||
"ZFS-8000-5E",
|
||||
"ZFS-8000-6X",
|
||||
"ZFS-8000-CS", /* overridden */
|
||||
"ZFS-8000-8A",
|
||||
"ZFS-8000-9P",
|
||||
"ZFS-8000-CS", /* overridden */
|
||||
};
|
||||
|
||||
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_CANT_OPEN &&
|
||||
aux == VDEV_AUX_OPEN_FAILED);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (errs != 0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_CANT_OPEN);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_OFFLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect if any leaf devices that have seen errors or could not be opened.
|
||||
*/
|
||||
static boolean_t
|
||||
find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
|
||||
{
|
||||
nvlist_t **child;
|
||||
vdev_stat_t *vs;
|
||||
uint_t c, children;
|
||||
char *type;
|
||||
|
||||
/*
|
||||
* Ignore problems within a 'replacing' vdev, since we're presumably in
|
||||
* the process of repairing any such errors, and don't want to call them
|
||||
* out again. We'll pick up the fact that a resilver is happening
|
||||
* later.
|
||||
*/
|
||||
verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
|
||||
&children) == 0) {
|
||||
for (c = 0; c < children; c++)
|
||||
if (find_vdev_problem(child[c], func))
|
||||
return (B_TRUE);
|
||||
} else {
|
||||
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
|
||||
if (func(vs->vs_state, vs->vs_aux,
|
||||
vs->vs_read_errors +
|
||||
vs->vs_write_errors +
|
||||
vs->vs_checksum_errors))
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Active pool health status.
|
||||
*
|
||||
* To determine the status for a pool, we make several passes over the config,
|
||||
* picking the most egregious error we find. In order of importance, we do the
|
||||
* following:
|
||||
*
|
||||
* - Check for a complete and valid configuration
|
||||
* - Look for any missing devices in a non-replicated config
|
||||
* - Check for any data errors
|
||||
* - Check for any missing devices in a replicated config
|
||||
* - Look for any devices showing errors
|
||||
* - Check for any resilvering devices
|
||||
*
|
||||
* There can obviously be multiple errors within a single pool, so this routine
|
||||
* only picks the most damaging of all the current errors to report.
|
||||
*/
|
||||
static zpool_status_t
|
||||
check_status(nvlist_t *config, boolean_t isimport)
|
||||
{
|
||||
nvlist_t *nvroot;
|
||||
vdev_stat_t *vs;
|
||||
uint_t vsc;
|
||||
uint64_t nerr;
|
||||
uint64_t version;
|
||||
uint64_t stateval;
|
||||
uint64_t hostid = 0;
|
||||
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
|
||||
&version) == 0);
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &vsc) == 0);
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
|
||||
&stateval) == 0);
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
|
||||
|
||||
/*
|
||||
* Pool last accessed by another system.
|
||||
*/
|
||||
if (hostid != 0 && (unsigned long)hostid != gethostid() &&
|
||||
stateval == POOL_STATE_ACTIVE)
|
||||
return (ZPOOL_STATUS_HOSTID_MISMATCH);
|
||||
|
||||
/*
|
||||
* Newer on-disk version.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_VERSION_NEWER)
|
||||
return (ZPOOL_STATUS_VERSION_NEWER);
|
||||
|
||||
/*
|
||||
* Check that the config is complete.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
|
||||
return (ZPOOL_STATUS_BAD_GUID_SUM);
|
||||
|
||||
/*
|
||||
* Missing devices in non-replicated config.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
find_vdev_problem(nvroot, vdev_missing))
|
||||
return (ZPOOL_STATUS_MISSING_DEV_NR);
|
||||
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
find_vdev_problem(nvroot, vdev_broken))
|
||||
return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
|
||||
|
||||
/*
|
||||
* Corrupted pool metadata
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
|
||||
return (ZPOOL_STATUS_CORRUPT_POOL);
|
||||
|
||||
/*
|
||||
* Persistent data errors.
|
||||
*/
|
||||
if (!isimport) {
|
||||
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
|
||||
&nerr) == 0 && nerr != 0)
|
||||
return (ZPOOL_STATUS_CORRUPT_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
* Missing devices in a replicated config.
|
||||
*/
|
||||
if (find_vdev_problem(nvroot, vdev_missing))
|
||||
return (ZPOOL_STATUS_MISSING_DEV_R);
|
||||
if (find_vdev_problem(nvroot, vdev_broken))
|
||||
return (ZPOOL_STATUS_CORRUPT_LABEL_R);
|
||||
|
||||
/*
|
||||
* Devices with errors
|
||||
*/
|
||||
if (!isimport && find_vdev_problem(nvroot, vdev_errors))
|
||||
return (ZPOOL_STATUS_FAILING_DEV);
|
||||
|
||||
/*
|
||||
* Offlined devices
|
||||
*/
|
||||
if (find_vdev_problem(nvroot, vdev_offlined))
|
||||
return (ZPOOL_STATUS_OFFLINE_DEV);
|
||||
|
||||
/*
|
||||
* Currently resilvering
|
||||
*/
|
||||
if (!vs->vs_scrub_complete && vs->vs_scrub_type == POOL_SCRUB_RESILVER)
|
||||
return (ZPOOL_STATUS_RESILVERING);
|
||||
|
||||
/*
|
||||
* Outdated, but usable, version
|
||||
*/
|
||||
if (version < ZFS_VERSION)
|
||||
return (ZPOOL_STATUS_VERSION_OLDER);
|
||||
|
||||
return (ZPOOL_STATUS_OK);
|
||||
}
|
||||
|
||||
zpool_status_t
|
||||
zpool_get_status(zpool_handle_t *zhp, char **msgid)
|
||||
{
|
||||
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
|
||||
|
||||
if (ret >= NMSGID)
|
||||
*msgid = NULL;
|
||||
else
|
||||
*msgid = zfs_msgid_table_active[ret];
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
zpool_status_t
|
||||
zpool_import_status(nvlist_t *config, char **msgid)
|
||||
{
|
||||
zpool_status_t ret = check_status(config, B_TRUE);
|
||||
|
||||
if (ret >= NMSGID)
|
||||
*msgid = NULL;
|
||||
else
|
||||
*msgid = zfs_msgid_table[ret];
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@@ -1,853 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Internal utility routines for the ZFS library.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
int
|
||||
libzfs_errno(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (hdl->libzfs_error);
|
||||
}
|
||||
|
||||
const char *
|
||||
libzfs_error_action(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (hdl->libzfs_action);
|
||||
}
|
||||
|
||||
const char *
|
||||
libzfs_error_description(libzfs_handle_t *hdl)
|
||||
{
|
||||
if (hdl->libzfs_desc[0] != '\0')
|
||||
return (hdl->libzfs_desc);
|
||||
|
||||
switch (hdl->libzfs_error) {
|
||||
case EZFS_NOMEM:
|
||||
return (dgettext(TEXT_DOMAIN, "out of memory"));
|
||||
case EZFS_BADPROP:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid property value"));
|
||||
case EZFS_PROPREADONLY:
|
||||
return (dgettext(TEXT_DOMAIN, "read only property"));
|
||||
case EZFS_PROPTYPE:
|
||||
return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
|
||||
"datasets of this type"));
|
||||
case EZFS_PROPNONINHERIT:
|
||||
return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
|
||||
case EZFS_PROPSPACE:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
|
||||
case EZFS_BADTYPE:
|
||||
return (dgettext(TEXT_DOMAIN, "operation not applicable to "
|
||||
"datasets of this type"));
|
||||
case EZFS_BUSY:
|
||||
return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
|
||||
case EZFS_EXISTS:
|
||||
return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
|
||||
case EZFS_NOENT:
|
||||
return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
|
||||
case EZFS_BADSTREAM:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
|
||||
case EZFS_DSREADONLY:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset is read only"));
|
||||
case EZFS_VOLTOOBIG:
|
||||
return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
|
||||
"this system"));
|
||||
case EZFS_VOLHASDATA:
|
||||
return (dgettext(TEXT_DOMAIN, "volume has data"));
|
||||
case EZFS_INVALIDNAME:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid name"));
|
||||
case EZFS_BADRESTORE:
|
||||
return (dgettext(TEXT_DOMAIN, "unable to restore to "
|
||||
"destination"));
|
||||
case EZFS_BADBACKUP:
|
||||
return (dgettext(TEXT_DOMAIN, "backup failed"));
|
||||
case EZFS_BADTARGET:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
|
||||
case EZFS_NODEVICE:
|
||||
return (dgettext(TEXT_DOMAIN, "no such device in pool"));
|
||||
case EZFS_BADDEV:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid device"));
|
||||
case EZFS_NOREPLICAS:
|
||||
return (dgettext(TEXT_DOMAIN, "no valid replicas"));
|
||||
case EZFS_RESILVERING:
|
||||
return (dgettext(TEXT_DOMAIN, "currently resilvering"));
|
||||
case EZFS_BADVERSION:
|
||||
return (dgettext(TEXT_DOMAIN, "unsupported version"));
|
||||
case EZFS_POOLUNAVAIL:
|
||||
return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
|
||||
case EZFS_DEVOVERFLOW:
|
||||
return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
|
||||
case EZFS_BADPATH:
|
||||
return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
|
||||
case EZFS_CROSSTARGET:
|
||||
return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
|
||||
"pools"));
|
||||
case EZFS_ZONED:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
|
||||
case EZFS_MOUNTFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "mount failed"));
|
||||
case EZFS_UMOUNTFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "umount failed"));
|
||||
case EZFS_UNSHARENFSFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
|
||||
case EZFS_SHARENFSFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
|
||||
case EZFS_DEVLINKS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
|
||||
case EZFS_PERM:
|
||||
return (dgettext(TEXT_DOMAIN, "permission denied"));
|
||||
case EZFS_NOSPC:
|
||||
return (dgettext(TEXT_DOMAIN, "out of space"));
|
||||
case EZFS_IO:
|
||||
return (dgettext(TEXT_DOMAIN, "I/O error"));
|
||||
case EZFS_INTR:
|
||||
return (dgettext(TEXT_DOMAIN, "signal received"));
|
||||
case EZFS_ISSPARE:
|
||||
return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
|
||||
"spare"));
|
||||
case EZFS_INVALCONFIG:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
|
||||
case EZFS_RECURSIVE:
|
||||
return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
|
||||
case EZFS_NOHISTORY:
|
||||
return (dgettext(TEXT_DOMAIN, "no history available"));
|
||||
case EZFS_UNSHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to unshare"));
|
||||
case EZFS_SHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to share"));
|
||||
case EZFS_POOLPROPS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to retrieve "
|
||||
"pool properties"));
|
||||
case EZFS_POOL_NOTSUP:
|
||||
return (dgettext(TEXT_DOMAIN, "operation not supported "
|
||||
"on this type of pool"));
|
||||
case EZFS_POOL_INVALARG:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid argument for "
|
||||
"this pool operation"));
|
||||
case EZFS_NAMETOOLONG:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset name is too long"));
|
||||
case EZFS_UNKNOWN:
|
||||
return (dgettext(TEXT_DOMAIN, "unknown error"));
|
||||
default:
|
||||
assert(hdl->libzfs_error == 0);
|
||||
return (dgettext(TEXT_DOMAIN, "no error"));
|
||||
}
|
||||
}
|
||||
|
||||
/*PRINTFLIKE2*/
|
||||
void
|
||||
zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
(void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
|
||||
fmt, ap);
|
||||
hdl->libzfs_desc_active = 1;
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
|
||||
{
|
||||
(void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
|
||||
fmt, ap);
|
||||
hdl->libzfs_error = error;
|
||||
|
||||
if (hdl->libzfs_desc_active)
|
||||
hdl->libzfs_desc_active = 0;
|
||||
else
|
||||
hdl->libzfs_desc[0] = '\0';
|
||||
|
||||
if (hdl->libzfs_printerr) {
|
||||
if (error == EZFS_UNKNOWN) {
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
|
||||
"error: %s\n"), libzfs_error_description(hdl));
|
||||
abort();
|
||||
}
|
||||
|
||||
(void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
|
||||
libzfs_error_description(hdl));
|
||||
if (error == EZFS_NOMEM)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zfs_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zfs_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
zfs_verror(hdl, error, fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
switch (error) {
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
zfs_verror(hdl, EZFS_PERM, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EIO:
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EINTR:
|
||||
zfs_verror(hdl, EZFS_INTR, fmt, ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zfs_standard_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (zfs_common_error(hdl, error, fmt, ap) != 0) {
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
switch (error) {
|
||||
case ENXIO:
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset does not exist"));
|
||||
zfs_verror(hdl, EZFS_NOENT, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOSPC:
|
||||
case EDQUOT:
|
||||
zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EEXIST:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset already exists"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset is busy"));
|
||||
zfs_verror(hdl, EZFS_BUSY, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
|
||||
break;
|
||||
|
||||
default:
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zpool_standard_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (zfs_common_error(hdl, error, fmt, ap) != 0) {
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
case ENODEV:
|
||||
zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
zfs_error_aux(hdl,
|
||||
dgettext(TEXT_DOMAIN, "no such pool or dataset"));
|
||||
zfs_verror(hdl, EZFS_NOENT, fmt, ap);
|
||||
break;
|
||||
|
||||
case EEXIST:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool already exists"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENXIO:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"one or more devices is currently unavailable"));
|
||||
zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOTSUP:
|
||||
zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);
|
||||
break;
|
||||
|
||||
case EINVAL:
|
||||
zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
|
||||
break;
|
||||
|
||||
default:
|
||||
zfs_error_aux(hdl, strerror(error));
|
||||
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display an out of memory error message and abort the current program.
|
||||
*/
|
||||
int
|
||||
no_memory(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of malloc() which will die if the allocation fails.
|
||||
*/
|
||||
void *
|
||||
zfs_alloc(libzfs_handle_t *hdl, size_t size)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if ((data = calloc(1, size)) == NULL)
|
||||
(void) no_memory(hdl);
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of realloc(), which also zeroes newly allocated space.
|
||||
*/
|
||||
void *
|
||||
zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if ((ret = realloc(ptr, newsize)) == NULL) {
|
||||
(void) no_memory(hdl);
|
||||
free(ptr);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
bzero((char *)ret + oldsize, (newsize - oldsize));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of strdup() which will die if the allocation fails.
|
||||
*/
|
||||
char *
|
||||
zfs_strdup(libzfs_handle_t *hdl, const char *str)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if ((ret = strdup(str)) == NULL)
|
||||
(void) no_memory(hdl);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a number to an appropriately human-readable output.
|
||||
*/
|
||||
void
|
||||
zfs_nicenum(uint64_t num, char *buf, size_t buflen)
|
||||
{
|
||||
uint64_t n = num;
|
||||
int index = 0;
|
||||
char u;
|
||||
|
||||
while (n >= 1024) {
|
||||
n /= 1024;
|
||||
index++;
|
||||
}
|
||||
|
||||
u = " KMGTPE"[index];
|
||||
|
||||
if (index == 0) {
|
||||
(void) snprintf(buf, buflen, "%llu", n);
|
||||
} else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
|
||||
/*
|
||||
* If this is an even multiple of the base, always display
|
||||
* without any decimal precision.
|
||||
*/
|
||||
(void) snprintf(buf, buflen, "%llu%c", n, u);
|
||||
} else {
|
||||
/*
|
||||
* We want to choose a precision that reflects the best choice
|
||||
* for fitting in 5 characters. This can get rather tricky when
|
||||
* we have numbers that are very close to an order of magnitude.
|
||||
* For example, when displaying 10239 (which is really 9.999K),
|
||||
* we want only a single place of precision for 10.0K. We could
|
||||
* develop some complex heuristics for this, but it's much
|
||||
* easier just to try each combination in turn.
|
||||
*/
|
||||
int i;
|
||||
for (i = 2; i >= 0; i--) {
|
||||
(void) snprintf(buf, buflen, "%.*f%c", i,
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
if (strlen(buf) <= 5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
|
||||
{
|
||||
hdl->libzfs_printerr = printerr;
|
||||
}
|
||||
|
||||
static int
|
||||
libzfs_load(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (modfind("zfs") < 0) {
|
||||
/* Not present in kernel, try loading it. */
|
||||
if (kldload("zfs") < 0 || modfind("zfs") < 0) {
|
||||
if (errno != EEXIST)
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
libzfs_init(void)
|
||||
{
|
||||
libzfs_handle_t *hdl;
|
||||
|
||||
if ((hdl = calloc(sizeof (libzfs_handle_t), 1)) == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
|
||||
if (libzfs_load() == 0)
|
||||
hdl->libzfs_fd = open(ZFS_DEV, O_RDWR);
|
||||
if (hdl->libzfs_fd < 0) {
|
||||
free(hdl);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
|
||||
(void) close(hdl->libzfs_fd);
|
||||
free(hdl);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
|
||||
|
||||
return (hdl);
|
||||
}
|
||||
|
||||
void
|
||||
libzfs_fini(libzfs_handle_t *hdl)
|
||||
{
|
||||
(void) close(hdl->libzfs_fd);
|
||||
if (hdl->libzfs_mnttab)
|
||||
(void) fclose(hdl->libzfs_mnttab);
|
||||
if (hdl->libzfs_sharetab)
|
||||
(void) fclose(hdl->libzfs_sharetab);
|
||||
namespace_clear(hdl);
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
zpool_get_handle(zpool_handle_t *zhp)
|
||||
{
|
||||
return (zhp->zpool_hdl);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
zfs_get_handle(zfs_handle_t *zhp)
|
||||
{
|
||||
return (zhp->zfs_hdl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a name, determine whether or not it's a valid path
|
||||
* (starts with '/' or "./"). If so, walk the mnttab trying
|
||||
* to match the device number. If not, treat the path as an
|
||||
* fs/vol/snap name.
|
||||
*/
|
||||
zfs_handle_t *
|
||||
zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
|
||||
{
|
||||
struct statfs statbuf;
|
||||
|
||||
if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
|
||||
/*
|
||||
* It's not a valid path, assume it's a name of type 'argtype'.
|
||||
*/
|
||||
return (zfs_open(hdl, path, argtype));
|
||||
}
|
||||
|
||||
if (statfs(path, &statbuf) != 0) {
|
||||
(void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (strcmp(statbuf.f_fstypename, MNTTYPE_ZFS) != 0) {
|
||||
(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
|
||||
path);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zfs_open(hdl, statbuf.f_mntfromname, ZFS_TYPE_FILESYSTEM));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
|
||||
* an ioctl().
|
||||
*/
|
||||
int
|
||||
zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
len = 2048;
|
||||
zc->zc_nvlist_dst_size = len;
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when an ioctl() which returns an nvlist fails with ENOMEM. This will
|
||||
* expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
|
||||
* filled in by the kernel to indicate the actual required size.
|
||||
*/
|
||||
int
|
||||
zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
|
||||
{
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size))
|
||||
== 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to free the src and dst nvlists stored in the command structure.
|
||||
*/
|
||||
void
|
||||
zcmd_free_nvlists(zfs_cmd_t *zc)
|
||||
{
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_src);
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
}
|
||||
|
||||
int
|
||||
zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl,
|
||||
size_t *size)
|
||||
{
|
||||
char *packed;
|
||||
size_t len;
|
||||
|
||||
verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
|
||||
|
||||
if ((packed = zfs_alloc(hdl, len)) == NULL)
|
||||
return (-1);
|
||||
|
||||
verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
|
||||
|
||||
zc->zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||
zc->zc_nvlist_src_size = len;
|
||||
|
||||
if (size)
|
||||
*size = len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpacks an nvlist from the ZFS ioctl command structure.
|
||||
*/
|
||||
int
|
||||
zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
|
||||
{
|
||||
if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
|
||||
zc->zc_nvlist_dst_size, nvlp, 0) != 0)
|
||||
return (no_memory(hdl));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_print_prop_headers(libzfs_get_cbdata_t *cbp)
|
||||
{
|
||||
zfs_proplist_t *pl = cbp->cb_proplist;
|
||||
int i;
|
||||
char *title;
|
||||
size_t len;
|
||||
|
||||
cbp->cb_first = B_FALSE;
|
||||
if (cbp->cb_scripted)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Start with the length of the column headers.
|
||||
*/
|
||||
cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"PROPERTY"));
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"VALUE"));
|
||||
cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"SOURCE"));
|
||||
|
||||
/*
|
||||
* Go through and calculate the widths for each column. For the
|
||||
* 'source' column, we kludge it up by taking the worst-case scenario of
|
||||
* inheriting from the longest name. This is acceptable because in the
|
||||
* majority of cases 'SOURCE' is the last column displayed, and we don't
|
||||
* use the width anyway. Note that the 'VALUE' column can be oversized,
|
||||
* if the name of the property is much longer the any values we find.
|
||||
*/
|
||||
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
|
||||
/*
|
||||
* 'PROPERTY' column
|
||||
*/
|
||||
if (pl->pl_prop != ZFS_PROP_INVAL) {
|
||||
len = strlen(zfs_prop_to_name(pl->pl_prop));
|
||||
if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = len;
|
||||
} else {
|
||||
len = strlen(pl->pl_user_prop);
|
||||
if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'VALUE' column
|
||||
*/
|
||||
if ((pl->pl_prop != ZFS_PROP_NAME || !pl->pl_all) &&
|
||||
pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
|
||||
|
||||
/*
|
||||
* 'NAME' and 'SOURCE' columns
|
||||
*/
|
||||
if (pl->pl_prop == ZFS_PROP_NAME &&
|
||||
pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
|
||||
cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
|
||||
cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
|
||||
strlen(dgettext(TEXT_DOMAIN, "inherited from"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now go through and print the headers.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
title = dgettext(TEXT_DOMAIN, "NAME");
|
||||
break;
|
||||
case GET_COL_PROPERTY:
|
||||
title = dgettext(TEXT_DOMAIN, "PROPERTY");
|
||||
break;
|
||||
case GET_COL_VALUE:
|
||||
title = dgettext(TEXT_DOMAIN, "VALUE");
|
||||
break;
|
||||
case GET_COL_SOURCE:
|
||||
title = dgettext(TEXT_DOMAIN, "SOURCE");
|
||||
break;
|
||||
default:
|
||||
title = NULL;
|
||||
}
|
||||
|
||||
if (title != NULL) {
|
||||
if (i == 3 || cbp->cb_columns[i + 1] == 0)
|
||||
(void) printf("%s", title);
|
||||
else
|
||||
(void) printf("%-*s ",
|
||||
cbp->cb_colwidths[cbp->cb_columns[i]],
|
||||
title);
|
||||
}
|
||||
}
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a single line of output, according to the settings in the callback
|
||||
* structure.
|
||||
*/
|
||||
void
|
||||
libzfs_print_one_property(const char *name, libzfs_get_cbdata_t *cbp,
|
||||
const char *propname, const char *value, zfs_source_t sourcetype,
|
||||
const char *source)
|
||||
{
|
||||
int i;
|
||||
const char *str;
|
||||
char buf[128];
|
||||
|
||||
/*
|
||||
* Ignore those source types that the user has chosen to ignore.
|
||||
*/
|
||||
if ((sourcetype & cbp->cb_sources) == 0)
|
||||
return;
|
||||
|
||||
if (cbp->cb_first)
|
||||
zfs_print_prop_headers(cbp);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
str = name;
|
||||
break;
|
||||
|
||||
case GET_COL_PROPERTY:
|
||||
str = propname;
|
||||
break;
|
||||
|
||||
case GET_COL_VALUE:
|
||||
str = value;
|
||||
break;
|
||||
|
||||
case GET_COL_SOURCE:
|
||||
switch (sourcetype) {
|
||||
case ZFS_SRC_NONE:
|
||||
str = "-";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_DEFAULT:
|
||||
str = "default";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_LOCAL:
|
||||
str = "local";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_TEMPORARY:
|
||||
str = "temporary";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_INHERITED:
|
||||
(void) snprintf(buf, sizeof (buf),
|
||||
"inherited from %s", source);
|
||||
str = buf;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cbp->cb_columns[i + 1] == 0)
|
||||
(void) printf("%s", str);
|
||||
else if (cbp->cb_scripted)
|
||||
(void) printf("%s\t", str);
|
||||
else
|
||||
(void) printf("%-*s ",
|
||||
cbp->cb_colwidths[cbp->cb_columns[i]],
|
||||
str);
|
||||
|
||||
}
|
||||
|
||||
(void) printf("\n");
|
||||
}
|
||||
@@ -1,852 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/processor.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/zmod.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
/*
|
||||
* Emulation of kernel services in userland.
|
||||
*/
|
||||
|
||||
int hz = 119; /* frequency when using gethrtime() >> 23 for lbolt */
|
||||
uint64_t physmem;
|
||||
vnode_t *rootdir = (vnode_t *)0xabcd1234;
|
||||
char hw_serial[11];
|
||||
|
||||
struct utsname utsname = {
|
||||
"userland", "libzpool", "1", "1", "na"
|
||||
};
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* threads
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
kthread_t *
|
||||
zk_thread_create(void (*func)(), void *arg)
|
||||
{
|
||||
thread_t tid;
|
||||
|
||||
VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED,
|
||||
&tid) == 0);
|
||||
|
||||
return ((void *)(uintptr_t)tid);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kstats
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
kstat_t *
|
||||
kstat_create(char *module, int instance, char *name, char *class,
|
||||
uchar_t type, ulong_t ndata, uchar_t ks_flag)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
kstat_install(kstat_t *ksp)
|
||||
{}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
kstat_delete(kstat_t *ksp)
|
||||
{}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* mutexes
|
||||
* =========================================================================
|
||||
*/
|
||||
void
|
||||
zmutex_init(kmutex_t *mp)
|
||||
{
|
||||
mp->m_owner = NULL;
|
||||
(void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
zmutex_destroy(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
(void) _mutex_destroy(&(mp)->m_lock);
|
||||
mp->m_owner = (void *)-1UL;
|
||||
}
|
||||
|
||||
void
|
||||
mutex_enter(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner != (void *)-1UL);
|
||||
ASSERT(mp->m_owner != curthread);
|
||||
VERIFY(mutex_lock(&mp->m_lock) == 0);
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
mp->m_owner = curthread;
|
||||
}
|
||||
|
||||
int
|
||||
mutex_tryenter(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner != (void *)-1UL);
|
||||
if (mutex_trylock(&mp->m_lock) == 0) {
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
mp->m_owner = curthread;
|
||||
return (1);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mutex_exit(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner == curthread);
|
||||
mp->m_owner = NULL;
|
||||
VERIFY(mutex_unlock(&mp->m_lock) == 0);
|
||||
}
|
||||
|
||||
void *
|
||||
mutex_owner(kmutex_t *mp)
|
||||
{
|
||||
return (mp->m_owner);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* rwlocks
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
rw_init(krwlock_t *rwlp, char *name, int type, void *arg)
|
||||
{
|
||||
rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL);
|
||||
rwlp->rw_owner = NULL;
|
||||
rwlp->rw_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
rw_destroy(krwlock_t *rwlp)
|
||||
{
|
||||
rwlock_destroy(&rwlp->rw_lock);
|
||||
rwlp->rw_owner = (void *)-1UL;
|
||||
rwlp->rw_count = -2;
|
||||
}
|
||||
|
||||
void
|
||||
rw_enter(krwlock_t *rwlp, krw_t rw)
|
||||
{
|
||||
//ASSERT(!RW_LOCK_HELD(rwlp));
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
ASSERT(rwlp->rw_owner != curthread);
|
||||
|
||||
if (rw == RW_READER) {
|
||||
(void) rw_rdlock(&rwlp->rw_lock);
|
||||
ASSERT(rwlp->rw_count >= 0);
|
||||
atomic_add_int(&rwlp->rw_count, 1);
|
||||
} else {
|
||||
(void) rw_wrlock(&rwlp->rw_lock);
|
||||
ASSERT(rwlp->rw_count == 0);
|
||||
rwlp->rw_count = -1;
|
||||
rwlp->rw_owner = curthread;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rw_exit(krwlock_t *rwlp)
|
||||
{
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
|
||||
if (rwlp->rw_owner == curthread) {
|
||||
/* Write locked. */
|
||||
ASSERT(rwlp->rw_count == -1);
|
||||
rwlp->rw_count = 0;
|
||||
rwlp->rw_owner = NULL;
|
||||
} else {
|
||||
/* Read locked. */
|
||||
ASSERT(rwlp->rw_count > 0);
|
||||
atomic_add_int(&rwlp->rw_count, -1);
|
||||
}
|
||||
(void) rw_unlock(&rwlp->rw_lock);
|
||||
}
|
||||
|
||||
int
|
||||
rw_tryenter(krwlock_t *rwlp, krw_t rw)
|
||||
{
|
||||
int rv;
|
||||
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
ASSERT(rwlp->rw_owner != curthread);
|
||||
|
||||
if (rw == RW_READER)
|
||||
rv = rw_tryrdlock(&rwlp->rw_lock);
|
||||
else
|
||||
rv = rw_trywrlock(&rwlp->rw_lock);
|
||||
|
||||
if (rv == 0) {
|
||||
ASSERT(rwlp->rw_owner == NULL);
|
||||
if (rw == RW_READER) {
|
||||
ASSERT(rwlp->rw_count >= 0);
|
||||
atomic_add_int(&rwlp->rw_count, 1);
|
||||
} else {
|
||||
ASSERT(rwlp->rw_count == 0);
|
||||
rwlp->rw_count = -1;
|
||||
rwlp->rw_owner = curthread;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
rw_tryupgrade(krwlock_t *rwlp)
|
||||
{
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rw_lock_held(krwlock_t *rwlp)
|
||||
{
|
||||
|
||||
return (rwlp->rw_count != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* condition variables
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
cv_init(kcondvar_t *cv, char *name, int type, void *arg)
|
||||
{
|
||||
VERIFY(cond_init(cv, name, NULL) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_destroy(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_destroy(cv) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_wait(kcondvar_t *cv, kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mutex_owner(mp) == curthread);
|
||||
mp->m_owner = NULL;
|
||||
int ret = cond_wait(cv, &mp->m_lock);
|
||||
VERIFY(ret == 0 || ret == EINTR);
|
||||
mp->m_owner = curthread;
|
||||
}
|
||||
|
||||
clock_t
|
||||
cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
|
||||
{
|
||||
int error;
|
||||
struct timespec ts;
|
||||
struct timeval tv;
|
||||
clock_t delta;
|
||||
|
||||
ASSERT(abstime > 0);
|
||||
top:
|
||||
delta = abstime;
|
||||
if (delta <= 0)
|
||||
return (-1);
|
||||
|
||||
if (gettimeofday(&tv, NULL) != 0)
|
||||
assert(!"gettimeofday() failed");
|
||||
|
||||
ts.tv_sec = tv.tv_sec + delta / hz;
|
||||
ts.tv_nsec = tv.tv_usec * 1000 + (delta % hz) * (NANOSEC / hz);
|
||||
ASSERT(ts.tv_nsec >= 0);
|
||||
|
||||
if(ts.tv_nsec >= NANOSEC) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= NANOSEC;
|
||||
}
|
||||
|
||||
ASSERT(mutex_owner(mp) == curthread);
|
||||
mp->m_owner = NULL;
|
||||
error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
|
||||
mp->m_owner = curthread;
|
||||
|
||||
if (error == EINTR)
|
||||
goto top;
|
||||
|
||||
if (error == ETIMEDOUT)
|
||||
return (-1);
|
||||
|
||||
ASSERT(error == 0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
cv_signal(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_signal(cv) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_broadcast(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_broadcast(cv) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* vnode operations
|
||||
* =========================================================================
|
||||
*/
|
||||
/*
|
||||
* Note: for the xxxat() versions of these functions, we assume that the
|
||||
* starting vp is always rootdir (which is true for spa_directory.c, the only
|
||||
* ZFS consumer of these interfaces). We assert this is true, and then emulate
|
||||
* them by adding '/' in front of the path.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||
{
|
||||
int fd;
|
||||
vnode_t *vp;
|
||||
int old_umask;
|
||||
char realpath[MAXPATHLEN];
|
||||
struct stat64 st;
|
||||
|
||||
/*
|
||||
* If we're accessing a real disk from userland, we need to use
|
||||
* the character interface to avoid caching. This is particularly
|
||||
* important if we're trying to look at a real in-kernel storage
|
||||
* pool from userland, e.g. via zdb, because otherwise we won't
|
||||
* see the changes occurring under the segmap cache.
|
||||
* On the other hand, the stupid character device returns zero
|
||||
* for its size. So -- gag -- we open the block device to get
|
||||
* its size, and remember it for subsequent VOP_GETATTR().
|
||||
*/
|
||||
if (strncmp(path, "/dev/", 5) == 0) {
|
||||
char *dsk;
|
||||
fd = open64(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
if (fstat64(fd, &st) == -1) {
|
||||
close(fd);
|
||||
return (errno);
|
||||
}
|
||||
close(fd);
|
||||
(void) sprintf(realpath, "%s", path);
|
||||
dsk = strstr(path, "/dsk/");
|
||||
if (dsk != NULL)
|
||||
(void) sprintf(realpath + (dsk - path) + 1, "r%s",
|
||||
dsk + 1);
|
||||
} else {
|
||||
(void) sprintf(realpath, "%s", path);
|
||||
if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
|
||||
return (errno);
|
||||
}
|
||||
|
||||
if (flags & FCREAT)
|
||||
old_umask = umask(0);
|
||||
|
||||
/*
|
||||
* The construct 'flags - FREAD' conveniently maps combinations of
|
||||
* FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
|
||||
*/
|
||||
fd = open64(realpath, flags - FREAD, mode);
|
||||
|
||||
if (flags & FCREAT)
|
||||
(void) umask(old_umask);
|
||||
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
|
||||
if (fstat64(fd, &st) == -1) {
|
||||
close(fd);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
*vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
|
||||
|
||||
vp->v_fd = fd;
|
||||
if (S_ISCHR(st.st_mode))
|
||||
ioctl(fd, DIOCGMEDIASIZE, &vp->v_size);
|
||||
else
|
||||
vp->v_size = st.st_size;
|
||||
vp->v_path = spa_strdup(path);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
|
||||
int x3, vnode_t *startvp)
|
||||
{
|
||||
char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
|
||||
int ret;
|
||||
|
||||
ASSERT(startvp == rootdir);
|
||||
(void) sprintf(realpath, "/%s", path);
|
||||
|
||||
ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
|
||||
|
||||
umem_free(realpath, strlen(path) + 2);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
|
||||
int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
|
||||
{
|
||||
ssize_t iolen, split;
|
||||
|
||||
if (uio == UIO_READ) {
|
||||
iolen = pread64(vp->v_fd, addr, len, offset);
|
||||
} else {
|
||||
/*
|
||||
* To simulate partial disk writes, we split writes into two
|
||||
* system calls so that the process can be killed in between.
|
||||
*/
|
||||
split = (len > 0 ? rand() % len : 0);
|
||||
iolen = pwrite64(vp->v_fd, addr, split, offset);
|
||||
iolen += pwrite64(vp->v_fd, (char *)addr + split,
|
||||
len - split, offset + split);
|
||||
}
|
||||
|
||||
if (iolen == -1)
|
||||
return (errno);
|
||||
if (residp)
|
||||
*residp = len - iolen;
|
||||
else if (iolen != len)
|
||||
return (EIO);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
vn_close(vnode_t *vp)
|
||||
{
|
||||
close(vp->v_fd);
|
||||
spa_strfree(vp->v_path);
|
||||
umem_free(vp, sizeof (vnode_t));
|
||||
}
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* Figure out which debugging statements to print
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
static char *dprintf_string;
|
||||
static int dprintf_print_all;
|
||||
|
||||
int
|
||||
dprintf_find_string(const char *string)
|
||||
{
|
||||
char *tmp_str = dprintf_string;
|
||||
int len = strlen(string);
|
||||
|
||||
/*
|
||||
* Find out if this is a string we want to print.
|
||||
* String format: file1.c,function_name1,file2.c,file3.c
|
||||
*/
|
||||
|
||||
while (tmp_str != NULL) {
|
||||
if (strncmp(tmp_str, string, len) == 0 &&
|
||||
(tmp_str[len] == ',' || tmp_str[len] == '\0'))
|
||||
return (1);
|
||||
tmp_str = strchr(tmp_str, ',');
|
||||
if (tmp_str != NULL)
|
||||
tmp_str++; /* Get rid of , */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dprintf_setup(int *argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* Debugging can be specified two ways: by setting the
|
||||
* environment variable ZFS_DEBUG, or by including a
|
||||
* "debug=..." argument on the command line. The command
|
||||
* line setting overrides the environment variable.
|
||||
*/
|
||||
|
||||
for (i = 1; i < *argc; i++) {
|
||||
int len = strlen("debug=");
|
||||
/* First look for a command line argument */
|
||||
if (strncmp("debug=", argv[i], len) == 0) {
|
||||
dprintf_string = argv[i] + len;
|
||||
/* Remove from args */
|
||||
for (j = i; j < *argc; j++)
|
||||
argv[j] = argv[j+1];
|
||||
argv[j] = NULL;
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
|
||||
if (dprintf_string == NULL) {
|
||||
/* Look for ZFS_DEBUG environment variable */
|
||||
dprintf_string = getenv("ZFS_DEBUG");
|
||||
}
|
||||
|
||||
/*
|
||||
* Are we just turning on all debugging?
|
||||
*/
|
||||
if (dprintf_find_string("on"))
|
||||
dprintf_print_all = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* debug printfs
|
||||
* =========================================================================
|
||||
*/
|
||||
void
|
||||
__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
|
||||
{
|
||||
const char *newfile;
|
||||
va_list adx;
|
||||
|
||||
/*
|
||||
* Get rid of annoying "../common/" prefix to filename.
|
||||
*/
|
||||
newfile = strrchr(file, '/');
|
||||
if (newfile != NULL) {
|
||||
newfile = newfile + 1; /* Get rid of leading / */
|
||||
} else {
|
||||
newfile = file;
|
||||
}
|
||||
|
||||
if (dprintf_print_all ||
|
||||
dprintf_find_string(newfile) ||
|
||||
dprintf_find_string(func)) {
|
||||
/* Print out just the function name if requested */
|
||||
flockfile(stdout);
|
||||
if (dprintf_find_string("pid"))
|
||||
(void) printf("%d ", getpid());
|
||||
if (dprintf_find_string("tid"))
|
||||
(void) printf("%u ", thr_self());
|
||||
#if 0
|
||||
if (dprintf_find_string("cpu"))
|
||||
(void) printf("%u ", getcpuid());
|
||||
#endif
|
||||
if (dprintf_find_string("time"))
|
||||
(void) printf("%llu ", gethrtime());
|
||||
if (dprintf_find_string("long"))
|
||||
(void) printf("%s, line %d: ", newfile, line);
|
||||
(void) printf("%s: ", func);
|
||||
va_start(adx, fmt);
|
||||
(void) vprintf(fmt, adx);
|
||||
va_end(adx);
|
||||
funlockfile(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZFS_DEBUG */
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* cmn_err() and panic()
|
||||
* =========================================================================
|
||||
*/
|
||||
static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
|
||||
static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
|
||||
|
||||
void
|
||||
vpanic(const char *fmt, va_list adx)
|
||||
{
|
||||
(void) fprintf(stderr, "error: ");
|
||||
(void) vfprintf(stderr, fmt, adx);
|
||||
(void) fprintf(stderr, "\n");
|
||||
|
||||
abort(); /* think of it as a "user-level crash dump" */
|
||||
}
|
||||
|
||||
void
|
||||
panic(const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
|
||||
va_start(adx, fmt);
|
||||
vpanic(fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
void
|
||||
vcmn_err(int ce, const char *fmt, va_list adx)
|
||||
{
|
||||
if (ce == CE_PANIC)
|
||||
vpanic(fmt, adx);
|
||||
if (ce != CE_NOTE) { /* suppress noise in userland stress testing */
|
||||
(void) fprintf(stderr, "%s", ce_prefix[ce]);
|
||||
(void) vfprintf(stderr, fmt, adx);
|
||||
(void) fprintf(stderr, "%s", ce_suffix[ce]);
|
||||
}
|
||||
}
|
||||
|
||||
/*PRINTFLIKE2*/
|
||||
void
|
||||
cmn_err(int ce, const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
|
||||
va_start(adx, fmt);
|
||||
vcmn_err(ce, fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kobj interfaces
|
||||
* =========================================================================
|
||||
*/
|
||||
struct _buf *
|
||||
kobj_open_file(char *name)
|
||||
{
|
||||
struct _buf *file;
|
||||
vnode_t *vp;
|
||||
|
||||
/* set vp as the _fd field of the file */
|
||||
if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir) != 0)
|
||||
return ((void *)-1UL);
|
||||
|
||||
file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
|
||||
file->_fd = (intptr_t)vp;
|
||||
return (file);
|
||||
}
|
||||
|
||||
int
|
||||
kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
|
||||
{
|
||||
ssize_t resid;
|
||||
|
||||
vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off,
|
||||
UIO_SYSSPACE, 0, 0, 0, &resid);
|
||||
|
||||
return (size - resid);
|
||||
}
|
||||
|
||||
void
|
||||
kobj_close_file(struct _buf *file)
|
||||
{
|
||||
vn_close((vnode_t *)file->_fd);
|
||||
umem_free(file, sizeof (struct _buf));
|
||||
}
|
||||
|
||||
int
|
||||
kobj_get_filesize(struct _buf *file, uint64_t *size)
|
||||
{
|
||||
struct stat64 st;
|
||||
vnode_t *vp = (vnode_t *)file->_fd;
|
||||
|
||||
if (fstat64(vp->v_fd, &st) == -1) {
|
||||
vn_close(vp);
|
||||
return (errno);
|
||||
}
|
||||
*size = st.st_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* misc routines
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
delay(clock_t ticks)
|
||||
{
|
||||
poll(0, 0, ticks * (1000 / hz));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Find highest one bit set.
|
||||
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
|
||||
* High order bit is 31 (or 63 in _LP64 kernel).
|
||||
*/
|
||||
int
|
||||
highbit(ulong_t i)
|
||||
{
|
||||
register int h = 1;
|
||||
|
||||
if (i == 0)
|
||||
return (0);
|
||||
#ifdef _LP64
|
||||
if (i & 0xffffffff00000000ul) {
|
||||
h += 32; i >>= 32;
|
||||
}
|
||||
#endif
|
||||
if (i & 0xffff0000) {
|
||||
h += 16; i >>= 16;
|
||||
}
|
||||
if (i & 0xff00) {
|
||||
h += 8; i >>= 8;
|
||||
}
|
||||
if (i & 0xf0) {
|
||||
h += 4; i >>= 4;
|
||||
}
|
||||
if (i & 0xc) {
|
||||
h += 2; i >>= 2;
|
||||
}
|
||||
if (i & 0x2) {
|
||||
h += 1;
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
random_get_bytes_common(uint8_t *ptr, size_t len, char *devname)
|
||||
{
|
||||
int fd = open(devname, O_RDONLY);
|
||||
size_t resid = len;
|
||||
ssize_t bytes;
|
||||
|
||||
ASSERT(fd != -1);
|
||||
|
||||
while (resid != 0) {
|
||||
bytes = read(fd, ptr, resid);
|
||||
ASSERT(bytes >= 0);
|
||||
ptr += bytes;
|
||||
resid -= bytes;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
random_get_bytes(uint8_t *ptr, size_t len)
|
||||
{
|
||||
return (random_get_bytes_common(ptr, len, "/dev/random"));
|
||||
}
|
||||
|
||||
int
|
||||
random_get_pseudo_bytes(uint8_t *ptr, size_t len)
|
||||
{
|
||||
return (random_get_bytes_common(ptr, len, "/dev/urandom"));
|
||||
}
|
||||
|
||||
int
|
||||
ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
|
||||
{
|
||||
char *end;
|
||||
|
||||
*result = strtoul(hw_serial, &end, base);
|
||||
if (*result == 0)
|
||||
return (errno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kernel emulation setup & teardown
|
||||
* =========================================================================
|
||||
*/
|
||||
static int
|
||||
umem_out_of_memory(void)
|
||||
{
|
||||
char errmsg[] = "out of memory -- generating core dump\n";
|
||||
|
||||
write(fileno(stderr), errmsg, sizeof (errmsg));
|
||||
abort();
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
kernel_init(int mode)
|
||||
{
|
||||
umem_nofail_callback(umem_out_of_memory);
|
||||
|
||||
physmem = sysconf(_SC_PHYS_PAGES);
|
||||
|
||||
dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
|
||||
(double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
|
||||
|
||||
snprintf(hw_serial, sizeof (hw_serial), "%ld", gethostid());
|
||||
|
||||
spa_init(mode);
|
||||
}
|
||||
|
||||
void
|
||||
kernel_fini(void)
|
||||
{
|
||||
spa_fini();
|
||||
}
|
||||
|
||||
int
|
||||
z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
|
||||
{
|
||||
int ret;
|
||||
uLongf len = *dstlen;
|
||||
|
||||
if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK)
|
||||
*dstlen = (size_t)len;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
|
||||
int level)
|
||||
{
|
||||
int ret;
|
||||
uLongf len = *dstlen;
|
||||
|
||||
if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK)
|
||||
*dstlen = (size_t)len;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@@ -1,511 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZFS_CONTEXT_H
|
||||
#define _SYS_ZFS_CONTEXT_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _SYS_MUTEX_H
|
||||
#define _SYS_RWLOCK_H
|
||||
#define _SYS_CONDVAR_H
|
||||
#define _SYS_SYSTM_H
|
||||
#define _SYS_DEBUG_H
|
||||
#define _SYS_T_LOCK_H
|
||||
#define _SYS_VNODE_H
|
||||
#define _SYS_VFS_H
|
||||
#define _SYS_SUNDDI_H
|
||||
#define _SYS_CALLB_H
|
||||
#define _SYS_SCHED_H_
|
||||
|
||||
#include <solaris.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <thread.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <umem.h>
|
||||
#include <vmem.h>
|
||||
#include <fsshare.h>
|
||||
#include <sys/note.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/bitmap.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/list.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/zfs_debug.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/sdt.h>
|
||||
#include <sys/kstat.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/disk.h>
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#define ZFS_EXPORTS_PATH "/etc/zfs/exports"
|
||||
|
||||
/*
|
||||
* Debugging
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that we are not using the debugging levels.
|
||||
*/
|
||||
|
||||
#define CE_CONT 0 /* continuation */
|
||||
#define CE_NOTE 1 /* notice */
|
||||
#define CE_WARN 2 /* warning */
|
||||
#define CE_PANIC 3 /* panic */
|
||||
#define CE_IGNORE 4 /* print nothing */
|
||||
|
||||
/*
|
||||
* ZFS debugging
|
||||
*/
|
||||
|
||||
#define ZFS_LOG(...) do { } while (0)
|
||||
|
||||
typedef u_longlong_t rlim64_t;
|
||||
#define RLIM64_INFINITY ((rlim64_t)-3)
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
extern void dprintf_setup(int *argc, char **argv);
|
||||
#endif /* ZFS_DEBUG */
|
||||
|
||||
extern void cmn_err(int, const char *, ...);
|
||||
extern void vcmn_err(int, const char *, __va_list);
|
||||
extern void panic(const char *, ...);
|
||||
extern void vpanic(const char *, __va_list);
|
||||
|
||||
/* This definition is copied from assert.h. */
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
#define verify(EX) (void)((EX) || \
|
||||
(__assert_c99(#EX, __FILE__, __LINE__, __func__), 0))
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
#define VERIFY verify
|
||||
#define ASSERT assert
|
||||
|
||||
extern void __assert(const char *, const char *, int);
|
||||
|
||||
#ifdef lint
|
||||
#define VERIFY3_IMPL(x, y, z, t) if (x == z) ((void)0)
|
||||
#else
|
||||
/* BEGIN CSTYLED */
|
||||
#define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE) do { \
|
||||
const TYPE __left = (TYPE)(LEFT); \
|
||||
const TYPE __right = (TYPE)(RIGHT); \
|
||||
if (!(__left OP __right)) { \
|
||||
char *__buf = alloca(256); \
|
||||
(void) snprintf(__buf, 256, "%s %s %s (0x%llx %s 0x%llx)", \
|
||||
#LEFT, #OP, #RIGHT, \
|
||||
(u_longlong_t)__left, #OP, (u_longlong_t)__right); \
|
||||
__assert(__buf, __FILE__, __LINE__); \
|
||||
} \
|
||||
_NOTE(CONSTCOND) } while (0)
|
||||
/* END CSTYLED */
|
||||
#endif /* lint */
|
||||
|
||||
#define VERIFY3S(x, y, z) VERIFY3_IMPL(x, y, z, int64_t)
|
||||
#define VERIFY3U(x, y, z) VERIFY3_IMPL(x, y, z, uint64_t)
|
||||
#define VERIFY3P(x, y, z) VERIFY3_IMPL(x, y, z, uintptr_t)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT3S(x, y, z) ((void)0)
|
||||
#define ASSERT3U(x, y, z) ((void)0)
|
||||
#define ASSERT3P(x, y, z) ((void)0)
|
||||
#else
|
||||
#define ASSERT3S(x, y, z) VERIFY3S(x, y, z)
|
||||
#define ASSERT3U(x, y, z) VERIFY3U(x, y, z)
|
||||
#define ASSERT3P(x, y, z) VERIFY3P(x, y, z)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dtrace SDT probes have different signatures in userland than they do in
|
||||
* kernel. If they're being used in kernel code, re-define them out of
|
||||
* existence for their counterparts in libzpool.
|
||||
*/
|
||||
|
||||
#ifdef DTRACE_PROBE1
|
||||
#undef DTRACE_PROBE1
|
||||
#define DTRACE_PROBE1(a, b, c) ((void)0)
|
||||
#endif /* DTRACE_PROBE1 */
|
||||
|
||||
#ifdef DTRACE_PROBE2
|
||||
#undef DTRACE_PROBE2
|
||||
#define DTRACE_PROBE2(a, b, c, d, e) ((void)0)
|
||||
#endif /* DTRACE_PROBE2 */
|
||||
|
||||
#ifdef DTRACE_PROBE3
|
||||
#undef DTRACE_PROBE3
|
||||
#define DTRACE_PROBE3(a, b, c, d, e, f, g) ((void)0)
|
||||
#endif /* DTRACE_PROBE3 */
|
||||
|
||||
#ifdef DTRACE_PROBE4
|
||||
#undef DTRACE_PROBE4
|
||||
#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) ((void)0)
|
||||
#endif /* DTRACE_PROBE4 */
|
||||
|
||||
/*
|
||||
* Threads
|
||||
*/
|
||||
#define curthread ((void *)(uintptr_t)thr_self())
|
||||
|
||||
typedef struct kthread kthread_t;
|
||||
|
||||
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
|
||||
zk_thread_create(func, arg)
|
||||
#define thread_exit() thr_exit(NULL)
|
||||
|
||||
extern kthread_t *zk_thread_create(void (*func)(), void *arg);
|
||||
|
||||
#define issig(why) (FALSE)
|
||||
#define ISSIG(thr, why) (FALSE)
|
||||
|
||||
/*
|
||||
* Mutexes
|
||||
*/
|
||||
typedef struct kmutex {
|
||||
void *m_owner;
|
||||
mutex_t m_lock;
|
||||
} kmutex_t;
|
||||
|
||||
#define MUTEX_DEFAULT USYNC_THREAD
|
||||
#undef MUTEX_HELD
|
||||
#define MUTEX_HELD(m) ((m)->m_owner == curthread)
|
||||
|
||||
/*
|
||||
* Argh -- we have to get cheesy here because the kernel and userland
|
||||
* have different signatures for the same routine.
|
||||
*/
|
||||
//extern int _mutex_init(mutex_t *mp, int type, void *arg);
|
||||
//extern int _mutex_destroy(mutex_t *mp);
|
||||
|
||||
#define mutex_init(mp, b, c, d) zmutex_init((kmutex_t *)(mp))
|
||||
#define mutex_destroy(mp) zmutex_destroy((kmutex_t *)(mp))
|
||||
|
||||
extern void zmutex_init(kmutex_t *mp);
|
||||
extern void zmutex_destroy(kmutex_t *mp);
|
||||
extern void mutex_enter(kmutex_t *mp);
|
||||
extern void mutex_exit(kmutex_t *mp);
|
||||
extern int mutex_tryenter(kmutex_t *mp);
|
||||
extern void *mutex_owner(kmutex_t *mp);
|
||||
|
||||
/*
|
||||
* RW locks
|
||||
*/
|
||||
typedef struct krwlock {
|
||||
int rw_count;
|
||||
void *rw_owner;
|
||||
rwlock_t rw_lock;
|
||||
} krwlock_t;
|
||||
|
||||
typedef int krw_t;
|
||||
|
||||
#define RW_READER 0
|
||||
#define RW_WRITER 1
|
||||
#define RW_DEFAULT USYNC_THREAD
|
||||
|
||||
#undef RW_READ_HELD
|
||||
|
||||
#undef RW_WRITE_HELD
|
||||
#define RW_WRITE_HELD(x) ((x)->rw_owner == curthread)
|
||||
#define RW_LOCK_HELD(x) rw_lock_held(x)
|
||||
|
||||
extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg);
|
||||
extern void rw_destroy(krwlock_t *rwlp);
|
||||
extern void rw_enter(krwlock_t *rwlp, krw_t rw);
|
||||
extern int rw_tryenter(krwlock_t *rwlp, krw_t rw);
|
||||
extern int rw_tryupgrade(krwlock_t *rwlp);
|
||||
extern void rw_exit(krwlock_t *rwlp);
|
||||
extern int rw_lock_held(krwlock_t *rwlp);
|
||||
#define rw_downgrade(rwlp) do { } while (0)
|
||||
|
||||
/*
|
||||
* Condition variables
|
||||
*/
|
||||
typedef cond_t kcondvar_t;
|
||||
|
||||
#define CV_DEFAULT USYNC_THREAD
|
||||
|
||||
extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
|
||||
extern void cv_destroy(kcondvar_t *cv);
|
||||
extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
|
||||
extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
|
||||
extern void cv_signal(kcondvar_t *cv);
|
||||
extern void cv_broadcast(kcondvar_t *cv);
|
||||
|
||||
/*
|
||||
* Kernel memory
|
||||
*/
|
||||
#define KM_SLEEP UMEM_NOFAIL
|
||||
#define KM_NOSLEEP UMEM_DEFAULT
|
||||
#define KMC_NODEBUG UMC_NODEBUG
|
||||
#define kmem_alloc(_s, _f) umem_alloc(_s, _f)
|
||||
#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f)
|
||||
#define kmem_free(_b, _s) umem_free(_b, _s)
|
||||
#define kmem_size() (physmem * PAGESIZE)
|
||||
#define kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
|
||||
umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i)
|
||||
#define kmem_cache_destroy(_c) umem_cache_destroy(_c)
|
||||
#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f)
|
||||
#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b)
|
||||
#define kmem_debugging() 0
|
||||
#define kmem_cache_reap_now(c)
|
||||
|
||||
typedef umem_cache_t kmem_cache_t;
|
||||
|
||||
/*
|
||||
* Task queues
|
||||
*/
|
||||
typedef struct taskq taskq_t;
|
||||
typedef uintptr_t taskqid_t;
|
||||
typedef void (task_func_t)(void *);
|
||||
|
||||
#define TASKQ_PREPOPULATE 0x0001
|
||||
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
|
||||
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
|
||||
|
||||
#define TQ_SLEEP KM_SLEEP /* Can block for memory */
|
||||
#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */
|
||||
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
||||
|
||||
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
||||
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
||||
extern void taskq_destroy(taskq_t *);
|
||||
extern void taskq_wait(taskq_t *);
|
||||
extern int taskq_member(taskq_t *, void *);
|
||||
|
||||
/*
|
||||
* vnodes
|
||||
*/
|
||||
typedef struct vnode {
|
||||
uint64_t v_size;
|
||||
int v_fd;
|
||||
char *v_path;
|
||||
} vnode_t;
|
||||
|
||||
typedef struct vattr {
|
||||
uint_t va_mask; /* bit-mask of attributes */
|
||||
u_offset_t va_size; /* file size in bytes */
|
||||
} vattr_t;
|
||||
|
||||
#define AT_TYPE 0x0001
|
||||
#define AT_MODE 0x0002
|
||||
#define AT_UID 0x0004
|
||||
#define AT_GID 0x0008
|
||||
#define AT_FSID 0x0010
|
||||
#define AT_NODEID 0x0020
|
||||
#define AT_NLINK 0x0040
|
||||
#define AT_SIZE 0x0080
|
||||
#define AT_ATIME 0x0100
|
||||
#define AT_MTIME 0x0200
|
||||
#define AT_CTIME 0x0400
|
||||
#define AT_RDEV 0x0800
|
||||
#define AT_BLKSIZE 0x1000
|
||||
#define AT_NBLOCKS 0x2000
|
||||
#define AT_SEQ 0x8000
|
||||
|
||||
#define CRCREAT 0
|
||||
|
||||
#define VOP_CLOSE(vp, f, c, o, cr) 0
|
||||
#define VOP_PUTPAGE(vp, of, sz, fl, cr) 0
|
||||
#define VOP_GETATTR(vp, vap, fl, cr) ((vap)->va_size = (vp)->v_size, 0)
|
||||
|
||||
#define VOP_FSYNC(vp, f, cr) fsync((vp)->v_fd)
|
||||
|
||||
#define VN_RELE(vp) vn_close(vp)
|
||||
|
||||
extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
|
||||
int x2, int x3);
|
||||
extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
|
||||
int x2, int x3, vnode_t *vp);
|
||||
extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len,
|
||||
offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp);
|
||||
extern void vn_close(vnode_t *vp);
|
||||
|
||||
#define vn_remove(path, x1, x2) remove(path)
|
||||
#define vn_rename(from, to, seg) rename((from), (to))
|
||||
#define vn_is_readonly(vp) B_FALSE
|
||||
|
||||
extern vnode_t *rootdir;
|
||||
|
||||
#include <sys/file.h> /* for FREAD, FWRITE, etc */
|
||||
#define FTRUNC O_TRUNC
|
||||
|
||||
/*
|
||||
* Random stuff
|
||||
*/
|
||||
#define lbolt (gethrtime() >> 23)
|
||||
#define lbolt64 (gethrtime() >> 23)
|
||||
//#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
|
||||
|
||||
extern void delay(clock_t ticks);
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
|
||||
#define max_ncpus 64
|
||||
|
||||
#define minclsyspri 60
|
||||
#define maxclsyspri 99
|
||||
|
||||
#define CPU_SEQID (thr_self() & (max_ncpus - 1))
|
||||
|
||||
#define kcred NULL
|
||||
#define CRED() NULL
|
||||
|
||||
extern uint64_t physmem;
|
||||
|
||||
extern int highbit(ulong_t i);
|
||||
extern int random_get_bytes(uint8_t *ptr, size_t len);
|
||||
extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
|
||||
|
||||
extern void kernel_init(int);
|
||||
extern void kernel_fini(void);
|
||||
|
||||
struct spa;
|
||||
extern void nicenum(uint64_t num, char *buf);
|
||||
extern void show_pool_stats(struct spa *);
|
||||
|
||||
typedef struct callb_cpr {
|
||||
kmutex_t *cc_lockp;
|
||||
} callb_cpr_t;
|
||||
|
||||
#define CALLB_CPR_INIT(cp, lockp, func, name) { \
|
||||
(cp)->cc_lockp = lockp; \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_SAFE_BEGIN(cp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_SAFE_END(cp, lockp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_EXIT(cp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
mutex_exit((cp)->cc_lockp); \
|
||||
}
|
||||
|
||||
#define zone_dataset_visible(x, y) (1)
|
||||
#define INGLOBALZONE(z) (1)
|
||||
|
||||
/*
|
||||
* Hostname information
|
||||
*/
|
||||
extern struct utsname utsname;
|
||||
extern char hw_serial[];
|
||||
extern int ddi_strtoul(const char *str, char **nptr, int base,
|
||||
unsigned long *result);
|
||||
|
||||
/* ZFS Boot Related stuff. */
|
||||
|
||||
struct _buf {
|
||||
intptr_t _fd;
|
||||
};
|
||||
|
||||
struct bootstat {
|
||||
uint64_t st_size;
|
||||
};
|
||||
|
||||
extern struct _buf *kobj_open_file(char *name);
|
||||
extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
|
||||
unsigned off);
|
||||
extern void kobj_close_file(struct _buf *file);
|
||||
extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
|
||||
/* Random compatibility stuff. */
|
||||
#define lbolt (gethrtime() >> 23)
|
||||
#define lbolt64 (gethrtime() >> 23)
|
||||
|
||||
extern int hz;
|
||||
extern uint64_t physmem;
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
|
||||
#define open64(...) open(__VA_ARGS__)
|
||||
#define pread64(d, p, n, o) pread(d, p, n, o)
|
||||
#define pwrite64(d, p, n, o) pwrite(d, p, n, o)
|
||||
#define readdir64(d) readdir(d)
|
||||
#define SIGPENDING(td) (0)
|
||||
#define root_mount_wait() do { } while (0)
|
||||
#define root_mounted() (1)
|
||||
|
||||
struct file {
|
||||
void *dummy;
|
||||
};
|
||||
|
||||
#define FCREAT O_CREAT
|
||||
#define FOFFMAX 0x0
|
||||
|
||||
#define SX_SYSINIT(name, lock, desc)
|
||||
|
||||
#define SYSCTL_DECL(...)
|
||||
#define SYSCTL_NODE(...)
|
||||
#define SYSCTL_INT(...)
|
||||
#define SYSCTL_ULONG(...)
|
||||
#ifdef TUNABLE_INT
|
||||
#undef TUNABLE_INT
|
||||
#undef TUNABLE_ULONG
|
||||
#endif
|
||||
#define TUNABLE_INT(...)
|
||||
#define TUNABLE_ULONG(...)
|
||||
|
||||
/* Errors */
|
||||
|
||||
#ifndef ERESTART
|
||||
#define ERESTART (-1)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_ZFS_CONTEXT_H */
|
||||
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License, Version 1.0 only
|
||||
* (the "License"). You may not use this file except in compliance
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
||||
int taskq_now;
|
||||
|
||||
typedef struct task {
|
||||
struct task *task_next;
|
||||
struct task *task_prev;
|
||||
task_func_t *task_func;
|
||||
void *task_arg;
|
||||
} task_t;
|
||||
|
||||
#define TASKQ_ACTIVE 0x00010000
|
||||
|
||||
struct taskq {
|
||||
kmutex_t tq_lock;
|
||||
krwlock_t tq_threadlock;
|
||||
kcondvar_t tq_dispatch_cv;
|
||||
kcondvar_t tq_wait_cv;
|
||||
thread_t *tq_threadlist;
|
||||
int tq_flags;
|
||||
int tq_active;
|
||||
int tq_nthreads;
|
||||
int tq_nalloc;
|
||||
int tq_minalloc;
|
||||
int tq_maxalloc;
|
||||
task_t *tq_freelist;
|
||||
task_t tq_task;
|
||||
};
|
||||
|
||||
static task_t *
|
||||
task_alloc(taskq_t *tq, int tqflags)
|
||||
{
|
||||
task_t *t;
|
||||
|
||||
if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
||||
tq->tq_freelist = t->task_next;
|
||||
} else {
|
||||
mutex_exit(&tq->tq_lock);
|
||||
if (tq->tq_nalloc >= tq->tq_maxalloc) {
|
||||
if (!(tqflags & KM_SLEEP)) {
|
||||
mutex_enter(&tq->tq_lock);
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* We don't want to exceed tq_maxalloc, but we can't
|
||||
* wait for other tasks to complete (and thus free up
|
||||
* task structures) without risking deadlock with
|
||||
* the caller. So, we just delay for one second
|
||||
* to throttle the allocation rate.
|
||||
*/
|
||||
delay(hz);
|
||||
}
|
||||
t = kmem_alloc(sizeof (task_t), tqflags);
|
||||
mutex_enter(&tq->tq_lock);
|
||||
if (t != NULL)
|
||||
tq->tq_nalloc++;
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
static void
|
||||
task_free(taskq_t *tq, task_t *t)
|
||||
{
|
||||
if (tq->tq_nalloc <= tq->tq_minalloc) {
|
||||
t->task_next = tq->tq_freelist;
|
||||
tq->tq_freelist = t;
|
||||
} else {
|
||||
tq->tq_nalloc--;
|
||||
mutex_exit(&tq->tq_lock);
|
||||
kmem_free(t, sizeof (task_t));
|
||||
mutex_enter(&tq->tq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
taskqid_t
|
||||
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
||||
{
|
||||
task_t *t;
|
||||
|
||||
if (taskq_now) {
|
||||
func(arg);
|
||||
return (1);
|
||||
}
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
ASSERT(tq->tq_flags & TASKQ_ACTIVE);
|
||||
if ((t = task_alloc(tq, tqflags)) == NULL) {
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (0);
|
||||
}
|
||||
t->task_next = &tq->tq_task;
|
||||
t->task_prev = tq->tq_task.task_prev;
|
||||
t->task_next->task_prev = t;
|
||||
t->task_prev->task_next = t;
|
||||
t->task_func = func;
|
||||
t->task_arg = arg;
|
||||
cv_signal(&tq->tq_dispatch_cv);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
taskq_wait(taskq_t *tq)
|
||||
{
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0)
|
||||
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
}
|
||||
|
||||
static void *
|
||||
taskq_thread(void *arg)
|
||||
{
|
||||
taskq_t *tq = arg;
|
||||
task_t *t;
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (tq->tq_flags & TASKQ_ACTIVE) {
|
||||
if ((t = tq->tq_task.task_next) == &tq->tq_task) {
|
||||
if (--tq->tq_active == 0)
|
||||
cv_broadcast(&tq->tq_wait_cv);
|
||||
cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
|
||||
tq->tq_active++;
|
||||
continue;
|
||||
}
|
||||
t->task_prev->task_next = t->task_next;
|
||||
t->task_next->task_prev = t->task_prev;
|
||||
mutex_exit(&tq->tq_lock);
|
||||
|
||||
rw_enter(&tq->tq_threadlock, RW_READER);
|
||||
t->task_func(t->task_arg);
|
||||
rw_exit(&tq->tq_threadlock);
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
task_free(tq, t);
|
||||
}
|
||||
tq->tq_nthreads--;
|
||||
cv_broadcast(&tq->tq_wait_cv);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
taskq_t *
|
||||
taskq_create(const char *name, int nthreads, pri_t pri,
|
||||
int minalloc, int maxalloc, uint_t flags)
|
||||
{
|
||||
taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
|
||||
int t;
|
||||
|
||||
rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
|
||||
tq->tq_flags = flags | TASKQ_ACTIVE;
|
||||
tq->tq_active = nthreads;
|
||||
tq->tq_nthreads = nthreads;
|
||||
tq->tq_minalloc = minalloc;
|
||||
tq->tq_maxalloc = maxalloc;
|
||||
tq->tq_task.task_next = &tq->tq_task;
|
||||
tq->tq_task.task_prev = &tq->tq_task;
|
||||
tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
|
||||
|
||||
if (flags & TASKQ_PREPOPULATE) {
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (minalloc-- > 0)
|
||||
task_free(tq, task_alloc(tq, KM_SLEEP));
|
||||
mutex_exit(&tq->tq_lock);
|
||||
}
|
||||
|
||||
for (t = 0; t < nthreads; t++)
|
||||
(void) thr_create(0, 0, taskq_thread,
|
||||
tq, THR_BOUND, &tq->tq_threadlist[t]);
|
||||
|
||||
return (tq);
|
||||
}
|
||||
|
||||
void
|
||||
taskq_destroy(taskq_t *tq)
|
||||
{
|
||||
int t;
|
||||
int nthreads = tq->tq_nthreads;
|
||||
|
||||
taskq_wait(tq);
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
|
||||
tq->tq_flags &= ~TASKQ_ACTIVE;
|
||||
cv_broadcast(&tq->tq_dispatch_cv);
|
||||
|
||||
while (tq->tq_nthreads != 0)
|
||||
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
||||
|
||||
tq->tq_minalloc = 0;
|
||||
while (tq->tq_nalloc != 0) {
|
||||
ASSERT(tq->tq_freelist != NULL);
|
||||
task_free(tq, task_alloc(tq, KM_SLEEP));
|
||||
}
|
||||
|
||||
mutex_exit(&tq->tq_lock);
|
||||
|
||||
for (t = 0; t < nthreads; t++)
|
||||
(void) thr_join(tq->tq_threadlist[t], NULL, NULL);
|
||||
|
||||
kmem_free(tq->tq_threadlist, nthreads * sizeof (thread_t));
|
||||
|
||||
rw_destroy(&tq->tq_threadlock);
|
||||
|
||||
kmem_free(tq, sizeof (taskq_t));
|
||||
}
|
||||
|
||||
int
|
||||
taskq_member(taskq_t *tq, void *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (taskq_now)
|
||||
return (1);
|
||||
|
||||
for (i = 0; i < tq->tq_nthreads; i++)
|
||||
if (tq->tq_threadlist[i] == (thread_t)(uintptr_t)t)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/avl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/refcount.h>
|
||||
|
||||
/*
|
||||
* Routines needed by more than one client of libzpool.
|
||||
*/
|
||||
|
||||
void
|
||||
nicenum(uint64_t num, char *buf)
|
||||
{
|
||||
uint64_t n = num;
|
||||
int index = 0;
|
||||
char u;
|
||||
|
||||
while (n >= 1024) {
|
||||
n = (n + (1024 / 2)) / 1024; /* Round up or down */
|
||||
index++;
|
||||
}
|
||||
|
||||
u = " KMGTPE"[index];
|
||||
|
||||
if (index == 0) {
|
||||
(void) sprintf(buf, "%llu", (u_longlong_t)n);
|
||||
} else if (n < 10 && (num & (num - 1)) != 0) {
|
||||
(void) sprintf(buf, "%.2f%c",
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
} else if (n < 100 && (num & (num - 1)) != 0) {
|
||||
(void) sprintf(buf, "%.1f%c",
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
} else {
|
||||
(void) sprintf(buf, "%llu%c", (u_longlong_t)n, u);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_vdev_stats(const char *desc, nvlist_t *nv, int indent)
|
||||
{
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
vdev_stat_t *vs;
|
||||
uint64_t sec;
|
||||
char used[6], avail[6];
|
||||
char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6];
|
||||
|
||||
if (indent == 0) {
|
||||
(void) printf(" "
|
||||
" capacity operations bandwidth ---- errors ----\n");
|
||||
(void) printf("description "
|
||||
"used avail read write read write read write cksum\n");
|
||||
}
|
||||
|
||||
VERIFY(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
|
||||
sec = MAX(1, vs->vs_timestamp / NANOSEC);
|
||||
|
||||
nicenum(vs->vs_alloc, used);
|
||||
nicenum(vs->vs_space - vs->vs_alloc, avail);
|
||||
nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops);
|
||||
nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops);
|
||||
nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes);
|
||||
nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes);
|
||||
nicenum(vs->vs_read_errors, rerr);
|
||||
nicenum(vs->vs_write_errors, werr);
|
||||
nicenum(vs->vs_checksum_errors, cerr);
|
||||
|
||||
(void) printf("%*s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
|
||||
indent, "",
|
||||
indent - 19 - (vs->vs_space ? 0 : 12), desc,
|
||||
vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
|
||||
vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
|
||||
rops, wops, rbytes, wbytes, rerr, werr, cerr);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0)
|
||||
return;
|
||||
|
||||
for (c = 0; c < children; c++) {
|
||||
nvlist_t *cnv = child[c];
|
||||
char *cname, *tname;
|
||||
uint64_t np;
|
||||
if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
|
||||
nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
|
||||
cname = "<unknown>";
|
||||
tname = calloc(1, strlen(cname) + 2);
|
||||
(void) strcpy(tname, cname);
|
||||
if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
|
||||
tname[strlen(tname)] = '0' + np;
|
||||
show_vdev_stats(tname, cnv, indent + 2);
|
||||
free(tname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
show_pool_stats(spa_t *spa)
|
||||
{
|
||||
nvlist_t *config, *nvroot;
|
||||
char *name;
|
||||
|
||||
spa_config_enter(spa, RW_READER, FTAG);
|
||||
config = spa_config_generate(spa, NULL, -1ULL, B_TRUE);
|
||||
spa_config_exit(spa, FTAG);
|
||||
|
||||
VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
|
||||
&name) == 0);
|
||||
|
||||
show_vdev_stats(name, nvroot, 0);
|
||||
}
|
||||
+278
-7
@@ -1,5 +1,117 @@
|
||||
|
||||
--- 9.4.1-P1 released ---
|
||||
--- 9.4.2 released ---
|
||||
--- 9.4.2rc2 released ---
|
||||
|
||||
2259. [bug] Reverse incorrect LIBINTERFACE bump of libisc
|
||||
in 9.4.2rc1. Applications built against 9.4.2rc1
|
||||
will need to be rebuilt.
|
||||
|
||||
2258. [bug] Fallback from IXFR/TSIG to SOA/AXFR/TSIG broken.
|
||||
[RT #17241]
|
||||
|
||||
2257. [bug] win32: Use the full path to vcredist_x86.exe when
|
||||
calling it. [RT #17222]
|
||||
|
||||
2256. [bug] win32: Correctly register the installation location of
|
||||
bindevt.dll. [RT #17159]
|
||||
|
||||
2255. [bug] L.ROOT-SERVERS.NET is now 199.7.83.42.
|
||||
|
||||
2254. [bug] timer.c:dispatch() failed to lock timer->lock
|
||||
when reading timer->idle allowing it to see
|
||||
intermediate values as timer->idle was reset by
|
||||
isc_timer_touch(). [RT #17243]
|
||||
|
||||
--- 9.4.2rc1 released ---
|
||||
|
||||
2251. [doc] Update memstatistics-file documentation to reflect
|
||||
reality. Note there is behaviour change for BIND 9.5.
|
||||
[RT #17113]
|
||||
|
||||
2249. [bug] Only set Authentic Data bit if client requested
|
||||
DNSSEC, per RFC 3655 [RT #17175]
|
||||
|
||||
2248. [cleanup] Fix several errors reported by Coverity. [RT #17160]
|
||||
|
||||
2245. [bug] Validating lack of DS records at trust anchors wasn't
|
||||
working. [RT #17151]
|
||||
|
||||
2238. [bug] It was possible to trigger a REQUIRE when a
|
||||
validation was cancelled. [RT #17106]
|
||||
|
||||
2237. [bug] libbind: res_init() was not thread aware. [RT #17123]
|
||||
|
||||
2236. [bug] dnssec-signzone failed to preserve the case of
|
||||
of wildcard owner names. [RT #17085]
|
||||
|
||||
2235. [bug] <isc/atomic.h> was not being installed. [RT #17135]
|
||||
|
||||
2234. [port] Correct some compiler warnings on SCO OSr5 [RT #17134]
|
||||
|
||||
2232. [bug] dns_adb_findaddrinfo() could fail and return
|
||||
ISC_R_SUCCESS. [RT #17137]
|
||||
|
||||
2231. [bug] Building dlzbdb (contrib/dlz/bin/dlzbdb) was broken.
|
||||
[RT #17088]
|
||||
|
||||
2230. [bug] We could INSIST reading a corrupted journal.
|
||||
[RT #17132]
|
||||
|
||||
2228. [contrib] contrib: Change 2188 was incomplete.
|
||||
|
||||
2227. [cleanup] Tidied up the FAQ. [RT #17121]
|
||||
|
||||
2225. [bug] More support for systems with no IPv4 addresses.
|
||||
[RT #17111]
|
||||
|
||||
2224. [bug] Defer journal compaction if a xfrin is in progress.
|
||||
[RT #17119]
|
||||
|
||||
2223. [bug] Make a new journal when compacting. [RT #17119]
|
||||
|
||||
2221. [bug] Set the event result code to reflect the actual
|
||||
record returned to caller when a cache update is
|
||||
rejected due to a more credible answer existing.
|
||||
[RT #17017]
|
||||
|
||||
2220. [bug] win32: Address a race condition in final shutdown of
|
||||
the Windows socket code. [RT #17028]
|
||||
|
||||
2219. [bug] Apply zone consistancy checks to additions, not
|
||||
removals, when updating. [RT #17049]
|
||||
|
||||
2218. [bug] Remove unnecessary REQUIRE from dns_validator_create().
|
||||
[RT #16976]
|
||||
|
||||
2216. [cleanup] Fix a number of errors reported by Coverity.
|
||||
[RT #17094]
|
||||
|
||||
2215. [bug] Bad REQUIRE check isc_hmacsha1_verify(). [RT #17094]
|
||||
|
||||
2214. [bug] Deregister OpenSSL lock callback when cleaning
|
||||
up. Reorder OpenSSL cleanup so that RAND_cleanup()
|
||||
is called before the locks are destroyed. [RT #17098]
|
||||
|
||||
2213. [bug] SIG0 diagnostic failure messages were looking at the
|
||||
wrong status code. [RT #17101]
|
||||
|
||||
2212. [func] 'host -m' now causes memory statistics and active
|
||||
memory to be printed at exit. [RT 17028]
|
||||
|
||||
2210. [bug] Deleting class specific records via UPDATE could
|
||||
fail. [RT #17074]
|
||||
|
||||
2209. [port] osx: linking against user supplied static OpenSSL
|
||||
libraries failed as the system ones were still being
|
||||
found. [RT #17078]
|
||||
|
||||
2208. [port] win32: make sure both build methods produce the
|
||||
same output. [RT #17058]
|
||||
|
||||
2207. [port] Some implementations of getaddrinfo() fail to set
|
||||
ai_canonname correctly. [RT #17061]
|
||||
|
||||
--- 9.4.2b1 released ---
|
||||
|
||||
2206. [security] "allow-query-cache" and "allow-recursion" now
|
||||
cross inherit from each other.
|
||||
@@ -16,12 +128,32 @@
|
||||
|
||||
[RT #16987]
|
||||
|
||||
2205. [bug] libbind: change #2119 broke thread support. [RT #16982]
|
||||
|
||||
2203. [security] Query id generation was cryptographically weak.
|
||||
[RT # 16915]
|
||||
|
||||
2202. [security] The default acls for allow-query-cache and
|
||||
allow-recursion were not being applied. [RT #16960]
|
||||
|
||||
2200. [bug] The search for cached NSEC records was stopping to
|
||||
early leading to excessive DLV queries. [RT #16930]
|
||||
|
||||
2199. [bug] win32: don't call WSAStartup() while loading dlls.
|
||||
[RT #16911]
|
||||
|
||||
2198. [bug] win32: RegCloseKey() could be called when
|
||||
RegOpenKeyEx() failed. [RT #16911]
|
||||
|
||||
2197. [bug] Add INSIST to catch negative responses which are
|
||||
not setting the event result code appropriately.
|
||||
[RT #16909]
|
||||
|
||||
2196. [port] win32: yield processor while waiting for once to
|
||||
to complete. [RT #16958]
|
||||
|
||||
2194. [bug] Close journal before calling 'done' in xfrin.c.
|
||||
|
||||
2193. [port] win32: BINDInstall.exe is now linked statically.
|
||||
[RT #16906]
|
||||
|
||||
@@ -29,6 +161,145 @@
|
||||
Studio's redistributable dlls if building with
|
||||
Visual Stdio 2005 or later.
|
||||
|
||||
2189. [bug] Handle socket() returning EINTR. [RT #15949]
|
||||
|
||||
2188. [contrib] queryperf: autoconf changes to make the search for
|
||||
libresolv or libbind more robust. [RT #16299]
|
||||
|
||||
2187. [bug] query_addds(), query_addwildcardproof() and
|
||||
query_addnxrrsetnsec() should take a version
|
||||
arguement. [RT #16368]
|
||||
|
||||
2186. [port] cygwin: libbind: check for struct sockaddr_storage
|
||||
independently of IPv6. [RT #16482]
|
||||
|
||||
2185. [port] sunos: libbind: check for ssize_t, memmove() and
|
||||
memchr(). [RT #16463]
|
||||
|
||||
2183. [bug] dnssec-signzone didn't handle offline private keys
|
||||
well. [RT #16832]
|
||||
|
||||
2182. [bug] dns_dispatch_createtcp() and dispatch_createudp()
|
||||
could return ISC_R_SUCCESS when they ran out of
|
||||
memory. [RT #16365]
|
||||
|
||||
2181. [port] sunos: libbind: add paths.h from BIND 8. [RT #16462]
|
||||
|
||||
2180. [cleanup] Remove bit test from 'compress_test' as they
|
||||
are no longer needed. [RT #16497]
|
||||
|
||||
2178. [bug] 'rndc reload' of a slave or stub zone resulted in
|
||||
a reference leak. [RT #16867]
|
||||
|
||||
2177. [bug] Array bounds overrun on read (rcodetext) at
|
||||
debug level 10+. [RT #16798]
|
||||
|
||||
2176. [contrib] dbus update to handle race condition during
|
||||
initialisation (Bugzilla 235809). [RT #16842]
|
||||
|
||||
2175. [bug] win32: windows broadcast condition variable support
|
||||
was broken. [RT #16592]
|
||||
|
||||
2174. [bug] I/O errors should always be fatal when reading
|
||||
master files. [RT #16825]
|
||||
|
||||
2173. [port] win32: When compiling with MSVS 2005 SP1 we also
|
||||
need to ship Microsoft.VC80.MFCLOC.
|
||||
|
||||
2171. [bug] Handle breaks in DNSSEC trust chains where the parent
|
||||
servers are not DS aware (DS queries to the parent
|
||||
return a referral to the child).
|
||||
|
||||
2170. [func] Add acache processing to test suite. [RT #16711]
|
||||
|
||||
2169. [bug] host, nslookup: when reporting NXDOMAIN report the
|
||||
given name and not the last name searched for.
|
||||
[RT #16763]
|
||||
|
||||
2168. [bug] nsupdate: in non-interactive mode treat syntax errors
|
||||
as fatal errors. [RT #16785]
|
||||
|
||||
2167. [bug] When re-using a automatic zone named failed to
|
||||
attach it to the new view. [RT #16786]
|
||||
|
||||
2166. [bug] When running in batch mode, dig could misinterpret
|
||||
a server address as a name to be looked up, causing
|
||||
unexpected output. [RT #16743]
|
||||
|
||||
2164. [bug] The code to determine how named-checkzone /
|
||||
named-compilezone was called failed under windows.
|
||||
[RT #16764]
|
||||
|
||||
2162. [func] Allow "rrset-order fixed" to be disabled at compile
|
||||
time. [RT #16665]
|
||||
|
||||
2161. [bug] 'rndc flush' could report a false success. [RT #16698]
|
||||
|
||||
2160. [bug] libisc wasn't handling NULL ifa_addr pointers returned
|
||||
from getifaddrs(). [RT #16708]
|
||||
|
||||
2159. [bug] Array bounds overrun in acache processing. [RT #16710]
|
||||
|
||||
2158. [bug] ns_client_isself() failed to initialise key
|
||||
leading to a REQUIRE failure. [RT #16688]
|
||||
|
||||
2156. [bug] Fix node reference leaks in lookup.c:lookup_find(),
|
||||
resolver.c:validated() and resolver.c:cache_name().
|
||||
Fix a memory leak in rbtdb.c:free_noqname().
|
||||
Make lookup.c:lookup_find() robust against
|
||||
event leaks. [RT #16685]
|
||||
|
||||
2155. [contrib] SQLite sdb module from [email protected].
|
||||
[RT #16694]
|
||||
|
||||
2153. [bug] nsupdate could leak memory. [RT #16691]
|
||||
|
||||
2152. [cleanup] Use sizeof(buf) instead of fixed number in
|
||||
dighost.c:get_trusted_key(). [RT #16678]
|
||||
|
||||
2151. [bug] Missing newline in usage message for journalprint.
|
||||
[RT #16679]
|
||||
|
||||
2150. [bug] 'rrset-order cyclic' uniformly distribute the
|
||||
starting point for the first response for a given
|
||||
RRset. [RT #16655]
|
||||
|
||||
2149. [bug] isc_mem_checkdestroyed() failed to abort on
|
||||
if there were still active memory contexts.
|
||||
[RT #16672]
|
||||
|
||||
2147. [bug] libbind: remove potential buffer overflow from
|
||||
hmac_link.c. [RT #16437]
|
||||
|
||||
2146. [cleanup] Silence Linux's spurious "obsolete setsockopt
|
||||
SO_BSDCOMPAT" message. [RT #16641]
|
||||
|
||||
2145. [bug] Check DS/DLV digest lengths for known digests.
|
||||
[RT #16622]
|
||||
|
||||
2144. [cleanup] Suppress logging of SERVFAIL from forwarders.
|
||||
[RT #16619]
|
||||
|
||||
2143. [bug] We failed to restart the IPv6 client when the
|
||||
kernel failed to return the destination the
|
||||
packet was sent to. [RT #16613]
|
||||
|
||||
2142. [bug] Handle master files with a modification time that
|
||||
matches the epoch. [RT# 16612]
|
||||
|
||||
2141. [bug] dig/host should not be setting IDN_ASCCHECK (IDN
|
||||
equivalent of LDH checks). [RT #16609]
|
||||
|
||||
2140. [bug] libbind: missing unlock on pthread_key_create()
|
||||
failures. [RT #16654]
|
||||
|
||||
2139. [bug] dns_view_find() was being called with wrong type
|
||||
in adb.c. [RT #16670]
|
||||
|
||||
2119. [compat] libbind: allow res_init() to succeed enough to
|
||||
return the default domain even if it was unable
|
||||
to allocate memory.
|
||||
|
||||
--- 9.4.1 released ---
|
||||
|
||||
2172. [bug] query_addsoa() was being called with a non zone db.
|
||||
@@ -524,7 +795,7 @@
|
||||
hex strings with comments. [RT #15814]
|
||||
|
||||
1974. [doc] List each of the zone types and associated zone
|
||||
options seperately in the ARM.
|
||||
options separately in the ARM.
|
||||
|
||||
1973. [func] TSIG HMACSHA1, HMACSHA224, HMACSHA256, HMACSHA384 and
|
||||
HMACSHA512 support. [RT #13606]
|
||||
@@ -551,7 +822,7 @@
|
||||
1965. [func] Suppress spurious "recusion requested but not
|
||||
available" warning with 'dig +qr'. [RT #15780].
|
||||
|
||||
1964. [func] Seperate out MX and SRV to CNAME checks. [RT #15723]
|
||||
1964. [func] Separate out MX and SRV to CNAME checks. [RT #15723]
|
||||
|
||||
1963. [port] Tru64 4.0E doesn't support send() and recv().
|
||||
[RT #15586]
|
||||
@@ -771,7 +1042,7 @@
|
||||
1898. [bug] Extend ISC_SOCKADDR_FORMATSIZE and
|
||||
ISC_NETADDR_FORMATSIZE to allow for scope details.
|
||||
|
||||
1897. [func] x86 and x86_64 now have seperate atomic locking
|
||||
1897. [func] x86 and x86_64 now have separate atomic locking
|
||||
implementations.
|
||||
|
||||
1896. [bug] Recursive clients soft quota support wasn't working
|
||||
@@ -825,7 +1096,7 @@
|
||||
[RT #14892]
|
||||
|
||||
1878. [func] Detect duplicates of UDP queries we are recursing on
|
||||
and drop them. New stats category "duplicates".
|
||||
and drop them. New stats category "duplicate".
|
||||
[RT #2471]
|
||||
|
||||
1877. [bug] Fix unreasonably low quantum on call to
|
||||
@@ -1769,7 +2040,7 @@
|
||||
[RT #6427]
|
||||
|
||||
1555. [func] 'rrset-order cyclic' no longer has a random starting
|
||||
point. [RT #7572]
|
||||
point per query. [RT #7572]
|
||||
|
||||
1554. [bug] dig, host, nslookup failed when no nameservers
|
||||
were specified in /etc/resolv.conf. [RT #8232]
|
||||
@@ -6250,7 +6521,7 @@
|
||||
and has been removed.
|
||||
|
||||
170. [cleanup] Remove inter server consistancy checks from zone,
|
||||
these should return as a seperate module in 9.1.
|
||||
these should return as a separate module in 9.1.
|
||||
dns_zone_checkservers(), dns_zone_checkparents(),
|
||||
dns_zone_checkchildren(), dns_zone_checkglue().
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
Copyright (C) 1996-2003 Internet Software Consortium.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
@@ -13,7 +13,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
$Id: COPYRIGHT,v 1.9.18.3 2007/01/08 02:41:59 marka Exp $
|
||||
$Id: COPYRIGHT,v 1.9.18.4 2007/08/28 07:19:54 tbox Exp $
|
||||
|
||||
Portions Copyright (C) 1996-2001 Nominum, Inc.
|
||||
|
||||
|
||||
+461
-401
File diff suppressed because it is too large.
Load diff
+511
-521
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
# Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
|
||||
# Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
# Copyright (C) 1998-2002 Internet Software Consortium.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
@@ -13,7 +13,7 @@
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id: Makefile.in,v 1.43.18.4 2006/05/19 00:04:01 marka Exp $
|
||||
# $Id: Makefile.in,v 1.43.18.6 2007/09/03 23:46:21 tbox Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@@ -61,7 +61,7 @@ test:
|
||||
|
||||
FAQ: FAQ.xml
|
||||
${XSLTPROC} doc/xsl/isc-docbook-text.xsl FAQ.xml | \
|
||||
${W3M} -T text/html -dump >$@.tmp
|
||||
LC_ALL=C ${W3M} -T text/html -dump -cols 72 >$@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
clean::
|
||||
|
||||
+19
-13
@@ -43,16 +43,19 @@ BIND 9
|
||||
Nominum, Inc.
|
||||
|
||||
|
||||
BIND 9.4.1-P1
|
||||
BIND 9.4.2
|
||||
|
||||
BIND 9.4.1-P1 is a security release, containing a fixes for a
|
||||
security bugs in BIND 9.4.1.
|
||||
BIND 9.4.2 is a maintenance release, containing fixes for
|
||||
a number of bugs in 9.4.1.
|
||||
|
||||
Warning: If you installed BIND 9.4.2rc1 then any applications
|
||||
linked against this release candidate will need to be rebuilt.
|
||||
|
||||
BIND 9.4.1
|
||||
|
||||
BIND 9.4.1 is a security release, containing a fix for a
|
||||
security bug in 9.4.0.
|
||||
|
||||
BIND 9.4.1 is a security release, containing a fix for
|
||||
a security bugs in 9.4.0.
|
||||
|
||||
BIND 9.4.0
|
||||
|
||||
BIND 9.4.0 has a number of new features over 9.3,
|
||||
@@ -74,7 +77,9 @@ BIND 9.4.0
|
||||
used to specify the default zone access level rather than
|
||||
having to have every zone override the global value.
|
||||
allow-query-cache can be set at both the options and view
|
||||
levels. If allow-query-cache is not set allow-query applies.
|
||||
levels. If allow-query-cache is not set then allow-recursion
|
||||
is used if set, otherwise allow-query is used if set, otherwise
|
||||
the default (localhost; localnets;) is used.
|
||||
|
||||
rndc: the source address can now be specified.
|
||||
|
||||
@@ -418,7 +423,7 @@ Building
|
||||
We've had successful builds and tests on the following systems:
|
||||
|
||||
COMPAQ Tru64 UNIX 5.1B
|
||||
FreeBSD 4.10, 5.2.1
|
||||
FreeBSD 4.10, 5.2.1, 6.2
|
||||
HP-UX 11.11
|
||||
NetBSD 1.5
|
||||
Slackware Linux 8.1
|
||||
@@ -475,6 +480,8 @@ Building
|
||||
-DDIG_SIGCHASE_BU=1)
|
||||
Disable dropping queries from particular well known ports.
|
||||
-DNS_CLIENT_DROPPORT=0
|
||||
Disable support for "rrset-order fixed".
|
||||
-DDNS_RDATASET_FIXED=0
|
||||
|
||||
LDFLAGS
|
||||
Linker flags. Defaults to empty string.
|
||||
@@ -587,9 +594,8 @@ Bug Reports and Mailing Lists
|
||||
http://www.isc.org/ops/lists/
|
||||
|
||||
If you're planning on making changes to the BIND 9 source
|
||||
code, you might want to join the BIND Workers mailing list.
|
||||
Send mail to
|
||||
|
||||
[email protected]
|
||||
|
||||
code, you might want to join the BIND Forum as a Worker.
|
||||
This gives you access to the [email protected] mailing
|
||||
list and pre-release access to the code.
|
||||
|
||||
http://www.isc.org/sw/guild/bf/
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2000-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
@@ -15,14 +15,13 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: check-tool.c,v 1.10.18.14 2006/06/08 01:43:00 marka Exp $ */
|
||||
/* $Id: check-tool.c,v 1.10.18.18 2007/09/13 05:04:01 each Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "check-tool.h"
|
||||
#include <isc/util.h>
|
||||
@@ -33,6 +32,7 @@
|
||||
#include <isc/netdb.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/stdio.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
@@ -130,7 +130,16 @@ checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
case 0:
|
||||
if (strcasecmp(ai->ai_canonname, namebuf) != 0) {
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
* fail to set ai_canonname on first entry.
|
||||
*/
|
||||
cur = ai;
|
||||
while (cur != NULL && cur->ai_canonname == NULL &&
|
||||
cur->ai_next != NULL)
|
||||
cur = cur->ai_next;
|
||||
if (cur != NULL && cur->ai_canonname != NULL &&
|
||||
strcasecmp(ai->ai_canonname, namebuf) != 0) {
|
||||
dns_zone_log(zone, ISC_LOG_ERROR,
|
||||
"%s/NS '%s' (out of zone) "
|
||||
"is a CNAME (illegal)",
|
||||
@@ -268,7 +277,7 @@ checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
|
||||
static isc_boolean_t
|
||||
checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
|
||||
#ifdef USE_GETADDRINFO
|
||||
struct addrinfo hints, *ai;
|
||||
struct addrinfo hints, *ai, *cur;
|
||||
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
||||
char ownerbuf[DNS_NAME_FORMATSIZE];
|
||||
int result;
|
||||
@@ -293,7 +302,16 @@ checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
case 0:
|
||||
if (strcasecmp(ai->ai_canonname, namebuf) != 0) {
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
* fail to set ai_canonname on first entry.
|
||||
*/
|
||||
cur = ai;
|
||||
while (cur != NULL && cur->ai_canonname == NULL &&
|
||||
cur->ai_next != NULL)
|
||||
cur = cur->ai_next;
|
||||
if (cur != NULL && cur->ai_canonname != NULL &&
|
||||
strcasecmp(cur->ai_canonname, namebuf) != 0) {
|
||||
if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
|
||||
level = ISC_LOG_WARNING;
|
||||
if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
|
||||
@@ -332,7 +350,7 @@ checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
|
||||
static isc_boolean_t
|
||||
checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
|
||||
#ifdef USE_GETADDRINFO
|
||||
struct addrinfo hints, *ai;
|
||||
struct addrinfo hints, *ai, *cur;
|
||||
char namebuf[DNS_NAME_FORMATSIZE + 1];
|
||||
char ownerbuf[DNS_NAME_FORMATSIZE];
|
||||
int result;
|
||||
@@ -357,7 +375,16 @@ checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
|
||||
dns_name_format(name, namebuf, sizeof(namebuf) - 1);
|
||||
switch (result) {
|
||||
case 0:
|
||||
if (strcasecmp(ai->ai_canonname, namebuf) != 0) {
|
||||
/*
|
||||
* Work around broken getaddrinfo() implementations that
|
||||
* fail to set ai_canonname on first entry.
|
||||
*/
|
||||
cur = ai;
|
||||
while (cur != NULL && cur->ai_canonname == NULL &&
|
||||
cur->ai_next != NULL)
|
||||
cur = cur->ai_next;
|
||||
if (cur != NULL && cur->ai_canonname != NULL &&
|
||||
strcasecmp(cur->ai_canonname, namebuf) != 0) {
|
||||
if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
|
||||
level = ISC_LOG_WARNING;
|
||||
if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
.\" PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $Id: named-checkconf.8,v 1.16.18.11 2007/01/30 00:23:44 marka Exp $
|
||||
.\" $Id: named-checkconf.8,v 1.16.18.13 2007/06/20 02:26:58 marka Exp $
|
||||
.\"
|
||||
.hy 0
|
||||
.ad l
|
||||
@@ -42,7 +42,7 @@ checks the syntax, but not the semantics, of a named configuration file.
|
||||
.PP
|
||||
\-t \fIdirectory\fR
|
||||
.RS 4
|
||||
chroot to
|
||||
Chroot to
|
||||
\fIdirectory\fR
|
||||
so that include directives in the configuration file are processed as if run by a similarly chrooted named.
|
||||
.RE
|
||||
@@ -56,7 +56,7 @@ program and exit.
|
||||
.PP
|
||||
\-z
|
||||
.RS 4
|
||||
Perform a check load the master zonefiles found in
|
||||
Perform a test load of all master zones found in
|
||||
\fInamed.conf\fR.
|
||||
.RE
|
||||
.PP
|
||||
@@ -77,6 +77,7 @@ returns an exit status of 1 if errors were detected and 0 otherwise.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBnamed\fR(8),
|
||||
\fBnamed\-checkzone\fR(8),
|
||||
BIND 9 Administrator Reference Manual.
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
- Copyright (C) 2000-2002 Internet Software Consortium.
|
||||
-
|
||||
- Permission to use, copy, modify, and distribute this software for any
|
||||
- Permission to use, copy, modify, and/or distribute this software for any
|
||||
- purpose with or without fee is hereby granted, provided that the above
|
||||
- copyright notice and this permission notice appear in all copies.
|
||||
-
|
||||
@@ -18,7 +18,7 @@
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- $Id: named-checkconf.docbook,v 1.8.18.7 2007/01/29 23:57:20 marka Exp $ -->
|
||||
<!-- $Id: named-checkconf.docbook,v 1.8.18.10 2007/08/28 07:19:55 tbox Exp $ -->
|
||||
<refentry id="man.named-checkconf">
|
||||
<refentryinfo>
|
||||
<date>June 14, 2000</date>
|
||||
@@ -77,7 +77,7 @@
|
||||
<term>-t <replaceable class="parameter">directory</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
chroot to <filename>directory</filename> so that
|
||||
Chroot to <filename>directory</filename> so that
|
||||
include
|
||||
directives in the configuration file are processed as if
|
||||
run by a similarly chrooted named.
|
||||
@@ -99,8 +99,8 @@
|
||||
<term>-z</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Perform a check load the master zonefiles found in
|
||||
<filename>named.conf</filename>.
|
||||
Perform a test load of all master zones found in
|
||||
<filename>named.conf</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -141,6 +141,9 @@
|
||||
<para><citerefentry>
|
||||
<refentrytitle>named</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>named-checkzone</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citetitle>BIND 9 Administrator Reference Manual</citetitle>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
<!-- $Id: named-checkconf.html,v 1.9.18.18 2007/01/30 00:23:44 marka Exp $ -->
|
||||
<!-- $Id: named-checkconf.html,v 1.9.18.20 2007/06/20 02:26:58 marka Exp $ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class="variablelist"><dl>
|
||||
<dt><span class="term">-t <em class="replaceable"><code>directory</code></em></span></dt>
|
||||
<dd><p>
|
||||
chroot to <code class="filename">directory</code> so that
|
||||
Chroot to <code class="filename">directory</code> so that
|
||||
include
|
||||
directives in the configuration file are processed as if
|
||||
run by a similarly chrooted named.
|
||||
@@ -55,8 +55,8 @@
|
||||
</p></dd>
|
||||
<dt><span class="term">-z</span></dt>
|
||||
<dd><p>
|
||||
Perform a check load the master zonefiles found in
|
||||
<code class="filename">named.conf</code>.
|
||||
Perform a test load of all master zones found in
|
||||
<code class="filename">named.conf</code>.
|
||||
</p></dd>
|
||||
<dt><span class="term">-j</span></dt>
|
||||
<dd><p>
|
||||
@@ -70,20 +70,21 @@
|
||||
</dl></div>
|
||||
</div>
|
||||
<div class="refsect1" lang="en">
|
||||
<a name="id2543488"></a><h2>RETURN VALUES</h2>
|
||||
<a name="id2543489"></a><h2>RETURN VALUES</h2>
|
||||
<p><span><strong class="command">named-checkconf</strong></span>
|
||||
returns an exit status of 1 if
|
||||
errors were detected and 0 otherwise.
|
||||
</p>
|
||||
</div>
|
||||
<div class="refsect1" lang="en">
|
||||
<a name="id2543499"></a><h2>SEE ALSO</h2>
|
||||
<a name="id2543500"></a><h2>SEE ALSO</h2>
|
||||
<p><span class="citerefentry"><span class="refentrytitle">named</span>(8)</span>,
|
||||
<span class="citerefentry"><span class="refentrytitle">named-checkzone</span>(8)</span>,
|
||||
<em class="citetitle">BIND 9 Administrator Reference Manual</em>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="refsect1" lang="en">
|
||||
<a name="id2543521"></a><h2>AUTHOR</h2>
|
||||
<a name="id2543530"></a><h2>AUTHOR</h2>
|
||||
<p><span class="corpauthor">Internet Systems Consortium</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
.\" PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $Id: named-checkzone.8,v 1.18.18.20 2007/01/30 00:23:44 marka Exp $
|
||||
.\" $Id: named-checkzone.8,v 1.18.18.23 2007/06/20 02:26:58 marka Exp $
|
||||
.\"
|
||||
.hy 0
|
||||
.ad l
|
||||
@@ -48,7 +48,7 @@ useful for checking zone files before configuring them into a name server.
|
||||
\fBnamed\-compilezone\fR
|
||||
is similar to
|
||||
\fBnamed\-checkzone\fR, but it always dumps the zone contents to a specified file in a specified format. Additionally, it applies stricter check levels by default, since the dump output will be used as an actual zone file loaded by
|
||||
\fBnamed\fR. When manaully specified otherwise, the check levels must at least be as strict as those specified in the
|
||||
\fBnamed\fR. When manually specified otherwise, the check levels must at least be as strict as those specified in the
|
||||
\fBnamed\fR
|
||||
configuration file.
|
||||
.SH "OPTIONS"
|
||||
@@ -82,7 +82,7 @@ Specify the class of the zone. If not specified "IN" is assumed.
|
||||
.PP
|
||||
\-i \fImode\fR
|
||||
.RS 4
|
||||
Perform post load zone integrity checks. Possible modes are
|
||||
Perform post\-load zone integrity checks. Possible modes are
|
||||
\fB"full"\fR
|
||||
(default),
|
||||
\fB"full\-sibling"\fR,
|
||||
@@ -105,7 +105,7 @@ only checks SRV records which refer to in\-zone hostnames.
|
||||
.sp
|
||||
Mode
|
||||
\fB"full"\fR
|
||||
checks that delegation NS records refer to A or AAAA record (both in\-zone and out\-of\-zone hostnames). It also checks that glue addresses records in the zone match those advertised by the child. Mode
|
||||
checks that delegation NS records refer to A or AAAA record (both in\-zone and out\-of\-zone hostnames). It also checks that glue address records in the zone match those advertised by the child. Mode
|
||||
\fB"local"\fR
|
||||
only checks NS records which refer to in\-zone hostnames or that some required glue exists, that is when the nameserver is in a child zone.
|
||||
.sp
|
||||
@@ -213,7 +213,7 @@ Check if a SRV record refers to a CNAME. Possible modes are
|
||||
.PP
|
||||
\-t \fIdirectory\fR
|
||||
.RS 4
|
||||
chroot to
|
||||
Chroot to
|
||||
\fIdirectory\fR
|
||||
so that include directives in the configuration file are processed as if run by a similarly chrooted named.
|
||||
.RE
|
||||
@@ -256,6 +256,7 @@ returns an exit status of 1 if errors were detected and 0 otherwise.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBnamed\fR(8),
|
||||
\fBnamed\-checkconf\fR(8),
|
||||
RFC 1035,
|
||||
BIND 9 Administrator Reference Manual.
|
||||
.SH "AUTHOR"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 1999-2003 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: named-checkzone.c,v 1.29.18.16 2006/10/05 05:24:35 marka Exp $ */
|
||||
/* $Id: named-checkzone.c,v 1.29.18.19 2007/08/28 07:19:55 tbox Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@@ -109,6 +109,8 @@ main(int argc, char **argv) {
|
||||
outputstyle = &dns_master_style_full;
|
||||
|
||||
prog_name = strrchr(argv[0], '/');
|
||||
if (prog_name == NULL)
|
||||
prog_name = strrchr(argv[0], '\\');
|
||||
if (prog_name != NULL)
|
||||
prog_name++;
|
||||
else
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
- Copyright (C) 2000-2002 Internet Software Consortium.
|
||||
-
|
||||
- Permission to use, copy, modify, and distribute this software for any
|
||||
- Permission to use, copy, modify, and/or distribute this software for any
|
||||
- purpose with or without fee is hereby granted, provided that the above
|
||||
- copyright notice and this permission notice appear in all copies.
|
||||
-
|
||||
@@ -18,7 +18,7 @@
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- $Id: named-checkzone.docbook,v 1.11.18.17 2007/01/29 23:57:20 marka Exp $ -->
|
||||
<!-- $Id: named-checkzone.docbook,v 1.11.18.21 2007/08/28 07:19:55 tbox Exp $ -->
|
||||
<refentry id="man.named-checkzone">
|
||||
<refentryinfo>
|
||||
<date>June 13, 2000</date>
|
||||
@@ -117,7 +117,7 @@
|
||||
Additionally, it applies stricter check levels by default,
|
||||
since the dump output will be used as an actual zone file
|
||||
loaded by <command>named</command>.
|
||||
When manaully specified otherwise, the check levels must at
|
||||
When manually specified otherwise, the check levels must at
|
||||
least be as strict as those specified in the
|
||||
<command>named</command> configuration file.
|
||||
</para>
|
||||
@@ -177,7 +177,7 @@
|
||||
<term>-i <replaceable class="parameter">mode</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Perform post load zone integrity checks. Possible modes are
|
||||
Perform post-load zone integrity checks. Possible modes are
|
||||
<command>"full"</command> (default),
|
||||
<command>"full-sibling"</command>,
|
||||
<command>"local"</command>,
|
||||
@@ -199,7 +199,7 @@
|
||||
<para>
|
||||
Mode <command>"full"</command> checks that delegation NS
|
||||
records refer to A or AAAA record (both in-zone and out-of-zone
|
||||
hostnames). It also checks that glue addresses records
|
||||
hostnames). It also checks that glue address records
|
||||
in the zone match those advertised by the child.
|
||||
Mode <command>"local"</command> only checks NS records which
|
||||
refer to in-zone hostnames or that some required glue exists,
|
||||
@@ -342,7 +342,7 @@
|
||||
<term>-t <replaceable class="parameter">directory</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
chroot to <filename>directory</filename> so that
|
||||
Chroot to <filename>directory</filename> so that
|
||||
include
|
||||
directives in the configuration file are processed as if
|
||||
run by a similarly chrooted named.
|
||||
@@ -422,6 +422,9 @@
|
||||
<para><citerefentry>
|
||||
<refentrytitle>named</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>named-checkconf</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citetitle>RFC 1035</citetitle>,
|
||||
<citetitle>BIND 9 Administrator Reference Manual</citetitle>.
|
||||
</para>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
<!-- $Id: named-checkzone.html,v 1.11.18.27 2007/01/30 00:23:44 marka Exp $ -->
|
||||
<!-- $Id: named-checkzone.html,v 1.11.18.30 2007/06/20 02:26:58 marka Exp $ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
@@ -47,7 +47,7 @@
|
||||
Additionally, it applies stricter check levels by default,
|
||||
since the dump output will be used as an actual zone file
|
||||
loaded by <span><strong class="command">named</strong></span>.
|
||||
When manaully specified otherwise, the check levels must at
|
||||
When manually specified otherwise, the check levels must at
|
||||
least be as strict as those specified in the
|
||||
<span><strong class="command">named</strong></span> configuration file.
|
||||
</p>
|
||||
@@ -79,7 +79,7 @@
|
||||
<dt><span class="term">-i <em class="replaceable"><code>mode</code></em></span></dt>
|
||||
<dd>
|
||||
<p>
|
||||
Perform post load zone integrity checks. Possible modes are
|
||||
Perform post-load zone integrity checks. Possible modes are
|
||||
<span><strong class="command">"full"</strong></span> (default),
|
||||
<span><strong class="command">"full-sibling"</strong></span>,
|
||||
<span><strong class="command">"local"</strong></span>,
|
||||
@@ -101,7 +101,7 @@
|
||||
<p>
|
||||
Mode <span><strong class="command">"full"</strong></span> checks that delegation NS
|
||||
records refer to A or AAAA record (both in-zone and out-of-zone
|
||||
hostnames). It also checks that glue addresses records
|
||||
hostnames). It also checks that glue address records
|
||||
in the zone match those advertised by the child.
|
||||
Mode <span><strong class="command">"local"</strong></span> only checks NS records which
|
||||
refer to in-zone hostnames or that some required glue exists,
|
||||
@@ -195,7 +195,7 @@
|
||||
</p></dd>
|
||||
<dt><span class="term">-t <em class="replaceable"><code>directory</code></em></span></dt>
|
||||
<dd><p>
|
||||
chroot to <code class="filename">directory</code> so that
|
||||
Chroot to <code class="filename">directory</code> so that
|
||||
include
|
||||
directives in the configuration file are processed as if
|
||||
run by a similarly chrooted named.
|
||||
@@ -242,12 +242,13 @@
|
||||
<div class="refsect1" lang="en">
|
||||
<a name="id2544311"></a><h2>SEE ALSO</h2>
|
||||
<p><span class="citerefentry"><span class="refentrytitle">named</span>(8)</span>,
|
||||
<span class="citerefentry"><span class="refentrytitle">named-checkconf</span>(8)</span>,
|
||||
<em class="citetitle">RFC 1035</em>,
|
||||
<em class="citetitle">BIND 9 Administrator Reference Manual</em>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="refsect1" lang="en">
|
||||
<a name="id2544336"></a><h2>AUTHOR</h2>
|
||||
<a name="id2544344"></a><h2>AUTHOR</h2>
|
||||
<p><span class="corpauthor">Internet Systems Consortium</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
+13
-13
@@ -13,7 +13,7 @@
|
||||
.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
.\" PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $Id: dig.1,v 1.23.18.19 2007/01/30 00:23:44 marka Exp $
|
||||
.\" $Id: dig.1,v 1.23.18.22 2007/05/16 06:11:27 marka Exp $
|
||||
.\"
|
||||
.hy 0
|
||||
.ad l
|
||||
@@ -50,7 +50,7 @@ Although
|
||||
\fBdig\fR
|
||||
is normally used with command\-line arguments, it also has a batch mode of operation for reading lookup requests from a file. A brief summary of its command\-line arguments and options is printed when the
|
||||
\fB\-h\fR
|
||||
option is given. Unlike earlier versions, the BIND9 implementation of
|
||||
option is given. Unlike earlier versions, the BIND 9 implementation of
|
||||
\fBdig\fR
|
||||
allows multiple lookups to be issued from the command line.
|
||||
.PP
|
||||
@@ -128,14 +128,14 @@ The default query class (IN for internet) is overridden by the
|
||||
\fB\-c\fR
|
||||
option.
|
||||
\fIclass\fR
|
||||
is any valid class, such as HS for Hesiod records or CH for CHAOSNET records.
|
||||
is any valid class, such as HS for Hesiod records or CH for Chaosnet records.
|
||||
.PP
|
||||
The
|
||||
\fB\-f\fR
|
||||
option makes
|
||||
\fBdig \fR
|
||||
operate in batch mode by reading a list of lookup requests to process from the file
|
||||
\fIfilename\fR. The file contains a number of queries, one per line. Each entry in the file should be organised in the same way they would be presented as queries to
|
||||
\fIfilename\fR. The file contains a number of queries, one per line. Each entry in the file should be organized in the same way they would be presented as queries to
|
||||
\fBdig\fR
|
||||
using the command\-line interface.
|
||||
.PP
|
||||
@@ -160,7 +160,7 @@ to only use IPv6 query transport.
|
||||
The
|
||||
\fB\-t\fR
|
||||
option sets the query type to
|
||||
\fItype\fR. It can be any valid query type which is supported in BIND9. The default query type "A", unless the
|
||||
\fItype\fR. It can be any valid query type which is supported in BIND 9. The default query type is "A", unless the
|
||||
\fB\-x\fR
|
||||
option is supplied to indicate a reverse lookup. A zone transfer can be requested by specifying a type of AXFR. When an incremental zone transfer (IXFR) is required,
|
||||
\fItype\fR
|
||||
@@ -171,11 +171,11 @@ ixfr=N. The incremental zone transfer will contain the changes made to the zone
|
||||
The
|
||||
\fB\-q\fR
|
||||
option sets the query name to
|
||||
\fIname\fR. This useful do distingish the
|
||||
\fIname\fR. This useful do distinguish the
|
||||
\fIname\fR
|
||||
from other arguments.
|
||||
.PP
|
||||
Reverse lookups \- mapping addresses to names \- are simplified by the
|
||||
Reverse lookups \(em mapping addresses to names \(em are simplified by the
|
||||
\fB\-x\fR
|
||||
option.
|
||||
\fIaddr\fR
|
||||
@@ -228,7 +228,7 @@ to negate the meaning of that keyword. Other keywords assign values to options l
|
||||
.PP
|
||||
\fB+[no]tcp\fR
|
||||
.RS 4
|
||||
Use [do not use] TCP when querying name servers. The default behaviour is to use UDP unless an AXFR or IXFR query is requested, in which case a TCP connection is used.
|
||||
Use [do not use] TCP when querying name servers. The default behavior is to use UDP unless an AXFR or IXFR query is requested, in which case a TCP connection is used.
|
||||
.RE
|
||||
.PP
|
||||
\fB+[no]vc\fR
|
||||
@@ -330,7 +330,7 @@ makes iterative queries to resolve the name being looked up. It will follow refe
|
||||
.PP
|
||||
\fB+[no]cmd\fR
|
||||
.RS 4
|
||||
toggles the printing of the initial comment in the output identifying the version of
|
||||
Toggles the printing of the initial comment in the output identifying the version of
|
||||
\fBdig\fR
|
||||
and the query options that have been applied. This comment is printed by default.
|
||||
.RE
|
||||
@@ -354,7 +354,7 @@ Toggle the display of comment lines in the output. The default is to print comme
|
||||
.PP
|
||||
\fB+[no]stats\fR
|
||||
.RS 4
|
||||
This query option toggles the printing of statistics: when the query was made, the size of the reply and so on. The default behaviour is to print the query statistics.
|
||||
This query option toggles the printing of statistics: when the query was made, the size of the reply and so on. The default behavior is to print the query statistics.
|
||||
.RE
|
||||
.PP
|
||||
\fB+[no]qr\fR
|
||||
@@ -391,7 +391,7 @@ Set or clear all display flags.
|
||||
.RS 4
|
||||
Sets the timeout for a query to
|
||||
\fIT\fR
|
||||
seconds. The default time out is 5 seconds. An attempt to set
|
||||
seconds. The default timeout is 5 seconds. An attempt to set
|
||||
\fIT\fR
|
||||
to less than 1 will result in a query timeout of 1 second being applied.
|
||||
.RE
|
||||
@@ -451,7 +451,7 @@ output.
|
||||
.PP
|
||||
\fB+[no]fail\fR
|
||||
.RS 4
|
||||
Do not try the next server if you receive a SERVFAIL. The default is to not try the next server which is the reverse of normal stub resolver behaviour.
|
||||
Do not try the next server if you receive a SERVFAIL. The default is to not try the next server which is the reverse of normal stub resolver behavior.
|
||||
.RE
|
||||
.PP
|
||||
\fB+[no]besteffort\fR
|
||||
@@ -487,7 +487,7 @@ Requires dig be compiled with \-DDIG_SIGCHASE.
|
||||
.PP
|
||||
\fB+[no]topdown\fR
|
||||
.RS 4
|
||||
When chasing DNSSEC signature chains perform a top down validation. Requires dig be compiled with \-DDIG_SIGCHASE.
|
||||
When chasing DNSSEC signature chains perform a top\-down validation. Requires dig be compiled with \-DDIG_SIGCHASE.
|
||||
.RE
|
||||
.SH "MULTIPLE QUERIES"
|
||||
.PP
|
||||
|
||||
+59
-67
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2000-2003 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: dig.c,v 1.186.18.26 2006/07/21 23:52:21 marka Exp $ */
|
||||
/* $Id: dig.c,v 1.186.18.29 2007/08/28 07:19:55 tbox Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@@ -650,42 +650,6 @@ printgreeting(int argc, char **argv, dig_lookup_t *lookup) {
|
||||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
* Reorder an argument list so that server names all come at the end.
|
||||
* This is a bit of a hack, to allow batch-mode processing to properly
|
||||
* handle the server options.
|
||||
*/
|
||||
static void
|
||||
reorder_args(int argc, char *argv[]) {
|
||||
int i, j;
|
||||
char *ptr;
|
||||
int end;
|
||||
|
||||
debug("reorder_args()");
|
||||
end = argc - 1;
|
||||
while (argv[end][0] == '@') {
|
||||
end--;
|
||||
if (end == 0)
|
||||
return;
|
||||
}
|
||||
debug("arg[end]=%s", argv[end]);
|
||||
for (i = 1; i < end - 1; i++) {
|
||||
if (argv[i][0] == '@') {
|
||||
debug("arg[%d]=%s", i, argv[i]);
|
||||
ptr = argv[i];
|
||||
for (j = i + 1; j < end; j++) {
|
||||
debug("Moving %s to %d", argv[j], j - 1);
|
||||
argv[j - 1] = argv[j];
|
||||
}
|
||||
debug("moving %s to end, %d", ptr, end - 1);
|
||||
argv[end - 1] = ptr;
|
||||
end--;
|
||||
if (end < 1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static isc_uint32_t
|
||||
parse_uint(char *arg, const char *desc, isc_uint32_t max) {
|
||||
isc_result_t result;
|
||||
@@ -1104,7 +1068,9 @@ static const char *single_dash_opts = "46dhimnv";
|
||||
static const char *dash_opts = "46bcdfhikmnptvyx";
|
||||
static isc_boolean_t
|
||||
dash_option(char *option, char *next, dig_lookup_t **lookup,
|
||||
isc_boolean_t *open_type_class, isc_boolean_t config_only)
|
||||
isc_boolean_t *open_type_class, isc_boolean_t *need_clone,
|
||||
isc_boolean_t config_only, int argc, char **argv,
|
||||
isc_boolean_t *firstarg)
|
||||
{
|
||||
char opt, *value, *ptr, *ptr2, *ptr3;
|
||||
isc_result_t result;
|
||||
@@ -1241,14 +1207,20 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
|
||||
return (value_from_next);
|
||||
case 'q':
|
||||
if (!config_only) {
|
||||
(*lookup) = clone_lookup(default_lookup,
|
||||
ISC_TRUE);
|
||||
if (*need_clone)
|
||||
(*lookup) = clone_lookup(default_lookup,
|
||||
ISC_TRUE);
|
||||
*need_clone = ISC_TRUE;
|
||||
strncpy((*lookup)->textname, value,
|
||||
sizeof((*lookup)->textname));
|
||||
(*lookup)->textname[sizeof((*lookup)->textname)-1]=0;
|
||||
(*lookup)->trace_root = ISC_TF((*lookup)->trace ||
|
||||
(*lookup)->ns_search_only);
|
||||
(*lookup)->new_search = ISC_TRUE;
|
||||
if (*firstarg) {
|
||||
printgreeting(argc, argv, *lookup);
|
||||
*firstarg = ISC_FALSE;
|
||||
}
|
||||
ISC_LIST_APPEND(lookup_list, (*lookup), link);
|
||||
debug("looking up %s", (*lookup)->textname);
|
||||
}
|
||||
@@ -1376,7 +1348,9 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
|
||||
keysecret[sizeof(keysecret)-1]=0;
|
||||
return (value_from_next);
|
||||
case 'x':
|
||||
*lookup = clone_lookup(default_lookup, ISC_TRUE);
|
||||
if (*need_clone)
|
||||
*lookup = clone_lookup(default_lookup, ISC_TRUE);
|
||||
*need_clone = ISC_TRUE;
|
||||
if (get_reverse(textname, sizeof(textname), value,
|
||||
ip6_int, ISC_FALSE) == ISC_R_SUCCESS) {
|
||||
strncpy((*lookup)->textname, textname,
|
||||
@@ -1390,6 +1364,10 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
|
||||
if (!(*lookup)->rdclassset)
|
||||
(*lookup)->rdclass = dns_rdataclass_in;
|
||||
(*lookup)->new_search = ISC_TRUE;
|
||||
if (*firstarg) {
|
||||
printgreeting(argc, argv, *lookup);
|
||||
*firstarg = ISC_FALSE;
|
||||
}
|
||||
ISC_LIST_APPEND(lookup_list, *lookup, link);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid IP address %s\n", value);
|
||||
@@ -1481,6 +1459,8 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
char rcfile[256];
|
||||
#endif
|
||||
char *input;
|
||||
int i;
|
||||
isc_boolean_t need_clone = ISC_TRUE;
|
||||
|
||||
/*
|
||||
* The semantics for parsing the args is a bit complex; if
|
||||
@@ -1528,7 +1508,9 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
bargv[0] = argv[0];
|
||||
argv0 = argv[0];
|
||||
|
||||
reorder_args(bargc, (char **)bargv);
|
||||
for(i = 0; i < bargc; i++)
|
||||
debug(".digrc argv %d: %s",
|
||||
i, bargv[i]);
|
||||
parse_args(ISC_TRUE, ISC_TRUE, bargc,
|
||||
(char **)bargv);
|
||||
}
|
||||
@@ -1537,7 +1519,12 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
#endif
|
||||
}
|
||||
|
||||
lookup = default_lookup;
|
||||
if (is_batchfile && !config_only) {
|
||||
/* Processing '-f batchfile'. */
|
||||
lookup = clone_lookup(default_lookup, ISC_TRUE);
|
||||
need_clone = ISC_FALSE;
|
||||
} else
|
||||
lookup = default_lookup;
|
||||
|
||||
rc = argc;
|
||||
rv = argv;
|
||||
@@ -1554,14 +1541,16 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
if (rc <= 1) {
|
||||
if (dash_option(&rv[0][1], NULL,
|
||||
&lookup, &open_type_class,
|
||||
config_only)) {
|
||||
&need_clone, config_only,
|
||||
argc, argv, &firstarg)) {
|
||||
rc--;
|
||||
rv++;
|
||||
}
|
||||
} else {
|
||||
if (dash_option(&rv[0][1], rv[1],
|
||||
&lookup, &open_type_class,
|
||||
config_only)) {
|
||||
&need_clone, config_only,
|
||||
argc, argv, &firstarg)) {
|
||||
rc--;
|
||||
rv++;
|
||||
}
|
||||
@@ -1629,21 +1618,29 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config_only) {
|
||||
lookup = clone_lookup(default_lookup,
|
||||
ISC_TRUE);
|
||||
if (need_clone)
|
||||
lookup = clone_lookup(default_lookup,
|
||||
ISC_TRUE);
|
||||
need_clone = ISC_TRUE;
|
||||
strncpy(lookup->textname, rv[0],
|
||||
sizeof(lookup->textname));
|
||||
lookup->textname[sizeof(lookup->textname)-1]=0;
|
||||
lookup->trace_root = ISC_TF(lookup->trace ||
|
||||
lookup->ns_search_only);
|
||||
lookup->new_search = ISC_TRUE;
|
||||
if (firstarg) {
|
||||
printgreeting(argc, argv, lookup);
|
||||
firstarg = ISC_FALSE;
|
||||
}
|
||||
ISC_LIST_APPEND(lookup_list, lookup, link);
|
||||
debug("looking up %s", lookup->textname);
|
||||
}
|
||||
/* XXX Error message */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a batchfile, seed the lookup list with the
|
||||
* first entry, then trust the callback in dighost_shutdown
|
||||
@@ -1678,15 +1675,20 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
bargv[0] = argv[0];
|
||||
argv0 = argv[0];
|
||||
|
||||
reorder_args(bargc, (char **)bargv);
|
||||
for(i = 0; i < bargc; i++)
|
||||
debug("batch argv %d: %s", i, bargv[i]);
|
||||
parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If no lookup specified, search for root
|
||||
*/
|
||||
if ((lookup_list.head == NULL) && !config_only) {
|
||||
lookup = clone_lookup(default_lookup, ISC_TRUE);
|
||||
if (need_clone)
|
||||
lookup = clone_lookup(default_lookup, ISC_TRUE);
|
||||
need_clone = ISC_TRUE;
|
||||
lookup->trace_root = ISC_TF(lookup->trace ||
|
||||
lookup->ns_search_only);
|
||||
lookup->new_search = ISC_TRUE;
|
||||
@@ -1698,10 +1700,9 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
|
||||
firstarg = ISC_FALSE;
|
||||
}
|
||||
ISC_LIST_APPEND(lookup_list, lookup, link);
|
||||
} else if (!config_only && firstarg) {
|
||||
printgreeting(argc, argv, lookup);
|
||||
firstarg = ISC_FALSE;
|
||||
}
|
||||
if (!need_clone)
|
||||
destroy_lookup(lookup);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1715,7 +1716,7 @@ dighost_shutdown(void) {
|
||||
int bargc;
|
||||
char *bargv[16];
|
||||
char *input;
|
||||
|
||||
int i;
|
||||
|
||||
if (batchname == NULL) {
|
||||
isc_app_shutdown();
|
||||
@@ -1743,7 +1744,8 @@ dighost_shutdown(void) {
|
||||
|
||||
bargv[0] = argv0;
|
||||
|
||||
reorder_args(bargc, (char **)bargv);
|
||||
for(i = 0; i < bargc; i++)
|
||||
debug("batch argv %d: %s", i, bargv[i]);
|
||||
parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
|
||||
start_lookup();
|
||||
} else {
|
||||
@@ -1759,7 +1761,6 @@ dighost_shutdown(void) {
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
isc_result_t result;
|
||||
dig_server_t *s, *s2;
|
||||
|
||||
ISC_LIST_INIT(lookup_list);
|
||||
ISC_LIST_INIT(server_list);
|
||||
@@ -1780,16 +1781,7 @@ main(int argc, char **argv) {
|
||||
result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
|
||||
check_result(result, "isc_app_onrun");
|
||||
isc_app_run();
|
||||
s = ISC_LIST_HEAD(default_lookup->my_server_list);
|
||||
while (s != NULL) {
|
||||
debug("freeing server %p belonging to %p",
|
||||
s, default_lookup);
|
||||
s2 = s;
|
||||
s = ISC_LIST_NEXT(s, link);
|
||||
ISC_LIST_DEQUEUE(default_lookup->my_server_list, s2, link);
|
||||
isc_mem_free(mctx, s2);
|
||||
}
|
||||
isc_mem_free(mctx, default_lookup);
|
||||
destroy_lookup(default_lookup);
|
||||
if (batchname != NULL) {
|
||||
if (batchfp != stdin)
|
||||
fclose(batchfp);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
- Copyright (C) 2000-2003 Internet Software Consortium.
|
||||
-
|
||||
- Permission to use, copy, modify, and distribute this software for any
|
||||
- Permission to use, copy, modify, and/or distribute this software for any
|
||||
- purpose with or without fee is hereby granted, provided that the above
|
||||
- copyright notice and this permission notice appear in all copies.
|
||||
-
|
||||
@@ -18,7 +18,7 @@
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- $Id: dig.docbook,v 1.17.18.17 2007/01/29 23:57:20 marka Exp $ -->
|
||||
<!-- $Id: dig.docbook,v 1.17.18.21 2007/08/28 07:19:55 tbox Exp $ -->
|
||||
<refentry id="man.dig">
|
||||
|
||||
<refentryinfo>
|
||||
@@ -104,7 +104,7 @@
|
||||
arguments, it also has a batch mode of operation for reading lookup
|
||||
requests from a file. A brief summary of its command-line arguments
|
||||
and options is printed when the <option>-h</option> option is given.
|
||||
Unlike earlier versions, the BIND9 implementation of
|
||||
Unlike earlier versions, the BIND 9 implementation of
|
||||
<command>dig</command> allows multiple lookups to be issued
|
||||
from the
|
||||
command line.
|
||||
@@ -216,7 +216,7 @@
|
||||
The default query class (IN for internet) is overridden by the
|
||||
<option>-c</option> option. <parameter>class</parameter> is
|
||||
any valid
|
||||
class, such as HS for Hesiod records or CH for CHAOSNET records.
|
||||
class, such as HS for Hesiod records or CH for Chaosnet records.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -225,7 +225,7 @@
|
||||
in batch mode by reading a list of lookup requests to process from the
|
||||
file <parameter>filename</parameter>. The file contains a
|
||||
number of
|
||||
queries, one per line. Each entry in the file should be organised in
|
||||
queries, one per line. Each entry in the file should be organized in
|
||||
the same way they would be presented as queries to
|
||||
<command>dig</command> using the command-line interface.
|
||||
</para>
|
||||
@@ -251,7 +251,7 @@
|
||||
The <option>-t</option> option sets the query type to
|
||||
<parameter>type</parameter>. It can be any valid query type
|
||||
which is
|
||||
supported in BIND9. The default query type "A", unless the
|
||||
supported in BIND 9. The default query type is "A", unless the
|
||||
<option>-x</option> option is supplied to indicate a reverse lookup.
|
||||
A zone transfer can be requested by specifying a type of AXFR. When
|
||||
an incremental zone transfer (IXFR) is required,
|
||||
@@ -263,12 +263,12 @@
|
||||
|
||||
<para>
|
||||
The <option>-q</option> option sets the query name to
|
||||
<parameter>name</parameter>. This useful do distingish the
|
||||
<parameter>name</parameter>. This useful do distinguish the
|
||||
<parameter>name</parameter> from other arguments.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Reverse lookups - mapping addresses to names - are simplified by the
|
||||
Reverse lookups — mapping addresses to names — are simplified by the
|
||||
<option>-x</option> option. <parameter>addr</parameter> is
|
||||
an IPv4
|
||||
address in dotted-decimal notation, or a colon-delimited IPv6 address.
|
||||
@@ -343,7 +343,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use [do not use] TCP when querying name servers. The default
|
||||
behaviour is to use UDP unless an AXFR or IXFR query is
|
||||
behavior is to use UDP unless an AXFR or IXFR query is
|
||||
requested, in
|
||||
which case a TCP connection is used.
|
||||
</para>
|
||||
@@ -536,7 +536,7 @@
|
||||
<term><option>+[no]cmd</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
toggles the printing of the initial comment in the output
|
||||
Toggles the printing of the initial comment in the output
|
||||
identifying
|
||||
the version of <command>dig</command> and the query
|
||||
options that have
|
||||
@@ -588,7 +588,7 @@
|
||||
This query option toggles the printing of statistics: when the
|
||||
query
|
||||
was made, the size of the reply and so on. The default
|
||||
behaviour is
|
||||
behavior is
|
||||
to print the query statistics.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -662,8 +662,8 @@
|
||||
<para>
|
||||
|
||||
Sets the timeout for a query to
|
||||
<parameter>T</parameter> seconds. The default time
|
||||
out is 5 seconds.
|
||||
<parameter>T</parameter> seconds. The default
|
||||
timeout is 5 seconds.
|
||||
An attempt to set <parameter>T</parameter> to less
|
||||
than 1 will result
|
||||
in a query timeout of 1 second being applied.
|
||||
@@ -763,7 +763,7 @@
|
||||
default is
|
||||
to not try the next server which is the reverse of normal stub
|
||||
resolver
|
||||
behaviour.
|
||||
behavior.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -822,7 +822,7 @@
|
||||
<term><option>+[no]topdown</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
When chasing DNSSEC signature chains perform a top down
|
||||
When chasing DNSSEC signature chains perform a top-down
|
||||
validation.
|
||||
Requires dig be compiled with -DDIG_SIGCHASE.
|
||||
</para>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
<!-- $Id: dig.html,v 1.13.18.25 2007/01/30 00:23:44 marka Exp $ -->
|
||||
<!-- $Id: dig.html,v 1.13.18.28 2007/05/16 06:11:27 marka Exp $ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
@@ -50,7 +50,7 @@
|
||||
arguments, it also has a batch mode of operation for reading lookup
|
||||
requests from a file. A brief summary of its command-line arguments
|
||||
and options is printed when the <code class="option">-h</code> option is given.
|
||||
Unlike earlier versions, the BIND9 implementation of
|
||||
Unlike earlier versions, the BIND 9 implementation of
|
||||
<span><strong class="command">dig</strong></span> allows multiple lookups to be issued
|
||||
from the
|
||||
command line.
|
||||
@@ -139,7 +139,7 @@
|
||||
The default query class (IN for internet) is overridden by the
|
||||
<code class="option">-c</code> option. <em class="parameter"><code>class</code></em> is
|
||||
any valid
|
||||
class, such as HS for Hesiod records or CH for CHAOSNET records.
|
||||
class, such as HS for Hesiod records or CH for Chaosnet records.
|
||||
</p>
|
||||
<p>
|
||||
The <code class="option">-f</code> option makes <span><strong class="command">dig </strong></span>
|
||||
@@ -147,7 +147,7 @@
|
||||
in batch mode by reading a list of lookup requests to process from the
|
||||
file <em class="parameter"><code>filename</code></em>. The file contains a
|
||||
number of
|
||||
queries, one per line. Each entry in the file should be organised in
|
||||
queries, one per line. Each entry in the file should be organized in
|
||||
the same way they would be presented as queries to
|
||||
<span><strong class="command">dig</strong></span> using the command-line interface.
|
||||
</p>
|
||||
@@ -170,7 +170,7 @@
|
||||
The <code class="option">-t</code> option sets the query type to
|
||||
<em class="parameter"><code>type</code></em>. It can be any valid query type
|
||||
which is
|
||||
supported in BIND9. The default query type "A", unless the
|
||||
supported in BIND 9. The default query type is "A", unless the
|
||||
<code class="option">-x</code> option is supplied to indicate a reverse lookup.
|
||||
A zone transfer can be requested by specifying a type of AXFR. When
|
||||
an incremental zone transfer (IXFR) is required,
|
||||
@@ -181,11 +181,11 @@
|
||||
</p>
|
||||
<p>
|
||||
The <code class="option">-q</code> option sets the query name to
|
||||
<em class="parameter"><code>name</code></em>. This useful do distingish the
|
||||
<em class="parameter"><code>name</code></em>. This useful do distinguish the
|
||||
<em class="parameter"><code>name</code></em> from other arguments.
|
||||
</p>
|
||||
<p>
|
||||
Reverse lookups - mapping addresses to names - are simplified by the
|
||||
Reverse lookups — mapping addresses to names — are simplified by the
|
||||
<code class="option">-x</code> option. <em class="parameter"><code>addr</code></em> is
|
||||
an IPv4
|
||||
address in dotted-decimal notation, or a colon-delimited IPv6 address.
|
||||
@@ -249,7 +249,7 @@
|
||||
<dt><span class="term"><code class="option">+[no]tcp</code></span></dt>
|
||||
<dd><p>
|
||||
Use [do not use] TCP when querying name servers. The default
|
||||
behaviour is to use UDP unless an AXFR or IXFR query is
|
||||
behavior is to use UDP unless an AXFR or IXFR query is
|
||||
requested, in
|
||||
which case a TCP connection is used.
|
||||
</p></dd>
|
||||
@@ -362,7 +362,7 @@
|
||||
</p></dd>
|
||||
<dt><span class="term"><code class="option">+[no]cmd</code></span></dt>
|
||||
<dd><p>
|
||||
toggles the printing of the initial comment in the output
|
||||
Toggles the printing of the initial comment in the output
|
||||
identifying
|
||||
the version of <span><strong class="command">dig</strong></span> and the query
|
||||
options that have
|
||||
@@ -394,7 +394,7 @@
|
||||
This query option toggles the printing of statistics: when the
|
||||
query
|
||||
was made, the size of the reply and so on. The default
|
||||
behaviour is
|
||||
behavior is
|
||||
to print the query statistics.
|
||||
</p></dd>
|
||||
<dt><span class="term"><code class="option">+[no]qr</code></span></dt>
|
||||
@@ -433,8 +433,8 @@
|
||||
<dd><p>
|
||||
|
||||
Sets the timeout for a query to
|
||||
<em class="parameter"><code>T</code></em> seconds. The default time
|
||||
out is 5 seconds.
|
||||
<em class="parameter"><code>T</code></em> seconds. The default
|
||||
timeout is 5 seconds.
|
||||
An attempt to set <em class="parameter"><code>T</code></em> to less
|
||||
than 1 will result
|
||||
in a query timeout of 1 second being applied.
|
||||
@@ -499,7 +499,7 @@
|
||||
default is
|
||||
to not try the next server which is the reverse of normal stub
|
||||
resolver
|
||||
behaviour.
|
||||
behavior.
|
||||
</p></dd>
|
||||
<dt><span class="term"><code class="option">+[no]besteffort</code></span></dt>
|
||||
<dd><p>
|
||||
@@ -535,7 +535,7 @@
|
||||
</dd>
|
||||
<dt><span class="term"><code class="option">+[no]topdown</code></span></dt>
|
||||
<dd><p>
|
||||
When chasing DNSSEC signature chains perform a top down
|
||||
When chasing DNSSEC signature chains perform a top-down
|
||||
validation.
|
||||
Requires dig be compiled with -DDIG_SIGCHASE.
|
||||
</p></dd>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2000-2003 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: dighost.c,v 1.259.18.39 2007/02/14 23:45:43 marka Exp $ */
|
||||
/* $Id: dighost.c,v 1.259.18.43 2007/08/28 07:19:55 tbox Exp $ */
|
||||
|
||||
/*! \file
|
||||
* \note
|
||||
@@ -144,6 +144,7 @@ static idn_result_t append_textname(char *name, const char *origin,
|
||||
static void idn_check_result(idn_result_t r, const char *msg);
|
||||
|
||||
#define MAXDLEN 256
|
||||
int idnoptions = 0;
|
||||
#endif
|
||||
|
||||
/*%
|
||||
@@ -1275,9 +1276,7 @@ clear_query(dig_query_t *query) {
|
||||
*/
|
||||
static isc_boolean_t
|
||||
try_clear_lookup(dig_lookup_t *lookup) {
|
||||
dig_server_t *s;
|
||||
dig_query_t *q;
|
||||
void *ptr;
|
||||
|
||||
REQUIRE(lookup != NULL);
|
||||
|
||||
@@ -1298,7 +1297,16 @@ try_clear_lookup(dig_lookup_t *lookup) {
|
||||
* At this point, we know there are no queries on the lookup,
|
||||
* so can make it go away also.
|
||||
*/
|
||||
debug("cleared");
|
||||
destroy_lookup(lookup);
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
destroy_lookup(dig_lookup_t *lookup) {
|
||||
dig_server_t *s;
|
||||
void *ptr;
|
||||
|
||||
debug("destroy");
|
||||
s = ISC_LIST_HEAD(lookup->my_server_list);
|
||||
while (s != NULL) {
|
||||
debug("freeing server %p belonging to %p", s, lookup);
|
||||
@@ -1323,7 +1331,6 @@ try_clear_lookup(dig_lookup_t *lookup) {
|
||||
dst_context_destroy(&lookup->tsigctx);
|
||||
|
||||
isc_mem_free(mctx, lookup);
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -1816,7 +1823,7 @@ setup_lookup(dig_lookup_t *lookup) {
|
||||
sizeof(utf8_textname));
|
||||
idn_check_result(mr, "append origin to textname");
|
||||
}
|
||||
mr = idn_encodename(IDN_LOCALMAP | IDN_NAMEPREP | IDN_ASCCHECK |
|
||||
mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
|
||||
IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
|
||||
idn_textname, sizeof(idn_textname));
|
||||
idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
|
||||
@@ -3891,7 +3898,7 @@ get_trusted_key(isc_mem_t *mctx)
|
||||
filename);
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
while (fgets(buf, 1500, fp) != NULL) {
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
result = opentmpkey(mctx,"tmp_file", &filetemp, &fptemp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fclose(fp);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
.\" PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $Id: host.1,v 1.14.18.13 2007/01/30 00:23:44 marka Exp $
|
||||
.\" $Id: host.1,v 1.14.18.14 2007/05/09 03:33:12 marka Exp $
|
||||
.\"
|
||||
.hy 0
|
||||
.ad l
|
||||
@@ -130,7 +130,7 @@ makes. This should mean that the name server receiving the query will not attemp
|
||||
\fB\-r\fR
|
||||
option enables
|
||||
\fBhost\fR
|
||||
to mimic the behaviour of a name server by making non\-recursive queries and expecting to receive answers to those queries that are usually referrals to other name servers.
|
||||
to mimic the behavior of a name server by making non\-recursive queries and expecting to receive answers to those queries that are usually referrals to other name servers.
|
||||
.PP
|
||||
By default
|
||||
\fBhost\fR
|
||||
@@ -152,7 +152,7 @@ The
|
||||
\fB\-t\fR
|
||||
option is used to select the query type.
|
||||
\fItype\fR
|
||||
can be any recognised query type: CNAME, NS, SOA, SIG, KEY, AXFR, etc. When no query type is specified,
|
||||
can be any recognized query type: CNAME, NS, SOA, SIG, KEY, AXFR, etc. When no query type is specified,
|
||||
\fBhost\fR
|
||||
automatically selects an appropriate query type. By default it looks for A records, but if the
|
||||
\fB\-C\fR
|
||||
@@ -185,7 +185,7 @@ The
|
||||
option tells
|
||||
\fBhost\fR
|
||||
\fInot\fR
|
||||
to send the query to the next nameserver if any server responds with a SERVFAIL response, which is the reverse of normal stub resolver behaviour.
|
||||
to send the query to the next nameserver if any server responds with a SERVFAIL response, which is the reverse of normal stub resolver behavior.
|
||||
.PP
|
||||
The
|
||||
\fB\-m\fR
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2000-2003 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
@@ -15,13 +15,25 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: host.c,v 1.94.18.14 2006/05/23 04:40:42 marka Exp $ */
|
||||
/* $Id: host.c,v 1.94.18.19 2007/08/28 07:19:55 tbox Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IDN
|
||||
#include <idn/result.h>
|
||||
#include <idn/log.h>
|
||||
#include <idn/resconf.h>
|
||||
#include <idn/api.h>
|
||||
#endif
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/commandline.h>
|
||||
#include <isc/netaddr.h>
|
||||
@@ -414,8 +426,10 @@ printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
|
||||
if (msg->rcode != 0) {
|
||||
char namestr[DNS_NAME_FORMATSIZE];
|
||||
dns_name_format(query->lookup->name, namestr, sizeof(namestr));
|
||||
printf("Host %s not found: %d(%s)\n", namestr,
|
||||
msg->rcode, rcodetext[msg->rcode]);
|
||||
printf("Host %s not found: %d(%s)\n",
|
||||
(msg->rcode != dns_rcode_nxdomain) ? namestr :
|
||||
query->lookup->textname, msg->rcode,
|
||||
rcodetext[msg->rcode]);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -569,6 +583,7 @@ pre_parse_args(int argc, char **argv) {
|
||||
while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) {
|
||||
switch (c) {
|
||||
case 'm':
|
||||
memdebugging = ISC_TRUE;
|
||||
if (strcasecmp("trace", isc_commandline_argument) == 0)
|
||||
isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
|
||||
else if (!strcasecmp("record",
|
||||
@@ -664,6 +679,9 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
|
||||
lookup->rdtype != dns_rdatatype_axfr)
|
||||
lookup->rdtype = rdtype;
|
||||
lookup->rdtypeset = ISC_TRUE;
|
||||
#ifdef WITH_IDN
|
||||
idnoptions = 0;
|
||||
#endif
|
||||
if (rdtype == dns_rdatatype_axfr) {
|
||||
/* -l -t any -v */
|
||||
list_type = dns_rdatatype_any;
|
||||
@@ -672,6 +690,13 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
|
||||
} else if (rdtype == dns_rdatatype_ixfr) {
|
||||
lookup->ixfr_serial = serial;
|
||||
list_type = rdtype;
|
||||
#ifdef WITH_IDN
|
||||
} else if (rdtype == dns_rdatatype_a ||
|
||||
rdtype == dns_rdatatype_aaaa ||
|
||||
rdtype == dns_rdatatype_mx) {
|
||||
idnoptions = IDN_ASCCHECK;
|
||||
list_type = rdtype;
|
||||
#endif
|
||||
} else
|
||||
list_type = rdtype;
|
||||
list_addresses = ISC_FALSE;
|
||||
@@ -814,6 +839,9 @@ main(int argc, char **argv) {
|
||||
ISC_LIST_INIT(search_list);
|
||||
|
||||
fatalexit = 1;
|
||||
#ifdef WITH_IDN
|
||||
idnoptions = IDN_ASCCHECK;
|
||||
#endif
|
||||
|
||||
debug("main()");
|
||||
progname = argv[0];
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
|
||||
- Copyright (C) 2000-2002 Internet Software Consortium.
|
||||
-
|
||||
- Permission to use, copy, modify, and distribute this software for any
|
||||
- Permission to use, copy, modify, and/or distribute this software for any
|
||||
- purpose with or without fee is hereby granted, provided that the above
|
||||
- copyright notice and this permission notice appear in all copies.
|
||||
-
|
||||
@@ -18,7 +18,7 @@
|
||||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- $Id: host.docbook,v 1.5.18.9 2007/01/29 23:57:20 marka Exp $ -->
|
||||
<!-- $Id: host.docbook,v 1.5.18.11 2007/08/28 07:19:55 tbox Exp $ -->
|
||||
<refentry id="man.host">
|
||||
|
||||
<refentryinfo>
|
||||
@@ -173,7 +173,7 @@
|
||||
attempt to resolve <parameter>name</parameter>. The
|
||||
<option>-r</option> option enables <command>host</command>
|
||||
to mimic
|
||||
the behaviour of a name server by making non-recursive queries and
|
||||
the behavior of a name server by making non-recursive queries and
|
||||
expecting to receive answers to those queries that are usually
|
||||
referrals to other name servers.
|
||||
</para>
|
||||
@@ -194,7 +194,7 @@
|
||||
|
||||
<para>
|
||||
The <option>-t</option> option is used to select the query type.
|
||||
<parameter>type</parameter> can be any recognised query
|
||||
<parameter>type</parameter> can be any recognized query
|
||||
type: CNAME,
|
||||
NS, SOA, SIG, KEY, AXFR, etc. When no query type is specified,
|
||||
<command>host</command> automatically selects an appropriate
|
||||
@@ -227,7 +227,7 @@
|
||||
The <option>-s</option> option tells <command>host</command>
|
||||
<emphasis>not</emphasis> to send the query to the next nameserver
|
||||
if any server responds with a SERVFAIL response, which is the
|
||||
reverse of normal stub resolver behaviour.
|
||||
reverse of normal stub resolver behavior.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
Loaded 100 of 1981 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user